package eu.simstadt.regionchooser; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Scanner; import java.util.concurrent.Callable; import java.util.logging.Logger; import org.locationtech.jts.geom.Polygon; import org.locationtech.jts.io.WKTReader; import org.locationtech.jts.io.WKTWriter; import org.osgeo.proj4j.CoordinateReferenceSystem; import picocli.CommandLine; import picocli.CommandLine.Command; import picocli.CommandLine.Option; // Example usage: // --input /home/ricou/Desktop/CGSC_Repository/Würzburg.proj/LoD2_566_5516_2_BY.gml,/home/ricou/Desktop/CGSC_Repository/Würzburg.proj/LoD2_568_5516_2_BY.gml // --output /home/ricou/Desktop/output.gml // --wkt /home/ricou/Desktop/grombuhl.txt @Command(name = "region_chooser", mixinStandardHelpOptions = true, version = "regionChooser x.x", description = "Extracts a region from one or more citygmls.", sortOptions = false) class RegionChooserCommandLineInterface implements Callable { private static final Logger LOGGER = Logger.getLogger(RegionChooserCommandLineInterface.class.getName()); @Option(names = { "-i", "--input" }, required = true, split = ",", description = "Citygml files to extract from", paramLabel = "input.gml") //TODO: Allow folders too? Path[] citygmls; @Option(names = { "-o", "--output" }, required = true, description = "Output file", paramLabel = "output.gml") Path outputCityGML; @Option(names = { "-e", "--epsg" }, description = "EPSG id for coordinate reference system", paramLabel = "31467") Integer espgId; @Option(names = { "-l", "--local" }, description = "Are WKT coordinates in local CRS?", paramLabel = "local_coordinates?") boolean localCoordinates; @Option(names = { "-w", "--wkt" }, required = true, description = "File containing WKT polygon, or - for stdin", paramLabel = "polygon.wkt") String wktFile = "-"; @Override public Integer call() throws Exception { //TODO: Move as much logic to utils as possible //TODO: Test CoordinateReferenceSystem localCRS; if (espgId == null) { localCRS = RegionChooserUtils.crsFromCityGMLHeader(citygmls[0]); } else { localCRS = RegionChooserUtils.crsFromSrsName("EPSG:" + espgId); } LOGGER.info("Coordinate system: " + localCRS); String wktPolygon; if (wktFile.equals("-")) { if (System.in.available() == 0) { throw new IllegalArgumentException("Please provide \"POLYGON((x1 y1, x2 y2, ...))\" to standard input."); } else { wktPolygon = getInput(); } } else { wktPolygon = new String(Files.readAllBytes(Paths.get(wktFile)), StandardCharsets.UTF_8); if (wktPolygon.isEmpty()) { throw new IllegalArgumentException("Please write \"POLYGON((x1 y1, x2 y2, ...))\" inside " + wktFile); } } if (!localCoordinates) { final WKTReader WKT_READER = new WKTReader(); final WKTWriter WKT_WRITER = new WKTWriter(); // WKT coordinates are in WGS84, so should be first converted to srsName Polygon wgs84Polygon = (Polygon) WKT_READER.read(wktPolygon); wktPolygon = WKT_WRITER .write(RegionChooserUtils.changePolygonCRS(wgs84Polygon, RegionChooserUtils.WGS84, localCRS)); } LOGGER.info("WKT Polygon expressed in local coordinates: " + wktPolygon); StringBuilder sb = RegionExtractor.selectRegionDirectlyFromCityGML(wktPolygon, localCRS.toString(), citygmls); RegionChooserUtils.writeStringBuilderToFile(sb, outputCityGML); return 0; } private static String getInput() { try (Scanner myObj = new Scanner(System.in)) { return myObj.nextLine(); } } // this example implements Callable, so parsing, error handling and handling user // requests for usage help or version help can be done with one line of code. public static void main(String... args) { int exitCode = new CommandLine(new RegionChooserCommandLineInterface()).execute(args); System.exit(exitCode); } }