From 66b4fd21938eb28a969b888975eaeaa98e4dc5d2 Mon Sep 17 00:00:00 2001 From: Eric Duminil <eric.duminil@gmail.com> Date: Wed, 19 Feb 2025 17:00:30 +0100 Subject: [PATCH] Allows RegionChooserCLI to export hull as WKT --- .../regionchooser/RegionChooserCLI.java | 62 +++++++++++-------- .../regionchooser/RegionChooserCLITests.java | 37 ++++++++++- 2 files changed, 73 insertions(+), 26 deletions(-) diff --git a/src/main/java/eu/simstadt/regionchooser/RegionChooserCLI.java b/src/main/java/eu/simstadt/regionchooser/RegionChooserCLI.java index 11e1232..5a87b9a 100644 --- a/src/main/java/eu/simstadt/regionchooser/RegionChooserCLI.java +++ b/src/main/java/eu/simstadt/regionchooser/RegionChooserCLI.java @@ -10,6 +10,7 @@ import java.util.concurrent.Callable; import org.locationtech.proj4j.CoordinateReferenceSystem; import eu.simstadt.regionchooser.RegionChooserCLI.GetVersion; +import eu.simstadt.regionchooser.fast_xml_parser.ConvexHullCalculator; import picocli.CommandLine; import picocli.CommandLine.Command; import picocli.CommandLine.IVersionProvider; @@ -24,26 +25,22 @@ * */ -// Usage: region_chooser [-hlV] [-e=31467] -o=output.gml -w=polygon.wkt -i=input. -// gml[,input.gml...] [-i=input.gml[,input.gml...]]... -// Extracts a region from one or more citygmls. -// -i, --input=input.gml[,input.gml...] -// Citygml files to extract from -// -o, --output=output.gml Output file -// -e, --epsg=31467 EPSG id for coordinate reference system -// -l, --local Are WKT coordinates in local CRS? -// -w, --wkt=polygon.wkt File containing WKT polygon, or - for stdin -// -h, --help Show this help message and exit. -// -V, --version Print version information and exit. - - -// Example: -// --input CGSC_Repository/Würzburg.proj/LoD2_566_5516_2_BY.gml,CGSC_Repository/Würzburg.proj/LoD2_568_5516_2_BY.gml -// --output ./output.gml -// --wkt ./grombuhl.txt - - -@Command(name = "region_chooser", mixinStandardHelpOptions = true, description = "Extracts a region from one or more citygmls.", sortOptions = false, versionProvider = GetVersion.class) +// Usage: region_chooser [-hlV] [--get-hull] [-e=31467] [-o=output.gml] +// [-w=polygon.wkt] -i=input.gml[,input.gml...] [-i=input.gml +// [,input.gml...]]... +// Extracts a region from one or more citygmls, or calculates the convex hull. +// -i, --input=input.gml[,input.gml...] +// Citygml files to extract from +// -o, --output=output.gml Output file +// -e, --epsg=31467 EPSG id for coordinate reference system. +// Will use the one from input.gml if unspecified. +// -l, --local Are WKT coordinates in local CRS? +// Coordinates are in WGS84 if unspecified. +// -w, --wkt=polygon.wkt File containing WKT polygon, or - for stdin +// --get-hull Calculate the convex hull of the input CityGML files +// -h, --help Show this help message and exit. +// -V, --version Print version information and exit. +@Command(name = "region_chooser", mixinStandardHelpOptions = true, description = "Extracts a region from one or more citygmls, or calculates the convex hull.", sortOptions = false, versionProvider = GetVersion.class) class RegionChooserCLI implements Callable<Integer> { @Spec @@ -53,8 +50,7 @@ class RegionChooserCLI implements Callable<Integer> "--input" }, required = true, split = ",", description = "Citygml files to extract from", paramLabel = "input.gml") Path[] citygmls; - @Option(names = { "-o", - "--output" }, required = true, description = "Output file", paramLabel = "output.gml") + @Option(names = { "-o", "--output" }, required = false, description = "Output file", paramLabel = "output.gml") Path outputCityGML; @Option(names = { "-e", @@ -66,11 +62,28 @@ class RegionChooserCLI implements Callable<Integer> boolean localCoordinates; @Option(names = { "-w", - "--wkt" }, required = true, description = "File containing WKT polygon, or - for stdin", paramLabel = "polygon.wkt") - String wktFile = "-"; + "--wkt" }, required = false, description = "File containing WKT polygon, or - for stdin", paramLabel = "polygon.wkt") + String wktFile; + + @Option(names = { "--get-hull" }, description = "Calculate the convex hull of the input CityGML files") + boolean getHull; @Override public Integer call() throws Exception { + // Validate that either get-hull is used alone or proper extraction parameters are provided + if (!getHull && (outputCityGML == null || wktFile == null)) { + throw new CommandLine.ParameterException(spec.commandLine(), + "Either --get-hull or both --output and --wkt must be specified"); + } + + if (getHull) { + // Call the hull calculation function and output the result + String hull = ConvexHullCalculator.calculateFromCityGML(citygmls[0]).toString(); + spec.commandLine().getOut().println(hull); + return 0; + } + + // Original region extraction logic CoordinateReferenceSystem localCRS; if (espgId == null) { @@ -146,5 +159,4 @@ public String[] getVersion() throws Exception { return new String[] { RegionChooserUtils.getApplicationVersion() }; } } - } \ No newline at end of file diff --git a/src/test/java/eu/simstadt/regionchooser/RegionChooserCLITests.java b/src/test/java/eu/simstadt/regionchooser/RegionChooserCLITests.java index 2098139..837bbf1 100644 --- a/src/test/java/eu/simstadt/regionchooser/RegionChooserCLITests.java +++ b/src/test/java/eu/simstadt/regionchooser/RegionChooserCLITests.java @@ -53,10 +53,31 @@ public void restore() throws IOException { @Test void testNoInput() { new CommandLine(new RegionChooserCLI()).execute(""); - String expectedErr = "Missing required options: '--input=input.gml', '--output=output.gml', '--wkt=polygon.wkt'"; + String expectedErr = "Missing required option: '--input=input.gml'"; assertTrue(err.toString().contains(expectedErr), err.toString() + " should contain " + expectedErr); } + @Test + void testIncompleteInput() { + new CommandLine(new RegionChooserCLI()).execute("--input=whatever.gml --output=whatever2.gml"); + String expectedErr = "Either --get-hull or both --output and --wkt"; + assertTrue(err.toString().contains(expectedErr), err.toString() + " should contain " + expectedErr); + } + + @Test + void testIncompleteInput2() { + new CommandLine(new RegionChooserCLI()).execute("--input=whatever.gml --wkt=whatever.wkt"); + String expectedErr = "Either --get-hull or both --output and --wkt"; + assertTrue(err.toString().contains(expectedErr), err.toString() + " should contain " + expectedErr); + } + + @Test + void testHelp() { + new CommandLine(new RegionChooserCLI()).execute("--help"); + String expectedOut = "Extracts a region from one or more citygmls, or calculates the convex hull."; + assertTrue(out.toString().contains(expectedOut), err.toString() + " should contain " + expectedOut); + } + @Test void testGetVersion() { new CommandLine(new RegionChooserCLI()).execute("--version"); @@ -153,6 +174,20 @@ void testExtractRegionWithMissingInput() throws IOException { assertFalse(Files.exists(outGML)); } + @Test + void testGetHull() throws IOException { + Path citygml = TEST_REPOSITORY.resolve("Stuttgart.proj/Stuttgart_LOD0_LOD1_small.gml"); + new CommandLine(new RegionChooserCLI()).execute("--input=" + citygml, "--get-hull"); + String expectedCoords = "POLYGON ((9.17288"; + assertTrue(out.toString().contains(expectedCoords), out.toString() + " should contain " + expectedCoords); + + out.reset(); + citygml = TEST_REPOSITORY.resolve("NewYork.proj/ManhattanSmall.gml"); + new CommandLine(new RegionChooserCLI()).execute("--input=" + citygml, "--get-hull"); + expectedCoords = "POLYGON ((-73.9977"; + assertTrue(out.toString().contains(expectedCoords), out.toString() + " should contain " + expectedCoords); + } + private long countBuildings(Path outGML) throws IOException { return Files.readAllLines(outGML).stream().filter(line -> line.contains("bldg:Building gml:id=")).count(); } -- GitLab