Eclipse SUMO - Simulation of Urban MObility
PCLoaderVisum.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3// Copyright (C) 2001-2022 German Aerospace Center (DLR) and others.
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// https://www.eclipse.org/legal/epl-2.0/
7// This Source Code may also be made available under the following Secondary
8// Licenses when the conditions for such availability set forth in the Eclipse
9// Public License 2.0 are satisfied: GNU General Public License, version 2
10// or later which is available at
11// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13/****************************************************************************/
21// A reader of pois and polygons stored in VISUM-format
22/****************************************************************************/
23#include <config.h>
24
25#include <string>
26#include <map>
27#include <fstream>
40#include "PCLoaderVisum.h"
43#include <utils/geom/Boundary.h>
44#include <utils/geom/Position.h>
47
49 // duplicates NIImporter_VISUM::KEYS_DE due to lack of suitable common location
50 { "VSYS", VISUM_SYS },
51 { "STRECKENTYP", VISUM_LINKTYPE },
52 { "KNOTEN", VISUM_NODE },
53 { "BEZIRK", VISUM_DISTRICT },
54 { "PUNKT", VISUM_POINT },
55 { "STRECKE", VISUM_LINK },
56 { "V0IV", VISUM_V0 },
57 { "VSYSSET", VISUM_TYPES },
58 { "RANG", VISUM_RANK },
59 { "KAPIV", VISUM_CAPACITY },
60 { "XKOORD", VISUM_XCOORD },
61 { "YKOORD", VISUM_YCOORD },
62 { "ID", VISUM_ID },
63 { "CODE", VISUM_CODE },
64 { "VONKNOTNR", VISUM_FROMNODE },
65 { "NACHKNOTNR", VISUM_TONODE },
66 { "TYPNR", VISUM_TYPE },
67 { "TYP", VISUM_TYP },
68 { "ANBINDUNG", VISUM_DISTRICT_CONNECTION },
69 { "BEZNR", VISUM_SOURCE_DISTRICT },
70 { "KNOTNR", VISUM_FROMNODENO },
71 { "RICHTUNG", VISUM_DIRECTION },
72 { "FLAECHEID", VISUM_SURFACEID },
73 { "TFLAECHEID", VISUM_FACEID },
74 { "VONPUNKTID", VISUM_FROMPOINTID },
75 { "NACHPUNKTID", VISUM_TOPOINTID },
76 { "KANTE", VISUM_EDGE },
77 { "ABBIEGER", VISUM_TURN },
78 { "UEBERKNOTNR", VISUM_VIANODENO },
79 { "ANZFAHRSTREIFEN", VISUM_NUMLANES },
80 { "INDEX", VISUM_INDEX },
81 { "STRECKENPOLY", VISUM_LINKPOLY },
82 { "FLAECHENELEMENT", VISUM_SURFACEITEM },
83 { "TEILFLAECHENELEMENT", VISUM_FACEITEM },
84 { "KANTEID", VISUM_EDGEID },
85 { "Q", VISUM_ORIGIN },
86 { "Z", VISUM_DESTINATION },
87 { "KATNR", VISUM_CATID },
88 { "ZWISCHENPUNKT", VISUM_EDGEITEM },
89 { "POIKATEGORIE", VISUM_POICATEGORY },
90 { "NR", VISUM_NO } // must be the last one
91};
92
93
95
96
97// ===========================================================================
98// method definitions
99// ===========================================================================
100void
102 PCTypeMap& tm) {
103 if (!oc.isSet("visum-files")) {
104 return;
105 }
106 const std::string languageFile = oc.getString("visum.language-file");
107 if (languageFile != "") {
108 loadLanguage(languageFile);
109 }
110 // parse file(s)
111 std::vector<std::string> files = oc.getStringVector("visum-files");
112 for (std::vector<std::string>::const_iterator file = files.begin(); file != files.end(); ++file) {
113 if (!FileHelpers::isReadable(*file)) {
114 throw ProcessError("Could not open visum-file '" + *file + "'.");
115 }
116 PROGRESS_BEGIN_MESSAGE("Parsing from visum-file '" + *file + "'");
117 load(*file, oc, toFill, tm);
119 }
120}
121
122
123
124void
125PCLoaderVisum::load(const std::string& file, OptionsCont& oc, PCPolyContainer& toFill,
126 PCTypeMap& tm) {
128 std::string what;
129 std::map<long long int, Position> punkte;
130 std::map<long long int, PositionVector> kanten;
131 std::map<long long int, PositionVector> teilflaechen;
132 std::map<long long int, long long int> flaechenelemente;
133 NamedColumnsParser lineParser;
134 LineReader lr(file);
135 while (lr.hasMore()) {
136 std::string line = lr.readLine();
137 // reset if current is over
138 if (line.length() == 0 || line[0] == '*' || line[0] == '$') {
139 what = "";
140 }
141 // read items
142 if (what == "$" + KEYS.getString(VISUM_POINT)) {
143 lineParser.parseLine(line);
144 long long int id = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_ID)));
145 double x = StringUtils::toDouble(lineParser.get(KEYS.getString(VISUM_XCOORD)));
146 double y = StringUtils::toDouble(lineParser.get(KEYS.getString(VISUM_YCOORD)));
147 Position pos(x, y);
148 if (!geoConvHelper.x2cartesian(pos)) {
149 WRITE_WARNING("Unable to project coordinates for point '" + toString(id) + "'.");
150 }
151 punkte[id] = pos;
152 continue;
153 } else if (what == "$" + KEYS.getString(VISUM_EDGE)) {
154 lineParser.parseLine(line);
155 long long int id = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_ID)));
156 long long int fromID = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_FROMPOINTID)));
157 long long int toID = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_TOPOINTID)));
158 PositionVector vec;
159 vec.push_back(punkte[fromID]);
160 vec.push_back(punkte[toID]);
161 kanten[id] = vec;
162 continue;
163 } else if (what == "$" + KEYS.getString(VISUM_EDGEITEM)) {
164 lineParser.parseLine(line);
165 long long int id = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_EDGEID)));
166 int index = StringUtils::toInt(lineParser.get(KEYS.getString(VISUM_INDEX)));
167 double x = StringUtils::toDouble(lineParser.get(KEYS.getString(VISUM_XCOORD)));
168 double y = StringUtils::toDouble(lineParser.get(KEYS.getString(VISUM_YCOORD)));
169 Position pos(x, y);
170 if (!geoConvHelper.x2cartesian(pos)) {
171 WRITE_WARNING("Unable to project coordinates for edge '" + toString(id) + "'.");
172 }
173 kanten[id].insert(kanten[id].begin() + index, pos);
174 continue;
175 } else if (what == "$" + KEYS.getString(VISUM_FACEITEM)) {
176 lineParser.parseLine(line);
177 long long int id = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_FACEID)));
178 //int index = StringUtils::toInt(lineParser.get("INDEX"));
179 //index = 0; /// hmmmm - assume it's sorted...
180 long long int kid = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_EDGEID)));
181 int dir = StringUtils::toInt(lineParser.get(KEYS.getString(VISUM_DIRECTION)));
182 if (teilflaechen.find(id) == teilflaechen.end()) {
183 teilflaechen[id] = PositionVector();
184 }
185 if (dir == 0) {
186 for (int i = 0; i < (int) kanten[kid].size(); ++i) {
187 teilflaechen[id].push_back_noDoublePos(kanten[kid][i]);
188 }
189 } else {
190 for (int i = (int) kanten[kid].size() - 1; i >= 0; --i) {
191 teilflaechen[id].push_back_noDoublePos(kanten[kid][i]);
192 }
193 }
194 continue;
195 } else if (what == "$" + KEYS.getString(VISUM_SURFACEITEM)) {
196 lineParser.parseLine(line);
197 long long int id = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_SURFACEID)));
198 long long int tid = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_FACEID)));
199 flaechenelemente[id] = tid;
200 continue;
201 }
202 // set if read
203 if (line[0] == '$') {
204 what = "";
205 if (line.find("$" + KEYS.getString(VISUM_POINT) + ":") == 0) {
206 what = "$" + KEYS.getString(VISUM_POINT);
207 } else if (line.find("$" + KEYS.getString(VISUM_EDGE) + ":") == 0) {
208 what = "$" + KEYS.getString(VISUM_EDGE);
209 } else if (line.find("$" + KEYS.getString(VISUM_EDGEITEM) + ":") == 0) {
210 what = "$" + KEYS.getString(VISUM_EDGEITEM);
211 } else if (line.find("$" + KEYS.getString(VISUM_FACEITEM) + ":") == 0) {
212 what = "$" + KEYS.getString(VISUM_FACEITEM);
213 } else if (line.find("$" + KEYS.getString(VISUM_SURFACEITEM) + ":") == 0) {
214 what = "$" + KEYS.getString(VISUM_SURFACEITEM);
215 }
216 if (what != "") {
217 lineParser.reinit(line.substr(what.length() + 1));
218 }
219 }
220 }
221
222 // do some more sane job...
223 RGBColor c = RGBColor::parseColor(oc.getString("color"));
224 std::map<std::string, std::string> typemap;
225 // load the pois/polys
226 lr.reinit();
227 bool parsingCategories = false;
228 bool parsingPOIs = false;
229 bool parsingDistrictsDirectly = false;
230 PositionVector vec;
231 std::string polyType, lastID;
232 bool first = true;
233 while (lr.hasMore()) {
234 std::string line = lr.readLine();
235 // do not parse empty lines
236 if (line.length() == 0) {
237 continue;
238 }
239 // do not parse comment lines
240 if (line[0] == '*') {
241 continue;
242 }
243
244 if (line[0] == '$') {
245 // reset parsing on new entry type
246 parsingCategories = false;
247 parsingPOIs = false;
248 parsingDistrictsDirectly = false;
249 polyType = "";
250 }
251
252 if (parsingCategories) {
253 // parse the category
254 StringTokenizer st(line, ";");
255 std::string catid = st.next();
256 std::string catname = st.next();
257 typemap[catid] = catname;
258 }
259 if (parsingPOIs) {
260 // parse the poi
261 // $POI:Nr;CATID;CODE;NAME;Kommentar;XKoord;YKoord;
262 lineParser.parseLine(line);
263 long long int idL = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_NO)));
264 std::string id = toString(idL);
265 std::string catid = lineParser.get(KEYS.getString(VISUM_CATID));
266 // process read values
267 double x = StringUtils::toDouble(lineParser.get(KEYS.getString(VISUM_XCOORD)));
268 double y = StringUtils::toDouble(lineParser.get(KEYS.getString(VISUM_YCOORD)));
269 Position pos(x, y);
270 if (!geoConvHelper.x2cartesian(pos)) {
271 WRITE_WARNING("Unable to project coordinates for POI '" + id + "'.");
272 }
273 std::string type = typemap[catid];
274 // patch the values
275 bool discard = oc.getBool("discard");
276 double layer = oc.getFloat("layer");
277 RGBColor color;
278 if (tm.has(type)) {
279 const PCTypeMap::TypeDef& def = tm.get(type);
280 id = def.prefix + id;
281 type = def.id;
282 color = def.color;
283 discard = def.discard;
284 layer = def.layer;
285 } else {
286 id = oc.getString("prefix") + id;
287 color = c;
288 }
289 if (!discard) {
290 const std::string origId = id;
291 int index = 1;
292 while (toFill.getPOIs().get(id) != nullptr) {
293 id = origId + "#" + toString(index++);
294 }
295 PointOfInterest* poi = new PointOfInterest(id, type, color, pos, false, "", 0, false, 0, layer);
296 toFill.add(poi);
297 }
298 }
299
300 // poly
301 if (polyType != "") {
302 StringTokenizer st(line, ";");
303 std::string id = st.next();
304 std::string type;
305 if (!first && lastID != id) {
306 // we have parsed a polygon completely
307 RGBColor color;
308 double layer = oc.getFloat("layer");
309 bool discard = oc.getBool("discard");
310 if (tm.has(polyType)) {
311 const PCTypeMap::TypeDef& def = tm.get(polyType);
312 id = def.prefix + id;
313 type = def.id;
314 color = def.color;
315 discard = def.discard;
316 layer = def.layer;
317 } else {
318 id = oc.getString("prefix") + id;
319 type = oc.getString("type");
320 color = c;
321 }
322 if (!discard) {
323 const std::string origId = id;
324 int index = 1;
325 while (toFill.getPolygons().get(id) != nullptr) {
326 id = origId + "#" + toString(index++);
327 }
328 SUMOPolygon* poly = new SUMOPolygon(id, type, color, vec, false, false, 1, layer);
329 toFill.add(poly);
330 }
331 vec.clear();
332 }
333 lastID = id;
334 first = false;
335 // parse current poly
336 std::string index = st.next();
337 std::string xpos = st.next();
338 std::string ypos = st.next();
339 Position pos2D((double) atof(xpos.c_str()), (double) atof(ypos.c_str()));
340 if (!geoConvHelper.x2cartesian(pos2D)) {
341 WRITE_WARNING("Unable to project coordinates for polygon '" + id + "'.");
342 }
343 vec.push_back(pos2D);
344 }
345
346 // district refering a shape
347 if (parsingDistrictsDirectly) {
348 //$BEZIRK:NR CODE NAME TYPNR XKOORD YKOORD FLAECHEID BEZART IVANTEIL_Q IVANTEIL_Z OEVANTEIL METHODEANBANTEILE ZWERT1 ZWERT2 ZWERT3 ISTINAUSWAHL OBEZNR NOM_COM COD_COM
349 lineParser.parseLine(line);
350 long long int idL = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_NO)));
351 std::string id = toString(idL);
352 long long int area = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_SURFACEID)));
353 double x = StringUtils::toDouble(lineParser.get(KEYS.getString(VISUM_XCOORD)));
354 double y = StringUtils::toDouble(lineParser.get(KEYS.getString(VISUM_YCOORD)));
355 // patch the values
356 std::string type = "district";
357 bool discard = oc.getBool("discard");
358 double layer = oc.getFloat("layer");
359 RGBColor color;
360 if (tm.has(type)) {
361 const PCTypeMap::TypeDef& def = tm.get(type);
362 id = def.prefix + id;
363 type = def.id;
364 color = def.color;
365 discard = def.discard;
366 layer = def.layer;
367 } else {
368 id = oc.getString("prefix") + id;
369 type = oc.getString("type");
370 color = c;
371 }
372 if (!discard) {
373 if (teilflaechen[flaechenelemente[area]].size() > 0) {
374 const std::string origId = id;
375 int index = 1;
376 while (toFill.getPolygons().get(id) != nullptr) {
377 id = origId + "#" + toString(index++);
378 }
379 const auto shape = teilflaechen[flaechenelemente[area]];
380 SUMOPolygon* poly = new SUMOPolygon(id, type, color, shape, false, false, 1, layer);
381 toFill.add(poly);
382 } else {
383 Position pos(x, y);
384 if (!geoConvHelper.x2cartesian(pos)) {
385 WRITE_WARNING("Unable to project coordinates for POI '" + id + "'.");
386 }
387 const std::string origId = id;
388 int index = 1;
389 while (toFill.getPOIs().get(id) != nullptr) {
390 id = origId + "#" + toString(index++);
391 }
392 PointOfInterest* poi = new PointOfInterest(id, type, color, pos, false, "", 0, false, 0, layer);
393 toFill.add(poi);
394 }
395 }
396 }
397
398
399 if (line.find("$POIKATEGORIEDEF:") == 0 || line.find("$" + KEYS.getString(VISUM_POICATEGORY) + ":") == 0) {
400 // ok, got categories, begin parsing from next line
401 parsingCategories = true;
402 lineParser.reinit(line.substr(line.find(":") + 1));
403 }
404 if ((line.find("$POI:") == 0) || line.find("$POIOFCAT") != std::string::npos) {
405 // ok, got pois, begin parsing from next line
406 parsingPOIs = true;
407 lineParser.reinit(line.substr(line.find(":") + 1));
408 }
409 if (line.find("$" + KEYS.getString(VISUM_DISTRICT)) == 0 && line.find(KEYS.getString(VISUM_SURFACEID)) != std::string::npos) {
410 // ok, have a district header, and it seems like districts would reference shapes...
411 parsingDistrictsDirectly = true;
412 lineParser.reinit(line.substr(line.find(":") + 1));
413 }
414
415
416 if (line.find("$BEZIRKPOLY") != std::string::npos) {
417 polyType = "district";
418 }
419 if (line.find("$GEBIETPOLY") != std::string::npos) {
420 polyType = "area";
421 }
422
423 }
424}
425
426
427void
428PCLoaderVisum::loadLanguage(const std::string& file) {
429 std::ifstream strm(file.c_str());
430 if (!strm.good()) {
431 throw ProcessError("Could not load VISUM language map from '" + file + "'.");
432 }
433 while (strm.good()) {
434 std::string keyDE;
435 std::string keyNew;
436 strm >> keyDE;
437 strm >> keyNew;
438 if (KEYS.hasString(keyDE)) {
439 VISUM_KEY key = KEYS.get(keyDE);
440 KEYS.remove(keyDE, key);
441 KEYS.insert(keyNew, key);
442 } else if (keyDE != "") {
443 // do not warn about network-related keys (NIImporter_VISUM)
444 //WRITE_WARNING("Unknown entry '" + keyDE + "' in VISUM language map");
445 }
446 }
447
448}
449
450/****************************************************************************/
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:265
#define PROGRESS_DONE_MESSAGE()
Definition: MsgHandler.h:270
#define PROGRESS_BEGIN_MESSAGE(msg)
Definition: MsgHandler.h:269
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:46
static bool isReadable(std::string path)
Checks whether the given file is readable.
Definition: FileHelpers.cpp:51
static methods for processing the coordinates conversion for the current net
Definition: GeoConvHelper.h:53
bool x2cartesian(Position &from, bool includeInBoundary=true)
Converts the given coordinate into a cartesian and optionally update myConvBoundary.
static GeoConvHelper & getProcessing()
the coordinate transformation to use for input conversion and processing
Definition: GeoConvHelper.h:84
Retrieves a file linewise and reports the lines to a handler.
Definition: LineReader.h:48
bool readLine(LineHandler &lh)
Reads a single (the next) line from the file and reports it to the given LineHandler.
Definition: LineReader.cpp:67
void reinit()
Reinitialises the reading (of the previous file)
Definition: LineReader.cpp:193
bool hasMore() const
Returns whether another line may be read (the file was not read completely)
Definition: LineReader.cpp:51
A parser to retrieve information from a table with known columns.
void reinit(const std::string &def, const std::string &defDelim=";", const std::string &lineDelim=";", bool chomp=false, bool ignoreCase=true)
Reinitialises the parser.
void parseLine(const std::string &line)
Parses the contents of the line.
std::string get(const std::string &name, bool prune=false) const
Returns the named information.
T get(const std::string &id) const
Retrieves an item.
A storage for options typed value containers)
Definition: OptionsCont.h:89
bool isSet(const std::string &name, bool failOnNonExistant=true) const
Returns the information whether the named option is set.
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
std::string getString(const std::string &name) const
Returns the string-value of the named option (only for Option_String)
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
const StringVector & getStringVector(const std::string &name) const
Returns the list of string-value of the named option (only for Option_StringVector)
static StringBijection< VISUM_KEY >::Entry KEYS_DE[]
Strings for the keywords.
static void loadLanguage(const std::string &file)
static void load(const std::string &file, OptionsCont &oc, PCPolyContainer &toFill, PCTypeMap &tm)
Parses pois/polys stored within the given file.
static StringBijection< VISUM_KEY > KEYS
link directions
static void loadIfSet(OptionsCont &oc, PCPolyContainer &toFill, PCTypeMap &tm)
Loads pois/polygons assumed to be stored using VISUM-format.
A storage for loaded polygons and pois.
bool add(SUMOPolygon *poly, bool ignorePruning=false)
Adds a polygon to the storage.
A storage for type mappings.
Definition: PCTypeMap.h:42
const TypeDef & get(const std::string &id)
Returns a type definition.
Definition: PCTypeMap.cpp:69
bool has(const std::string &id)
Returns the information whether the named type is known.
Definition: PCTypeMap.cpp:75
A point-of-interest.
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:37
A list of positions.
static RGBColor parseColor(std::string coldef)
Parses a color information.
Definition: RGBColor.cpp:239
const Polygons & getPolygons() const
Returns all polygons.
const POIs & getPOIs() const
Returns all pois.
const std::string & getString(const T key) const
void remove(const std::string str, const T key)
bool hasString(const std::string &str) const
T get(const std::string &str) const
void insert(const std::string str, const T key, bool checkDuplicates=true)
std::string next()
returns the next substring when it exists. Otherwise the behaviour is undefined
static long long int toLong(const std::string &sData)
converts a string into the long value described by it by calling the char-type converter,...
static double toDouble(const std::string &sData)
converts a string into the double value described by it by calling the char-type converter
static int toInt(const std::string &sData)
converts a string into the integer value described by it by calling the char-type converter,...
A single definition of values that shall be used for a given type.
Definition: PCTypeMap.h:56
bool discard
Information whether polygons of this type shall be discarded.
Definition: PCTypeMap.h:70
std::string prefix
The prefix to use.
Definition: PCTypeMap.h:62
double layer
The layer to use.
Definition: PCTypeMap.h:64
std::string id
The new type id to use.
Definition: PCTypeMap.h:58
RGBColor color
The color to use.
Definition: PCTypeMap.h:60