Skip to content

Commit

Permalink
Intersect features of compound sites individually #929
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisala committed Jun 17, 2024
1 parent 8c8ee76 commit eb944af
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 25 deletions.
15 changes: 13 additions & 2 deletions grails-app/conf/ecodata-ehcache.xml
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,13 @@
<heap unit="entries">100</heap>
</resources>
</cache>
<cache alias="spatialGeoJsonPidObjectGeometry">
<cache alias="spatialPidObjectGeometry">

<key-type>java.io.Serializable</key-type>
<value-type>java.io.Serializable</value-type>

<expiry>
<tti unit="days">45</tti>
<tti unit="days">365</tti>
</expiry>
<resources>
<heap unit="entries">100</heap>
Expand All @@ -69,6 +69,17 @@
</expiry>
<heap>10</heap>
</cache>

<cache alias="userDetailsCache">

<expiry>
<ttl unit="days">1</ttl>
</expiry>
<resources>
<heap unit="entries">2000</heap>
</resources>
</cache>

<cache-template name="defaultSetting">
<key-type>java.io.Serializable</key-type>
<value-type>java.util.HashMap</value-type>
Expand Down
4 changes: 3 additions & 1 deletion grails-app/conf/logback.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
</encoder>
</appender>

<logger name="au.org.ala.ecodata" level="DEBUG" />
<logger name="au.org.ala.ecodata" level="INFO" />
<logger name="au.org.ala.ecodata.SpatialService" level="DEBUG"/>
<logger name="org.elasticsearch.client" level="ERROR" />

<logger name="org.ehcache" level="DEBUG" />

