RegionChooserCLI.java 4.74 KB
Newer Older
Eric Duminil's avatar
Eric Duminil committed
1
2
package eu.simstadt.regionchooser;

Eric Duminil's avatar
Eric Duminil committed
3
import java.io.BufferedWriter;
Eric Duminil's avatar
Eric Duminil committed
4
import java.io.PrintWriter;
Eric Duminil's avatar
Eric Duminil committed
5
import java.nio.charset.StandardCharsets;
Eric Duminil's avatar
Eric Duminil committed
6
import java.nio.file.Files;
Eric Duminil's avatar
Eric Duminil committed
7
import java.nio.file.Path;
Eric Duminil's avatar
Eric Duminil committed
8
import java.nio.file.Paths;
Eric Duminil's avatar
Eric Duminil committed
9
import java.util.Scanner;
Eric Duminil's avatar
Eric Duminil committed
10
import java.util.concurrent.Callable;
Eric Duminil's avatar
Eric Duminil committed
11
import org.osgeo.proj4j.CoordinateReferenceSystem;
Eric Duminil's avatar
Eric Duminil committed
12
13
import picocli.CommandLine;
import picocli.CommandLine.Command;
14
import picocli.CommandLine.Model.CommandSpec;
Eric Duminil's avatar
Eric Duminil committed
15
import picocli.CommandLine.Option;
16
import picocli.CommandLine.Spec;
Eric Duminil's avatar
Eric Duminil committed
17

Eric Duminil's avatar
Eric Duminil committed
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

/**
 * Command Line Interface for RegionChooser. Could be useful to extract large regions on server, or automate the process
 * from batch/python scripts.
 * 
 */

// 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
Eric Duminil's avatar
Eric Duminil committed
42

Eric Duminil's avatar
Eric Duminil committed
43

Eric Duminil's avatar
Notes.    
Eric Duminil committed
44
@Command(name = "region_chooser", mixinStandardHelpOptions = true, version = "regionChooser 0.2.9", description = "Extracts a region from one or more citygmls.", sortOptions = false)
Eric Duminil's avatar
Eric Duminil committed
45
class RegionChooserCLI implements Callable<Integer>
Eric Duminil's avatar
Eric Duminil committed
46
{
47
48
	@Spec
	CommandSpec spec;
Eric Duminil's avatar
Notes.    
Eric Duminil committed
49

50
	//TODO: Add --gui?
Eric Duminil's avatar
Notes.    
Eric Duminil committed
51

Eric Duminil's avatar
Eric Duminil committed
52
53
	@Option(names = { "-i",
			"--input" }, required = true, split = ",", description = "Citygml files to extract from", paramLabel = "input.gml")
Eric Duminil's avatar
todo    
Eric Duminil committed
54
	//TODO: Allow folders too?
Eric Duminil's avatar
Eric Duminil committed
55
	Path[] citygmls;
Eric Duminil's avatar
Eric Duminil committed
56

Eric Duminil's avatar
Eric Duminil committed
57
58
	@Option(names = { "-o",
			"--output" }, required = true, description = "Output file", paramLabel = "output.gml")
Eric Duminil's avatar
Eric Duminil committed
59
	Path outputCityGML;
Eric Duminil's avatar
Eric Duminil committed
60

Eric Duminil's avatar
Notes.    
Eric Duminil committed
61
62
	@Option(names = { "-e",
			"--epsg" }, description = "EPSG id for coordinate reference system.\nWill use the one from input.gml if unspecified.", paramLabel = "31467")
Eric Duminil's avatar
Eric Duminil committed
63
	Integer espgId;
Eric Duminil's avatar
Eric Duminil committed
64

Eric Duminil's avatar
Eric Duminil committed
65
	@Option(names = { "-l",
Eric Duminil's avatar
Notes.    
Eric Duminil committed
66
			"--local" }, description = "Are WKT coordinates in local CRS?\nCoordinates are in WGS84 if unspecified.", paramLabel = "local_coordinates?")
Eric Duminil's avatar
Eric Duminil committed
67
	boolean localCoordinates;
Eric Duminil's avatar
Eric Duminil committed
68

Eric Duminil's avatar
Eric Duminil committed
69
	@Option(names = { "-w",
Eric Duminil's avatar
Eric Duminil committed
70
			"--wkt" }, required = true, description = "File containing WKT polygon, or - for stdin", paramLabel = "polygon.wkt")
Eric Duminil's avatar
Eric Duminil committed
71
72
	String wktFile = "-";

Eric Duminil's avatar
Eric Duminil committed
73
	@Override
Eric Duminil's avatar
Eric Duminil committed
74
	public Integer call() throws Exception {
Eric Duminil's avatar
Eric Duminil committed
75
		CoordinateReferenceSystem localCRS;
Eric Duminil's avatar
Eric Duminil committed
76

Eric Duminil's avatar
Eric Duminil committed
77
		if (espgId == null) {
Eric Duminil's avatar
Eric Duminil committed
78
			localCRS = RegionChooserUtils.crsFromCityGMLHeader(citygmls[0]);
Eric Duminil's avatar
Eric Duminil committed
79
		} else {
Eric Duminil's avatar
Eric Duminil committed
80
			localCRS = RegionChooserUtils.crsFromSrsName("EPSG:" + espgId);
Eric Duminil's avatar
Eric Duminil committed
81
		}
82
		logInfo("Coordinate system: " + localCRS);
Eric Duminil's avatar
Eric Duminil committed
83

Eric Duminil's avatar
Eric Duminil committed
84
		String wktPolygon;
Eric Duminil's avatar
Eric Duminil committed
85

Eric Duminil's avatar
Eric Duminil committed
86
87
		if (wktFile.equals("-")) {
			if (System.in.available() == 0) {
Eric Duminil's avatar
Eric Duminil committed
88
				throw new IllegalArgumentException("Please provide \"POLYGON((x1 y1, x2 y2, ...))\" to standard input.");
Eric Duminil's avatar
Eric Duminil committed
89
			} else {
Eric Duminil's avatar
Eric Duminil committed
90
				wktPolygon = getInput();
Eric Duminil's avatar
Eric Duminil committed
91
			}
Eric Duminil's avatar
Eric Duminil committed
92
		} else {
Eric Duminil's avatar
Eric Duminil committed
93
94
95
96
			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);
			}
Eric Duminil's avatar
Eric Duminil committed
97
		}
