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>
33 #include <utils/common/ToString.h>
36 #include <utils/options/Option.h>
38 #include <utils/common/StdDefs.h>
40 #include "PCLoaderVisum.h"
41 #include <utils/common/RGBColor.h>
42 #include <utils/geom/GeomHelper.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 // ===========================================================================
100 void
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 
124 void
125 PCLoaderVisum::load(const std::string& file, OptionsCont& oc, PCPolyContainer& toFill,
126  PCTypeMap& tm) {
127  GeoConvHelper& geoConvHelper = GeoConvHelper::getProcessing();
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 
427 void
428 PCLoaderVisum::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:280
#define PROGRESS_DONE_MESSAGE()
Definition: MsgHandler.h:284
#define PROGRESS_BEGIN_MESSAGE(msg)
Definition: MsgHandler.h:283
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:49
static methods for processing the coordinates conversion for the current net
Definition: GeoConvHelper.h:53
static GeoConvHelper & getProcessing()
the coordinate transformation to use for input conversion and processing
Definition: GeoConvHelper.h:84
bool x2cartesian(Position &from, bool includeInBoundary=true)
Converts the given coordinate into a cartesian and optionally update myConvBoundary.
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:236
const Polygons & getPolygons() const
Returns all polygons.
const POIs & getPOIs() const
Returns all pois.
void remove(const std::string str, const T key)
bool hasString(const std::string &str) const
const std::string & getString(const T key) 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