diff --git a/src/main/java/eu/simstadt/regionchooser/fast_xml_parser/ConvexHullCalculator.java b/src/main/java/eu/simstadt/regionchooser/fast_xml_parser/ConvexHullCalculator.java index ff23cf17780675bb483dd436b3f29608f48f1ad6..c529e7a79083e3e175b8b8e5c8b72001bd5235ab 100644 --- a/src/main/java/eu/simstadt/regionchooser/fast_xml_parser/ConvexHullCalculator.java +++ b/src/main/java/eu/simstadt/regionchooser/fast_xml_parser/ConvexHullCalculator.java @@ -52,6 +52,26 @@ private ConvexHullCalculator() { */ public static Geometry calculateFromCityGML(Path citygmlPath) throws XPathParseException, IOException { + Polygon originalConvexHull = getConvexHull(citygmlPath); + + CoordinateReferenceSystem originalCRS = RegionChooserUtils.crsFromCityGMLHeader(citygmlPath); + Polygon convexHull = RegionChooserUtils.changePolygonCRS(originalConvexHull, originalCRS, + RegionChooserUtils.WGS84); + convexHull.setUserData(originalCRS.toString()); + return convexHull; + } + + /** + * @param citygmlPath + * @return area of convex hull, in the same unit as original file. Hopefully m², but possibly ft² or even °². + * @throws XPathParseException + */ + public static double calculateArea(Path citygmlPath) throws XPathParseException { + Polygon originalConvexHull = getConvexHull(citygmlPath); + return originalConvexHull.getArea(); + } + + private static Polygon getConvexHull(Path citygmlPath) throws XPathParseException { GeometryFactory geometryFactory = new GeometryFactory(); ArrayList<Coordinate> allPoints = new ArrayList<>(); CityGmlIterator citygml = new CityGmlIterator(citygmlPath); @@ -70,12 +90,13 @@ public static Geometry calculateFromCityGML(Path citygmlPath) throws XPathParseE // Convert convex hull in original coordinates to WGS84 coordinates. // NOTE: It's faster to convert to WGS84 once the convex hull is calculated, because there are fewer points Polygon originalConvexHull = (Polygon) ch.getConvexHull(); + return originalConvexHull; + } - CoordinateReferenceSystem originalCRS = RegionChooserUtils.crsFromCityGMLHeader(citygmlPath); - Polygon convexHull = RegionChooserUtils.changePolygonCRS(originalConvexHull, originalCRS, - RegionChooserUtils.WGS84); - convexHull.setUserData(originalCRS.toString()); - return convexHull; + public static Geometry getArea(Path citygmlPath) throws XPathParseException, IOException { + Geometry geometry = calculateFromCityGML(citygmlPath); + RegionChooserUtils.changePolygonCRS((Polygon) geometry, RegionChooserUtils.WGS84, RegionChooserUtils.WGS84); + return geometry; } /** diff --git a/src/test/java/eu/simstadt/regionchooser/fast_xml_parser/ConvexHullCalculatorTests.java b/src/test/java/eu/simstadt/regionchooser/fast_xml_parser/ConvexHullCalculatorTests.java index c2b1ecb1ed97fe96cffc11e324b5123c58b4b52d..a9a52dfafac018cd45726095798687af04bcb81a 100644 --- a/src/test/java/eu/simstadt/regionchooser/fast_xml_parser/ConvexHullCalculatorTests.java +++ b/src/test/java/eu/simstadt/regionchooser/fast_xml_parser/ConvexHullCalculatorTests.java @@ -4,7 +4,6 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; - import java.io.File; import java.io.IOException; import java.nio.file.Files; @@ -46,6 +45,30 @@ public void testExtractConvexHullFromOneSmallRegion() throws IOException, XPathP assertTrue(hull.contains(somewhereBetweenBuildings), "Hull should contain region between buildings"); } + @Test + public void testAreaFromOneSmallRegion() throws IOException, XPathParseException { + Path citygmlPath = repository.resolve("Gruenbuehl.proj/Gruenbuehl_LOD2_ALKIS_1010.gml"); + double squareMeters = ConvexHullCalculator.calculateArea(citygmlPath); + double hectares = squareMeters / 10000; + assertEquals(19.0, hectares, 0.2); + + citygmlPath = repository.resolve("NewYork.proj/FamilyCourt_LOD2_with_PLUTO_attributes.gml"); + squareMeters = ConvexHullCalculator.calculateArea(citygmlPath); + // Checked with GoogleEarth + assertEquals(13000, squareMeters, 1000); + + citygmlPath = repository.resolve("NewYork.proj/ManhattanSmall.gml"); + squareMeters = ConvexHullCalculator.calculateArea(citygmlPath); + // Checked with GoogleEarth + double squareKilometers = squareMeters / 1000000; + assertEquals(1.0, squareKilometers, 0.1); + + citygmlPath = repository.resolve("Stuttgart.proj/Stuttgart_LOD0_LOD1_small.gml"); + squareMeters = ConvexHullCalculator.calculateArea(citygmlPath); + hectares = squareMeters / 10000; + assertEquals(47.5, hectares, 1); + } + @Test public void testExtractConvexHullFromStoeckachNoBuildingPart() throws IOException, XPathParseException { Path citygmlPath = repository.resolve("Stuttgart.proj/Stöckach_überarbeitete GML-NoBuildingPart.gml");