RegionChooserCLI.java 5.05 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
import eu.simstadt.regionchooser.RegionChooserCLI.GetVersion;
Eric Duminil's avatar
Eric Duminil committed
13
14
import picocli.CommandLine;
import picocli.CommandLine.Command;
Eric Duminil's avatar
Eric Duminil committed
15
import picocli.CommandLine.IVersionProvider;
16
import picocli.CommandLine.Model.CommandSpec;
Eric Duminil's avatar
Eric Duminil committed
17
import picocli.CommandLine.Option;
18
import picocli.CommandLine.Spec;
Eric Duminil's avatar
Eric Duminil committed
19

Eric Duminil's avatar
Eric Duminil committed
20
21
22
23

/**
 * Command Line Interface for RegionChooser. Could be useful to extract large regions on server, or automate the process
 * from batch/python scripts.
Eric Duminil's avatar
Eric Duminil committed
24
 *
Eric Duminil's avatar
Eric Duminil committed
25
26
27
28
29
30
31
32
33
 */

// 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
Eric Duminil's avatar
comment    
Eric Duminil committed
34
//   -l, --local               Are WKT coordinates in local CRS?
Eric Duminil's avatar
Eric Duminil committed
35
36
37
38
39
40
41
42
43
//   -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
44

Eric Duminil's avatar
Eric Duminil committed
45

Eric Duminil's avatar
Eric Duminil committed
46
@Command(name = "region_chooser", mixinStandardHelpOptions = true, description = "Extracts a region from one or more citygmls.", sortOptions = false, versionProvider = GetVersion.class)
Eric Duminil's avatar
Eric Duminil committed
47
class RegionChooserCLI implements Callable<Integer>
Eric Duminil's avatar
Eric Duminil committed
48
{
49
50
	@Spec
	CommandSpec spec;
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
Eric Duminil committed
54
	Path[] citygmls;
Eric Duminil's avatar
Eric Duminil committed
55

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

Eric Duminil's avatar
Notes.    
Eric Duminil committed
60
61
	@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
62
	Integer espgId;
Eric Duminil's avatar
Eric Duminil committed
63

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

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

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

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

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

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

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

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

Eric Duminil's avatar
Eric Duminil committed
105
106
107
108
109
110
		int count;

		if (outputCityGML.toString().equals("-")) {
			logInfo("CityGML written to stdout.");
			PrintWriter stdOut = spec.commandLine().getOut();
			count = RegionExtractor.selectRegionDirectlyFromCityGML(wktPolygon, localCRS.toString(), stdOut, citygmls);
Eric Duminil's avatar
Eric Duminil committed
111
			stdOut.flush(); // To make sure the footer is written too.
Eric Duminil's avatar
Eric Duminil committed
112
113
114
115
116
		} 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
	}

Eric Duminil's avatar
Eric Duminil committed
124
125
126
127
128
129
130
	// 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 RegionChooserCLI()).execute(args);
		System.exit(exitCode);
	}

131
132
133
134
	private void logInfo(String message) {
		spec.commandLine().getErr().println(message);
	}

Eric Duminil's avatar
Eric Duminil committed
135
	private static String getInput() {
Eric Duminil's avatar
Eric Duminil committed
136
137
138
		try (Scanner myObj = new Scanner(System.in)) {
			return myObj.nextLine();
		}
Eric Duminil's avatar
Eric Duminil committed
139
140
	}

Eric Duminil's avatar
Eric Duminil committed
141
142
143
144
145
146
	static class GetVersion implements IVersionProvider
	{
		@Override
		public String[] getVersion() throws Exception {
			return new String[] { RegionChooserUtils.getApplicationVersion() };
		}
Eric Duminil's avatar
Eric Duminil committed
147
	}
Eric Duminil's avatar
Eric Duminil committed
148

Eric Duminil's avatar
Eric Duminil committed
149
}