Eric Duminil's avatar
Eric Duminil committed
98

Eric Duminil's avatar
Eric Duminil committed
99
100
		if (!localCoordinates) {
			// WKT coordinates are in WGS84, so should be first converted to srsName
Eric Duminil's avatar
Eric Duminil committed
101
			wktPolygon = RegionChooserUtils.wktPolygonToLocalCRS(wktPolygon, localCRS);
Eric Duminil's avatar
Eric Duminil committed
102
103
		}

104
		logInfo("WKT Polygon expressed in local coordinates: " + wktPolygon);
Eric Duminil's avatar
Eric Duminil committed
105

Eric Duminil's avatar
Eric Duminil committed
106
107
108
109
110
111
112
113
114
115
116
		int count;

		if (outputCityGML.toString().equals("-")) {
			logInfo("CityGML written to stdout.");
			PrintWriter stdOut = spec.commandLine().getOut();
			count = RegionExtractor.selectRegionDirectlyFromCityGML(wktPolygon, localCRS.toString(), stdOut, citygmls);
		} else {
			try (BufferedWriter gmlWriter = Files.newBufferedWriter(outputCityGML)) {
				count = RegionExtractor.selectRegionDirectlyFromCityGML(wktPolygon, localCRS.toString(), gmlWriter,
						citygmls);
			}
Eric Duminil's avatar
Eric Duminil committed
117
		}
Eric Duminil's avatar
Eric Duminil committed
118

Eric Duminil's avatar
Eric Duminil committed
119
120
		logInfo("Found buildings : " + count);

Eric Duminil's avatar
Eric Duminil committed
121
		return 0;
Eric Duminil's avatar
Eric Duminil committed
122
123
	}

124
125
126
127
	private void logInfo(String message) {
		spec.commandLine().getErr().println(message);
	}

Eric Duminil's avatar
Eric Duminil committed
128
	private static String getInput() {
Eric Duminil's avatar
Eric Duminil committed
129
130
131
		try (Scanner myObj = new Scanner(System.in)) {
			return myObj.nextLine();
		}
Eric Duminil's avatar
Eric Duminil committed
132
133
	}

Eric Duminil's avatar
Eric Duminil committed
134
135
136
	// 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) {
Eric Duminil's avatar
Eric Duminil committed
137
		int exitCode = new CommandLine(new RegionChooserCLI()).execute(args);
Eric Duminil's avatar
Eric Duminil committed
138
		System.exit(exitCode);
Eric Duminil's avatar
Eric Duminil committed
139
	}
Eric Duminil's avatar
Eric Duminil committed
140
}