From 6d9708e7e8688727fbb6e1db04cf667854addba7 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 19 Nov 2020 22:09:54 -0800 Subject: Fix polygon area calculation --- build.gradle | 2 ++ .../java/org/traccar/geofence/GeofencePolygon.java | 40 +++++++--------------- .../org/traccar/geofence/GeofencePolygonTest.java | 13 +++++-- 3 files changed, 24 insertions(+), 31 deletions(-) diff --git a/build.gradle b/build.gradle index 7207328f2..fb3eceaa6 100644 --- a/build.gradle +++ b/build.gradle @@ -68,6 +68,8 @@ dependencies { implementation "org.apache.velocity:velocity-tools:2.0" implementation "org.apache.commons:commons-collections4:4.4" implementation "org.mnode.ical4j:ical4j:2.0.5" // needs upgrade + implementation "org.locationtech.spatial4j:spatial4j:0.7" + implementation "org.locationtech.jts:jts-core:1.17.1" implementation "com.fizzed:ch-smpp:6.0.0-netty4-beta-3" implementation "net.java.dev.jna:jna-platform:5.6.0" implementation "com.github.jnr:jnr-posix:3.1.2" diff --git a/src/main/java/org/traccar/geofence/GeofencePolygon.java b/src/main/java/org/traccar/geofence/GeofencePolygon.java index c03a71225..cd2cbf16a 100644 --- a/src/main/java/org/traccar/geofence/GeofencePolygon.java +++ b/src/main/java/org/traccar/geofence/GeofencePolygon.java @@ -15,9 +15,16 @@ */ package org.traccar.geofence; +import org.locationtech.spatial4j.context.SpatialContext; +import org.locationtech.spatial4j.context.jts.JtsSpatialContextFactory; +import org.locationtech.spatial4j.shape.ShapeFactory; +import org.locationtech.spatial4j.shape.jts.JtsShapeFactory; + import java.text.ParseException; import java.util.ArrayList; +import static org.locationtech.spatial4j.distance.DistanceUtils.DEG_TO_KM; + public class GeofencePolygon extends GeofenceGeometry { public GeofencePolygon() { @@ -107,37 +114,14 @@ public class GeofencePolygon extends GeofenceGeometry { return oddNodes; } - private double toRadians(double input) { - return input / 180.0 * Math.PI; - } - - private double polarTriangleArea(double tan1, double lng1, double tan2, double lng2) { - double deltaLng = lng1 - lng2; - double t = tan1 * tan2; - return 2 * Math.atan2(t * Math.sin(deltaLng), 1 + t * Math.sin(deltaLng)); - } - @Override public double calculateArea() { - if (coordinates.size() < 3) { - return 0; - } - - double total = 0; - Coordinate prev = coordinates.get(coordinates.size() - 1); - double prevTanLat = Math.tan((Math.PI / 2 - toRadians(prev.getLat())) / 2); - double prevLng = toRadians(prev.getLon()); - - for (Coordinate point : coordinates) { - double tanLat = Math.tan((Math.PI / 2 - toRadians(point.getLat())) / 2); - double lng = toRadians(point.getLon()); - total += polarTriangleArea(tanLat, lng, prevTanLat, prevLng); - prevTanLat = tanLat; - prevLng = lng; + JtsShapeFactory jtsShapeFactory = new JtsSpatialContextFactory().newSpatialContext().getShapeFactory(); + ShapeFactory.PolygonBuilder polygonBuilder = jtsShapeFactory.polygon(); + for (Coordinate coordinate : coordinates) { + polygonBuilder.pointXY(coordinate.getLon(), coordinate.getLat()); } - - double earthRadius = 6371009; - return total * (earthRadius * earthRadius); + return polygonBuilder.build().getArea(SpatialContext.GEO) * DEG_TO_KM * DEG_TO_KM; } @Override diff --git a/src/test/java/org/traccar/geofence/GeofencePolygonTest.java b/src/test/java/org/traccar/geofence/GeofencePolygonTest.java index 94b73af3a..cc9c46c94 100644 --- a/src/test/java/org/traccar/geofence/GeofencePolygonTest.java +++ b/src/test/java/org/traccar/geofence/GeofencePolygonTest.java @@ -5,10 +5,17 @@ import java.text.ParseException; import org.junit.Test; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; public class GeofencePolygonTest { + @Test + public void testCalculateArea() throws ParseException { + String test = "POLYGON((-23.559204099194772 148.8653145299711, -23.6000443437826 148.85956016213583, -23.600411843430095 148.89462111436828, -23.5626384786532 148.90278297873897, -23.5574863232753 148.88137329347367, -23.559204099194772 148.8653145299711))"; + assertEquals(17, new GeofencePolygon(test).calculateArea(), 1); + } + @Test public void testPolygonWkt() throws ParseException { String test = "POLYGON ((55.75474 37.61823, 55.75513 37.61888, 55.7535 37.6222, 55.75315 37.62165))"; @@ -23,7 +30,7 @@ public class GeofencePolygonTest { GeofenceGeometry geofenceGeometry = new GeofencePolygon(); geofenceGeometry.fromWkt(test); assertTrue(geofenceGeometry.containsPoint(55.75476, 37.61915)); - assertTrue(!geofenceGeometry.containsPoint(55.75545, 37.61921)); + assertFalse(geofenceGeometry.containsPoint(55.75545, 37.61921)); } @@ -34,7 +41,7 @@ public class GeofencePolygonTest { geofenceGeometry.fromWkt(test); assertTrue(geofenceGeometry.containsPoint(66.9015, -180.0096)); assertTrue(geofenceGeometry.containsPoint(66.9015, 179.991)); - assertTrue(!geofenceGeometry.containsPoint(66.8368, -179.8792)); + assertFalse(geofenceGeometry.containsPoint(66.8368, -179.8792)); } @@ -45,7 +52,7 @@ public class GeofencePolygonTest { geofenceGeometry.fromWkt(test); assertTrue(geofenceGeometry.containsPoint(51.0466, -0.0165)); assertTrue(geofenceGeometry.containsPoint(51.0466, 0.018)); - assertTrue(!geofenceGeometry.containsPoint(50.9477, 0.5836)); + assertFalse(geofenceGeometry.containsPoint(50.9477, 0.5836)); } -- cgit v1.2.3