From 8a93bab962302bc9bb41831cbb0daa419dc0a485 Mon Sep 17 00:00:00 2001 From: temi Date: Wed, 18 Sep 2024 17:00:09 +1000 Subject: [PATCH] AtlasOfLivingAustralia/fieldcapture#3292 - fixed issue with large GeometryCollection object intersection with spatial layer failing - added cache to pid intersection - added siteId parameter to controller action --- grails-app/conf/ecodata-ehcache.xml | 14 +++++ .../au/org/ala/ecodata/AdminController.groovy | 13 ++++- .../au/org/ala/ecodata/SpatialService.groovy | 56 +++++++++---------- 3 files changed, 52 insertions(+), 31 deletions(-) diff --git a/grails-app/conf/ecodata-ehcache.xml b/grails-app/conf/ecodata-ehcache.xml index 81f57baa3..b2a21cef9 100644 --- a/grails-app/conf/ecodata-ehcache.xml +++ b/grails-app/conf/ecodata-ehcache.xml @@ -38,6 +38,20 @@ 100 + + + java.io.Serializable + java.io.Serializable + + + 365 + + + 200 + + 500 + + java.io.Serializable diff --git a/grails-app/controllers/au/org/ala/ecodata/AdminController.groovy b/grails-app/controllers/au/org/ala/ecodata/AdminController.groovy index 774f96e92..67a21b83a 100644 --- a/grails-app/controllers/au/org/ala/ecodata/AdminController.groovy +++ b/grails-app/controllers/au/org/ala/ecodata/AdminController.groovy @@ -272,6 +272,7 @@ class AdminController { dateFormat.setTimeZone(timeZoneUTC) def isMERIT = params.getBoolean('isMERIT', true) Date startDate = params.getDate("startDate", ["yyyy", "yyyy-MM-dd"]) ?: dateFormat.parse(defaultStartDate) + List siteIds = params.get("siteId")?.split(",") def code = 'success' def total = 0 def offset = 0 @@ -281,7 +282,10 @@ class AdminController { log.debug("Number of fids to intersect: ${defaultFids.size()}; they are - ${defaultFids}") def totalSites List projectIds = [] - if (isMERIT) { + if (siteIds) { + totalSites = siteIds.size() + } + else if (isMERIT) { projectIds = projectService.getAllMERITProjectIds() totalSites = Site.countByStatusAndProjectsInListAndDateCreatedGreaterThan('active', projectIds, startDate) } @@ -293,7 +297,12 @@ class AdminController { while (count == batchSize) { batchStartTime = startInterimTime = System.currentTimeMillis() def sites - if (isMERIT) { + if (siteIds) { + sites = Site.findAllBySiteIdInList(siteIds, [offset: offset, max: batchSize, sort: "siteId", order: "asc"]).collect { + siteService.toMap(it, 'flat') + } + } + else if (isMERIT) { sites = Site.findAllByProjectsInListAndStatusAndDateCreatedGreaterThan(projectIds, 'active', startDate, [offset: offset, max: batchSize, sort: "siteId", order: "asc"]).collect { siteService.toMap(it, 'flat') } diff --git a/grails-app/services/au/org/ala/ecodata/SpatialService.groovy b/grails-app/services/au/org/ala/ecodata/SpatialService.groovy index 4fe2e8076..f0cb3f3aa 100644 --- a/grails-app/services/au/org/ala/ecodata/SpatialService.groovy +++ b/grails-app/services/au/org/ala/ecodata/SpatialService.groovy @@ -47,11 +47,25 @@ class SpatialService { * supplied geometry */ Map intersectGeometry(Map geoJson, List fieldIds = null) { - int length = geoJson?.toString().size() + // We are using a WKT string instead of geojson as the spatial portal validates geojson - using + // WKT allows us to get away with self intersecting polygons that users occasionally draw. + String wkt int threshold = grailsApplication.config.getProperty('spatial.geoJsonEnvelopeConversionThreshold', Integer) - Geometry geo = GeometryUtils.geoJsonMapToGeometry (geoJson) - if(length > threshold){ - geoJson = GeometryUtils.geometryToGeoJsonMap (geo.getEnvelope()) + Geometry geo + // Ignore threshold check for GeometryCollection collection + if (geo.geometryType != 'GeometryCollection') { + int length = geoJson?.toString().size() + if (length > threshold) { + geoJson = GeometryUtils.geometryToGeoJsonMap(geo.getEnvelope()) + } + + geo = GeometryUtils.geoJsonMapToGeometry (geoJson) + wkt = geo.toText() + } else { + geo = GeometryUtils.geoJsonMapToGeometry (geoJson) + GeometryCollection geometryCollection = (GeometryCollection)geo + Geometry convexHullGeometry = geometryCollection.union().convexHull() + wkt = convexHullGeometry.toText() } String url = grailsApplication.config.getProperty('spatial.baseUrl')+WKT_INTERSECT_URL_PREFIX @@ -60,9 +74,6 @@ class SpatialService { } long start = System.currentTimeMillis() - // We are using a WKT string instead of geojson as the spatial portal validates geojson - using - // WKT allows us to get away with self intersecting polygons that users occasionally draw. - String wkt = geo.toText() long end = System.currentTimeMillis() log.info("Time taken to convert geojson to wkt: ${end-start}ms") @@ -70,26 +81,9 @@ class SpatialService { Map result = [:] fieldIds.each { fid -> start = end - Map response - if (geo.geometryType == 'GeometryCollection') { - Map geometryCollectionIntersections = [:] - GeometryCollection geometryCollection = (GeometryCollection)geo - for (int i=0; i