source: josm/trunk/src/org/openstreetmap/josm/data/projection/ProjectionCLI.java

Last change on this file was 18366, checked in by taylor.smock, 2 years ago

Replace usages of System.exit with Lifecycle.exitJosm

This fixes some coverity scan issues (spotbugs) with respect to exiting the VM.

See #15182: Standalone JOSM validator

File size: 8.0 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.projection;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.io.BufferedReader;
7import java.io.IOException;
8import java.io.InputStreamReader;
9import java.nio.charset.Charset;
10import java.nio.charset.StandardCharsets;
11import java.nio.file.Files;
12import java.nio.file.Paths;
13import java.util.ArrayList;
14import java.util.Arrays;
15import java.util.List;
16import java.util.function.ToDoubleFunction;
17
18import org.openstreetmap.josm.cli.CLIModule;
19import org.openstreetmap.josm.data.coor.EastNorth;
20import org.openstreetmap.josm.data.coor.LatLon;
21import org.openstreetmap.josm.data.coor.conversion.LatLonParser;
22import org.openstreetmap.josm.spi.lifecycle.Lifecycle;
23import org.openstreetmap.josm.tools.OptionParser;
24
25/**
26 * Command line interface for projecting coordinates.
27 * @since 12792
28 */
29public class ProjectionCLI implements CLIModule {
30
31 /** The unique instance **/
32 public static final ProjectionCLI INSTANCE = new ProjectionCLI();
33
34 private boolean argInverse;
35 private boolean argSwitchInput;
36 private boolean argSwitchOutput;
37
38 @Override
39 public String getActionKeyword() {
40 return "project";
41 }
42
43 @Override
44 public void processArguments(String[] argArray) {
45 List<String> positionalArguments = new OptionParser("JOSM projection")
46 .addFlagParameter("help", ProjectionCLI::showHelp)
47 .addShortAlias("help", "h")
48 .addFlagParameter("inverse", () -> argInverse = true)
49 .addShortAlias("inverse", "I")
50 .addFlagParameter("switch-input", () -> argSwitchInput = true)
51 .addShortAlias("switch-input", "r")
52 .addFlagParameter("switch-output", () -> argSwitchOutput = true)
53 .addShortAlias("switch-output", "s")
54 .parseOptionsOrExit(Arrays.asList(argArray));
55
56 List<String> projParamFrom = new ArrayList<>();
57 List<String> projParamTo = new ArrayList<>();
58 List<String> otherPositional = new ArrayList<>();
59 boolean toTokenSeen = false;
60 // positional arguments:
61 for (String arg: positionalArguments) {
62 if (arg.isEmpty()) throw new IllegalArgumentException("non-empty argument expected");
63 if (arg.startsWith("+")) {
64 if ("+to".equals(arg)) {
65 toTokenSeen = true;
66 } else {
67 (toTokenSeen ? projParamTo : projParamFrom).add(arg);
68 }
69 } else {
70 otherPositional.add(arg);
71 }
72 }
73 String fromStr = String.join(" ", projParamFrom);
74 String toStr = String.join(" ", projParamTo);
75 try {
76 run(fromStr, toStr, otherPositional);
77 } catch (ProjectionConfigurationException | IllegalArgumentException | IOException ex) {
78 System.err.println(tr("Error: {0}", ex.getMessage()));
79 Lifecycle.exitJosm(true, 1);
80 }
81 Lifecycle.exitJosm(true, 0);
82 }
83
84 /**
85 * Displays help on the console
86 */
87 private static void showHelp() {
88 System.out.println(getHelp());
89 Lifecycle.exitJosm(true, 0);
90 }
91
92 private static String getHelp() {
93 return tr("JOSM projection command line interface")+"\n\n"+
94 tr("Usage")+":\n"+
95 "\tjava -jar josm.jar project <options> <crs> +to <crs> [file]\n\n"+
96 tr("Description")+":\n"+
97 tr("Converts coordinates from one coordinate reference system to another.")+"\n\n"+
98 tr("Options")+":\n"+
99 "\t--help|-h "+tr("Show this help")+"\n"+
100 "\t-I "+tr("Switch input and output crs")+"\n"+
101 "\t-r "+tr("Switch order of input coordinates (east/north, lon/lat)")+"\n"+
102 "\t-s "+tr("Switch order of output coordinates (east/north, lon/lat)")+"\n\n"+
103 tr("<crs>")+":\n"+
104 tr("The format for input and output coordinate reference system"
105 + " is similar to that of the PROJ.4 software.")+"\n\n"+
106 tr("[file]")+":\n"+
107 tr("Reads input data from one or more files listed as positional arguments. "
108 + "When no files are given, or the filename is \"-\", data is read from "
109 + "standard input.")+"\n\n"+
110 tr("Examples")+":\n"+
111 " java -jar josm.jar project +init=epsg:4326 +to +init=epsg:3857 <<<\"11.232274 50.5685716\"\n"+
112 " => 1250371.1334500168 6545331.055189664\n\n"+
113 " java -jar josm.jar project +proj=lonlat +datum=WGS84 +to +proj=merc +a=6378137 +b=6378137 +nadgrids=@null <<EOF\n" +
114 " 11d13'56.19\"E 50d34'6.86\"N\n" +
115 " 118d39'30.42\"W 37d20'18.76\"N\n"+
116 " EOF\n"+
117 " => 1250371.1334500168 6545331.055189664\n" +
118 " -1.3208998232319113E7 4486401.160664663\n";
119 }
120
121 private void run(String fromStr, String toStr, List<String> files) throws ProjectionConfigurationException, IOException {
122 CustomProjection fromProj = createProjection(fromStr);
123 CustomProjection toProj = createProjection(toStr);
124 if (this.argInverse) {
125 CustomProjection tmp = fromProj;
126 fromProj = toProj;
127 toProj = tmp;
128 }
129
130 if (files.isEmpty() || "-".equals(files.get(0))) {
131 processInput(fromProj, toProj, new BufferedReader(new InputStreamReader(System.in, Charset.defaultCharset())));
132 } else {
133 for (String file : files) {
134 try (BufferedReader br = Files.newBufferedReader(Paths.get(file), StandardCharsets.UTF_8)) {
135 processInput(fromProj, toProj, br);
136 }
137 }
138 }
139 }
140
141 private void processInput(CustomProjection fromProj, CustomProjection toProj, BufferedReader reader) throws IOException {
142 String line;
143 while ((line = reader.readLine()) != null) {
144 line = line.trim();
145 if (line.isEmpty() || line.startsWith("#"))
146 continue;
147 EastNorth enIn;
148 if (fromProj.isGeographic()) {
149 enIn = parseEastNorth(line, LatLonParser::parseCoordinate);
150 } else {
151 enIn = parseEastNorth(line, ProjectionCLI::parseDouble);
152 }
153 LatLon ll = fromProj.eastNorth2latlon(enIn);
154 EastNorth enOut = toProj.latlon2eastNorth(ll);
155 double cOut1 = argSwitchOutput ? enOut.north() : enOut.east();
156 double cOut2 = argSwitchOutput ? enOut.east() : enOut.north();
157 System.out.println(Double.toString(cOut1) + " " + Double.toString(cOut2));
158 System.out.flush();
159 }
160 }
161
162 private static CustomProjection createProjection(String params) throws ProjectionConfigurationException {
163 CustomProjection proj = new CustomProjection();
164 proj.update(params);
165 return proj;
166 }
167
168 private EastNorth parseEastNorth(String s, ToDoubleFunction<String> parser) {
169 String[] en = s.split("[;, ]+", -1);
170 if (en.length != 2)
171 throw new IllegalArgumentException(tr("Expected two coordinates, separated by white space, found {0} in ''{1}''", en.length, s));
172 double east = parser.applyAsDouble(en[0]);
173 double north = parser.applyAsDouble(en[1]);
174 if (this.argSwitchInput)
175 return new EastNorth(north, east);
176 else
177 return new EastNorth(east, north);
178 }
179
180 private static double parseDouble(String s) {
181 try {
182 return Double.parseDouble(s);
183 } catch (NumberFormatException nfe) {
184 throw new IllegalArgumentException(tr("Unable to parse number ''{0}''", s), nfe);
185 }
186 }
187
188 /**
189 * Main class to run just the projection CLI.
190 * @param args command line arguments
191 */
192 public static void main(String[] args) {
193 ProjectionCLI.INSTANCE.processArguments(args);
194 }
195}
Note: See TracBrowser for help on using the repository browser.