Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
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>
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(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
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_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
431void
432PCLoaderVisum::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.
static methods for processing the coordinates conversion for the current net
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
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.
void reinit()
Reinitialises the reading (of the previous file)
bool hasMore() const
Returns whether another line may be read (the file was not read completely)
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.
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: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