Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/polyconvert/PCLoaderVisum.cpp
169666 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-2025 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
/****************************************************************************/
14
/// @file PCLoaderVisum.cpp
15
/// @author Daniel Krajzewicz
16
/// @author Jakob Erdmann
17
/// @author Christoph Sommer
18
/// @author Michael Behrisch
19
/// @date Thu, 02.11.2006
20
///
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>
28
#include <utils/common/StringTokenizer.h>
29
#include <utils/common/UtilExceptions.h>
30
#include <utils/common/MsgHandler.h>
31
#include <utils/common/StringUtils.h>
32
#include <utils/common/StringUtils.h>
33
#include <utils/common/ToString.h>
34
#include <utils/common/FileHelpers.h>
35
#include <utils/options/OptionsCont.h>
36
#include <utils/options/Option.h>
37
#include <utils/importio/LineReader.h>
38
#include <utils/common/StdDefs.h>
39
#include <polyconvert/PCPolyContainer.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>
45
#include <utils/geom/GeoConvHelper.h>
46
#include <utils/importio/NamedColumnsParser.h>
47
48
StringBijection<PCLoaderVisum::VISUM_KEY>::Entry PCLoaderVisum::KEYS_DE[] = {
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
94
StringBijection<PCLoaderVisum::VISUM_KEY> PCLoaderVisum::KEYS(PCLoaderVisum::KEYS_DE, VISUM_NO);
95
96
97
// ===========================================================================
98
// method definitions
99
// ===========================================================================
100
void
101
PCLoaderVisum::loadIfSet(OptionsCont& oc, PCPolyContainer& toFill,
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);
118
PROGRESS_DONE_MESSAGE();
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
/****************************************************************************/
455
456