Expand Down
16 changes: 14 additions & 2 deletions grails-app/services/au/org/ala/ecodata/SiteService.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -860,8 +860,20 @@ class SiteService {
geographicFacets = spatialService.intersectPid(site.extent.geometry.pid as String, fid, fidsToLookup)
break
default:
Map geom = geometryAsGeoJson(site)
geographicFacets = spatialService.intersectGeometry(geom, fidsToLookup)
if (site.type == Site.TYPE_COMPOUND) {
geographicFacets = [:].withDefault{[]}
site.features.each { Map feature ->
Map featureIntersection = spatialService.intersectGeometry(feature.geometry, fidsToLookup)
featureIntersection.each{k, v ->
geographicFacets[k] += v
geographicFacets[k] = geographicFacets[k].unique()
}
}
}
else {
Map geom = geometryAsGeoJson(site)
geographicFacets = spatialService.intersectGeometry(geom, fidsToLookup)
}
break
}
geographicFacets ?: [:]
Expand Down
37 changes: 17 additions & 20 deletions grails-app/services/au/org/ala/ecodata/SpatialService.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import grails.core.GrailsApplication
import grails.plugin.cache.Cacheable
import groovy.json.JsonParserType
import groovy.json.JsonSlurper
import org.geotools.geojson.geom.GeometryJSON
import org.locationtech.jts.geom.Coordinate
import org.locationtech.jts.geom.Geometry
import org.locationtech.jts.geom.GeometryFactory
Expand Down Expand Up @@ -47,8 +46,8 @@ class SpatialService {
Map<String,List<String>> intersectGeometry(Map geoJson, List<String> fieldIds = null) {
int length = geoJson?.toString().size()
int threshold = grailsApplication.config.getProperty('spatial.geoJsonEnvelopeConversionThreshold', Integer)
Geometry geo = GeometryUtils.geoJsonMapToGeometry (geoJson)
if(length > threshold){
Geometry geo = GeometryUtils.geoJsonMapToGeometry (geoJson)
geoJson = GeometryUtils.geometryToGeoJsonMap (geo.getEnvelope())
}

Expand All @@ -60,12 +59,11 @@ 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 = GeometryUtils.geoJsonMapToGeometry(geoJson).toText()
String wkt = geo.toText()
long end = System.currentTimeMillis()
log.info("Time taken to convert geojson to wkt: ${end-start}ms")



Map result = [:]
fieldIds.each { fid ->
start = end
Expand All @@ -78,7 +76,7 @@ class SpatialService {
}

start = end
filterOutObjectsInBoundary(result, geoJson)
filterOutObjectsInBoundary(result, geo)
end = System.currentTimeMillis()
log.info("Time taken to filter out objects in boundary: ${end-start}ms")

Expand Down Expand Up @@ -124,15 +122,20 @@ class SpatialService {
convertResponsesToGeographicFacets(result)
}

private void filterOutObjectsInBoundary(Map response, Map mainObjectGeoJson) {
Geometry mainGeometry = GeometryUtils.geoJsonMapToGeometry(mainObjectGeoJson)
filterOutObjectsInBoundary(response, mainGeometry)
}

/**
* Spatial portal intersection returns values at the boundary. This function filters the boundary intersection by
* comparing if the area of intersection is less than a predefined amount 5% (this is configurable).
* NOTE: GeoJSON objects must be valid for filtering out to work.
* @param response - per layer/fid intersection values - [ "cl34" : [[pid: 123, name: "ACT", fid: "cl34", id: "ACT" ...], ...]
* @param mainObjectGeoJson - GeoJSON object that is used to intersect with layers.
*/
void filterOutObjectsInBoundary(Map response, Map mainObjectGeoJson) {
Geometry mainGeometry = GeometryUtils.geoJsonMapToGeometry(mainObjectGeoJson)
private void filterOutObjectsInBoundary(Map response, Geometry mainGeometry) {

if (!mainGeometry.isValid()) {
log.info("Main geometry invalid. Cannot check intersection is near boundary.")
return
Expand All @@ -146,14 +149,8 @@ class SpatialService {
log.debug("Intersecting ${obj.fieldname}(${fid}) - ${obj.name} ")
// Get geoJSON of the object stored in spatial portal
long start = System.currentTimeMillis()
// def boundaryGeoJson = getGeoJsonForPidToMap(boundaryPid)
// long end = System.currentTimeMillis()
// log.debug("Time taken to get geojson for pid $boundaryPid: ${end-start}ms")
//
// start = end
// Geometry boundaryGeometry = GeometryUtils.geoJsonMapToGeometry(boundaryGeoJson)
//def proxy = grailsApplication.mainContext.spatialService
Geometry boundaryGeometry = getGeoJsonForPidToGeometry(boundaryPid)

Geometry boundaryGeometry = getGeometryForPid(boundaryPid)
long end = System.currentTimeMillis()
log.debug("Time taken to convert geojson to geometry for pid $boundaryPid: ${end-start}ms")

Expand Down Expand Up @@ -246,20 +243,20 @@ class SpatialService {
getGeoJsonForPid(pid)
}

@Cacheable(value = "spatialGeoJsonPidObjectGeometry", key={pid})
Geometry getGeoJsonForPidToGeometry(String pid) {
log.debug("Cache miss for getGeoJsonForPidToMap($pid)")
log.debug("Cache miss for getGeoJsonForPid($pid)")
@Cacheable(value = "spatialPidObjectGeometry", key={pid})
Geometry getGeometryForPid(String pid) {
log.debug("Cache miss for getGeometryForPid($pid)")
String url = grailsApplication.config.getProperty('spatial.baseUrl')+"/ws/shapes/wkt/$pid"
String wkt = webService.get(url)

Geometry geometry = null
try {
geometry = new WKTReader().read(wkt)
log.info("*************************************Successfully created geometry for pid $pid")
}
catch (Exception e) {
log.error("Error reading geometry for pid $pid")
// Ehcache throws an error if a null value is returned, so we create a dummy geometry
// that won't intersect with anything.
geometry = new GeometryFactory().createPoint(new Coordinate(0, 0))
}
geometry
Expand Down

0 comments on commit eb944af

Please sign in to comment.