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.dev/sumo
3 // Copyright (C) 2001-2024 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(TLF("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_WARNINGF(TL("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_WARNINGF(TL("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_WARNINGF(TL("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  std::string icon = oc.getString("icon");
277  double layer = oc.getFloat("layer");
278  RGBColor color;
279  if (tm.has(type)) {
280  const PCTypeMap::TypeDef& def = tm.get(type);
281  id = def.prefix + id;
282  type = def.id;
283  color = def.color;
284  discard = def.discard;
285  icon = def.icon;
286  layer = def.layer;
287  } else {
288  id = oc.getString("prefix") + id;
289  color = c;
290  }
291  if (!discard) {
292  const std::string origId = id;
293  int index = 1;
294  while (toFill.getPOIs().get(id) != nullptr) {
295  id = origId + "#" + toString(index++);
296  }
297  PointOfInterest* poi = new PointOfInterest(id, type, color, pos, false, "", 0, false, 0, icon, layer);
298  toFill.add(poi);
299  }
300  }
301 
302  // poly
303  if (polyType != "") {
304  StringTokenizer st(line, ";");
305  std::string id = st.next();
306  std::string type;
307  if (!first && lastID != id) {
308  // we have parsed a polygon completely
309  RGBColor color;
310  double layer = oc.getFloat("layer");
311  bool discard = oc.getBool("discard");
312  if (tm.has(polyType)) {
313  const PCTypeMap::TypeDef& def = tm.get(polyType);
314  id = def.prefix + id;
315  type = def.id;
316  color = def.color;
317  discard = def.discard;
318  layer = def.layer;
319  } else {
320  id = oc.getString("prefix") + id;
321  type = oc.getString("type");
322  color = c;
323  }
324  if (!discard) {
325  const std::string origId = id;
326  int index = 1;
327  while (toFill.getPolygons().get(id) != nullptr) {
328  id = origId + "#" + toString(index++);
329  }
330  SUMOPolygon* poly = new SUMOPolygon(id, type, color, vec, false, false, 1, layer);
331  toFill.add(poly);
332  }
333  vec.clear();
334  }
335  lastID = id;
336  first = false;
337  // parse current poly
338  std::string index = st.next();
339  std::string xpos = st.next();
340  std::string ypos = st.next();
341  Position pos2D((double) atof(xpos.c_str()), (double) atof(ypos.c_str()));
342  if (!geoConvHelper.x2cartesian(pos2D)) {
343  WRITE_WARNINGF(TL("Unable to project coordinates for polygon '%'."), id);
344  }
345  vec.push_back(pos2D);
346  }
347 
348  // district refering a shape
349  if (parsingDistrictsDirectly) {
350  //$BEZIRK:NR CODE NAME TYPNR XKOORD YKOORD FLAECHEID BEZART IVANTEIL_Q IVANTEIL_Z OEVANTEIL METHODEANBANTEILE ZWERT1 ZWERT2 ZWERT3 ISTINAUSWAHL OBEZNR NOM_COM COD_COM
351  lineParser.parseLine(line);
352  long long int idL = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_NO)));
353  std::string id = toString(idL);
354  long long int area = StringUtils::toLong(lineParser.get(KEYS.getString(VISUM_SURFACEID)));
355  double x = StringUtils::toDouble(lineParser.get(KEYS.getString(VISUM_XCOORD)));
356  double y = StringUtils::toDouble(lineParser.get(KEYS.getString(VISUM_YCOORD)));
357  // patch the values
358  std::string type = "district";
359  bool discard = oc.getBool("discard");
360  std::string icon = oc.getString("icon");
361  double layer = oc.getFloat("layer");
362  RGBColor color;
363  if (tm.has(type)) {
364  const PCTypeMap::TypeDef& def = tm.get(type);
365  id = def.prefix + id;
366  type = def.id;
367  color = def.color;
368  discard = def.discard;
369  icon = def.icon;
370  layer = def.layer;
371  } else {
372  id = oc.getString("prefix") + id;
373  type = oc.getString("type");
374  color = c;
375  }
376  if (!discard) {
377  if (teilflaechen[flaechenelemente[area]].size() > 0) {
378  const std::string origId = id;
379  int index = 1;
380  while (toFill.getPolygons().get(id) != nullptr) {
381  id = origId + "#" + toString(index++);
382  }
383  const auto shape = teilflaechen[flaechenelemente[area]];
384  SUMOPolygon* poly = new SUMOPolygon(id, type, color, shape, false, false, 1, layer);
385  toFill.add(poly);
386  } else {
387  Position pos(x, y);
388  if (!geoConvHelper.x2cartesian(pos)) {
389  WRITE_WARNINGF(TL("Unable to project coordinates for POI '%'."), id);
390  }
391  const std::string origId = id;
392  int index = 1;
393  while (toFill.getPOIs().get(id) != nullptr) {
394  id = origId + "#" + toString(index++);
395  }
396  PointOfInterest* poi = new PointOfInterest(id, type, color, pos, false, "", 0, false, 0, icon, layer);
397  toFill.add(poi);
398  }
399  }
400  }
401 
402 
403  if (line.find("$POIKATEGORIEDEF:") == 0 || line.find("$" + KEYS.getString(VISUM_POICATEGORY) + ":") == 0) {
404  // ok, got categories, begin parsing from next line
405  parsingCategories = true;
406  lineParser.reinit(line.substr(line.find(":") + 1));
407  }
408  if ((line.find("$POI:") == 0) || line.find("$POIOFCAT") != std::string::npos) {
409  // ok, got pois, begin parsing from next line
410  parsingPOIs = true;
411  lineParser.reinit(line.substr(line.find(":") + 1));
412  }
413  if (line.find("$" + KEYS.getString(VISUM_DISTRICT)) == 0 && line.find(KEYS.getString(VISUM_SURFACEID)) != std::string::npos) {
414  // ok, have a district header, and it seems like districts would reference shapes...
415  parsingDistrictsDirectly = true;
416  lineParser.reinit(line.substr(line.find(":") + 1));
417  }
418 
419 
420  if (line.find("$BEZIRKPOLY") != std::string::npos) {
421  polyType = "district";
422  }
423  if (line.find("$GEBIETPOLY") != std::string::npos) {
424  polyType = "area";
425  }
426 
427  }
428 }
429 
430 
431 void
432 PCLoaderVisum::loadLanguage(const std::string& file) {
433  std::ifstream strm(file.c_str());
434  if (!strm.good()) {
435  throw ProcessError(TLF("Could not load VISUM language map from '%'.", file));
436  }
437  while (strm.good()) {
438  std::string keyDE;
439  std::string keyNew;
440  strm >> keyDE;
441  strm >> keyNew;
442  if (KEYS.hasString(keyDE)) {
443  VISUM_KEY key = KEYS.get(keyDE);
444  KEYS.remove(keyDE, key);
445  KEYS.insert(keyNew, key);
446  } else if (keyDE != "") {
447  // do not warn about network-related keys (NIImporter_VISUM)
448  //WRITE_WARNINGF(TL("Unknown entry '%' in VISUM language map"), keyDE);
449  }
450  }
451 
452 }
453 
454 /****************************************************************************/
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:296
#define TL(string)
Definition: MsgHandler.h:315
#define PROGRESS_DONE_MESSAGE()
Definition: MsgHandler.h:300
#define TLF(string,...)
Definition: MsgHandler.h:317
#define PROGRESS_BEGIN_MESSAGE(msg)
Definition: MsgHandler.h:299
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
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:68
void reinit()
Reinitialises the reading (of the previous file)
Definition: LineReader.cpp:194
bool hasMore() const
Returns whether another line may be read (the file was not read completely)
Definition: LineReader.cpp:52
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:70
bool has(const std::string &id)
Returns the information whether the named type is known.
Definition: PCTypeMap.cpp:76
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.
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:61
std::string icon
the icon to use
Definition: PCTypeMap.h:69
bool discard
Information whether polygons of this type shall be discarded.
Definition: PCTypeMap.h:77
std::string prefix
The prefix to use.
Definition: PCTypeMap.h:67
double layer
The layer to use.
Definition: PCTypeMap.h:71
std::string id
The new type id to use.
Definition: PCTypeMap.h:63
RGBColor color
The color to use.
Definition: PCTypeMap.h:65