1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2005-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
10 /// @file    polyconvert_main.cpp
11 /// @author  Daniel Krajzewicz
12 /// @author  Jakob Erdmann
13 /// @author  Christoph Sommer
14 /// @author  Michael Behrisch
15 /// @author  Melanie Knocke
16 /// @date    Mon, 05 Dec 2005
17 /// @version $Id$
18 ///
19 // Main for POLYCONVERT
20 /****************************************************************************/
21 
22 
23 // ===========================================================================
24 // included modules
25 // ===========================================================================
26 #include <config.h>
27 
28 #ifdef HAVE_VERSION_H
29 #include <version.h>
30 #endif
31 
32 #include <iostream>
33 #include <string>
34 #include <utils/options/OptionsIO.h>
35 #include <utils/options/OptionsCont.h>
36 #include <utils/common/UtilExceptions.h>
37 #include <utils/common/StringTokenizer.h>
38 #include <utils/common/SystemFrame.h>
39 #include <utils/common/MsgHandler.h>
40 #include <utils/common/StringUtils.h>
41 #include <utils/common/ToString.h>
42 #include <utils/iodevices/OutputDevice.h>
43 #include <utils/importio/LineReader.h>
44 #include <utils/geom/GeoConvHelper.h>
45 #include <utils/geom/GeomConvHelper.h>
46 #include <utils/geom/Boundary.h>
47 #include <utils/xml/SUMOSAXReader.h>
48 #include <utils/xml/XMLSubSys.h>
49 #include <polyconvert/PCLoaderVisum.h>
50 #include <polyconvert/PCLoaderDlrNavteq.h>
51 #include <polyconvert/PCLoaderXML.h>
52 #include <polyconvert/PCLoaderOSM.h>
53 #include <polyconvert/PCLoaderArcView.h>
54 #include <polyconvert/PCTypeMap.h>
55 #include <polyconvert/PCTypeDefHandler.h>
56 #include <polyconvert/PCNetProjectionLoader.h>
57 #include <polyconvert/pc_typemap.h>
58 
59 
60 // ===========================================================================
61 // method definitions
62 // ===========================================================================
63 void
fillOptions()64 fillOptions() {
65     OptionsCont& oc = OptionsCont::getOptions();
66     oc.addCallExample("-c <CONFIGURATION>", "run with configuration options set in file");
67 
68     // insert options sub-topics
69     SystemFrame::addConfigurationOptions(oc); // fill this subtopic, too
70     oc.addOptionSubTopic("Input");
71     oc.addOptionSubTopic("Output");
72     GeoConvHelper::addProjectionOptions(oc);
73     oc.addOptionSubTopic("Pruning");
74     oc.addOptionSubTopic("Processing");
75     oc.addOptionSubTopic("Building Defaults");
76     SystemFrame::addReportOptions(oc); // fill this subtopic, too
77 
78 
79     // register options
80     // add i/o options
81     // original network
82     oc.doRegister("net-file", 'n', new Option_FileName());
83     oc.addSynonyme("net-file", "net");
84     oc.addDescription("net-file", "Input", "Loads SUMO-network FILE as reference to offset and projection");
85 
86     // dlrnavteq import
87     oc.doRegister("dlr-navteq-poly-files", new Option_FileName());
88     oc.addDescription("dlr-navteq-poly-files", "Input", "Reads polygons from FILE assuming they're coded in DLR-Navteq (Elmar)-format");
89     oc.doRegister("dlr-navteq-poi-files", new Option_FileName());
90     oc.addDescription("dlr-navteq-poi-files", "Input", "Reads pois from FILE+ assuming they're coded in DLR-Navteq (Elmar)-format");
91 
92     // visum import
93     oc.doRegister("visum-files", new Option_FileName());
94     oc.addSynonyme("visum-files", "visum");
95     oc.addDescription("visum-files", "Input", "Reads polygons from FILE assuming it's a Visum-net");
96 
97     // xml import
98     oc.doRegister("xml-files", new Option_FileName());
99     oc.addSynonyme("xml-files", "xml");
100     oc.addDescription("xml-files", "Input", "Reads pois and shapes from FILE assuming they're coded in XML");
101 
102     // osm import
103     oc.doRegister("osm-files", new Option_FileName());
104     oc.addSynonyme("osm-files", "osm");
105     oc.addDescription("osm-files", "Input", "Reads pois from FILE+ assuming they're coded in OSM");
106     oc.doRegister("osm.keep-full-type", new Option_Bool(false));
107     oc.addDescription("osm.keep-full-type", "Input", "The type will be made of the key-value - pair");
108     oc.doRegister("osm.use-name", new Option_Bool(false));
109     oc.addDescription("osm.use-name", "Input", "The id will be set from the given 'name' attribute");
110     oc.doRegister("osm.merge-relations", new Option_Float(-1));
111     oc.addDescription("osm.merge-relations", "Input", "If FLOAT >= 0, assemble one polygon from all ways of a relation if they all connect with gaps below FLOAT");
112 
113     // arcview import
114     oc.doRegister("shapefile-prefixes", new Option_FileName());
115     oc.addSynonyme("shapefile-prefixes", "shapefile-prefix");
116     oc.addSynonyme("shapefile-prefixes", "shapefile");
117     oc.addSynonyme("shapefile-prefixes", "shape-files", true);
118     oc.addDescription("shapefile-prefixes", "Input", "Reads shapes from shapefiles FILE+");
119 
120     oc.doRegister("shapefile.guess-projection", new Option_Bool(false));
121     oc.addSynonyme("shapefile.guess-projection", "arcview.guess-projection", true);
122     oc.addDescription("shapefile.guess-projection", "Input", "Guesses the shapefile's projection");
123 
124     oc.doRegister("shapefile.id-column", new Option_String());
125     oc.addSynonyme("shapefile.id-column", "shapefile.id-name", true);
126     oc.addSynonyme("shapefile.id-column", "shape-files.id-name", true);
127     oc.addDescription("shapefile.id-column", "Input", "Defines in which column the id can be found");
128 
129     oc.doRegister("shapefile.use-running-id", new Option_Bool(false));
130     oc.addDescription("shapefile.use-running-id", "Input", "A running number will be used as id");
131 
132     oc.doRegister("shapefile.add-param", new Option_Bool(false));
133     oc.addDescription("shapefile.add-param", "Input", "Extract all additional columns as params");
134 
135     oc.doRegister("shapefile.fill", new Option_String());
136     oc.addDescription("shapefile.fill", "Input", "[auto|true|false]. Forces the 'fill' status to the given value. Default 'auto' tries to determine it from the data type");
137 
138     // typemap reading
139     oc.doRegister("type-file", new Option_FileName());
140     oc.addSynonyme("type-file", "typemap", true);
141     oc.addDescription("type-file", "Input", "Reads types from FILE");
142 
143 
144     // output
145     oc.doRegister("output-file", 'o', new Option_FileName());
146     oc.addSynonyme("output-file", "output");
147     oc.addDescription("output-file", "Output", "Write generated polygons/pois to FILE");
148 
149     oc.doRegister("dlr-tdp-output", new Option_FileName());
150     oc.addDescription("dlr-tdp-output", "Output", "Write generated polygons/pois to a dlr-tdp file with the given prefix");
151 
152 
153     // prunning options
154     oc.doRegister("prune.in-net", new Option_Bool(false));
155     oc.addSynonyme("prune.in-net", "prune.on-net", true);
156     oc.addDescription("prune.in-net", "Pruning", "Enables pruning on net boundaries");
157 
158     oc.doRegister("prune.in-net.offsets", new Option_String("0,0,0,0"));
159     oc.addSynonyme("prune.in-net.offsets", "prune.on-net.offsets", true);
160     oc.addDescription("prune.in-net.offsets", "Pruning", "Uses STR as offset definition added to the net boundaries");
161 
162     oc.doRegister("prune.boundary", new Option_String());
163     oc.addDescription("prune.boundary", "Pruning", "Uses STR as pruning boundary");
164 
165     oc.doRegister("prune.keep-list", new Option_String());
166     oc.addSynonyme("prune.keep-list", "prune.keep");
167     oc.addSynonyme("prune.keep-list", "prune.ignore", true);
168     oc.addDescription("prune.keep-list", "Pruning", "Items in STR will be kept though out of boundary");
169 
170     oc.doRegister("prune.explicit", new Option_String(""));
171     oc.addSynonyme("prune.explicit", "remove");
172     oc.addDescription("prune.explicit", "Pruning", "Items with names in STR will be removed");
173 
174 
175     oc.doRegister("offset.x", new Option_Float(0));
176     oc.addSynonyme("offset.x", "x-offset-to-apply", true);
177     oc.addDescription("offset.x", "Processing", "Adds FLOAT to net x-positions");
178 
179     oc.doRegister("offset.y", new Option_Float(0));
180     oc.addSynonyme("offset.y", "y-offset-to-apply", true);
181     oc.addDescription("offset.y", "Processing", "Adds FLOAT to net y-positions");
182 
183     oc.doRegister("all-attributes", new Option_Bool(false));
184     oc.addDescription("all-attributes", "Processing", "Imports all attributes as key/value pairs");
185 
186     oc.doRegister("ignore-errors", new Option_Bool(false));
187     oc.addDescription("ignore-errors", "Processing", "Continue on broken input");
188 
189     oc.doRegister("poi-layer-offset", new Option_Float(0));
190     oc.addDescription("poi-layer-offset", "Processing", "Adds FLOAT to the layer value for each poi (i.e. to raise it above polygons)");
191 
192     // building defaults options
193     oc.doRegister("color", new Option_String("0.2,0.5,1."));
194     oc.addDescription("color", "Building Defaults", "Sets STR as default color");
195 
196     oc.doRegister("prefix", new Option_String(""));
197     oc.addDescription("prefix", "Building Defaults", "Sets STR as default prefix");
198 
199     oc.doRegister("type", new Option_String("unknown"));
200     oc.addDescription("type", "Building Defaults", "Sets STR as default type");
201 
202     oc.doRegister("fill", new Option_Bool("false"));
203     oc.addDescription("fill", "Building Defaults", "Fills polygons by default");
204 
205     oc.doRegister("layer", new Option_Float(-1));
206     oc.addDescription("layer", "Building Defaults", "Sets FLOAT as default layer");
207 
208     oc.doRegister("discard", new Option_Bool(false));
209     oc.addDescription("discard", "Building Defaults", "Sets default action to discard");
210 
211     // projection
212     oc.doRegister("proj.plain-geo", new Option_Bool(false));
213     oc.addDescription("proj.plain-geo", "Projection", "Write geo coordinates in output");
214 }
215 
216 
217 int
main(int argc,char ** argv)218 main(int argc, char** argv) {
219     OptionsCont& oc = OptionsCont::getOptions();
220     oc.setApplicationDescription("Importer of polygons and POIs for the microscopic, multi-modal traffic simulation SUMO.");
221     oc.setApplicationName("polyconvert", "Eclipse SUMO polyconvert Version " VERSION_STRING);
222     int ret = 0;
223     try {
224         // initialise subsystems
225         XMLSubSys::init();
226         fillOptions();
227         OptionsIO::setArgs(argc, argv);
228         OptionsIO::getOptions();
229         if (oc.processMetaOptions(argc < 2)) {
230             SystemFrame::close();
231             return 0;
232         }
233         XMLSubSys::setValidation(oc.getString("xml-validation"), oc.getString("xml-validation.net"));
234         MsgHandler::initOutputOptions();
235         // build the projection
236         double scale = 1.0;
237         if ((oc.isSet("dlr-navteq-poly-files") || oc.isSet("dlr-navteq-poi-files")) && oc.isDefault("proj.scale")) {
238             scale = 1e-5;
239         }
240         if (!oc.isSet("net")) {
241             // from the given options
242 #ifdef PROJ_API_FILE
243             unsigned numProjections = oc.getBool("simple-projection") + oc.getBool("proj.utm") + oc.getBool("proj.dhdn") + (oc.getString("proj").length() > 1);
244             if ((oc.isSet("osm-files") || oc.isSet("dlr-navteq-poly-files") || oc.isSet("dlr-navteq-poi-files")) && numProjections == 0) {
245                 oc.set("proj.utm", "true");
246             }
247             if (oc.isDefault("proj.scale")) {
248                 oc.set("proj.scale", toString(scale, 5));
249             }
250 #endif
251             if (!GeoConvHelper::init(oc)) {
252                 throw ProcessError("Could not build projection!");
253             }
254         } else {
255             // from the supplied network
256             // @todo warn about given options being ignored
257             PCNetProjectionLoader::load(oc.getString("net"), scale);
258         }
259         Boundary pruningBoundary = GeoConvHelper::getFinal().getConvBoundary();
260         // check whether the input shall be pruned
261         bool prune = false;
262         if (oc.getBool("prune.in-net")) {
263             if (!oc.isSet("net")) {
264                 throw ProcessError("In order to prune the input on the net, you have to supply a network.");
265             }
266             bool ok = true;
267             // !!! no proper error handling
268             Boundary offsets = GeomConvHelper::parseBoundaryReporting(oc.getString("prune.in-net.offsets"), "--prune.on-net.offsets", nullptr, ok);
269             pruningBoundary = Boundary(
270                                   pruningBoundary.xmin() + offsets.xmin(),
271                                   pruningBoundary.ymin() + offsets.ymin(),
272                                   pruningBoundary.xmax() + offsets.xmax(),
273                                   pruningBoundary.ymax() + offsets.ymax());
274             prune = true;
275         }
276         if (oc.isSet("prune.boundary")) {
277             bool ok = true;
278             // !!! no proper error handling
279             pruningBoundary = GeomConvHelper::parseBoundaryReporting(oc.getString("prune.boundary"), "--prune.boundary", nullptr, ok);
280             prune = true;
281         }
282         if (oc.isSet("osm-files") && oc.isDefault("poi-layer-offset")) {
283             oc.set("poi-layer-offset", "5"); // sufficient when using the default typemap
284         }
285 
286         PCPolyContainer toFill(prune, pruningBoundary, oc.getStringVector("remove"));
287 
288         // read in the type defaults
289         if (!oc.isSet("type-file")) {
290             const char* sumoPath = std::getenv("SUMO_HOME");
291             if (sumoPath == nullptr) {
292                 WRITE_WARNING("Environment variable SUMO_HOME is not set, using built in type maps.");
293             } else {
294                 const std::string path = sumoPath + std::string("/data/typemap/");
295                 if (oc.isSet("dlr-navteq-poly-files")) {
296                     oc.setDefault("type-file", path + "navteqPolyconvert.typ.xml");
297                 }
298                 if (oc.isSet("osm-files")) {
299                     oc.setDefault("type-file", path + "osmPolyconvert.typ.xml");
300                 }
301                 if (oc.isSet("visum-files")) {
302                     oc.setDefault("type-file", path + "visumPolyconvert.typ.xml");
303                 }
304             }
305         }
306         PCTypeMap tm(oc);
307         PCTypeDefHandler handler(oc, tm);
308         if (oc.isSet("type-file")) {
309             if (!XMLSubSys::runParser(handler, oc.getString("type-file"))) {
310                 // something failed
311                 throw ProcessError();
312             }
313         } else {
314             handler.setFileName("built in type map");
315             SUMOSAXReader* reader = XMLSubSys::getSAXReader(handler);
316             if (oc.isSet("dlr-navteq-poly-files")) {
317                 reader->parseString(navteqTypemap);
318             }
319             if (oc.isSet("osm-files")) {
320                 reader->parseString(osmTypemap);
321             }
322             if (oc.isSet("visum-files")) {
323                 reader->parseString(visumTypemap);
324             }
325             delete reader;
326         }
327         SystemFrame::checkOptions();
328         // read in the data
329         PCLoaderXML::loadIfSet(oc, toFill, tm); // SUMO-XML
330         PCLoaderOSM::loadIfSet(oc, toFill, tm); // OSM-XML
331         PCLoaderDlrNavteq::loadIfSet(oc, toFill, tm); // Elmar-files
332         PCLoaderVisum::loadIfSet(oc, toFill, tm); // VISUM
333         PCLoaderArcView::loadIfSet(oc, toFill, tm); // shape-files
334         GeoConvHelper::computeFinal();
335         // error processing
336         if (MsgHandler::getErrorInstance()->wasInformed() && !oc.getBool("ignore-errors")) {
337             throw ProcessError();
338         }
339         // output
340         if (!oc.isSet("output-file") && !oc.isSet("dlr-tdp-output")) {
341             std::string out = "polygons.xml";
342             if (oc.isSet("configuration-file")) {
343                 out = FileHelpers::getConfigurationRelative(oc.getString("configuration-file"), out);
344             }
345             oc.setDefault("output-file", out);
346         }
347         if (oc.isSet("output-file")) {
348             toFill.save(oc.getString("output-file"), oc.getBool("proj.plain-geo"));
349         }
350         if (oc.isSet("dlr-tdp-output")) {
351             toFill.saveDlrTDP(oc.getString("dlr-tdp-output"));
352         }
353 
354     } catch (const ProcessError& e) {
355         if (std::string(e.what()) != std::string("Process Error") && std::string(e.what()) != std::string("")) {
356             WRITE_ERROR(e.what());
357         }
358         MsgHandler::getErrorInstance()->inform("Quitting (on error).", false);
359         ret = 1;
360 #ifndef _DEBUG
361     } catch (const std::exception& e) {
362         if (std::string(e.what()) != std::string("")) {
363             WRITE_ERROR(e.what());
364         }
365         MsgHandler::getErrorInstance()->inform("Quitting (on error).", false);
366         ret = 1;
367     } catch (...) {
368         MsgHandler::getErrorInstance()->inform("Quitting (on unknown error).", false);
369         ret = 1;
370 #endif
371     }
372     SystemFrame::close();
373     // report about ending
374     if (ret == 0) {
375         std::cout << "Success." << std::endl;
376     }
377     return ret;
378 }
379 
380 
381 
382 /****************************************************************************/
383 
384