package eu.simstadt.geo.fast_xml_parser; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Comparator; import java.util.concurrent.atomic.AtomicInteger; import org.junit.jupiter.api.Test; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.geom.GeometryFactory; import org.locationtech.jts.geom.Point; import com.ximpleware.XPathParseException; import eu.simstadt.geo.RegionChooserUtils; public class ConvexHullCalculatorTests { private static final GeometryFactory gf = new GeometryFactory(); private static final Path repository = Paths.get("src/test/resources/testdata"); @Test public void testExtractConvexHullFromOneBuilding() throws IOException, XPathParseException { Path citygmlPath = repository.resolve("Gruenbuehl.proj/20140218_Gruenbuehl_LOD2_1building.gml"); Geometry hull = ConvexHullCalculator.calculateFromCityGML(citygmlPath); assertEquals(4 + 1, hull.getCoordinates().length); // Convex hull of a building should be a closed rectangle Point someBuildingPoint = gf.createPoint(new Coordinate(9.216845, 48.878196)); // WGS84 assertTrue(hull.contains(someBuildingPoint), "Hull should contain every building point"); } @Test public void testExtractConvexHullFromOneSmallRegion() throws IOException, XPathParseException { Path citygmlPath = repository.resolve("Gruenbuehl.proj/Gruenbuehl_LOD2_ALKIS_1010.gml"); Geometry hull = ConvexHullCalculator.calculateFromCityGML(citygmlPath); assertTrue(hull.getCoordinates().length > 4); // Convex hull should have at least 4 corners // Point somewhereBetweenBuildings = gf.createPoint(new Coordinate(3515883.6668538367, 5415843.300640578)); // Original coordinates, GSK3 Point somewhereBetweenBuildings = gf.createPoint(new Coordinate(9.21552249084, 48.87980446)); // WGS84 assertTrue(hull.contains(somewhereBetweenBuildings), "Hull should contain region between buildings"); } @Test public void testExtractConvexHullFromStoeckachNoBuildingPart() throws IOException, XPathParseException { Path citygmlPath = repository.resolve("Stuttgart.proj/Stöckach_überarbeitete GML-NoBuildingPart.gml"); Geometry hull = ConvexHullCalculator.calculateFromCityGML(citygmlPath); assertTrue(hull.getCoordinates().length > 4); // Convex hull should have at least 4 corners Point somewhereBetweenBuildings = gf.createPoint(new Coordinate(9.195212, 48.789062)); // WGS84 assertTrue(hull.contains(somewhereBetweenBuildings), "Hull should contain region between buildings"); } @Test public void testExtractConvexHullFromEveryCitygmlInRepository() throws IOException { int minHullCount = 6; Path cachePath = repository.resolve(".cache/hulls"); if (Files.exists(cachePath)) { // In order to make sure that hulls are calculated during the test, not just read from Cache Files.walk(cachePath).sorted(Comparator.reverseOrder()).map(Path::toFile).forEach(File::delete); } long gmlCount = RegionChooserUtils.everyCityGML(repository).count(); AtomicInteger hullCount = new AtomicInteger(0); ConvexHullCalculator.extractHullsForEveryCityGML(repository, kmlHull -> { assertTrue(kmlHull.contains("Data name=\"project\""), "KML hull should contain project name"); assertTrue(kmlHull.contains("Data name=\"srsName\""), "KML hull should contain srs name"); assertTrue(kmlHull.contains("EPSG:"), "KML hull should contain epsg id"); assertTrue(kmlHull.contains(""), "KML hull should contain coordinates"); hullCount.getAndIncrement(); }); assertTrue(gmlCount >= minHullCount, "At least " + minHullCount + " citygmls should be present in repository"); assertTrue(hullCount.get() >= minHullCount, "At least " + minHullCount + " hulls should have been calculated"); } }