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-2023 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 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_WARNINGF(TL("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_WARNINGF(TL("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(TLF("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_WARNINGF(TL("Unknown entry '%' in VISUM language map"), keyDE);
445 }
446 }
447
448}
449
450/****************************************************************************/
#define WRITE_WARNINGF(...)
Definition MsgHandler.h:271
#define TL(string)
Definition MsgHandler.h:287
#define PROGRESS_DONE_MESSAGE()
Definition MsgHandler.h:275
#define TLF(string,...)
Definition MsgHandler.h:288
#define PROGRESS_BEGIN_MESSAGE(msg)
Definition MsgHandler.h:274
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: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