Skip to content

Commit

Permalink
[doi-geolocation-fix] avoid creating hulls from polygons
Browse files Browse the repository at this point in the history
  • Loading branch information
klarakristina committed Apr 3, 2024
1 parent 6bd7760 commit ba669ff
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package se.lu.nateko.cp.meta.services.upload
import org.locationtech.jts.algorithm.hull.ConcaveHull
import org.locationtech.jts.geom.Geometry
import org.locationtech.jts.geom.GeometryCollection
import org.locationtech.jts.geom.LineString as JtsLineString
import org.locationtech.jts.geom.Point as JtsPoint
import org.locationtech.jts.geom.Polygon as JtsPolygon
import org.locationtech.jts.io.geojson.GeoJsonReader
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,23 +30,30 @@ object JtsGeoFeatureConverter:

def toCollection(points: Seq[Position]) =
GeometryCollection(points.toArray.map(toPoint), JtsGeoFactory)

def toPolygon(polygon: Polygon): JtsPolygon =
val firstPoint = polygon.vertices.headOption.toArray
val vertices = (polygon.vertices.toArray ++ firstPoint).map(v => Coordinate(v.lon, v.lat))
JtsGeoFactory.createPolygon(vertices)


object DoiGeoLocationCreator:
import JtsGeoFeatureConverter.*

def createHulls(geoFeatures: Seq[GeoFeature]): Seq[Geometry] =
geoFeatures.map: g =>
toCollection(extractPoints(g)).convexHull
g match
case b: LatLonBox => JtsGeoFeatureConverter.toPolygon(b.asPolygon)
case c: Circle => JtsGeoFeatureConverter.toPolygon(DoiGeoLocationConverter.toLatLonBox(c).asPolygon)
case poly: Polygon => JtsGeoFeatureConverter.toPolygon(poly)
case other => ConcaveHull.concaveHullByLengthRatio(toCollection(extractPoints(other)), ConcaveHullLengthRatio)

private def extractPoints(g: GeoFeature): Seq[Position] = g match
case p: Position => Seq(p)
case pin: Pin => Seq(pin.position)
case b: LatLonBox => b.asPolygon.vertices
case c: Circle => DoiGeoLocationConverter.toLatLonBox(c).asPolygon.vertices
case gt: GeoTrack => gt.points
case poly: Polygon => poly.vertices
case fc: FeatureCollection => fc.features.flatMap(extractPoints)
case _ => Seq.empty


def mergeHulls(hulls: Seq[Geometry]): Seq[Geometry] =
Expand All @@ -62,8 +69,7 @@ object DoiGeoLocationCreator:
added = true
else if hull.intersects(res(i)) then
val joined = GeometryCollection(Array(hull, res(i)), JtsGeoFactory)
// TODO Test concave hull again
val newHull = joined.convexHull()
val newHull = ConcaveHull.concaveHullByLengthRatio(joined, ConcaveHullLengthRatio)
res(i) = newHull
added = true
i += 1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class DoiGeoLocationCreatorTests extends AnyFunSpec:
"POLYGON ((2.778997883361892 48.47586819977188, 2.778997883361892 48.47632180022812, 2.779682116638108 48.47632180022812, 2.779682116638108 48.47586819977188, 2.778997883361892 48.47586819977188))",
"POLYGON ((2.7793398803880227 48.47630919977188, 2.7793398803880227 48.47676280022812, 2.7800241196119777 48.47676280022812, 2.7800241196119777 48.47630919977188, 2.7793398803880227 48.47630919977188))",
"POLYGON ((2.7802158824852485 48.47599819977188, 2.7802158824852485 48.47645180022812, 2.7809001175147516 48.47645180022812, 2.7809001175147516 48.47599819977188, 2.7802158824852485 48.47599819977188))",
"POLYGON ((2.779432 48.47323, 2.775239 48.476735, 2.783067 48.480903, 2.783584 48.480944, 2.785678 48.480789, 2.786456 48.480506, 2.786875 48.479848, 2.787856 48.478101, 2.783961 48.473986, 2.779432 48.47323))"
"POLYGON ((2.785777 48.475908, 2.787856 48.478101, 2.786875 48.479848, 2.786456 48.480506, 2.785678 48.480789, 2.784824 48.480814, 2.783953 48.480794, 2.783584 48.480944, 2.783067 48.480903, 2.782683 48.480689, 2.777622 48.477977, 2.775239 48.476735, 2.779432 48.47323, 2.782723 48.474982, 2.783961 48.473986, 2.785777 48.475908)))"
)

assert(hulls == expectedGeometries)
Expand All @@ -53,27 +53,30 @@ class DoiGeoLocationCreatorTests extends AnyFunSpec:
val mergedHulls = mergeHulls(hulls)

for (hull <- hulls)
assert(mergedHulls.exists(_.contains(hull)))
assert(mergedHulls.exists(_.covers(hull)))

assert(mergedHulls.length == 1)

it("createHulls from ocean data"):
val hulls = createHulls(TestGeoFeatures.oceanGeoTracks)

val expectedGeometries = convertStringsToJTS(
"POLYGON ((12.654 56.036, 10.852 56.056, -43.881 59.562, -52.267 63.864, -52.275 63.996, -51.726 64.159, -22.047 64.188, -6.766 62, 11.164 57.669, 11.364 57.49, 12.654 56.036))",
"POLYGON ((10.835 56.053, -42.009 58.666, -45.139 59.042, -48.277 60.092, -50.167 61.87, -52.277 63.889, -51.889 64.123, -13.521 64.9, 11.866 56.77, 10.835 56.053))",
"POLYGON ((12.667 56.014, 10.823 56.052, -42.663 59.102, -48.399 59.791, -52.265 64.002, -51.722 64.167, -23.225 64.141, -6.766 62, -0.776 60.901, 11.13 57.679, 12.667 56.014))"
"POLYGON ((-52.267 63.864, -52.275 63.996, -51.726 64.159, -22.047 64.188, -6.766 62, 11.164 57.669, 11.364 57.49, 12.654 56.036, 10.852 56.056, -1.746 59.746, -43.881 59.562, -52.267 63.864))",
"POLYGON ((-50.167 61.87, -52.277 63.889, -51.889 64.123, -13.521 64.9, 11.866 56.77, 10.835 56.053, 10.252 56.158, 0.899 58.833, -40.092 59.12, -42.009 58.666, -45.139 59.042, -48.277 60.092, -50.167 61.87))",
"POLYGON ((-48.399 59.791, -52.265 64.002, -51.722 64.167, -23.225 64.141, -6.766 62, -0.776 60.901, 11.13 57.679, 12.667 56.014, 10.823 56.052, 10.414 56.115, 6.649 57.807, -42.663 59.102, -48.399 59.791)))"
)

assert(hulls == expectedGeometries)

it("mergeHulls from ocean data"):
val hulls = createHulls(TestGeoFeatures.geoFeatures)
val hulls = createHulls(TestGeoFeatures.oceanGeoTracks)
val mergedHulls = mergeHulls(hulls)

for (hull <- hulls)
assert(mergedHulls.exists(_.contains(hull)))
val hullVertices = hull.getCoordinates().map(JtsGeoFactory.createPoint)
assert(mergedHulls.exists(h =>
hullVertices.forall(h.covers)
))

assert(mergedHulls.length == 1)

Expand Down

0 comments on commit ba669ff

Please sign in to comment.