From c5581a3899d412017fde939772761dd31520b5dd Mon Sep 17 00:00:00 2001 From: utas-raymondng Date: Fri, 31 May 2024 14:22:21 +1000 Subject: [PATCH 1/8] Tighten the object type --- .../esindexer/service/StacCollectionMapperService.java | 8 ++++---- .../main/java/au/org/aodn/esindexer/utils/BBoxUtils.java | 5 +++-- .../java/au/org/aodn/esindexer/utils/GeometryBase.java | 4 ++-- .../java/au/org/aodn/esindexer/utils/GeometryUtils.java | 5 +++-- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/indexer/src/main/java/au/org/aodn/esindexer/service/StacCollectionMapperService.java b/indexer/src/main/java/au/org/aodn/esindexer/service/StacCollectionMapperService.java index 2236adf2..674ad46c 100644 --- a/indexer/src/main/java/au/org/aodn/esindexer/service/StacCollectionMapperService.java +++ b/indexer/src/main/java/au/org/aodn/esindexer/service/StacCollectionMapperService.java @@ -666,8 +666,8 @@ protected List mapLanguages(MDMetadataType source) { protected R createGeometryItems( MDMetadataType source, - Function, R> exBoundingPolygonTypeHandler, - Function, R> exGeographicBoundingBoxTypeHandler) { + Function, R> exBoundingPolygonTypeHandler, + Function, R> exGeographicBoundingBoxTypeHandler) { List items = MapperUtils.findMDDataIdentificationType(source); if(!items.isEmpty()) { @@ -686,7 +686,7 @@ protected R createGeometryItems( for(EXExtentType e : ext) { try { // TODO: pay attention here - List rawInput = e.getGeographicElement() + List rawInput = e.getGeographicElement() .stream() .map(AbstractEXGeographicExtentPropertyType::getAbstractEXGeographicExtent) .filter(m -> m != null && (m.getValue() instanceof EXBoundingPolygonType || m.getValue() instanceof EXGeographicBoundingBoxType)) @@ -696,7 +696,7 @@ protected R createGeometryItems( return exBoundingPolygonType; } } else if (m.getValue() instanceof EXGeographicBoundingBoxType) { - return (EXGeographicBoundingBoxType) m.getValue(); + return m.getValue(); } return null; // Handle other cases or return appropriate default value }) diff --git a/indexer/src/main/java/au/org/aodn/esindexer/utils/BBoxUtils.java b/indexer/src/main/java/au/org/aodn/esindexer/utils/BBoxUtils.java index 323fe4c5..105fffc5 100644 --- a/indexer/src/main/java/au/org/aodn/esindexer/utils/BBoxUtils.java +++ b/indexer/src/main/java/au/org/aodn/esindexer/utils/BBoxUtils.java @@ -1,5 +1,6 @@ package au.org.aodn.esindexer.utils; +import au.org.aodn.metadata.iso19115_3_2018.AbstractEXGeographicExtentType; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.locationtech.jts.geom.*; @@ -11,13 +12,13 @@ public class BBoxUtils { protected static Logger logger = LogManager.getLogger(BBoxUtils.class); - public static List> createBBoxFromEXBoundingPolygonType(List rawInput) { + public static List> createBBoxFromEXBoundingPolygonType(List rawInput) { //TODO: avoid hardcode CRS, get it from document List polygons = GeometryBase.findPolygonsFromEXBoundingPolygonType(GeometryBase.COORDINATE_SYSTEM_CRS84, rawInput); return StacUtils.createStacBBox(polygons); } - public static List> createBBoxFromEXGeographicBoundingBoxType(List rawInput) { + public static List> createBBoxFromEXGeographicBoundingBoxType(List rawInput) { //TODO: avoid hardcode CRS, get it from document List polygons = GeometryBase.findPolygonsFromEXGeographicBoundingBoxType(GeometryBase.COORDINATE_SYSTEM_CRS84, rawInput); return StacUtils.createStacBBox(polygons); diff --git a/indexer/src/main/java/au/org/aodn/esindexer/utils/GeometryBase.java b/indexer/src/main/java/au/org/aodn/esindexer/utils/GeometryBase.java index 3a7094f5..ac7349b1 100644 --- a/indexer/src/main/java/au/org/aodn/esindexer/utils/GeometryBase.java +++ b/indexer/src/main/java/au/org/aodn/esindexer/utils/GeometryBase.java @@ -43,7 +43,7 @@ public static Envelope calculateBoundingBox(Envelope boundingBox, Polygon... pol return boundingBox; } - public static List findPolygonsFromEXBoundingPolygonType(String rawCRS, List rawInput) { + public static List findPolygonsFromEXBoundingPolygonType(String rawCRS, List rawInput) { List polygons = new ArrayList<>(); if(COORDINATE_SYSTEM_CRS84.equals(rawCRS)) { @@ -116,7 +116,7 @@ public static List findPolygonsFromEXBoundingPolygonType(String rawCRS, return polygons; } - public static List findPolygonsFromEXGeographicBoundingBoxType(String rawCRS, List rawInput) { + public static List findPolygonsFromEXGeographicBoundingBoxType(String rawCRS, List rawInput) { List polygons = new ArrayList<>(); if(COORDINATE_SYSTEM_CRS84.equals(rawCRS)) { diff --git a/indexer/src/main/java/au/org/aodn/esindexer/utils/GeometryUtils.java b/indexer/src/main/java/au/org/aodn/esindexer/utils/GeometryUtils.java index feb8a31f..dc7bf9a3 100644 --- a/indexer/src/main/java/au/org/aodn/esindexer/utils/GeometryUtils.java +++ b/indexer/src/main/java/au/org/aodn/esindexer/utils/GeometryUtils.java @@ -1,5 +1,6 @@ package au.org.aodn.esindexer.utils; +import au.org.aodn.metadata.iso19115_3_2018.AbstractEXGeographicExtentType; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -49,7 +50,7 @@ protected static Map createGeoJson(List polygons) { return null; } - public static Map createGeometryFromEXGeographicBoundingBoxType(List rawInput) { + public static Map createGeometryFromEXGeographicBoundingBoxType(List rawInput) { // The return polygon is in EPSG:4326, so we can call createGeoJson directly //TODO: avoid hardcode CRS, get it from document List polygons = GeometryBase.findPolygonsFromEXGeographicBoundingBoxType(GeometryBase.COORDINATE_SYSTEM_CRS84, rawInput); @@ -60,7 +61,7 @@ public static Map createGeometryFromEXGeographicBoundingBoxType(List raw return null; } - public static Map createGeometryFromFromEXBoundingPolygonType(List rawInput) { + public static Map createGeometryFromFromEXBoundingPolygonType(List rawInput) { // The return polygon is in EPSG:4326, so we can call createGeoJson directly //TODO: avoid hardcode CRS, get it from document List polygons = GeometryBase.findPolygonsFromEXBoundingPolygonType(GeometryBase.COORDINATE_SYSTEM_CRS84, rawInput); From 263f3993fc3c512fe990aba68dbac1537d7eed5f Mon Sep 17 00:00:00 2001 From: utas-raymondng Date: Fri, 31 May 2024 16:36:23 +1000 Subject: [PATCH 2/8] Check with fix to geo error --- .../service/StacCollectionMapperService.java | 96 +- .../org/aodn/esindexer/utils/BBoxUtils.java | 10 +- .../aodn/esindexer/utils/GeometryBase.java | 37 +- .../aodn/esindexer/utils/GeometryUtils.java | 82 +- .../org/aodn/esindexer/utils/StacUtils.java | 85 +- .../StacCollectionMapperServiceTests.java | 16 + .../test/resources/canned/sample8_stac.json | 4 +- indexer/src/test/resources/canned/sample9.xml | 931 ++++++++++++++++++ .../test/resources/canned/sample9_stac.json | 109 ++ 9 files changed, 1235 insertions(+), 135 deletions(-) create mode 100644 indexer/src/test/resources/canned/sample9.xml create mode 100644 indexer/src/test/resources/canned/sample9_stac.json diff --git a/indexer/src/main/java/au/org/aodn/esindexer/service/StacCollectionMapperService.java b/indexer/src/main/java/au/org/aodn/esindexer/service/StacCollectionMapperService.java index 674ad46c..eceb99e2 100644 --- a/indexer/src/main/java/au/org/aodn/esindexer/service/StacCollectionMapperService.java +++ b/indexer/src/main/java/au/org/aodn/esindexer/service/StacCollectionMapperService.java @@ -76,8 +76,7 @@ String mapUUID(MDMetadataType source) { List> mapExtentBbox(MDMetadataType source) { return createGeometryItems( source, - BBoxUtils::createBBoxFromEXBoundingPolygonType, - BBoxUtils::createBBoxFromEXGeographicBoundingBoxType + BBoxUtils::createBBoxFrom ); } @@ -209,11 +208,10 @@ List> mapSummariesTemporal(MDMetadataType source) { } @Named("mapSummaries.geometry") - Map mapSummariesGeometry(MDMetadataType source) { + Map mapSummariesGeometry(MDMetadataType source) { return createGeometryItems( source, - GeometryUtils::createGeometryFromFromEXBoundingPolygonType, - GeometryUtils::createGeometryFromEXGeographicBoundingBoxType + GeometryUtils::createGeometryFrom ); } @@ -666,55 +664,53 @@ protected List mapLanguages(MDMetadataType source) { protected R createGeometryItems( MDMetadataType source, - Function, R> exBoundingPolygonTypeHandler, - Function, R> exGeographicBoundingBoxTypeHandler) { + Function>, R> handler) { List items = MapperUtils.findMDDataIdentificationType(source); if(!items.isEmpty()) { - // Need to assert only 1 block contains our target - for(MDDataIdentificationType i : items) { - // We only concern geographicElement here - List ext = i.getExtent() - .stream() - .filter(f -> f.getAbstractExtent() != null) - .filter(f -> f.getAbstractExtent().getValue() != null) - .filter(f -> f.getAbstractExtent().getValue() instanceof EXExtentType) - .map(f -> (EXExtentType)f.getAbstractExtent().getValue()) - .filter(f -> f.getGeographicElement() != null) - .toList(); - - for(EXExtentType e : ext) { - try { - // TODO: pay attention here - List rawInput = e.getGeographicElement() - .stream() - .map(AbstractEXGeographicExtentPropertyType::getAbstractEXGeographicExtent) - .filter(m -> m != null && (m.getValue() instanceof EXBoundingPolygonType || m.getValue() instanceof EXGeographicBoundingBoxType)) - .map(m -> { - if (m.getValue() instanceof EXBoundingPolygonType exBoundingPolygonType) { - if (!exBoundingPolygonType.getPolygon().isEmpty() && exBoundingPolygonType.getPolygon().get(0).getAbstractGeometry() != null) { - return exBoundingPolygonType; - } - } else if (m.getValue() instanceof EXGeographicBoundingBoxType) { - return m.getValue(); - } - return null; // Handle other cases or return appropriate default value - }) - .filter(Objects::nonNull) // Filter out null values if any - .collect(Collectors.toList()); - - if (!rawInput.isEmpty() && rawInput.get(0) instanceof EXBoundingPolygonType) { - return exBoundingPolygonTypeHandler.apply(rawInput); - } - else if (!rawInput.isEmpty() && rawInput.get(0) instanceof EXGeographicBoundingBoxType) { - return exGeographicBoundingBoxTypeHandler.apply(rawInput); - } - } - catch (MappingValueException ex) { - logger.warn(ex.getMessage() + " for metadata record: " + this.mapUUID(source)); - } - } + if(items.size() > 1) { + logger.warn("!! More than 1 block of MDDataIdentificationType, data will be missed !!"); } + // Assume only 1 block of + // We only concern geographicElement here + List ext = items.get(0) + .getExtent() + .stream() + .filter(f -> f.getAbstractExtent() != null) + .filter(f -> f.getAbstractExtent().getValue() != null) + .filter(f -> f.getAbstractExtent().getValue() instanceof EXExtentType) + .map(f -> (EXExtentType) f.getAbstractExtent().getValue()) + .filter(f -> f.getGeographicElement() != null) + .toList(); + + // We want to get a list of item where each item contains multiple, (aka list) of + // (EXGeographicBoundingBoxType or EXBoundingPolygonType) + List> rawInput = ext.stream() + .map(EXExtentType::getGeographicElement) + .map(l -> + /* + l = List + For each AbstractEXGeographicExtentPropertyType, we get the tag that store the + coordinate, it is either a EXBoundingPolygonType or EXGeographicBoundingBoxType + */ + l.stream() + .map(AbstractEXGeographicExtentPropertyType::getAbstractEXGeographicExtent) + .filter(m -> m != null && (m.getValue() instanceof EXBoundingPolygonType || m.getValue() instanceof EXGeographicBoundingBoxType)) + .map(m -> { + if (m.getValue() instanceof EXBoundingPolygonType exBoundingPolygonType) { + if (!exBoundingPolygonType.getPolygon().isEmpty() && exBoundingPolygonType.getPolygon().get(0).getAbstractGeometry() != null) { + return exBoundingPolygonType; + } + } else if (m.getValue() instanceof EXGeographicBoundingBoxType) { + return m.getValue(); + } + return null; // Handle other cases or return appropriate default value + }) + .filter(Objects::nonNull) // Filter out null values if any + .toList() + ) + .toList(); + return handler.apply(rawInput); } return null; } diff --git a/indexer/src/main/java/au/org/aodn/esindexer/utils/BBoxUtils.java b/indexer/src/main/java/au/org/aodn/esindexer/utils/BBoxUtils.java index 105fffc5..6987d13f 100644 --- a/indexer/src/main/java/au/org/aodn/esindexer/utils/BBoxUtils.java +++ b/indexer/src/main/java/au/org/aodn/esindexer/utils/BBoxUtils.java @@ -12,15 +12,9 @@ public class BBoxUtils { protected static Logger logger = LogManager.getLogger(BBoxUtils.class); - public static List> createBBoxFromEXBoundingPolygonType(List rawInput) { + public static List> createBBoxFrom(List> rawInput) { //TODO: avoid hardcode CRS, get it from document - List polygons = GeometryBase.findPolygonsFromEXBoundingPolygonType(GeometryBase.COORDINATE_SYSTEM_CRS84, rawInput); - return StacUtils.createStacBBox(polygons); - } - - public static List> createBBoxFromEXGeographicBoundingBoxType(List rawInput) { - //TODO: avoid hardcode CRS, get it from document - List polygons = GeometryBase.findPolygonsFromEXGeographicBoundingBoxType(GeometryBase.COORDINATE_SYSTEM_CRS84, rawInput); + List> polygons = GeometryBase.findPolygonsFrom(GeometryBase.COORDINATE_SYSTEM_CRS84, rawInput); return StacUtils.createStacBBox(polygons); } } diff --git a/indexer/src/main/java/au/org/aodn/esindexer/utils/GeometryBase.java b/indexer/src/main/java/au/org/aodn/esindexer/utils/GeometryBase.java index ac7349b1..e47ab920 100644 --- a/indexer/src/main/java/au/org/aodn/esindexer/utils/GeometryBase.java +++ b/indexer/src/main/java/au/org/aodn/esindexer/utils/GeometryBase.java @@ -7,10 +7,7 @@ import org.opengis.referencing.FactoryException; import org.opengis.referencing.operation.TransformException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; public class GeometryBase { @@ -42,8 +39,36 @@ public static Envelope calculateBoundingBox(Envelope boundingBox, Polygon... pol return boundingBox; } + /** + * Ths function is use to extract a list of list of polygon from the XML, the coor can be store in box type of geometry type and hence + * we need to use a if state to correctly locate the coordinate based on type. + * + * The EXBoundingPolygonType should return a box while the EXGeographicBoundingBoxType will be a polygon, in either case + * this can fit into a polygon + * + * @param rawCRS + * @param rawInput - A list of list of AbstractEXGeographicExtentType, AbstractEXGeographicExtentType is a base type, and can be a bbox or geometry + * @return + */ + public static List> findPolygonsFrom(final String rawCRS, List> rawInput) { + return rawInput + .stream() + .map(r -> { + if(!r.isEmpty() && r.get(0) instanceof EXBoundingPolygonType) { + return findPolygonsFromEXBoundingPolygonType(rawCRS, r); + } + else if(!r.isEmpty() && r.get(0) instanceof EXGeographicBoundingBoxType) { + return findPolygonsFromEXGeographicBoundingBoxType(rawCRS, r); + } + // Some type not support so return null + return null; + }) + .filter(Objects::nonNull) + .filter(i -> !i.isEmpty()) + .toList(); + } - public static List findPolygonsFromEXBoundingPolygonType(String rawCRS, List rawInput) { + protected static List findPolygonsFromEXBoundingPolygonType(String rawCRS, List rawInput) { List polygons = new ArrayList<>(); if(COORDINATE_SYSTEM_CRS84.equals(rawCRS)) { @@ -116,7 +141,7 @@ public static List findPolygonsFromEXBoundingPolygonType(String rawCRS, return polygons; } - public static List findPolygonsFromEXGeographicBoundingBoxType(String rawCRS, List rawInput) { + protected static List findPolygonsFromEXGeographicBoundingBoxType(String rawCRS, List rawInput) { List polygons = new ArrayList<>(); if(COORDINATE_SYSTEM_CRS84.equals(rawCRS)) { diff --git a/indexer/src/main/java/au/org/aodn/esindexer/utils/GeometryUtils.java b/indexer/src/main/java/au/org/aodn/esindexer/utils/GeometryUtils.java index dc7bf9a3..4239fe2c 100644 --- a/indexer/src/main/java/au/org/aodn/esindexer/utils/GeometryUtils.java +++ b/indexer/src/main/java/au/org/aodn/esindexer/utils/GeometryUtils.java @@ -5,10 +5,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.geotools.geojson.geom.GeometryJSON; -import org.locationtech.jts.geom.GeometryFactory; -import org.locationtech.jts.geom.MultiPolygon; -import org.locationtech.jts.geom.Polygon; -import org.locationtech.jts.geom.PrecisionModel; +import org.locationtech.jts.geom.*; import java.io.IOException; import java.io.StringWriter; @@ -23,52 +20,71 @@ public class GeometryUtils { protected static GeometryFactory factory = new GeometryFactory(new PrecisionModel(), 4326); protected static ObjectMapper objectMapper = new ObjectMapper(); + + protected static boolean areCollinear(Coordinate p1, Coordinate p2, Coordinate p3) { + // Use the area of the triangle method to check collinearity + double area = p1.x * (p2.y - p3.y) + + p2.x * (p3.y - p1.y) + + p3.x * (p1.y - p2.y); + return area == 0; + } + + protected static boolean hasAtLeastThreeNonCollinearPoints(MultiPolygon multiPolygon) { + // Extract coordinates + Coordinate[] coordinates = multiPolygon.getCoordinates(); + + // Check all triplets of points + for (int i = 0; i < coordinates.length - 2; i++) { + for (int j = i + 1; j < coordinates.length - 1; j++) { + for (int k = j + 1; k < coordinates.length; k++) { + if (!areCollinear(coordinates[i], coordinates[j], coordinates[k])) { + return true; + } + } + } + } + return false; + } /** * * @param polygons - Assume to be EPSG:4326, as GeoJson always use this encoding. * @return */ - protected static Map createGeoJson(List polygons) { + protected static Map createGeoJson(List> polygons) { if(!polygons.isEmpty()) { - try (StringWriter writer = new StringWriter()) { - MultiPolygon multiPolygon = new MultiPolygon(polygons.toArray(new Polygon[polygons.size()]), factory); - GeometryJSON geometryJson = new GeometryJSON(); - geometryJson.write(multiPolygon, writer); + // Convert list> to list + List reduced = polygons.stream().flatMap(List::stream).toList(); + MultiPolygon multiPolygon = new MultiPolygon(reduced.toArray(new Polygon[0]), factory); - Map values = objectMapper.readValue(writer.toString(), HashMap.class); + // Some bad data just create a line which will cause elastic polygon failed + if(hasAtLeastThreeNonCollinearPoints(multiPolygon)) { + try (StringWriter writer = new StringWriter()) { - logger.debug("Created geometry {}", values); - return values; - } - catch (IOException e) { - logger.error("Error create geometry", e); - return null; - } - } - return null; - } + GeometryJSON geometryJson = new GeometryJSON(); + geometryJson.write(multiPolygon, writer); - public static Map createGeometryFromEXGeographicBoundingBoxType(List rawInput) { - // The return polygon is in EPSG:4326, so we can call createGeoJson directly - //TODO: avoid hardcode CRS, get it from document - List polygons = GeometryBase.findPolygonsFromEXGeographicBoundingBoxType(GeometryBase.COORDINATE_SYSTEM_CRS84, rawInput); + Map values = objectMapper.readValue(writer.toString(), HashMap.class); - if (polygons != null && !polygons.isEmpty()) { - return createGeoJson(polygons); + logger.debug("Created geometry {}", values); + return values; + } catch (IOException e) { + logger.error("Error create geometry", e); + return null; + } + } + else { + logger.warn("Polygon invalid, less than 3 non collinear points, this cannot store in Elastic Search"); + } } return null; } - public static Map createGeometryFromFromEXBoundingPolygonType(List rawInput) { + public static Map createGeometryFrom(List> rawInput) { // The return polygon is in EPSG:4326, so we can call createGeoJson directly //TODO: avoid hardcode CRS, get it from document - List polygons = GeometryBase.findPolygonsFromEXBoundingPolygonType(GeometryBase.COORDINATE_SYSTEM_CRS84, rawInput); - - if (polygons != null && !polygons.isEmpty()) { - return createGeoJson(polygons); - } - return null; + List> polygons = GeometryBase.findPolygonsFrom(GeometryBase.COORDINATE_SYSTEM_CRS84, rawInput); + return (polygons != null && !polygons.isEmpty()) ? createGeoJson(polygons) : null; } } diff --git a/indexer/src/main/java/au/org/aodn/esindexer/utils/StacUtils.java b/indexer/src/main/java/au/org/aodn/esindexer/utils/StacUtils.java index ee08298e..9e5193fd 100644 --- a/indexer/src/main/java/au/org/aodn/esindexer/utils/StacUtils.java +++ b/indexer/src/main/java/au/org/aodn/esindexer/utils/StacUtils.java @@ -11,6 +11,8 @@ import java.math.RoundingMode; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + /* According to spec https://github.com/radiantearth/stac-spec/blob/master/collection-spec/collection-spec.md @@ -41,49 +43,60 @@ public class StacUtils { /** * - * @param polygons - Assume to be EPSG:4326 as this is what GeoJson use + * @param listOfPolygons - Assume to be EPSG:4326 as this is what GeoJson use * @return */ - public static List> createStacBBox(List polygons) { - if(polygons != null) { - Envelope envelope = new Envelope(); - try { - for (Polygon polygon : polygons) { - // Add polygon one by one to extend the overall bounding box area, this is requirement - // of STAC to have an overall bounding box of all smaller area as the first bbox in the list. - if (polygon != null) { - envelope.expandToInclude(polygon.getEnvelopeInternal()); - } - } + public static List> createStacBBox(List> listOfPolygons) { + List> result = new ArrayList<>(); - if (!polygons.isEmpty()) { - // If it didn't contain polygon, then the envelope is just the initial empty object and thus invalid. - List> result = new ArrayList<>(); - result.add(List.of( - BigDecimal.valueOf(envelope.getMinX()).setScale(scale, RoundingMode.HALF_UP), - BigDecimal.valueOf(envelope.getMinY()).setScale(scale, RoundingMode.HALF_UP), - BigDecimal.valueOf(envelope.getMaxX()).setScale(scale, RoundingMode.HALF_UP), - BigDecimal.valueOf(envelope.getMaxY()).setScale(scale, RoundingMode.HALF_UP))); - - for (Polygon p : polygons) { - List points = new ArrayList<>(); - for (Coordinate c : p.getCoordinates()) { - points.addAll(List.of( - BigDecimal.valueOf(c.getX()).setScale(scale, RoundingMode.HALF_UP), - BigDecimal.valueOf(c.getY()).setScale(scale, RoundingMode.HALF_UP) - )); + if(listOfPolygons != null) { + final Envelope overallBoundingBox = new Envelope(); + final AtomicBoolean hasBoundingBoxUpdate = new AtomicBoolean(false); + listOfPolygons + .forEach(polygons -> { + for (Polygon polygon : polygons) { + // Add polygon one by one to expand the overall bounding box area, this is requirement + // of STAC to have an overall bounding box of all smaller area as the first bbox in the list. + if (polygon != null) { + overallBoundingBox.expandToInclude(polygon.getEnvelopeInternal()); + hasBoundingBoxUpdate.set(true); + } } - result.add(points); + }); + + // Now write the first box to the head of list only if we have at least on polygon exist, if no polygon + // exist then we can skip the reset of operation + if(hasBoundingBoxUpdate.get()) { + result.add(List.of( + BigDecimal.valueOf(overallBoundingBox.getMinX()).setScale(scale, RoundingMode.HALF_UP), + BigDecimal.valueOf(overallBoundingBox.getMinY()).setScale(scale, RoundingMode.HALF_UP), + BigDecimal.valueOf(overallBoundingBox.getMaxX()).setScale(scale, RoundingMode.HALF_UP), + BigDecimal.valueOf(overallBoundingBox.getMaxY()).setScale(scale, RoundingMode.HALF_UP))); + + for (List polygons : listOfPolygons) { + final Envelope individualEnvelope = new Envelope(); + + if (!polygons.isEmpty()) { + for (Polygon p : polygons) { + if (p != null) { + individualEnvelope.expandToInclude(p.getEnvelopeInternal()); + } + } + result.add(List.of( + BigDecimal.valueOf(individualEnvelope.getMinX()).setScale(scale, RoundingMode.HALF_UP), + BigDecimal.valueOf(individualEnvelope.getMinY()).setScale(scale, RoundingMode.HALF_UP), + BigDecimal.valueOf(individualEnvelope.getMaxX()).setScale(scale, RoundingMode.HALF_UP), + BigDecimal.valueOf(individualEnvelope.getMaxY()).setScale(scale, RoundingMode.HALF_UP))); + } - return result; - } else { - logger.warn("No applicable BBOX calculation found"); - return new ArrayList<>(); } - } catch (Exception e) { - logger.error("Error processing", e); } } - return new ArrayList<>(); + + if(result.isEmpty()) { + logger.warn("No applicable BBOX calculation found"); + } + + return result; } } diff --git a/indexer/src/test/java/au/org/aodn/esindexer/service/StacCollectionMapperServiceTests.java b/indexer/src/test/java/au/org/aodn/esindexer/service/StacCollectionMapperServiceTests.java index a999430e..956d29af 100644 --- a/indexer/src/test/java/au/org/aodn/esindexer/service/StacCollectionMapperServiceTests.java +++ b/indexer/src/test/java/au/org/aodn/esindexer/service/StacCollectionMapperServiceTests.java @@ -150,6 +150,22 @@ public void verifyPointOfContactCorrect() throws IOException, JAXBException { // and now we can use it to compare expected result. Map content = objectMapper.readValue(lastRequest.get().document().toString(), Map.class); String out = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(content); + log.info(out); + assertEquals("Stac equals", objectMapper.readTree(expected), objectMapper.readTree(out.strip())); + } + + @Test + public void verifySummaryGeoCorrect1() throws IOException, JAXBException { + // We only index one record, the + String xml = readResourceFile("classpath:canned/sample9.xml"); + String expected = readResourceFile("classpath:canned/sample9_stac.json"); + indexerService.indexMetadata(xml); + + // We use a mock to pretend insert value into Elastic, there we store what is being send to elastic + // and now we can use it to compare expected result. + Map content = objectMapper.readValue(lastRequest.get().document().toString(), Map.class); + String out = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(content); + assertEquals("Stac equals", objectMapper.readTree(expected), objectMapper.readTree(out.strip())); } } diff --git a/indexer/src/test/resources/canned/sample8_stac.json b/indexer/src/test/resources/canned/sample8_stac.json index c45af197..fa92407b 100644 --- a/indexer/src/test/resources/canned/sample8_stac.json +++ b/indexer/src/test/resources/canned/sample8_stac.json @@ -2,7 +2,7 @@ "title" : "RV Investigator Voyage IN2019_V06 End of Voyage (EOV) Archive", "description" : "This record describes the End of Voyage (EOV) archive from the Marine National Facility (MNF) RV Investigator research voyage IN2019_V06, titled \"Tropical observations of atmospheric convection, biogenic emissions, ocean mixing, and processes generating intraseasonal SST variability.\" The voyage took place from Darwin (NT) to Darwin between October 19 and December 17, 2019 (AEST).\n\n For further information please refer to the voyage documentation links below.\n\n Instruments used and data collected include:\n Regular measurements:\n Acoustic Doppler Current Profiler (ADCP; 75, 150 KHz ), Lowered ADCP (LADCP), Disdrometer, Fisheries echosounder (EK60), Multibeam Echosounder (EM710, EM122), Sub-bottom Profiler (SBP120), Gravimeter, GPS Positioning System, Doppler Velocity Log, Atmospheric Temperature, Humidity, Pressure, Wind and Rain sensors, Photosynthetically Active Radiation (PAR) sensor, Precision Infrared Radiometer (PIR), Precision Spectral Pyranometer (PSP), Nephelometer, pCO2, Condensation Particle Counters (CPC), Cloud Condensation Nuclei counter (CCN), Multiangle Absorption Photometer (MAAP), Starboard and Portside Radiometers, Ozone sensors, Weather Radar, Greenhouse Gas Analysers (Aerodyne, Picarro), Infrared Sea Surface Temperature Autonomous Radiometer (ISAR), Fluorometer, Oxygen optode, Thermosalinographs (TSG), CTD, Hydrochemistry, Expendable Bathythermographs (XBTs).\n\n Voyage-specific measurements:\n AIRBOX (TSI 3772 Condensation Particle Counter (3772CPC), Black Carbon sensor (Aethalometer), Aerosol mass spectrometer (AMS), Chemical Ionisation Mass Spectrometer (CIMS), Cloud Radar (BASTA), Weather Station, Multi-AXis Differential Optical Absorption Spectrometer (MAX-DOAS), mini Micro-Pulse LIDAR (miniMPL), Neutral Cluster Air Ion Spectrometer (NAIS), Radon sensor, Cloud and Aerosol Backscatter Lidar (RMAN), Scanning Mobility Particle Sizers (SMPS), Sonic Anemometer, Greenhouse Gas Analyser (Fourier Transform Infrared (FTIR) spectrometer - Spectronus), Mercury Analyser (Tekran), Gas Chromatograph - Electron Capture Detector (uDirac), Volatility-Hygroscopicity Tandem Differential Mobility Analyser (VH-TDMA)), Radiosondes, Wave-powered Profiler (Wirewalker), Sea State cameras, Triaxus, ECO Triplet, Sound Velocity Profile (SVP).\n\n The archive for the IN2019_V06 EOV raw data is curated by the CSIRO NCMI Information and Data Centre (IDC) in Hobart, with a permanent archive at the CSIRO Data Access Portal (DAP, https://data.csiro.au/dap/), providing access to participants and processors of the data collected in the voyage.\n\n All voyage documentation is available electronically to MNF support via the local network. Access to voyage documentation for non-CSIRO participants can be made via NCMI_DataLibrarians@csiro.au.", "extent" : { - "bbox" : [ [ 120.55, -14.68, 133.45, -10.8 ], [ 120.55, -14.68, 133.45, -14.68, 133.45, -10.8, 120.55, -10.8, 120.55, -14.68 ] ], + "bbox" : [ [ 120.55, -14.68, 133.45, -10.8 ], [ 120.55, -14.68, 133.45, -10.8 ] ], "temporal" : [ [ "2019-10-18T13:00:00Z", "2019-12-16T13:00:00Z" ], [ "2019-10-18T13:00:00Z", "2019-12-16T13:00:00Z" ] ] }, "summaries" : { @@ -475,4 +475,4 @@ "type" : "Collection", "stac_version" : "1.0.0", "stac_extensions" : [ "https://stac-extensions.github.io/scientific/v1.0.0/schema.json", "https://stac-extensions.github.io/contacts/v0.1.1/schema.json", "https://stac-extensions.github.io/projection/v1.1.0/schema.json", "https://stac-extensions.github.io/language/v1.0.0/schema.json", "https://stac-extensions.github.io/themes/v1.0.0/schema.json" ] -} +} \ No newline at end of file diff --git a/indexer/src/test/resources/canned/sample9.xml b/indexer/src/test/resources/canned/sample9.xml new file mode 100644 index 00000000..fa4753e1 --- /dev/null +++ b/indexer/src/test/resources/canned/sample9.xml @@ -0,0 +1,931 @@ + + + + + + 1e13ab6e-e546-44f2-a007-061c2815268a + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Australian Institute of Marine Science (AIMS) + + + + + + + +61 7 4753 4444 + + + + + + + + + + +61 7 4772 5852 + + + + + + + + + + PRIVATE MAIL BAG 3 + + + TOWNSVILLE MAIL CENTRE + + + Queensland + + + 4810 + + + Australia + + + adc@aims.gov.au + + + + + + + https://www.aims.gov.au/adc + + + WWW:LINK-1.0-http--link + + + + + 0800 to 1640 UTC+10: Monday to Friday + + + + + + + AIMS Data Centre + + + + + + + + + + + 2022-02-08T00:00:00 + + + + + + + + + + 2024-03-15T00:00:00 + + + + + + + + + + ISO 19115-3:2018 + + + + + + + https://apps.aims.gov.au/metadata/view/1e13ab6e-e546-44f2-a007-061c2815268a + + + WWW:LINK-1.0-http--metadata-URL + + + Point of truth URL of this metadata record + + + Point of truth URL of this metadata record + + + + + + + + + + + + Heat-evolved microalgal symbionts increase thermal bleaching tolerance of coral juveniles without a trade-off against growth + + + + + 2024-05-30T00:00:00 + + + + + + + + + + + + + + + Australian Institute of Marine Science (AIMS) + + + + + + + +61 7 4753 4444 + + + + + + + + + + + + + + + + + + + + PRIVATE MAIL BAG 3, TOWNSVILLE MAIL CENTRE + + + TOWNSVILLE + + + Queensland + + + 4810 + + + Australia + + + reception@aims.gov.au + + + + + + + https://www.aims.gov.au + + + WWW:LINK-1.0-http--link + + + AIMS Web Site + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Australian Institute of Marine Science (AIMS) + + + + + + + +61 7 4753 4444 + + + + + + + + + + + + + + + + + + + + PRIVATE MAIL BAG 3, TOWNSVILLE MAIL CENTRE + + + TOWNSVILLE + + + Queensland + + + 4810 + + + Australia + + + reception@aims.gov.au + + + + + + + https://www.aims.gov.au + + + WWW:LINK-1.0-http--link + + + AIMS Web Site + + + + + + + + + + + + + + + + + + + + + + + + + + https://www.aims.gov.au + + + WWW:LINK-1.0-http--link + + + AIMS Web Site + + + + + + + https://www.aims.gov.au + + + WWW:LINK-1.0-http--link + + + AIMS Web Site + + + + + + + This study was designed to test the effect of heat-evolved macroalgal symbionts against bleaching tolerance in juvenile corals in response to a simulated heatwave. + + + Juveniles of the coral Acropora tenuis were infected with either wildtype (WT10) or heat-evolved (SS1 or SS8) strains of the Symbiodiniaceae species Cladocopium C1acro (formerly Cladocopium goreaui 2&ndash;4). + + + The juveniles were maintained at ambient conditions (27&deg;C) for 10 months at which time their size was measured. Growth, survival, and metabolism data were collected following a simulated heatwave (31&deg;C for 41 days). + + + Photographs and PSII maximum quantum yields (Fv/Fm) were collected throughout the heat stress period, stable isotope incubation and cell counts were carried out on day 39, and respirometry on days 40-41. Symbiodiniaceae cell densities per juvenile were quantified to assess bleaching. + + + Statistical analyses were run in R and respirometry data was analysed using the respR package. + + + Full methods and technical details are found in the paper https://ssrn.com/abstract=3981099 + + + Quigley, KM. Australian Institute of Marine Science (AIMS) + + + Alvarez Roa, C. (AIMS) + + + Raina, JB. University of Technology, Sydney (UTS) + + + Pernice, M. (UTS) + + + van Oppen, MJH. (AIMS) and University of Melbourne + + + + + + + + + + + + + Australian Institute of Marine Science (AIMS) + + + + + + + +61 7 4753 4444 + + + + + + + + + + + + + + + + + + + + PRIVATE MAIL BAG 3, TOWNSVILLE MAIL CENTRE + + + TOWNSVILLE + + + Queensland + + + 4810 + + + Australia + + + reception@aims.gov.au + + + + + + + https://www.aims.gov.au + + + WWW:LINK-1.0-http--link + + + AIMS Web Site + + + + + + + + + + + + Quigley, KM + + + + + + + + + + + + + + + + + + + Australian Institute of Marine Science (AIMS) + + + + + + + +61 7 4753 4444 + + + + + + + + + + + + + + + + + + + + PRIVATE MAIL BAG 3, TOWNSVILLE MAIL CENTRE + + + TOWNSVILLE + + + Queensland + + + 4810 + + + Australia + + + adc@aims.gov.au + + + + + + + https://www.aims.gov.au + + + WWW:LINK-1.0-http--link + + + AIMS Web Site + + + + + + + + + + + + AIMS Data Centre + + + + + + + + + + + + P1Y0M0DT0H0M0S + + + oceans + + + + + Magnetic Island + + + + + 146.862133 + + + 146.862133 + + + -19.10415 + + + -19.10415 + + + + + + + + + Nelly Bay, Magnetic Island + + + + + 146.85 + + + 146.85 + + + -19.168333 + + + -19.168333 + + + + + + + + + Collective resources start and end dates + + + + + + + + 2018-10-29 + + + + + 2019-11-20 + + + + + + + + + + + + + + + + + + + + + + + + http://i.creativecommons.org/l/by/3.0/au/88x31.png + + + WWW:LINK-1.0-http--related + + + License Graphic + + + + + + + + + Creative Commons Attribution 3.0 Australia License + + + + + + + + + + + + + + + + + + + + + + + + http://creativecommons.org/international/au/ + + + WWW:LINK-1.0-http--related + + + + + + + + + + + + + + + + + + + http://creativecommons.org/licenses/by/3.0/au/ + + + WWW:LINK-1.0-http--related + + + License Text + + + + + + + Use Limitation: All AIMS data, products and services are provided "as is" and AIMS does not warrant their fitness for a particular purpose or non-infringement. While AIMS has made every reasonable effort to ensure high quality of the data, products and services, to the extent permitted by law the data, products and services are provided without any warranties of any kind, either expressed or implied, including without limitation any implied warranties of title, merchantability, and fitness for a particular purpose or non-infringement. AIMS make no representation or warranty that the data, products and services are accurate, complete, reliable or current. To the extent permitted by law, AIMS exclude all liability to any person arising directly or indirectly from the use of the data, products and services. + + + Attribution: Format for citation of metadata sourced from Australian Institute of Marine Science (AIMS) in a list of reference is as follows: "Australian Institute of Marine Science (AIMS). (2022). Heat-evolved microalgal symbionts increase thermal bleaching tolerance of coral juveniles without a trade-off against growth. https://apps.aims.gov.au/metadata/view/1e13ab6e-e546-44f2-a007-061c2815268a, accessed[date-of-access]". + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Australian Institute of Marine Science (AIMS) + + + + + + + +61 7 4753 4444 + + + + + + + + + + PRIVATE MAIL BAG 3, TOWNSVILLE MAIL CENTRE + + + TOWNSVILLE + + + Queensland + + + 4810 + + + Australia + + + reception@aims.gov.au + + + + + + + https://www.aims.gov.au + + + WWW:LINK-1.0-http--link + + + AIMS Home Page + + + + + + + + + + + + AIMS Data Centre + + + + + + + + + + + + + + + + + + https://doi.org/10.1007/s00338-023-02426-z + + + WWW:LINK-1.0-http--related + + + Quigley, K.M., Alvarez-Roa, C., Raina, JB. et al. Heat-evolved microalgal symbionts increase thermal bleaching tolerance of coral juveniles without a trade-off against growth. Coral Reefs 42, 1227–1232 (2023). https://doi.org/10.1007/s00338-023-02426-z + + + Quigley, K.M., Alvarez-Roa, C., Raina, JB. et al. Heat-evolved microalgal symbionts increase thermal bleaching tolerance of coral juveniles without a trade-off against growth. Coral Reefs 42, 1227–1232 (2023). https://doi.org/10.1007/s00338-023-02426-z + + + + + + + + + + https://doi.org/10.1111/2041-210X.13162 + + + WWW:LINK-1.0-http--related + + + Harianto, J, Carey, N, Byrne, M. respR—An R package for the manipulation and analysis of respirometry data. Methods Ecol Evol. 2019; 10: 912– 920. https://doi.org/10.1111/2041-210X.13162 + + + Harianto, J, Carey, N, Byrne, M. respR—An R package for the manipulation and analysis of respirometry data. Methods Ecol Evol. 2019; 10: 912– 920. https://doi.org/10.1111/2041-210X.13162 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/indexer/src/test/resources/canned/sample9_stac.json b/indexer/src/test/resources/canned/sample9_stac.json new file mode 100644 index 00000000..4924ee2a --- /dev/null +++ b/indexer/src/test/resources/canned/sample9_stac.json @@ -0,0 +1,109 @@ +{ + "title" : "Heat-evolved microalgal symbionts increase thermal bleaching tolerance of coral juveniles without a trade-off against growth", + "description" : "This study was designed to test the effect of heat-evolved macroalgal symbionts against bleaching tolerance in juvenile corals in response to a simulated heatwave.\n\n\n Juveniles of the coral Acropora tenuis were infected with either wildtype (WT10) or heat-evolved (SS1 or SS8) strains of the Symbiodiniaceae species Cladocopium C1acro (formerly Cladocopium goreaui 2–4).\n\n\n The juveniles were maintained at ambient conditions (27°C) for 10 months at which time their size was measured. Growth, survival, and metabolism data were collected following a simulated heatwave (31°C for 41 days).\n\n\n Photographs and PSII maximum quantum yields (Fv/Fm) were collected throughout the heat stress period, stable isotope incubation and cell counts were carried out on day 39, and respirometry on days 40-41. Symbiodiniaceae cell densities per juvenile were quantified to assess bleaching.\n\n\n Statistical analyses were run in R and respirometry data was analysed using the respR package.\n\n\n Full methods and technical details are found in the paper https://ssrn.com/abstract=3981099", + "extent" : { + "bbox" : [ [ 146.85, -19.168333, 146.862133, -19.10415 ], [ 146.862133, -19.10415, 146.862133, -19.10415 ], [ 146.85, -19.168333, 146.85, -19.168333 ] ], + "temporal" : [ [ "2018-10-28T13:00:00Z", "2019-11-19T13:00:00Z" ], [ "2018-10-28T13:00:00Z", "2019-11-19T13:00:00Z" ] ] + }, + "summaries" : { + "score" : 1, + "status" : "completed", + "scope" : { + "code" : "dataset", + "name" : "" + }, + "dataset_group" : null, + "dataset_provider" : null, + "update_frequency" : null, + "proj:geometry" : null, + "temporal" : [ { + "start" : "2018-10-28T13:00:00Z", + "end" : "2019-11-19T13:00:00Z" + } ], + "discovery_categories" : null + }, + "contacts" : [ { + "roles" : "principalInvestigator", + "organization" : "Australian Institute of Marine Science (AIMS)", + "name" : "Quigley, KM", + "position" : "", + "emails" : [ "reception@aims.gov.au" ], + "addresses" : [ { + "deliveryPoint" : [ "PRIVATE MAIL BAG 3, TOWNSVILLE MAIL CENTRE" ], + "city" : "TOWNSVILLE", + "country" : "Australia", + "postalCode" : "4810", + "administrativeArea" : "Queensland" + } ], + "phones" : [ { + "roles" : [ "voice" ], + "value" : "+61 7 4753 4444" + }, { + "roles" : [ "facsimile" ], + "value" : "" + } ], + "links" : [ { + "href" : "https://www.aims.gov.au", + "rel" : null, + "type" : "WWW:LINK-1.0-http--link", + "title" : "AIMS Web Site" + } ] + }, { + "roles" : "pointOfContact", + "organization" : "Australian Institute of Marine Science (AIMS)", + "name" : "AIMS Data Centre", + "position" : "", + "emails" : [ "adc@aims.gov.au" ], + "addresses" : [ { + "deliveryPoint" : [ "PRIVATE MAIL BAG 3, TOWNSVILLE MAIL CENTRE" ], + "city" : "TOWNSVILLE", + "country" : "Australia", + "postalCode" : "4810", + "administrativeArea" : "Queensland" + } ], + "phones" : [ { + "roles" : [ "voice" ], + "value" : "+61 7 4753 4444" + }, { + "roles" : [ "facsimile" ], + "value" : "" + } ], + "links" : [ { + "href" : "https://www.aims.gov.au", + "rel" : null, + "type" : "WWW:LINK-1.0-http--link", + "title" : "AIMS Web Site" + } ] + } ], + "languages" : [ { + "code" : "eng", + "name" : "English" + } ], + "links" : [ { + "href" : "https://doi.org/10.1007/s00338-023-02426-z", + "rel" : "self", + "type" : "", + "title" : "Quigley, K.M., Alvarez-Roa, C., Raina, JB. et al. Heat-evolved microalgal symbionts increase thermal bleaching tolerance of coral juveniles without a trade-off against growth. Coral Reefs 42, 1227–1232 (2023). https://doi.org/10.1007/s00338-023-02426-z" + }, { + "href" : "https://doi.org/10.1111/2041-210X.13162", + "rel" : "self", + "type" : "", + "title" : "Harianto, J, Carey, N, Byrne, M. respR—An R package for the manipulation and analysis of respirometry data. Methods Ecol Evol. 2019; 10: 912– 920. https://doi.org/10.1111/2041-210X.13162" + } ], + "license" : "Creative Commons Attribution 3.0 Australia License", + "providers" : [ { + "name" : "Australian Institute of Marine Science (AIMS)", + "description" : null, + "roles" : [ "pointOfContact" ], + "url" : null + } ], + "themes" : [ ], + "id" : "1e13ab6e-e546-44f2-a007-061c2815268a", + "record_suggest" : { + "title" : "Heat-evolved microalgal symbionts increase thermal bleaching tolerance of coral juveniles without a trade-off against growth", + "description" : null + }, + "type" : "Collection", + "stac_version" : "1.0.0", + "stac_extensions" : [ "https://stac-extensions.github.io/scientific/v1.0.0/schema.json", "https://stac-extensions.github.io/contacts/v0.1.1/schema.json", "https://stac-extensions.github.io/projection/v1.1.0/schema.json", "https://stac-extensions.github.io/language/v1.0.0/schema.json", "https://stac-extensions.github.io/themes/v1.0.0/schema.json" ] +} From f227a96d478ed4cc8823a98ac1354be24053ae0c Mon Sep 17 00:00:00 2001 From: utas-raymondng Date: Fri, 31 May 2024 17:01:11 +1000 Subject: [PATCH 3/8] fix test result --- indexer/src/test/resources/canned/sample4_stac.json | 2 +- indexer/src/test/resources/canned/sample5_stac.json | 2 +- indexer/src/test/resources/canned/sample6_stac.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/indexer/src/test/resources/canned/sample4_stac.json b/indexer/src/test/resources/canned/sample4_stac.json index 804fff45..d4696bf0 100644 --- a/indexer/src/test/resources/canned/sample4_stac.json +++ b/indexer/src/test/resources/canned/sample4_stac.json @@ -2,7 +2,7 @@ "title" : "Ocean acidification historical reconstruction", "description" : "This dataset contains the reconstructed time series of monthly mean aragonite, calcite and pH together with distribution of dissolved inorganic carbon (DIC), total alkalinity (ALK), sea surface temperature and salinity in the Australian region at a 1 degree resolution over the period 1870-2013.", "extent" : { - "bbox" : [ [ 95.5, -44.5, 169.5, -0.5 ], [ 95.5, -44.5, 169.5, -44.5, 169.5, -0.5, 95.5, -0.5, 95.5, -44.5 ] ], + "bbox" : [ [ 95.5, -44.5, 169.5, -0.5 ], [ 95.5, -44.5, 169.5, -0.5 ] ], "temporal" : [ [ "1870-07-16T14:10:44Z", "2013-06-16T14:00:00Z" ], [ "1870-07-16T14:10:44Z", "2013-06-16T14:00:00Z" ] ] }, "summaries" : { diff --git a/indexer/src/test/resources/canned/sample5_stac.json b/indexer/src/test/resources/canned/sample5_stac.json index 19215d64..35ee83c4 100644 --- a/indexer/src/test/resources/canned/sample5_stac.json +++ b/indexer/src/test/resources/canned/sample5_stac.json @@ -2,7 +2,7 @@ "title" : "IMOS - ACORN - Bonney Coast HF ocean radar site (South Australia, Australia)", "description" : "The Bonney Coast (BONC) HF ocean radar system covers an area of the Bonney Coast, South Australia, which has a recurring annual upwelling feature near to the coast that significantly changes the ecosystem from one of warm water originating in Western Australia, to one dominated by cold upwelling water from off the continental shelf. The dynamics of this area and the relationship between ocean circulation, chemistry and sediments control the larval species and the higher marine species and ecosystems in which they forage.\n\n The data from this site provide linking observations between the Southern Ocean and NSW through processes that occur on weekly to El Nino time scales.\n\n The BONC HF ocean radar system consists of two SeaSonde crossed loop direction finding stations located at Nora Creina (37.329 S 139.850 E) and Blackfellows Cave (37.940 S 140.457 E). These radars operate at a frequency of 5.211 MHz, with a bandwidth of 50 KHz, a maximum range of 200 Km\n and a range resolution of 3 Km. Within the HF radar coverage area surface currents are measured.\n\n This site was decommissioned in March 2017.", "extent" : { - "bbox" : [ [ 138.2, -39.4, 140.8, -37.0 ], [ 138.2, -39.4, 140.8, -39.4, 140.8, -37.0, 138.2, -37.0, 138.2, -39.4 ] ], + "bbox" : [ [ 138.2, -39.4, 140.8, -37.0 ], [ 138.2, -39.4, 140.8, -37.0 ] ], "temporal" : [ [ "2010-01-21T01:00:00Z", "2017-03-26T13:00:00Z" ], [ "2010-01-21T01:00:00Z", "2017-03-26T13:00:00Z" ] ] }, "summaries" : { diff --git a/indexer/src/test/resources/canned/sample6_stac.json b/indexer/src/test/resources/canned/sample6_stac.json index 0f93abdd..f9fa8259 100644 --- a/indexer/src/test/resources/canned/sample6_stac.json +++ b/indexer/src/test/resources/canned/sample6_stac.json @@ -2,7 +2,7 @@ "title" : "RV Investigator Voyage IN2024_V01 End of Voyage (EOV) Archive", "description" : "This record describes the End of Voyage (EOV) data archive from the Marine National Facility (MNF) RV Investigator voyage IN2024_V01, titled \"Multidisciplinary Investigations of the Southern Ocean (MISO): linking physics, biogeochemistry, plankton, aerosols, clouds, and climate.\" The voyage took place between January 02, 2024 and March 05, 2024 (AEST), departing from Hobart and returning to Fremantle.\n\n For further information please refer to the voyage documentation links.\n\n Instruments used and data collected include:\n Regular measurements:\n Lowered ADCP (LADCP), Acoustic Doppler Current Profiler (ADCP; 75, 150 KHz ), Greenhouse Gas Analysers (Picarro), Cloud Condensation Nuclei counter (CCN), Condensation Particle Counters (CPC), Disdrometer, Radon sensor, Scanning Mobility Particle Sizers (SMPS), CTD, Hydrochemistry, Triaxus, Fisheries Echosounder (EK80), Multibeam Echosounder (EM710, EM122), Sub-bottom Profiler (SBP120), GPS Positioning System, Doppler Velocity Log, Thermosalinographs (TSG), Fluorometer, Oxygen Optode, pCO2, Multiangle Absorption Photometer (MAAP), Ozone Sensor, Nephelometer, Atmospheric Temperature, Humidity, Pressure, Wind and Rain sensors, Photosynthetically Active Radiation (PAR) sensor, Precision Infrared Radiometer (PIR), Precision Spectral Pyranometer (PSP), Starboard and Portside Radiometers, Air Sampler, Ultra Short BaseLine Underwater Positioning System (USBL), Weather Radar, Expendable Bathythermographs (XBTs).\n\n Voyage-specific measurements:\n Black Carbon sensor (Aethalometer), Mobility particle size spectrometer (MPSS), Bongo Net, Chemical Ionisation Mass Spectrometer (CIMS), Cloud Radar (BASTA), Fast Repetition Rate Chlorophyll-a Fluorometer (FRRf), Mini Micro-Pulse LIDAR (miniMPL), Micro Rain Radar (MRR), Neutral Cluster Air Ion Spectrometer (NAIS), Proton-Transfer-Reaction Mass Spectrometry (PTR-MS), Radiosondes, Cloud and Aerosol Backscatter Lidar (RMAN), Stabilised Platform, Mercury Analyser (Tekran), Time of Flight Aerosol Chemical Speciation Monitor (ToF-ACSM), Water Vapor Radiometer (WVR), Aerosol mass spectrometer (AMS), Core Argo floats, Biogeochemical (BGC) Argo floats, Near-surface Drifters, In situ pumps (ISPs), Ice Nucleating Particles (INPs), Ozone Sensor, Trace Metal Aerosol Sampling, Trace Metal CTD Rosette and Bottles, Organic Sulfur Sequential Chemical Analysis Robot (OSSCAR), Omics data and various biological data.\n\n The archive for the IN2024_V01 EOV raw data is curated by the CSIRO National Collections and Marine Infrastructure (NCMI) Information and Data Centre (IDC) in Hobart, with a permanent archive at the CSIRO Data Access Portal (https://data.csiro.au/), providing access to voyage participants and processors of the data collected on the voyage.\n\n All voyage documentation is available electronically to MNF support via the local network. Applications to access voyage documentation by non-CSIRO participants can be made via data-requests-hf@csiro.au.\n\n All processed data from this voyage are made publicly available through the MNF Data Trawler (in the related links).", "extent" : { - "bbox" : [ [ 113.2462, -67.0026, 151.4171, -31.9323 ], [ 113.2462, -67.0026, 151.4171, -67.0026, 151.4171, -31.9323, 113.2462, -31.9323, 113.2462, -67.0026 ] ], + "bbox" : [ [ 113.2462, -67.0026, 151.4171, -31.9323 ], [ 113.2462, -67.0026, 151.4171, -31.9323 ] ], "temporal" : [ [ "2024-01-01T13:00:00Z", "2024-03-04T13:00:00Z" ], [ "2024-01-01T13:00:00Z", "2024-03-04T13:00:00Z" ] ] }, "summaries" : { From 2bf02ef7046b2581be1f8046559729bf2d8d3460 Mon Sep 17 00:00:00 2001 From: utas-raymondng Date: Fri, 31 May 2024 17:20:27 +1000 Subject: [PATCH 4/8] change line to reduce un-necessary object --- .../src/main/java/au/org/aodn/esindexer/utils/StacUtils.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/indexer/src/main/java/au/org/aodn/esindexer/utils/StacUtils.java b/indexer/src/main/java/au/org/aodn/esindexer/utils/StacUtils.java index 9e5193fd..07b768a8 100644 --- a/indexer/src/main/java/au/org/aodn/esindexer/utils/StacUtils.java +++ b/indexer/src/main/java/au/org/aodn/esindexer/utils/StacUtils.java @@ -74,9 +74,10 @@ public static List> createStacBBox(List> listOfPo BigDecimal.valueOf(overallBoundingBox.getMaxY()).setScale(scale, RoundingMode.HALF_UP))); for (List polygons : listOfPolygons) { - final Envelope individualEnvelope = new Envelope(); if (!polygons.isEmpty()) { + final Envelope individualEnvelope = new Envelope(); + for (Polygon p : polygons) { if (p != null) { individualEnvelope.expandToInclude(p.getEnvelopeInternal()); From 6364e109cd24a36577879886102d7019038c243e Mon Sep 17 00:00:00 2001 From: utas-raymondng Date: Mon, 3 Jun 2024 14:54:27 +1000 Subject: [PATCH 5/8] use geometrycollection for proj:geometry --- .../service/StacCollectionMapperService.java | 8 +- .../org/aodn/esindexer/utils/BBoxUtils.java | 2 +- .../aodn/esindexer/utils/GeometryBase.java | 113 +++++++++++++++--- .../aodn/esindexer/utils/GeometryUtils.java | 49 ++------ .../org/aodn/esindexer/utils/StacUtils.java | 9 +- .../StacCollectionMapperServiceTests.java | 3 +- .../esindexer/utils/GeometryBaseTest.java | 60 ++++++++++ .../test/resources/canned/sample8_stac.json | 7 +- .../test/resources/canned/sample9_stac.json | 11 +- 9 files changed, 198 insertions(+), 64 deletions(-) create mode 100644 indexer/src/test/java/au/org/aodn/esindexer/utils/GeometryBaseTest.java diff --git a/indexer/src/main/java/au/org/aodn/esindexer/service/StacCollectionMapperService.java b/indexer/src/main/java/au/org/aodn/esindexer/service/StacCollectionMapperService.java index eceb99e2..4bb618b4 100644 --- a/indexer/src/main/java/au/org/aodn/esindexer/service/StacCollectionMapperService.java +++ b/indexer/src/main/java/au/org/aodn/esindexer/service/StacCollectionMapperService.java @@ -71,7 +71,13 @@ public abstract class StacCollectionMapperService { String mapUUID(MDMetadataType source) { return source.getMetadataIdentifier().getMDIdentifier().getCode().getCharacterString().getValue().toString(); } - + /** + * According to the spec, the bbox must be an of length 2*n where n is number of dimension, so a 2D map, the + * dimension is 4 and therefore it must be a box. + * + * @param source + * @return The list must be of size 4 due to 2D map. + */ @Named("mapExtentBbox") List> mapExtentBbox(MDMetadataType source) { return createGeometryItems( diff --git a/indexer/src/main/java/au/org/aodn/esindexer/utils/BBoxUtils.java b/indexer/src/main/java/au/org/aodn/esindexer/utils/BBoxUtils.java index 6987d13f..0ddb33fb 100644 --- a/indexer/src/main/java/au/org/aodn/esindexer/utils/BBoxUtils.java +++ b/indexer/src/main/java/au/org/aodn/esindexer/utils/BBoxUtils.java @@ -14,7 +14,7 @@ public class BBoxUtils { public static List> createBBoxFrom(List> rawInput) { //TODO: avoid hardcode CRS, get it from document - List> polygons = GeometryBase.findPolygonsFrom(GeometryBase.COORDINATE_SYSTEM_CRS84, rawInput); + List> polygons = GeometryBase.findPolygonsFrom(GeometryBase.COORDINATE_SYSTEM_CRS84, rawInput); return StacUtils.createStacBBox(polygons); } } diff --git a/indexer/src/main/java/au/org/aodn/esindexer/utils/GeometryBase.java b/indexer/src/main/java/au/org/aodn/esindexer/utils/GeometryBase.java index e47ab920..ae94b697 100644 --- a/indexer/src/main/java/au/org/aodn/esindexer/utils/GeometryBase.java +++ b/indexer/src/main/java/au/org/aodn/esindexer/utils/GeometryBase.java @@ -1,6 +1,7 @@ package au.org.aodn.esindexer.utils; import au.org.aodn.metadata.iso19115_3_2018.*; +import org.apache.commons.lang3.ArrayUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.locationtech.jts.geom.*; @@ -8,6 +9,8 @@ import org.opengis.referencing.operation.TransformException; import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; public class GeometryBase { @@ -50,7 +53,7 @@ public static Envelope calculateBoundingBox(Envelope boundingBox, Polygon... pol * @param rawInput - A list of list of AbstractEXGeographicExtentType, AbstractEXGeographicExtentType is a base type, and can be a bbox or geometry * @return */ - public static List> findPolygonsFrom(final String rawCRS, List> rawInput) { + public static List> findPolygonsFrom(final String rawCRS, List> rawInput) { return rawInput .stream() .map(r -> { @@ -68,8 +71,8 @@ else if(!r.isEmpty() && r.get(0) instanceof EXGeographicBoundingBoxType) { .toList(); } - protected static List findPolygonsFromEXBoundingPolygonType(String rawCRS, List rawInput) { - List polygons = new ArrayList<>(); + protected static List findPolygonsFromEXBoundingPolygonType(String rawCRS, List rawInput) { + List polygons = new ArrayList<>(); if(COORDINATE_SYSTEM_CRS84.equals(rawCRS)) { List> input = rawInput.stream() @@ -101,7 +104,7 @@ protected static List findPolygonsFromEXBoundingPolygonType(String rawC } // We need to store it so that we can create the multi-array as told by spec - Polygon polygon = geoJsonFactory.createPolygon(items.toArray(new Coordinate[items.size()])); + Polygon polygon = geoJsonFactory.createPolygon(items.toArray(new Coordinate[0])); polygons.add(polygon); logger.debug("2D Polygon added {}", polygon); } @@ -123,7 +126,7 @@ protected static List findPolygonsFromEXBoundingPolygonType(String rawC } // We need to store it so that we can create the multi-array as told by spec - Polygon polygon = geoJsonFactory.createPolygon(items.toArray(new Coordinate[items.size()])); + Polygon polygon = geoJsonFactory.createPolygon(items.toArray(new Coordinate[0])); polygons.add(polygon); logger.debug("2D Polygon added {}", polygon); @@ -140,9 +143,32 @@ protected static List findPolygonsFromEXBoundingPolygonType(String rawC } return polygons; } - - protected static List findPolygonsFromEXGeographicBoundingBoxType(String rawCRS, List rawInput) { - List polygons = new ArrayList<>(); + /** + * This function look into the EXGeographicBoundingBox amd extract the coordinate, this block will be like this + * + * + * 146.862133 + * + * + * 146.862133 + * + * + * -19.10415 + * + * + * -19.10415 + * + * + * + * with North, East, South, West only, but people may not necessary create a box are but can set coordinate to + * Points or Line, so our return type needs to be Geometry + * + * @param rawCRS + * @param rawInput + * @return - List of Geometry, where it can be Point, Line or Box aka (Polygon) + */ + protected static List findPolygonsFromEXGeographicBoundingBoxType(String rawCRS, List rawInput) { + final List geometries = new ArrayList<>(); if(COORDINATE_SYSTEM_CRS84.equals(rawCRS)) { List input = rawInput.stream() @@ -150,20 +176,20 @@ protected static List findPolygonsFromEXGeographicBoundingBoxType(Strin .map(m -> (EXGeographicBoundingBoxType) m) .toList(); + // Noted that some user do not create a box in this section but a Point!! This isn't correct but + // the geonetwork allow this, so we need to deal with it. for (EXGeographicBoundingBoxType bbt : input) { if (bbt.getWestBoundLongitude().getDecimal() == null || bbt.getEastBoundLongitude().getDecimal() == null || bbt.getNorthBoundLatitude().getDecimal() == null || bbt.getSouthBoundLatitude().getDecimal() == null) { logger.warn("Invalid BBOX found for findPolygonsFromEXGeographicBoundingBoxType using CRS {}", rawCRS); } else { logger.debug("BBOX found for findPolygonsFromEXGeographicBoundingBoxType using CRS {}", rawCRS); - Coordinate[] coordinates = getCoordinates(bbt); - Polygon polygon = geoJsonFactory.createPolygon(coordinates); - polygons.add(polygon); + getCoordinates(bbt).ifPresent(geometries::add); } } } - if(!polygons.isEmpty()) { - return polygons; + if(!geometries.isEmpty()) { + return geometries; } else { logger.warn("No applicable BBOX calculation found for findPolygonsFromEXGeographicBoundingBoxType using CRS {}", rawCRS); @@ -171,18 +197,71 @@ protected static List findPolygonsFromEXGeographicBoundingBoxType(Strin } } - protected static Coordinate[] getCoordinates(EXGeographicBoundingBoxType bbt) { + protected static Optional getCoordinates(EXGeographicBoundingBoxType bbt) { + double east = bbt.getEastBoundLongitude().getDecimal().doubleValue(); double west = bbt.getWestBoundLongitude().getDecimal().doubleValue(); double north = bbt.getNorthBoundLatitude().getDecimal().doubleValue(); double south = bbt.getSouthBoundLatitude().getDecimal().doubleValue(); + // Define the coordinates for the bounding box - return new Coordinate[]{ + Coordinate[] coordinates = new Coordinate[]{ new Coordinate(west, south), new Coordinate(east, south), new Coordinate(east, north), - new Coordinate(west, north), - new Coordinate(west, south) // Closing the ring + new Coordinate(west, north) }; + + if(verifyPoint(coordinates)) { + // This is a point as all 4 point same + return Optional.of(geoJsonFactory.createPoint(coordinates[0])); + } + else { + coordinates = ArrayUtils.add(coordinates, new Coordinate(west, south)); // Closing the ring + if(verifyPolygon(coordinates)) { + return Optional.of(geoJsonFactory.createPolygon(coordinates)); + } + else { + logger.warn("Unknown shape, not point or polygon {}", coordinates); + return Optional.empty(); + } + } + } + + protected static boolean verifyPoint(Coordinate[] coordinates) { + + // Groups the coordinates by their values and counts the occurrences of each coordinate. + Map coordinateCountMap = Arrays.stream(coordinates) + .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())); + + // Filters out the coordinates that occur more than once. + long total = coordinateCountMap.values().stream() + .filter(count -> count > 1) + .reduce(0L, Long::sum); + + if(total != coordinates.length) { + // Some points not the same + return false; + } + Point point = geoJsonFactory.createPoint(coordinates[0]); + + // A point's dimension should be 0 + return point.getDimension() == 0; + } + + protected static boolean verifyPolygon(Coordinate[] coordinates) { + if (coordinates.length < 4) { + return false; // At least three distinct points plus a closing point are needed to form a polygon + } + + // The first and last coordinates must be the same to close the polygon + if (!coordinates[0].equals2D(coordinates[coordinates.length - 1])) { + return false; + } + + Polygon polygon = geoJsonFactory.createPolygon(coordinates); + + // A polygon's dimension should be 2 + return polygon.getDimension() == 2; } } diff --git a/indexer/src/main/java/au/org/aodn/esindexer/utils/GeometryUtils.java b/indexer/src/main/java/au/org/aodn/esindexer/utils/GeometryUtils.java index 4239fe2c..9f46cfa3 100644 --- a/indexer/src/main/java/au/org/aodn/esindexer/utils/GeometryUtils.java +++ b/indexer/src/main/java/au/org/aodn/esindexer/utils/GeometryUtils.java @@ -28,54 +28,31 @@ protected static boolean areCollinear(Coordinate p1, Coordinate p2, Coordinate p p3.x * (p1.y - p2.y); return area == 0; } - - protected static boolean hasAtLeastThreeNonCollinearPoints(MultiPolygon multiPolygon) { - // Extract coordinates - Coordinate[] coordinates = multiPolygon.getCoordinates(); - - // Check all triplets of points - for (int i = 0; i < coordinates.length - 2; i++) { - for (int j = i + 1; j < coordinates.length - 1; j++) { - for (int k = j + 1; k < coordinates.length; k++) { - if (!areCollinear(coordinates[i], coordinates[j], coordinates[k])) { - return true; - } - } - } - } - return false; - } /** * * @param polygons - Assume to be EPSG:4326, as GeoJson always use this encoding. * @return */ - protected static Map createGeoJson(List> polygons) { + protected static Map createGeoJson(List> polygons) { if(!polygons.isEmpty()) { // Convert list> to list - List reduced = polygons.stream().flatMap(List::stream).toList(); - MultiPolygon multiPolygon = new MultiPolygon(reduced.toArray(new Polygon[0]), factory); + List reduced = polygons.stream().flatMap(List::stream).toList(); + GeometryCollection collection = new GeometryCollection(reduced.toArray(new Geometry[0]), factory); - // Some bad data just create a line which will cause elastic polygon failed - if(hasAtLeastThreeNonCollinearPoints(multiPolygon)) { - try (StringWriter writer = new StringWriter()) { + try (StringWriter writer = new StringWriter()) { - GeometryJSON geometryJson = new GeometryJSON(); - geometryJson.write(multiPolygon, writer); + GeometryJSON geometryJson = new GeometryJSON(); + geometryJson.write(collection, writer); - Map values = objectMapper.readValue(writer.toString(), HashMap.class); + Map values = objectMapper.readValue(writer.toString(), HashMap.class); - logger.debug("Created geometry {}", values); - return values; - } catch (IOException e) { - logger.error("Error create geometry", e); - return null; - } - } - else { - logger.warn("Polygon invalid, less than 3 non collinear points, this cannot store in Elastic Search"); + logger.debug("Created geometry {}", values); + return values; + } catch (IOException e) { + logger.error("Error create geometry", e); + return null; } } return null; @@ -84,7 +61,7 @@ protected static Map createGeoJson(List> polygons) { public static Map createGeometryFrom(List> rawInput) { // The return polygon is in EPSG:4326, so we can call createGeoJson directly //TODO: avoid hardcode CRS, get it from document - List> polygons = GeometryBase.findPolygonsFrom(GeometryBase.COORDINATE_SYSTEM_CRS84, rawInput); + List> polygons = GeometryBase.findPolygonsFrom(GeometryBase.COORDINATE_SYSTEM_CRS84, rawInput); return (polygons != null && !polygons.isEmpty()) ? createGeoJson(polygons) : null; } } diff --git a/indexer/src/main/java/au/org/aodn/esindexer/utils/StacUtils.java b/indexer/src/main/java/au/org/aodn/esindexer/utils/StacUtils.java index 07b768a8..a41e35df 100644 --- a/indexer/src/main/java/au/org/aodn/esindexer/utils/StacUtils.java +++ b/indexer/src/main/java/au/org/aodn/esindexer/utils/StacUtils.java @@ -5,6 +5,7 @@ import org.apache.logging.log4j.Logger; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.Envelope; +import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.geom.Polygon; import java.math.BigDecimal; @@ -46,7 +47,7 @@ public class StacUtils { * @param listOfPolygons - Assume to be EPSG:4326 as this is what GeoJson use * @return */ - public static List> createStacBBox(List> listOfPolygons) { + public static List> createStacBBox(List> listOfPolygons) { List> result = new ArrayList<>(); if(listOfPolygons != null) { @@ -54,7 +55,7 @@ public static List> createStacBBox(List> listOfPo final AtomicBoolean hasBoundingBoxUpdate = new AtomicBoolean(false); listOfPolygons .forEach(polygons -> { - for (Polygon polygon : polygons) { + for (Geometry polygon : polygons) { // Add polygon one by one to expand the overall bounding box area, this is requirement // of STAC to have an overall bounding box of all smaller area as the first bbox in the list. if (polygon != null) { @@ -73,12 +74,12 @@ public static List> createStacBBox(List> listOfPo BigDecimal.valueOf(overallBoundingBox.getMaxX()).setScale(scale, RoundingMode.HALF_UP), BigDecimal.valueOf(overallBoundingBox.getMaxY()).setScale(scale, RoundingMode.HALF_UP))); - for (List polygons : listOfPolygons) { + for (List polygons : listOfPolygons) { if (!polygons.isEmpty()) { final Envelope individualEnvelope = new Envelope(); - for (Polygon p : polygons) { + for (Geometry p : polygons) { if (p != null) { individualEnvelope.expandToInclude(p.getEnvelopeInternal()); } diff --git a/indexer/src/test/java/au/org/aodn/esindexer/service/StacCollectionMapperServiceTests.java b/indexer/src/test/java/au/org/aodn/esindexer/service/StacCollectionMapperServiceTests.java index 956d29af..b83b7423 100644 --- a/indexer/src/test/java/au/org/aodn/esindexer/service/StacCollectionMapperServiceTests.java +++ b/indexer/src/test/java/au/org/aodn/esindexer/service/StacCollectionMapperServiceTests.java @@ -150,7 +150,6 @@ public void verifyPointOfContactCorrect() throws IOException, JAXBException { // and now we can use it to compare expected result. Map content = objectMapper.readValue(lastRequest.get().document().toString(), Map.class); String out = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(content); - log.info(out); assertEquals("Stac equals", objectMapper.readTree(expected), objectMapper.readTree(out.strip())); } @@ -165,7 +164,7 @@ public void verifySummaryGeoCorrect1() throws IOException, JAXBException { // and now we can use it to compare expected result. Map content = objectMapper.readValue(lastRequest.get().document().toString(), Map.class); String out = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(content); - + log.info(out); assertEquals("Stac equals", objectMapper.readTree(expected), objectMapper.readTree(out.strip())); } } diff --git a/indexer/src/test/java/au/org/aodn/esindexer/utils/GeometryBaseTest.java b/indexer/src/test/java/au/org/aodn/esindexer/utils/GeometryBaseTest.java new file mode 100644 index 00000000..32e3633e --- /dev/null +++ b/indexer/src/test/java/au/org/aodn/esindexer/utils/GeometryBaseTest.java @@ -0,0 +1,60 @@ +package au.org.aodn.esindexer.utils; + +import au.org.aodn.metadata.iso19115_3_2018.DecimalPropertyType; +import au.org.aodn.metadata.iso19115_3_2018.EXGeographicBoundingBoxType; +import org.junit.jupiter.api.Test; +import org.locationtech.jts.geom.Geometry; +import org.locationtech.jts.geom.Point; +import org.locationtech.jts.geom.Polygon; + +import java.math.BigDecimal; +import java.util.Optional; + +import static org.junit.Assert.assertTrue; + +public class GeometryBaseTest { + + @Test + public void verifyGetCoordinatesPoint() { + EXGeographicBoundingBoxType boundingBoxType = new EXGeographicBoundingBoxType(); + + DecimalPropertyType a = new DecimalPropertyType(); + a.setDecimal(BigDecimal.valueOf(146.85)); + + boundingBoxType.setEastBoundLongitude(a); + boundingBoxType.setWestBoundLongitude(a); + + DecimalPropertyType b = new DecimalPropertyType(); + b.setDecimal(BigDecimal.valueOf(-19.168333)); + + boundingBoxType.setSouthBoundLatitude(b); + boundingBoxType.setNorthBoundLatitude(b); + + Optional point = GeometryBase.getCoordinates(boundingBoxType); + assertTrue("We found a point", point.get() instanceof Point); + } + + @Test + public void verifyGetCoordinatesPolygon() { + EXGeographicBoundingBoxType boundingBoxType = new EXGeographicBoundingBoxType(); + + DecimalPropertyType w = new DecimalPropertyType(); + w.setDecimal(BigDecimal.valueOf(60)); + boundingBoxType.setWestBoundLongitude(w); + + DecimalPropertyType s = new DecimalPropertyType(); + s.setDecimal(BigDecimal.valueOf(-68)); + boundingBoxType.setSouthBoundLatitude(s); + + DecimalPropertyType e = new DecimalPropertyType(); + e.setDecimal(BigDecimal.valueOf(78)); + boundingBoxType.setEastBoundLongitude(e); + + DecimalPropertyType n = new DecimalPropertyType(); + n.setDecimal(BigDecimal.valueOf(-66)); + boundingBoxType.setNorthBoundLatitude(n); + + Optional point = GeometryBase.getCoordinates(boundingBoxType); + assertTrue("We found a polygon", point.get() instanceof Polygon); + } +} diff --git a/indexer/src/test/resources/canned/sample8_stac.json b/indexer/src/test/resources/canned/sample8_stac.json index fa92407b..dcead507 100644 --- a/indexer/src/test/resources/canned/sample8_stac.json +++ b/indexer/src/test/resources/canned/sample8_stac.json @@ -16,8 +16,11 @@ "dataset_provider" : null, "update_frequency" : null, "proj:geometry" : { - "coordinates" : [ [ [ [ 120.55, -14.68 ], [ 133.45, -14.68 ], [ 133.45, -10.8 ], [ 120.55, -10.8 ], [ 120.55, -14.68 ] ] ] ], - "type" : "MultiPolygon" + "geometries" : [ { + "type" : "Polygon", + "coordinates" : [ [ [ 120.55, -14.68 ], [ 133.45, -14.68 ], [ 133.45, -10.8 ], [ 120.55, -10.8 ], [ 120.55, -14.68 ] ] ] + } ], + "type" : "GeometryCollection" }, "temporal" : [ { "start" : "2019-10-18T13:00:00Z", diff --git a/indexer/src/test/resources/canned/sample9_stac.json b/indexer/src/test/resources/canned/sample9_stac.json index 4924ee2a..ffee4538 100644 --- a/indexer/src/test/resources/canned/sample9_stac.json +++ b/indexer/src/test/resources/canned/sample9_stac.json @@ -15,7 +15,16 @@ "dataset_group" : null, "dataset_provider" : null, "update_frequency" : null, - "proj:geometry" : null, + "proj:geometry" : { + "geometries" : [ { + "type" : "Point", + "coordinates" : [ 146.8621, -19.1041 ] + }, { + "type" : "Point", + "coordinates" : [ 146.85, -19.1683 ] + } ], + "type" : "GeometryCollection" + }, "temporal" : [ { "start" : "2018-10-28T13:00:00Z", "end" : "2019-11-19T13:00:00Z" From 05e14ba20714ca5a5afbad67e47ce017ff34983c Mon Sep 17 00:00:00 2001 From: utas-raymondng Date: Mon, 3 Jun 2024 15:55:26 +1000 Subject: [PATCH 6/8] add back disabled test case --- .../service/IndexerServiceTests.java | 40 +++--- .../test/resources/canned/sample4_stac.json | 7 +- .../test/resources/canned/sample5_stac.json | 7 +- .../test/resources/canned/sample6_stac.json | 7 +- .../test/resources/canned/sample7_stac.json | 127 ++++++++++++++++++ 5 files changed, 159 insertions(+), 29 deletions(-) create mode 100644 indexer/src/test/resources/canned/sample7_stac.json diff --git a/indexer/src/test/java/au/org/aodn/esindexer/service/IndexerServiceTests.java b/indexer/src/test/java/au/org/aodn/esindexer/service/IndexerServiceTests.java index a11f4185..dd7ca7d8 100644 --- a/indexer/src/test/java/au/org/aodn/esindexer/service/IndexerServiceTests.java +++ b/indexer/src/test/java/au/org/aodn/esindexer/service/IndexerServiceTests.java @@ -2,7 +2,6 @@ import au.org.aodn.esindexer.BaseTestClass; import au.org.aodn.esindexer.configuration.GeoNetworkSearchTestConfig; -import au.org.aodn.stac.model.StacCollectionModel; import co.elastic.clients.elasticsearch.core.search.Hit; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -10,13 +9,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.http.ResponseEntity; import org.springframework.test.context.ActiveProfiles; -import org.testcontainers.shaded.org.checkerframework.checker.units.qual.A; import java.io.IOException; - -import static org.junit.Assert.*; +import java.util.Objects; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @ActiveProfiles("test") @@ -61,9 +57,9 @@ public void verifyIsMetadataPublished() throws IOException { insertMetadataRecords(uuid1, "classpath:canned/sample1.xml"); insertMetadataRecords(uuid2, "classpath:canned/sample2.xml"); - assertTrue(uuid1 + " published", indexerService.isMetadataPublished(uuid1)); - assertTrue(uuid2 + " published", indexerService.isMetadataPublished(uuid2)); - assertFalse("Not exist and not published", indexerService.isMetadataPublished("not-exist")); + Assertions.assertTrue(indexerService.isMetadataPublished(uuid1), uuid1 + " published"); + Assertions.assertTrue(indexerService.isMetadataPublished(uuid2), uuid2 + " published"); + Assertions.assertFalse(indexerService.isMetadataPublished("not-exist"), "Not exist and not published"); } finally { deleteRecord(uuid1); @@ -72,14 +68,14 @@ public void verifyIsMetadataPublished() throws IOException { } /** * Read the function implementation on why need to insert 1 docs - * @throws IOException + * @throws IOException Not expected to throws */ @Test public void verifyGeoNetworkInstanceReinstalled() throws IOException { String uuid = "9e5c3031-a026-48b3-a153-a70c2e2b78b9"; try { insertMetadataRecords(uuid, "classpath:canned/sample1.xml"); - assertTrue("New installed", indexerService.isGeoNetworkInstanceReinstalled(1)); + Assertions.assertTrue(indexerService.isGeoNetworkInstanceReinstalled(1), "New installed"); } finally { deleteRecord(uuid); @@ -100,7 +96,7 @@ public void verifyGetDocumentCount() throws IOException { // ErrorCause: {"type":"illegal_argument_exception","reason":"Polygon self-intersection at lat=57.0 lon=-66.0"} // // So it will not insert correctly and result in 1 doc only - assertEquals("Doc count correct", 1L, elasticSearchIndexService.getDocumentsCount(INDEX_NAME)); + Assertions.assertEquals(1L, elasticSearchIndexService.getDocumentsCount(INDEX_NAME), "Doc count correct"); } finally { deleteRecord(uuid2); @@ -117,11 +113,11 @@ public void verifyDeleteDocumentByUUID() throws IOException { insertMetadataRecords(uuid2, "classpath:canned/sample3.xml"); indexerService.indexAllMetadataRecordsFromGeoNetwork(true, null); - assertEquals("Doc count correct", 2L, elasticSearchIndexService.getDocumentsCount(INDEX_NAME)); + Assertions.assertEquals(2L, elasticSearchIndexService.getDocumentsCount(INDEX_NAME), "Doc count correct"); // Only 2 doc in elastic, if we delete it then should be zero indexerService.deleteDocumentByUUID(uuid1); - assertEquals("Doc count correct", 1L, elasticSearchIndexService.getDocumentsCount(INDEX_NAME)); + Assertions.assertEquals(1L, elasticSearchIndexService.getDocumentsCount(INDEX_NAME), "Doc count correct"); } finally { @@ -141,8 +137,8 @@ public void verifyGetDocumentByUUID() throws IOException { indexerService.indexAllMetadataRecordsFromGeoNetwork(true, null); Hit objectNodeHit = indexerService.getDocumentByUUID(uuid); - String test = objectNodeHit.source().toPrettyString(); - assertEquals("Stac equals " + uuid, indexerObjectMapper.readTree(expected), indexerObjectMapper.readTree(test)); + String test = Objects.requireNonNull(objectNodeHit.source()).toPrettyString(); + Assertions.assertEquals(indexerObjectMapper.readTree(expected), indexerObjectMapper.readTree(test), "Stac equals " + uuid); } finally { deleteRecord(uuid); @@ -166,8 +162,8 @@ public void verifyLogoLinkAddedOnIndex() throws IOException { indexerService.indexAllMetadataRecordsFromGeoNetwork(true, null); Hit objectNodeHit = indexerService.getDocumentByUUID(uuid); - String test = objectNodeHit.source().toPrettyString(); - assertEquals("Stac equals " + uuid, indexerObjectMapper.readTree(expected), indexerObjectMapper.readTree(test)); + String test = Objects.requireNonNull(objectNodeHit.source()).toPrettyString(); + Assertions.assertEquals(indexerObjectMapper.readTree(expected), indexerObjectMapper.readTree(test), "Stac equals " + uuid); } finally { deleteRecord(uuid); @@ -188,9 +184,8 @@ public void verifyThumbnailLinkAddedOnIndex() throws IOException { indexerService.indexAllMetadataRecordsFromGeoNetwork(true, null); Hit objectNodeHit = indexerService.getDocumentByUUID(uuid); - String test = objectNodeHit.source().toPrettyString(); - logger.info(test); - assertEquals("Stac equals " + uuid, indexerObjectMapper.readTree(expected), indexerObjectMapper.readTree(test)); + String test = Objects.requireNonNull(objectNodeHit.source()).toPrettyString(); + Assertions.assertEquals(indexerObjectMapper.readTree(expected), indexerObjectMapper.readTree(test), "Stac equals " + uuid); } finally { deleteRecord(uuid); @@ -201,7 +196,6 @@ public void verifyThumbnailLinkAddedOnIndex() throws IOException { * in the related/5905b3eb-aad0-4f9c-a03e-a02fb3488082.json, the thumbnails: [] is empty * @throws IOException */ - @Disabled("Bug in code where bounding box not right") @Test public void verifyThumbnailLinkNullAddedOnIndex() throws IOException { String uuid = "5905b3eb-aad0-4f9c-a03e-a02fb3488082"; @@ -213,9 +207,9 @@ public void verifyThumbnailLinkNullAddedOnIndex() throws IOException { indexerService.indexAllMetadataRecordsFromGeoNetwork(true, null); Hit objectNodeHit = indexerService.getDocumentByUUID(uuid); - String test = objectNodeHit.source().toPrettyString(); + String test = Objects.requireNonNull(objectNodeHit.source()).toPrettyString(); logger.info(test); - assertEquals("Stac equals " + uuid, indexerObjectMapper.readTree(expected), indexerObjectMapper.readTree(test)); + Assertions.assertEquals(indexerObjectMapper.readTree(expected), indexerObjectMapper.readTree(test), "Stac equals " + uuid); } finally { deleteRecord(uuid); diff --git a/indexer/src/test/resources/canned/sample4_stac.json b/indexer/src/test/resources/canned/sample4_stac.json index d4696bf0..4f0137f1 100644 --- a/indexer/src/test/resources/canned/sample4_stac.json +++ b/indexer/src/test/resources/canned/sample4_stac.json @@ -15,8 +15,11 @@ "dataset_group" : "sample", "dataset_provider" : "IMOS", "proj:geometry" : { - "coordinates" : [ [ [ [ 95.5, -44.5 ], [ 169.5, -44.5 ], [ 169.5, -0.5 ], [ 95.5, -0.5 ], [ 95.5, -44.5 ] ] ] ], - "type" : "MultiPolygon" + "geometries" : [ { + "type" : "Polygon", + "coordinates" : [ [ [ 95.5, -44.5 ], [ 169.5, -44.5 ], [ 169.5, -0.5 ], [ 95.5, -0.5 ], [ 95.5, -44.5 ] ] ] + } ], + "type" : "GeometryCollection" }, "temporal" : [ { "start" : "1870-07-16T14:10:44Z", diff --git a/indexer/src/test/resources/canned/sample5_stac.json b/indexer/src/test/resources/canned/sample5_stac.json index 35ee83c4..945193d1 100644 --- a/indexer/src/test/resources/canned/sample5_stac.json +++ b/indexer/src/test/resources/canned/sample5_stac.json @@ -15,8 +15,11 @@ "dataset_group" : "sample", "dataset_provider" : "IMOS", "proj:geometry" : { - "coordinates" : [ [ [ [ 138.2, -39.4 ], [ 140.8, -39.4 ], [ 140.8, -37 ], [ 138.2, -37 ], [ 138.2, -39.4 ] ] ] ], - "type" : "MultiPolygon" + "geometries" : [ { + "type" : "Polygon", + "coordinates" : [ [ [ 138.2, -39.4 ], [ 140.8, -39.4 ], [ 140.8, -37 ], [ 138.2, -37 ], [ 138.2, -39.4 ] ] ] + } ], + "type" : "GeometryCollection" }, "temporal" : [ { "start" : "2010-01-21T01:00:00Z", diff --git a/indexer/src/test/resources/canned/sample6_stac.json b/indexer/src/test/resources/canned/sample6_stac.json index f9fa8259..74847328 100644 --- a/indexer/src/test/resources/canned/sample6_stac.json +++ b/indexer/src/test/resources/canned/sample6_stac.json @@ -14,8 +14,11 @@ }, "dataset_group" : "sample", "proj:geometry" : { - "coordinates" : [ [ [ [ 113.2462, -67.0026 ], [ 151.4171, -67.0026 ], [ 151.4171, -31.9323 ], [ 113.2462, -31.9323 ], [ 113.2462, -67.0026 ] ] ] ], - "type" : "MultiPolygon" + "geometries" : [ { + "type" : "Polygon", + "coordinates" : [ [ [ 113.2462, -67.0026 ], [ 151.4171, -67.0026 ], [ 151.4171, -31.9323 ], [ 113.2462, -31.9323 ], [ 113.2462, -67.0026 ] ] ] + } ], + "type" : "GeometryCollection" }, "temporal" : [ { "start" : "2024-01-01T13:00:00Z", diff --git a/indexer/src/test/resources/canned/sample7_stac.json b/indexer/src/test/resources/canned/sample7_stac.json new file mode 100644 index 00000000..6f00b00a --- /dev/null +++ b/indexer/src/test/resources/canned/sample7_stac.json @@ -0,0 +1,127 @@ +{ + "title" : "RapidBenthos", + "description" : "Link to 12 3D photogrammetric models and underlying images to replicate the method presented in the publication titled “RapidBenthos – Automated segmentation and multi-view classification of coral reef communities from photogrammetric reconstruction”. These sites were selected to assess the performance of RapidBenthos in different environmental conditions and reef habitats, as they ranged from high visibility offshore reefs to turbid inshore reefs, spanned depths from 5 to 15 meters, and included a range of intra-reefal environments (i.e., reef front, flank, back, and lagoon).\n\n\n All sites were imaged using a standardized diver-rig photogrammetry workflow described by Gordon et al. (2023). High-resolution benthic images (5686 x 3217 pixels) were captured using two Nikon D850 DSLR cameras with 20 mm Nikkor prime lens shooting at 0.5 second intervals (full camera settings described in (Gordon et al., 2023). Cameras were housed in Nauticam underwater housings with 8-inch dome ports and were mounted on an aluminium rig at a distance of 57 cm between lenses (60 % overlap between adjacent images, Figure 1c). Each site was imaged by a single diver on SCUBA over a period of 10-15 minutes to capture approximately 3,000 photos. Nadiral and oblique imagery was captured at an altitude of approximately 1.5 m using a “lawn-mowing” swim pattern consisting of 5 longitudinal passes and an additional 4-8 perpendicular passes. The swim pattern and speed used ensured a minimum overlap of 80 and 60 % between temporally and spatially adjacent photos, respectively (Figure 1d). Six GPCs were distributed across the depth gradient of the site prior imaging to scale resultant models in X, Y, and Z axes (details provided in(Gordon et al., 2023). Depth was also recorded for each GPC to incorporate bathymetric information into 3D model building.\n\n\n The RapidBenthos workflow was applyed to each plots, segmenting and calssifying benthic constituents on the orthomosaics. This method resulted in extracting community compostion and colony-level metrics (i.e., colony planar-area and colony frequency). The significance of this research lies in devlopping a workflow that automatically extract community composition information from close-range photogrammetry in any coral reefs environment. We eveluated that our method was 195 time faster than manual segmentation and classification allowing to sustainably scale 3D photogrammetry mointoring, both in replication and size of reefs surveyed compared to manual data extraction.\n\n\n Due to the large data files, the data can be accessed on request.", + "extent" : { + "bbox" : [ [ 142.9417419434, -23.8933715259, 152.3920440674, -9.7347748815 ], [ 142.9417419434, -9.998605505, 142.9417419434, -9.998605505 ], [ 143.396987915, -9.7347748815, 143.396987915, -9.7347748815 ], [ 143.396987915, -9.8470978307, 143.396987915, -9.8470978307 ], [ 145.4428482056, -14.6852319114, 145.4428482056, -14.6852319114 ], [ 146.227684021, -16.86303383, 146.227684021, -16.86303383 ], [ 146.4995956421, -18.5720601133, 146.4995956421, -18.5720601133 ], [ 146.5195083618, -18.643642707, 146.5195083618, -18.643642707 ], [ 147.6466369629, -18.778916369, 147.6466369629, -18.778916369 ], [ 150.9700870514, -23.1967007098, 150.9700870514, -23.1967007098 ], [ 151.9247817993, -23.4456087744, 151.9247817993, -23.4456087744 ], [ 152.3920440674, -23.8933715259, 152.3920440674, -23.8933715259 ] ], + "temporal" : [ [ "2021-09-30T14:00:00Z", "2022-12-30T13:00:00Z" ], [ "2021-09-30T14:00:00Z", "2022-12-30T13:00:00Z" ] ] + }, + "summaries" : { + "score" : 60, + "status" : "completed", + "scope" : { + "code" : "dataset", + "name" : "" + }, + "dataset_group" : "sample", + "proj:geometry" : { + "geometries" : [ { + "type" : "Point", + "coordinates" : [ 142.9417, -9.9986 ] + }, { + "type" : "Point", + "coordinates" : [ 143.397, -9.7348 ] + }, { + "type" : "Point", + "coordinates" : [ 143.397, -9.8471 ] + }, { + "type" : "Point", + "coordinates" : [ 145.4428, -14.6852 ] + }, { + "type" : "Point", + "coordinates" : [ 146.2277, -16.863 ] + }, { + "type" : "Point", + "coordinates" : [ 146.4996, -18.5721 ] + }, { + "type" : "Point", + "coordinates" : [ 146.5195, -18.6436 ] + }, { + "type" : "Point", + "coordinates" : [ 147.6466, -18.7789 ] + }, { + "type" : "Point", + "coordinates" : [ 150.9701, -23.1967 ] + }, { + "type" : "Point", + "coordinates" : [ 151.9248, -23.4456 ] + }, { + "type" : "Point", + "coordinates" : [ 152.392, -23.8934 ] + } ], + "type" : "GeometryCollection" + }, + "temporal" : [ { + "start" : "2021-09-30T14:00:00Z", + "end" : "2022-12-30T13:00:00Z" + } ] + }, + "contacts" : [ { + "roles" : "principalInvestigator", + "organization" : "Australian Institute of Marine Science (AIMS)", + "name" : "Remmers T", + "position" : "", + "emails" : [ "reception@aims.gov.au" ], + "addresses" : [ { + "deliveryPoint" : [ "PRIVATE MAIL BAG 3, TOWNSVILLE MAIL CENTRE" ], + "city" : "TOWNSVILLE", + "country" : "Australia", + "postalCode" : "4810", + "administrativeArea" : "Queensland" + } ], + "phones" : [ { + "roles" : [ "voice" ], + "value" : "+61 7 4753 4444" + }, { + "roles" : [ "facsimile" ], + "value" : "" + } ], + "links" : [ { + "href" : "https://www.aims.gov.au", + "type" : "WWW:LINK-1.0-http--link", + "title" : "AIMS Web Site" + } ] + }, { + "roles" : "pointOfContact", + "organization" : "Australian Institute of Marine Science (AIMS)", + "name" : "AIMS Data Centre", + "position" : "", + "emails" : [ "adc@aims.gov.au" ], + "addresses" : [ { + "deliveryPoint" : [ "PRIVATE MAIL BAG 3, TOWNSVILLE MAIL CENTRE" ], + "city" : "TOWNSVILLE", + "country" : "Australia", + "postalCode" : "4810", + "administrativeArea" : "Queensland" + } ], + "phones" : [ { + "roles" : [ "voice" ], + "value" : "+61 7 4753 4444" + }, { + "roles" : [ "facsimile" ], + "value" : "" + } ], + "links" : [ { + "href" : "https://www.aims.gov.au", + "type" : "WWW:LINK-1.0-http--link", + "title" : "AIMS Web Site" + } ] + } ], + "languages" : [ { + "code" : "eng", + "name" : "English" + } ], + "links" : [ ], + "license" : "", + "providers" : [ { + "name" : "Australian Institute of Marine Science (AIMS)", + "roles" : [ "pointOfContact" ] + } ], + "themes" : [ ], + "id" : "5905b3eb-aad0-4f9c-a03e-a02fb3488082", + "record_suggest" : { + "title" : "RapidBenthos" + }, + "type" : "Collection", + "stac_version" : "1.0.0", + "stac_extensions" : [ "https://stac-extensions.github.io/scientific/v1.0.0/schema.json", "https://stac-extensions.github.io/contacts/v0.1.1/schema.json", "https://stac-extensions.github.io/projection/v1.1.0/schema.json", "https://stac-extensions.github.io/language/v1.0.0/schema.json", "https://stac-extensions.github.io/themes/v1.0.0/schema.json" ] +} From d8f70819cd54d98c8e72ec8deedc56e630317d2c Mon Sep 17 00:00:00 2001 From: utas-raymondng Date: Mon, 3 Jun 2024 15:57:25 +1000 Subject: [PATCH 7/8] pre-commit fix --- indexer/src/test/resources/canned/sample8_stac.json | 2 +- indexer/src/test/resources/canned/sample9.xml | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/indexer/src/test/resources/canned/sample8_stac.json b/indexer/src/test/resources/canned/sample8_stac.json index dcead507..d138766d 100644 --- a/indexer/src/test/resources/canned/sample8_stac.json +++ b/indexer/src/test/resources/canned/sample8_stac.json @@ -478,4 +478,4 @@ "type" : "Collection", "stac_version" : "1.0.0", "stac_extensions" : [ "https://stac-extensions.github.io/scientific/v1.0.0/schema.json", "https://stac-extensions.github.io/contacts/v0.1.1/schema.json", "https://stac-extensions.github.io/projection/v1.1.0/schema.json", "https://stac-extensions.github.io/language/v1.0.0/schema.json", "https://stac-extensions.github.io/themes/v1.0.0/schema.json" ] -} \ No newline at end of file +} diff --git a/indexer/src/test/resources/canned/sample9.xml b/indexer/src/test/resources/canned/sample9.xml index fa4753e1..819977a9 100644 --- a/indexer/src/test/resources/canned/sample9.xml +++ b/indexer/src/test/resources/canned/sample9.xml @@ -928,4 +928,3 @@ - From 50f2603416f4027df1bffed54017bfab16a33ae5 Mon Sep 17 00:00:00 2001 From: utas-raymondng Date: Tue, 4 Jun 2024 14:25:50 +1000 Subject: [PATCH 8/8] update due to PR --- .../java/au/org/aodn/esindexer/utils/GeometryUtils.java | 7 ------- .../main/java/au/org/aodn/esindexer/utils/StacUtils.java | 4 ++-- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/indexer/src/main/java/au/org/aodn/esindexer/utils/GeometryUtils.java b/indexer/src/main/java/au/org/aodn/esindexer/utils/GeometryUtils.java index 9f46cfa3..956b4ab2 100644 --- a/indexer/src/main/java/au/org/aodn/esindexer/utils/GeometryUtils.java +++ b/indexer/src/main/java/au/org/aodn/esindexer/utils/GeometryUtils.java @@ -21,13 +21,6 @@ public class GeometryUtils { protected static ObjectMapper objectMapper = new ObjectMapper(); - protected static boolean areCollinear(Coordinate p1, Coordinate p2, Coordinate p3) { - // Use the area of the triangle method to check collinearity - double area = p1.x * (p2.y - p3.y) + - p2.x * (p3.y - p1.y) + - p3.x * (p1.y - p2.y); - return area == 0; - } /** * * @param polygons - Assume to be EPSG:4326, as GeoJson always use this encoding. diff --git a/indexer/src/main/java/au/org/aodn/esindexer/utils/StacUtils.java b/indexer/src/main/java/au/org/aodn/esindexer/utils/StacUtils.java index a41e35df..3a10f3e8 100644 --- a/indexer/src/main/java/au/org/aodn/esindexer/utils/StacUtils.java +++ b/indexer/src/main/java/au/org/aodn/esindexer/utils/StacUtils.java @@ -58,7 +58,7 @@ public static List> createStacBBox(List> listOfP for (Geometry polygon : polygons) { // Add polygon one by one to expand the overall bounding box area, this is requirement // of STAC to have an overall bounding box of all smaller area as the first bbox in the list. - if (polygon != null) { + if (polygon != null && polygon.getEnvelopeInternal() != null) { overallBoundingBox.expandToInclude(polygon.getEnvelopeInternal()); hasBoundingBoxUpdate.set(true); } @@ -80,7 +80,7 @@ public static List> createStacBBox(List> listOfP final Envelope individualEnvelope = new Envelope(); for (Geometry p : polygons) { - if (p != null) { + if (p != null && p.getEnvelopeInternal() != null) { individualEnvelope.expandToInclude(p.getEnvelopeInternal()); } }