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

Last change on this file since 14415 was 14415, checked in by michael2402, 4 months ago

See #16866: Drop getopt, use own option parser.

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