1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
10 /// @file NIImporter_VISUM.cpp
11 /// @author Daniel Krajzewicz
12 /// @author Jakob Erdmann
13 /// @author Sascha Krieg
14 /// @author Michael Behrisch
15 /// @date Fri, 19 Jul 2002
16 /// @version $Id$
17 ///
18 // A VISUM network importer
19 /****************************************************************************/
20
21
22 // ===========================================================================
23 // included modules
24 // ===========================================================================
25 #include <config.h>
26
27 #include <string>
28 #include <utils/common/MsgHandler.h>
29 #include <utils/common/StringUtils.h>
30 #include <utils/common/ToString.h>
31 #include <utils/common/StringUtils.h>
32 #include <utils/options/OptionsCont.h>
33 #include <utils/geom/GeoConvHelper.h>
34 #include <netbuild/NBDistrict.h>
35
36 #include <netbuild/NBNetBuilder.h>
37 #include "NILoader.h"
38 #include "NIImporter_VISUM.h"
39
40
41 // ===========================================================================
42 // method definitions
43 // ===========================================================================
44 // ---------------------------------------------------------------------------
45 // static methods (interface in this case)
46 // ---------------------------------------------------------------------------
47 void
loadNetwork(const OptionsCont & oc,NBNetBuilder & nb)48 NIImporter_VISUM::loadNetwork(const OptionsCont& oc, NBNetBuilder& nb) {
49 // check whether the option is set (properly)
50 if (!oc.isSet("visum-file")) {
51 return;
52 }
53 // build the handler
54 NIImporter_VISUM loader(nb, oc.getString("visum-file"),
55 NBCapacity2Lanes(oc.getFloat("lanes-from-capacity.norm")),
56 oc.getBool("visum.use-type-priority"));
57 loader.load();
58 }
59
60
61
62 // ---------------------------------------------------------------------------
63 // loader methods
64 // ---------------------------------------------------------------------------
NIImporter_VISUM(NBNetBuilder & nb,const std::string & file,NBCapacity2Lanes capacity2Lanes,bool useVisumPrio)65 NIImporter_VISUM::NIImporter_VISUM(NBNetBuilder& nb,
66 const std::string& file,
67 NBCapacity2Lanes capacity2Lanes,
68 bool useVisumPrio)
69 : myNetBuilder(nb), myFileName(file),
70 myCapacity2Lanes(capacity2Lanes), myUseVisumPrio(useVisumPrio) {
71 // the order of process is important!
72 // set1
73 addParser("VSYS", &NIImporter_VISUM::parse_VSysTypes);
74 addParser("STRECKENTYP", &NIImporter_VISUM::parse_Types);
75 addParser("KNOTEN", &NIImporter_VISUM::parse_Nodes);
76 addParser("BEZIRK", &NIImporter_VISUM::parse_Districts);
77 addParser("PUNKT", &NIImporter_VISUM::parse_Point);
78
79 // set2
80 // two types of "strecke"
81 addParser("STRECKE", &NIImporter_VISUM::parse_Edges);
82 addParser("STRECKEN", &NIImporter_VISUM::parse_Edges);
83 addParser("KANTE", &NIImporter_VISUM::parse_Kante);
84
85 // set3
86 addParser("ANBINDUNG", &NIImporter_VISUM::parse_Connectors);
87 // two types of "abbieger"
88 addParser("ABBIEGEBEZIEHUNG", &NIImporter_VISUM::parse_Turns);
89 addParser("ABBIEGER", &NIImporter_VISUM::parse_Turns);
90
91 addParser("STRECKENPOLY", &NIImporter_VISUM::parse_EdgePolys);
92 addParser("FAHRSTREIFEN", &NIImporter_VISUM::parse_Lanes);
93 addParser("FLAECHENELEMENT", &NIImporter_VISUM::parse_PartOfArea);
94
95 // set4
96 // two types of lsa
97 addParser("LSA", &NIImporter_VISUM::parse_TrafficLights);
98 addParser("SIGNALANLAGE", &NIImporter_VISUM::parse_TrafficLights);
99 // two types of knotenzulsa
100 addParser("KNOTENZULSA", &NIImporter_VISUM::parse_NodesToTrafficLights);
101 addParser("LSAZUKNOTEN", &NIImporter_VISUM::parse_NodesToTrafficLights);
102 addParser("SIGNALANLAGEZUKNOTEN", &NIImporter_VISUM::parse_NodesToTrafficLights);
103 // two types of signalgruppe
104 addParser("LSASIGNALGRUPPE", &NIImporter_VISUM::parse_SignalGroups);
105 addParser("SIGNALGRUPPE", &NIImporter_VISUM::parse_SignalGroups);
106 // three types of ABBZULSASIGNALGRUPPE
107 addParser("ABBZULSASIGNALGRUPPE", &NIImporter_VISUM::parse_TurnsToSignalGroups);
108 addParser("SIGNALGRUPPEZUABBIEGER", &NIImporter_VISUM::parse_TurnsToSignalGroups);
109 addParser("SIGNALGRUPPEZUFSABBIEGER", &NIImporter_VISUM::parse_TurnsToSignalGroups);
110
111 addParser("TEILFLAECHENELEMENT", &NIImporter_VISUM::parse_AreaSubPartElement);
112
113 // two types of LSAPHASE
114 addParser("LSAPHASE", &NIImporter_VISUM::parse_Phases);
115 addParser("PHASE", &NIImporter_VISUM::parse_Phases);
116
117 addParser("LSASIGNALGRUPPEZULSAPHASE", &NIImporter_VISUM::parse_SignalGroupsToPhases);
118 addParser("FAHRSTREIFENABBIEGER", &NIImporter_VISUM::parse_LanesConnections);
119 }
120
121
~NIImporter_VISUM()122 NIImporter_VISUM::~NIImporter_VISUM() {
123 for (NIVisumTL_Map::iterator j = myTLS.begin(); j != myTLS.end(); j++) {
124 delete j->second;
125 }
126 }
127
128
129 void
addParser(const std::string & name,ParsingFunction function)130 NIImporter_VISUM::addParser(const std::string& name, ParsingFunction function) {
131 TypeParser p;
132 p.name = name;
133 p.function = function;
134 p.position = -1;
135 mySingleDataParsers.push_back(p);
136 }
137
138
139 void
load()140 NIImporter_VISUM::load() {
141 // open the file
142 if (!myLineReader.setFile(myFileName)) {
143 throw ProcessError("Can not open visum-file '" + myFileName + "'.");
144 }
145 // scan the file for data positions
146 while (myLineReader.hasMore()) {
147 std::string line = myLineReader.readLine();
148 if (line.length() > 0 && line[0] == '$') {
149 ParserVector::iterator i;
150 for (i = mySingleDataParsers.begin(); i != mySingleDataParsers.end(); i++) {
151 std::string dataName = "$" + (*i).name + ":";
152 if (line.substr(0, dataName.length()) == dataName) {
153 (*i).position = myLineReader.getPosition();
154 (*i).pattern = line.substr(dataName.length());
155 WRITE_MESSAGE("Found: " + dataName + " at " + toString<int>(myLineReader.getPosition()));
156 }
157 }
158 }
159 }
160 // go through the parsers and process all entries
161 for (ParserVector::iterator i = mySingleDataParsers.begin(); i != mySingleDataParsers.end(); i++) {
162 if ((*i).position < 0) {
163 // do not process using parsers for which no information was found
164 continue;
165 }
166 // ok, the according information is stored in the file
167 PROGRESS_BEGIN_MESSAGE("Parsing " + (*i).name);
168 // reset the line reader and let it point to the begin of the according data field
169 myLineReader.reinit();
170 myLineReader.setPos((*i).position);
171 // prepare the line parser
172 myLineParser.reinit((*i).pattern);
173 // read
174 bool singleDataEndFound = false;
175 while (myLineReader.hasMore() && !singleDataEndFound) {
176 std::string line = myLineReader.readLine();
177 if (line.length() == 0 || line[0] == '*' || line[0] == '$') {
178 singleDataEndFound = true;
179 } else {
180 myLineParser.parseLine(line);
181 try {
182 myCurrentID = "<unknown>";
183 (this->*(*i).function)();
184 } catch (OutOfBoundsException&) {
185 WRITE_ERROR("Too short value line in " + (*i).name + " occurred.");
186 } catch (NumberFormatException&) {
187 WRITE_ERROR("A value in " + (*i).name + " should be numeric but is not (id='" + myCurrentID + "').");
188 } catch (UnknownElement& e) {
189 WRITE_ERROR("One of the needed values ('" + std::string(e.what()) + "') is missing in " + (*i).name + ".");
190 }
191 }
192 }
193 // close single reader processing
194 PROGRESS_DONE_MESSAGE();
195 }
196 // build traffic lights
197 for (NIVisumTL_Map::iterator j = myTLS.begin(); j != myTLS.end(); j++) {
198 j->second->build(myNetBuilder.getEdgeCont(), myNetBuilder.getTLLogicCont());
199 }
200 // build district shapes
201 for (std::map<NBDistrict*, PositionVector>::const_iterator k = myDistrictShapes.begin(); k != myDistrictShapes.end(); ++k) {
202 (*k).first->addShape((*k).second);
203 }
204 }
205
206
207
208
209
210 void
parse_VSysTypes()211 NIImporter_VISUM::parse_VSysTypes() {
212 std::string name = myLineParser.know("VSysCode") ? myLineParser.get("VSysCode").c_str() : myLineParser.get("CODE").c_str();
213 std::string type = myLineParser.know("VSysMode") ? myLineParser.get("VSysMode").c_str() : myLineParser.get("Typ").c_str();
214 myVSysTypes[name] = type;
215 }
216
217
218 void
parse_Types()219 NIImporter_VISUM::parse_Types() {
220 // get the id
221 myCurrentID = NBHelpers::normalIDRepresentation(myLineParser.get("Nr"));
222 // get the maximum speed
223 double speed = getWeightedFloat2("v0-IV", "V0IV", "km/h");
224 if (speed == 0) {
225 // unlimited speed
226 speed = 3600;
227 } else if (speed < 0) {
228 WRITE_ERROR("Type '" + myCurrentID + "' has speed " + toString(speed));
229 }
230 // get the permissions
231 SVCPermissions permissions = getPermissions("VSYSSET", true);
232 // get the priority
233 const int priority = 1000 - StringUtils::toInt(myLineParser.get("Rang"));
234 // try to retrieve the number of lanes
235 const int numLanes = myCapacity2Lanes.get(getNamedFloat("Kap-IV", "KAPIV"));
236 // insert the type
237 myNetBuilder.getTypeCont().insert(myCurrentID, numLanes, speed / (double) 3.6, priority, permissions, NBEdge::UNSPECIFIED_WIDTH, false, NBEdge::UNSPECIFIED_WIDTH, NBEdge::UNSPECIFIED_WIDTH);
238 myNetBuilder.getTypeCont().markAsSet(myCurrentID, SUMO_ATTR_NUMLANES);
239 myNetBuilder.getTypeCont().markAsSet(myCurrentID, SUMO_ATTR_SPEED);
240 myNetBuilder.getTypeCont().markAsSet(myCurrentID, SUMO_ATTR_PRIORITY);
241 myNetBuilder.getTypeCont().markAsSet(myCurrentID, SUMO_ATTR_ONEWAY);
242 myNetBuilder.getTypeCont().markAsSet(myCurrentID, SUMO_ATTR_ALLOW);
243 }
244
245
246 void
parse_Nodes()247 NIImporter_VISUM::parse_Nodes() {
248 // get the id
249 myCurrentID = NBHelpers::normalIDRepresentation(myLineParser.get("Nr"));
250 // get the position
251 double x = getNamedFloat("XKoord");
252 double y = getNamedFloat("YKoord");
253 Position pos(x, y);
254 if (!NBNetBuilder::transformCoordinate(pos)) {
255 WRITE_ERROR("Unable to project coordinates for node " + myCurrentID + ".");
256 return;
257 }
258 // add to the list
259 if (!myNetBuilder.getNodeCont().insert(myCurrentID, pos)) {
260 WRITE_ERROR("Duplicate node occurred ('" + myCurrentID + "').");
261 }
262 }
263
264
265 void
parse_Districts()266 NIImporter_VISUM::parse_Districts() {
267 // get the id
268 myCurrentID = NBHelpers::normalIDRepresentation(myLineParser.get("Nr"));
269 // get the information whether the source and the destination
270 // connections are weighted
271 //bool sourcesWeighted = getWeightedBool("Proz_Q");
272 //bool destWeighted = getWeightedBool("Proz_Z");
273 // get the node information
274 double x = getNamedFloat("XKoord");
275 double y = getNamedFloat("YKoord");
276 Position pos(x, y);
277 if (!NBNetBuilder::transformCoordinate(pos, false)) {
278 WRITE_ERROR("Unable to project coordinates for district " + myCurrentID + ".");
279 return;
280 }
281 // build the district
282 NBDistrict* district = new NBDistrict(myCurrentID, pos);
283 if (!myNetBuilder.getDistrictCont().insert(district)) {
284 WRITE_ERROR("Duplicate district occurred ('" + myCurrentID + "').");
285 delete district;
286 return;
287 }
288 if (myLineParser.know("FLAECHEID")) {
289 long long int flaecheID = StringUtils::toLong(myLineParser.get("FLAECHEID"));
290 myShapeDistrictMap[flaecheID] = district;
291 }
292 }
293
294
295 void
parse_Point()296 NIImporter_VISUM::parse_Point() {
297 long long int id = StringUtils::toLong(myLineParser.get("ID"));
298 double x = StringUtils::toDouble(myLineParser.get("XKOORD"));
299 double y = StringUtils::toDouble(myLineParser.get("YKOORD"));
300 Position pos(x, y);
301 if (!NBNetBuilder::transformCoordinate(pos, false)) {
302 WRITE_ERROR("Unable to project coordinates for point " + toString(id) + ".");
303 return;
304 }
305 myPoints[id] = pos;
306 }
307
308
309 void
parse_Edges()310 NIImporter_VISUM::parse_Edges() {
311 if (myLineParser.know("VSYSSET") && myLineParser.get("VSYSSET") == "") {
312 // no vehicle allowed; don't add
313 return;
314 }
315 // get the id
316 myCurrentID = NBHelpers::normalIDRepresentation(myLineParser.get("Nr"));
317 // get the from- & to-node and validate them
318 NBNode* from = getNamedNode("VonKnot", "VonKnotNr");
319 NBNode* to = getNamedNode("NachKnot", "NachKnotNr");
320 if (!checkNodes(from, to)) {
321 return;
322 }
323 // get the type
324 std::string type = myLineParser.know("Typ") ? myLineParser.get("Typ") : myLineParser.get("TypNr");
325 // get the speed
326 double speed = myNetBuilder.getTypeCont().getSpeed(type);
327 if (!OptionsCont::getOptions().getBool("visum.use-type-speed")) {
328 try {
329 std::string speedS = myLineParser.know("v0-IV") ? myLineParser.get("v0-IV") : myLineParser.get("V0IV");
330 if (speedS.find("km/h") != std::string::npos) {
331 speedS = speedS.substr(0, speedS.find("km/h"));
332 }
333 speed = StringUtils::toDouble(speedS) / 3.6;
334 } catch (OutOfBoundsException&) {}
335 }
336 if (speed <= 0) {
337 speed = myNetBuilder.getTypeCont().getSpeed(type);
338 }
339
340 // get the information whether the edge is a one-way
341 bool oneway = myLineParser.know("Einbahn")
342 ? StringUtils::toBool(myLineParser.get("Einbahn"))
343 : true;
344 // get the number of lanes
345 int nolanes = myNetBuilder.getTypeCont().getNumLanes(type);
346 if (!OptionsCont::getOptions().getBool("visum.recompute-lane-number")) {
347 if (!OptionsCont::getOptions().getBool("visum.use-type-laneno")) {
348 if (myLineParser.know("Fahrstreifen")) {
349 nolanes = StringUtils::toInt(myLineParser.get("Fahrstreifen"));
350 } else if (myLineParser.know("ANZFAHRSTREIFEN")) {
351 nolanes = StringUtils::toInt(myLineParser.get("ANZFAHRSTREIFEN"));
352 }
353 }
354 } else {
355 if (myLineParser.know("KAPIV")) {
356 nolanes = myCapacity2Lanes.get(StringUtils::toDouble(myLineParser.get("KAPIV")));
357 } else if (myLineParser.know("KAP-IV")) {
358 nolanes = myCapacity2Lanes.get(StringUtils::toDouble(myLineParser.get("KAP-IV")));
359 }
360 }
361 // check whether the id is already used
362 // (should be the opposite direction)
363 bool oneway_checked = oneway;
364 NBEdge* previous = myNetBuilder.getEdgeCont().retrieve(myCurrentID);
365 if (previous != nullptr) {
366 myCurrentID = '-' + myCurrentID;
367 previous->setLaneSpreadFunction(LANESPREAD_RIGHT);
368 oneway_checked = false;
369 }
370 if (find(myTouchedEdges.begin(), myTouchedEdges.end(), myCurrentID) != myTouchedEdges.end()) {
371 oneway_checked = false;
372 }
373 std::string tmpid = '-' + myCurrentID;
374 if (find(myTouchedEdges.begin(), myTouchedEdges.end(), tmpid) != myTouchedEdges.end()) {
375 previous = myNetBuilder.getEdgeCont().retrieve(tmpid);
376 if (previous != nullptr) {
377 previous->setLaneSpreadFunction(LANESPREAD_RIGHT);
378 }
379 oneway_checked = false;
380 }
381 // add the edge
382 const SVCPermissions permissions = getPermissions("VSYSSET", false, myNetBuilder.getTypeCont().getPermissions(type));
383 int prio = myUseVisumPrio ? myNetBuilder.getTypeCont().getPriority(type) : -1;
384 if (nolanes != 0 && speed != 0) {
385 LaneSpreadFunction lsf = oneway_checked ? LANESPREAD_CENTER : LANESPREAD_RIGHT;
386 // @todo parse name from visum files
387 NBEdge* e = new NBEdge(myCurrentID, from, to, type, speed, nolanes, prio,
388 NBEdge::UNSPECIFIED_WIDTH, NBEdge::UNSPECIFIED_OFFSET, "", lsf);
389 e->setPermissions(permissions);
390 if (!myNetBuilder.getEdgeCont().insert(e)) {
391 delete e;
392 WRITE_ERROR("Duplicate edge occurred ('" + myCurrentID + "').");
393 }
394 }
395 myTouchedEdges.push_back(myCurrentID);
396 // nothing more to do, when the edge is a one-way street
397 if (oneway) {
398 return;
399 }
400 // add the opposite edge
401 myCurrentID = '-' + myCurrentID;
402 if (nolanes != 0 && speed != 0) {
403 LaneSpreadFunction lsf = oneway_checked ? LANESPREAD_CENTER : LANESPREAD_RIGHT;
404 // @todo parse name from visum files
405 NBEdge* e = new NBEdge(myCurrentID, from, to, type, speed, nolanes, prio,
406 NBEdge::UNSPECIFIED_WIDTH, NBEdge::UNSPECIFIED_OFFSET, "", lsf);
407 e->setPermissions(permissions);
408 if (!myNetBuilder.getEdgeCont().insert(e)) {
409 delete e;
410 WRITE_ERROR("Duplicate edge occurred ('" + myCurrentID + "').");
411 }
412 }
413 myTouchedEdges.push_back(myCurrentID);
414 }
415
416
417 void
parse_Kante()418 NIImporter_VISUM::parse_Kante() {
419 long long int id = StringUtils::toLong(myLineParser.get("ID"));
420 long long int from = StringUtils::toLong(myLineParser.get("VONPUNKTID"));
421 long long int to = StringUtils::toLong(myLineParser.get("NACHPUNKTID"));
422 myEdges[id] = std::make_pair(from, to);
423 }
424
425
426 void
parse_PartOfArea()427 NIImporter_VISUM::parse_PartOfArea() {
428 long long int flaecheID = StringUtils::toLong(myLineParser.get("FLAECHEID"));
429 long long int flaechePartID = StringUtils::toLong(myLineParser.get("TFLAECHEID"));
430 if (mySubPartsAreas.find(flaechePartID) == mySubPartsAreas.end()) {
431 mySubPartsAreas[flaechePartID] = std::vector<long long int>();
432 }
433 mySubPartsAreas[flaechePartID].push_back(flaecheID);
434 }
435
436
437 void
parse_Connectors()438 NIImporter_VISUM::parse_Connectors() {
439 if (OptionsCont::getOptions().getBool("visum.no-connectors")) {
440 // do nothing, if connectors shall not be imported
441 return;
442 }
443 // get the source district
444 std::string bez = NBHelpers::normalIDRepresentation(myLineParser.get("BezNr"));
445 // get the destination node
446 NBNode* dest = getNamedNode("KnotNr");
447 if (dest == nullptr) {
448 return;
449 }
450 // get the weight of the connection
451 double proz = 1;
452 if (myLineParser.know("Proz") || myLineParser.know("Proz(IV)")) {
453 proz = getNamedFloat("Proz", "Proz(IV)") / 100;
454 }
455 // get the duration to wait (unused)
456 // double retard = -1;
457 // if (myLineParser.know("t0-IV")) {
458 // retard = getNamedFloat("t0-IV", -1);
459 // }
460 // get the type;
461 // use a standard type with a large speed when a type is not given
462 std::string type = myLineParser.know("Typ")
463 ? NBHelpers::normalIDRepresentation(myLineParser.get("Typ"))
464 : "";
465 // add the connectors as an edge
466 std::string id = bez + "-" + dest->getID();
467 // get the information whether this is a sink or a source
468 std::string dir = myLineParser.get("Richtung");
469 if (dir.length() == 0) {
470 dir = "QZ";
471 }
472 // build the source when needed
473 if (dir.find('Q') != std::string::npos) {
474 const EdgeVector& edges = dest->getOutgoingEdges();
475 bool hasContinuation = false;
476 for (EdgeVector::const_iterator i = edges.begin(); i != edges.end(); ++i) {
477 if (!(*i)->isMacroscopicConnector()) {
478 hasContinuation = true;
479 }
480 }
481 if (!hasContinuation) {
482 // obviously, there is no continuation on the net
483 WRITE_WARNING("Incoming connector '" + id + "' will not be build - would be not connected to network.");
484 } else {
485 NBNode* src = buildDistrictNode(bez, dest, true);
486 if (src == nullptr) {
487 WRITE_ERROR("The district '" + bez + "' could not be built.");
488 return;
489 }
490 NBEdge* edge = new NBEdge(id, src, dest, "VisumConnector",
491 OptionsCont::getOptions().getFloat("visum.connector-speeds"),
492 OptionsCont::getOptions().getInt("visum.connectors-lane-number"),
493 -1, NBEdge::UNSPECIFIED_WIDTH, NBEdge::UNSPECIFIED_OFFSET,
494 "", LANESPREAD_RIGHT);
495 edge->setAsMacroscopicConnector();
496 if (!myNetBuilder.getEdgeCont().insert(edge)) {
497 WRITE_ERROR("A duplicate edge id occurred (ID='" + id + "').");
498 return;
499 }
500 edge = myNetBuilder.getEdgeCont().retrieve(id);
501 if (edge != nullptr) {
502 myNetBuilder.getDistrictCont().addSource(bez, edge, proz);
503 }
504 }
505 }
506 // build the sink when needed
507 if (dir.find('Z') != std::string::npos) {
508 const EdgeVector& edges = dest->getIncomingEdges();
509 bool hasPredeccessor = false;
510 for (EdgeVector::const_iterator i = edges.begin(); i != edges.end(); ++i) {
511 if (!(*i)->isMacroscopicConnector()) {
512 hasPredeccessor = true;
513 }
514 }
515 if (!hasPredeccessor) {
516 // obviously, the network is not connected to this node
517 WRITE_WARNING("Outgoing connector '" + id + "' will not be build - would be not connected to network.");
518 } else {
519 NBNode* src = buildDistrictNode(bez, dest, false);
520 if (src == nullptr) {
521 WRITE_ERROR("The district '" + bez + "' could not be built.");
522 return;
523 }
524 id = "-" + id;
525 NBEdge* edge = new NBEdge(id, dest, src, "VisumConnector",
526 OptionsCont::getOptions().getFloat("visum.connector-speeds"),
527 OptionsCont::getOptions().getInt("visum.connectors-lane-number"),
528 -1, NBEdge::UNSPECIFIED_WIDTH, NBEdge::UNSPECIFIED_OFFSET,
529 "", LANESPREAD_RIGHT);
530 edge->setAsMacroscopicConnector();
531 if (!myNetBuilder.getEdgeCont().insert(edge)) {
532 WRITE_ERROR("A duplicate edge id occurred (ID='" + id + "').");
533 return;
534 }
535 edge = myNetBuilder.getEdgeCont().retrieve(id);
536 if (edge != nullptr) {
537 myNetBuilder.getDistrictCont().addSink(bez, edge, proz);
538 }
539 }
540 }
541 }
542
543
544 void
parse_Turns()545 NIImporter_VISUM::parse_Turns() {
546 if (myLineParser.know("VSYSSET") && myLineParser.get("VSYSSET") == "") {
547 // no vehicle allowed; don't add
548 return;
549 }
550 // retrieve the nodes
551 NBNode* from = getNamedNode("VonKnot", "VonKnotNr");
552 NBNode* via = getNamedNode("UeberKnot", "UeberKnotNr");
553 NBNode* to = getNamedNode("NachKnot", "NachKnotNr");
554 if (from == nullptr || via == nullptr || to == nullptr) {
555 return;
556 }
557 // all nodes are known
558 std::string type = myLineParser.know("VSysCode")
559 ? myLineParser.get("VSysCode")
560 : myLineParser.get("VSYSSET");
561 if (myVSysTypes.find(type) != myVSysTypes.end() && myVSysTypes.find(type)->second == "IV") {
562 // try to set the turning definition
563 NBEdge* src = from->getConnectionTo(via);
564 NBEdge* dest = via->getConnectionTo(to);
565 // check both
566 if (src == nullptr) {
567 if (OptionsCont::getOptions().getBool("visum.verbose-warnings")) {
568 WRITE_WARNING("There is no edge from node '" + from->getID() + "' to node '" + via->getID() + "'.");
569 }
570 return;
571 }
572 if (dest == nullptr) {
573 if (OptionsCont::getOptions().getBool("visum.verbose-warnings")) {
574 WRITE_WARNING("There is no edge from node '" + via->getID() + "' to node '" + to->getID() + "'.");
575 }
576 return;
577 }
578 // both edges found
579 // set them into the edge
580 src->addEdge2EdgeConnection(dest);
581 }
582 }
583
584
585 void
parse_EdgePolys()586 NIImporter_VISUM::parse_EdgePolys() {
587 // get the from- & to-node and validate them
588 NBNode* from = getNamedNode("VonKnot", "VonKnotNr");
589 NBNode* to = getNamedNode("NachKnot", "NachKnotNr");
590 if (!checkNodes(from, to)) {
591 return;
592 }
593 bool failed = false;
594 int index;
595 double x, y;
596 try {
597 index = StringUtils::toInt(myLineParser.get("INDEX"));
598 x = getNamedFloat("XKoord");
599 y = getNamedFloat("YKoord");
600 } catch (NumberFormatException&) {
601 WRITE_ERROR("Error in geometry description from node '" + from->getID() + "' to node '" + to->getID() + "'.");
602 return;
603 }
604 Position pos(x, y);
605 if (!NBNetBuilder::transformCoordinate(pos)) {
606 WRITE_ERROR("Unable to project coordinates for node '" + from->getID() + "'.");
607 return;
608 }
609 NBEdge* e = from->getConnectionTo(to);
610 if (e != nullptr) {
611 e->addGeometryPoint(index, pos);
612 } else {
613 failed = true;
614 }
615 e = to->getConnectionTo(from);
616 if (e != nullptr) {
617 e->addGeometryPoint(-index, pos);
618 failed = false;
619 }
620 // check whether the operation has failed
621 if (failed) {
622 if (OptionsCont::getOptions().getBool("visum.verbose-warnings")) {
623 WRITE_WARNING("There is no edge from node '" + from->getID() + "' to node '" + to->getID() + "'.");
624 }
625 }
626 }
627
628
629 void
parse_Lanes()630 NIImporter_VISUM::parse_Lanes() {
631 // The base number of lanes for the edge was already defined in STRECKE
632 // this refines lane specific attribute (width) and optionally introduces splits for additional lanes
633 // It is permitted for KNOTNR to be 0
634 //
635 // get the edge
636 NBEdge* baseEdge = getNamedEdge("STRNR");
637 if (baseEdge == nullptr) {
638 return;
639 }
640 NBEdge* edge = baseEdge;
641 // get the node
642 NBNode* node = getNamedNodeSecure("KNOTNR");
643 if (node == nullptr) {
644 node = edge->getToNode();
645 } else {
646 edge = getNamedEdgeContinuating("STRNR", node);
647 }
648 // check
649 if (edge == nullptr) {
650 return;
651 }
652 // get the lane
653 std::string laneS = myLineParser.know("FSNR")
654 ? NBHelpers::normalIDRepresentation(myLineParser.get("FSNR"))
655 : NBHelpers::normalIDRepresentation(myLineParser.get("NR"));
656 int lane = -1;
657 try {
658 lane = StringUtils::toInt(laneS);
659 } catch (NumberFormatException&) {
660 WRITE_ERROR("A lane number for edge '" + edge->getID() + "' is not numeric (" + laneS + ").");
661 return;
662 }
663 lane -= 1;
664 if (lane < 0) {
665 WRITE_ERROR("A lane number for edge '" + edge->getID() + "' is not positive (" + laneS + ").");
666 return;
667 }
668 // get the direction
669 std::string dirS = NBHelpers::normalIDRepresentation(myLineParser.get("RICHTTYP"));
670 int prevLaneNo = baseEdge->getNumLanes();
671 if ((dirS == "1" && !(node->hasIncoming(edge))) || (dirS == "0" && !(node->hasOutgoing(edge)))) {
672 // get the last part of the turnaround direction
673 NBEdge* cand = getReversedContinuating(edge, node);
674 if (cand) {
675 edge = cand;
676 }
677 }
678 // get the length
679 std::string lengthS = NBHelpers::normalIDRepresentation(myLineParser.get("LAENGE"));
680 double length = -1;
681 try {
682 length = StringUtils::toDouble(lengthS);
683 } catch (NumberFormatException&) {
684 WRITE_ERROR("A lane length for edge '" + edge->getID() + "' is not numeric (" + lengthS + ").");
685 return;
686 }
687 if (length < 0) {
688 WRITE_ERROR("A lane length for edge '" + edge->getID() + "' is not positive (" + lengthS + ").");
689 return;
690 }
691 //
692 if (dirS == "1") {
693 lane -= prevLaneNo;
694 }
695 //
696 if (length == 0) {
697 if ((int) edge->getNumLanes() > lane) {
698 // ok, we know this already...
699 return;
700 }
701 // increment by one
702 edge->incLaneNo(1);
703 } else {
704 // check whether this edge already has been created
705 if (isSplitEdge(edge, node)) {
706 if (edge->getID().substr(edge->getID().find('_')) == "_" + toString(length) + "_" + node->getID()) {
707 if ((int) edge->getNumLanes() > lane) {
708 // ok, we know this already...
709 return;
710 }
711 // increment by one
712 edge->incLaneNo(1);
713 return;
714 }
715 }
716 // nope, we have to split the edge...
717 // maybe it is not the proper edge to split - VISUM seems not to sort the splits...
718 bool mustRecheck = true;
719 double seenLength = 0;
720 while (mustRecheck) {
721 if (isSplitEdge(edge, node)) {
722 // ok, we have a previously created edge here
723 std::string sub = edge->getID();
724 sub = sub.substr(sub.rfind('_', sub.rfind('_') - 1));
725 sub = sub.substr(1, sub.find('_', 1) - 1);
726 double dist = StringUtils::toDouble(sub);
727 if (dist < length) {
728 seenLength += edge->getLength();
729 if (dirS == "1") {
730 // incoming -> move back
731 edge = edge->getFromNode()->getIncomingEdges()[0];
732 } else {
733 // outgoing -> move forward
734 edge = edge->getToNode()->getOutgoingEdges()[0];
735 }
736 } else {
737 mustRecheck = false;
738 }
739 } else {
740 // we have the center edge - do not continue...
741 mustRecheck = false;
742 }
743 }
744 // compute position
745 Position p;
746 double useLength = length - seenLength;
747 useLength = edge->getLength() - useLength;
748 if (useLength < 0 || useLength > edge->getLength()) {
749 WRITE_WARNING("Could not find split position for edge '" + edge->getID() + "'.");
750 return;
751 }
752 std::string edgeID = edge->getID();
753 p = edge->getGeometry().positionAtOffset(useLength);
754 if (isSplitEdge(edge, node)) {
755 edgeID = edgeID.substr(0, edgeID.find('_'));
756 }
757 NBNode* rn = new NBNode(edgeID + "_" + toString((int) length) + "_" + node->getID(), p);
758 if (!myNetBuilder.getNodeCont().insert(rn)) {
759 throw ProcessError("Ups - could not insert node!");
760 }
761 std::string nid = edgeID + "_" + toString((int) length) + "_" + node->getID();
762 myNetBuilder.getEdgeCont().splitAt(myNetBuilder.getDistrictCont(), edge, useLength, rn,
763 edge->getID(), nid, edge->getNumLanes() + 0, edge->getNumLanes() + 1);
764 NBEdge* nedge = myNetBuilder.getEdgeCont().retrieve(nid);
765 nedge = nedge->getToNode()->getOutgoingEdges()[0];
766 while (isSplitEdge(edge, node)) {
767 assert(nedge->getToNode()->getOutgoingEdges().size() > 0);
768 nedge->incLaneNo(1);
769 nedge = nedge->getToNode()->getOutgoingEdges()[0];
770 }
771 }
772 }
773
774
775 void
parse_TrafficLights()776 NIImporter_VISUM::parse_TrafficLights() {
777 myCurrentID = NBHelpers::normalIDRepresentation(myLineParser.get("Nr"));
778 SUMOTime cycleTime = (SUMOTime) getWeightedFloat2("Umlaufzeit", "UMLZEIT", "s");
779 SUMOTime intermediateTime = (SUMOTime) getWeightedFloat2("StdZwischenzeit", "STDZWZEIT", "s");
780 bool phaseBased = myLineParser.know("PhasenBasiert")
781 ? StringUtils::toBool(myLineParser.get("PhasenBasiert"))
782 : false;
783 SUMOTime offset = myLineParser.know("ZEITVERSATZ") ? TIME2STEPS(getWeightedFloat("ZEITVERSATZ", "s")) : 0;
784 // add to the list
785 myTLS[myCurrentID] = new NIVisumTL(myCurrentID, cycleTime, offset, intermediateTime, phaseBased);
786 }
787
788
789 void
parse_NodesToTrafficLights()790 NIImporter_VISUM::parse_NodesToTrafficLights() {
791 std::string node = myLineParser.get("KnotNr").c_str();
792 if (node == "0") {
793 // this is a dummy value which cannot be assigned to
794 return;
795 }
796 std::string trafficLight = myLineParser.get("LsaNr").c_str();
797 // add to the list
798 NBNode* n = myNetBuilder.getNodeCont().retrieve(node);
799 auto tlIt = myTLS.find(trafficLight);
800 if (n != nullptr && tlIt != myTLS.end()) {
801 tlIt->second->addNode(n);
802 } else {
803 WRITE_ERROR("Could not assign" + std::string(n == nullptr ? " missing" : "") + " node '" + node
804 + "' to" + std::string(tlIt == myTLS.end() ? " missing" : "") + " traffic light '" + trafficLight + "'");
805 }
806 }
807
808
809 void
parse_SignalGroups()810 NIImporter_VISUM::parse_SignalGroups() {
811 myCurrentID = NBHelpers::normalIDRepresentation(myLineParser.get("Nr"));
812 std::string LSAid = NBHelpers::normalIDRepresentation(myLineParser.get("LsaNr"));
813 double startTime = getNamedFloat("GzStart", "GRUENANF");
814 double endTime = getNamedFloat("GzEnd", "GRUENENDE");
815 double yellowTime = myLineParser.know("GELB") ? getNamedFloat("GELB") : -1;
816 // add to the list
817 if (myTLS.find(LSAid) == myTLS.end()) {
818 WRITE_ERROR("Could not find TLS '" + LSAid + "' for setting the signal group.");
819 return;
820 }
821 myTLS.find(LSAid)->second->addSignalGroup(myCurrentID, (SUMOTime) startTime, (SUMOTime) endTime, (SUMOTime) yellowTime);
822 }
823
824
825 void
parse_TurnsToSignalGroups()826 NIImporter_VISUM::parse_TurnsToSignalGroups() {
827 // get the id
828 std::string SGid = getNamedString("SGNR", "SIGNALGRUPPENNR");
829 if (!myLineParser.know("LsaNr")) {
830 /// XXX could be retrieved from context
831 WRITE_WARNING("Ignoring SIGNALGRUPPEZUFSABBIEGER because LsaNr is not known");
832 return;
833 }
834 std::string LSAid = getNamedString("LsaNr");
835 // nodes
836 NBNode* from = myLineParser.know("VonKnot") ? getNamedNode("VonKnot") : nullptr;
837 NBNode* via = myLineParser.know("KNOTNR")
838 ? getNamedNode("KNOTNR")
839 : getNamedNode("UeberKnot", "UeberKnotNr");
840 NBNode* to = myLineParser.know("NachKnot") ? getNamedNode("NachKnot") : nullptr;
841 // edges
842 NBEdge* edg1 = nullptr;
843 NBEdge* edg2 = nullptr;
844 if (from == nullptr && to == nullptr) {
845 edg1 = getNamedEdgeContinuating("VONSTRNR", via);
846 edg2 = getNamedEdgeContinuating("NACHSTRNR", via);
847 } else {
848 edg1 = getEdge(from, via);
849 edg2 = getEdge(via, to);
850 }
851 // add to the list
852 NIVisumTL::SignalGroup& SG = myTLS.find(LSAid)->second->getSignalGroup(SGid);
853 if (edg1 != nullptr && edg2 != nullptr) {
854 if (!via->hasIncoming(edg1)) {
855 std::string sid;
856 if (edg1->getID()[0] == '-') {
857 sid = edg1->getID().substr(1);
858 } else {
859 sid = "-" + edg1->getID();
860 }
861 if (sid.find('_') != std::string::npos) {
862 sid = sid.substr(0, sid.find('_'));
863 }
864 edg1 = getNamedEdgeContinuating(myNetBuilder.getEdgeCont().retrieve(sid), via);
865 }
866 if (!via->hasOutgoing(edg2)) {
867 std::string sid;
868 if (edg2->getID()[0] == '-') {
869 sid = edg2->getID().substr(1);
870 } else {
871 sid = "-" + edg2->getID();
872 }
873 if (sid.find('_') != std::string::npos) {
874 sid = sid.substr(0, sid.find('_'));
875 }
876 edg2 = getNamedEdgeContinuating(myNetBuilder.getEdgeCont().retrieve(sid), via);
877 }
878 SG.connections().push_back(NBConnection(edg1, edg2));
879 }
880 }
881
882
883 void
parse_AreaSubPartElement()884 NIImporter_VISUM::parse_AreaSubPartElement() {
885 long long int id = StringUtils::toLong(myLineParser.get("TFLAECHEID"));
886 long long int edgeid = StringUtils::toLong(myLineParser.get("KANTEID"));
887 if (myEdges.find(edgeid) == myEdges.end()) {
888 WRITE_ERROR("Unknown edge in TEILFLAECHENELEMENT");
889 return;
890 }
891 std::string dir = myLineParser.get("RICHTUNG");
892 // get index (unused)
893 // std::string indexS = NBHelpers::normalIDRepresentation(myLineParser.get("INDEX"));
894 // int index = -1;
895 // try {
896 // index = StringUtils::toInt(indexS) - 1;
897 // } catch (NumberFormatException&) {
898 // WRITE_ERROR("An index for a TEILFLAECHENELEMENT is not numeric (id='" + toString(id) + "').");
899 // return;
900 // }
901 PositionVector shape;
902 shape.push_back(myPoints[myEdges[edgeid].first]);
903 shape.push_back(myPoints[myEdges[edgeid].second]);
904 if (dir.length() > 0 && dir[0] == '1') {
905 shape = shape.reverse();
906 }
907 if (mySubPartsAreas.find(id) == mySubPartsAreas.end()) {
908 WRITE_ERROR("Unkown are for area part '" + myCurrentID + "'.");
909 return;
910 }
911
912 const std::vector<long long int>& areas = mySubPartsAreas.find(id)->second;
913 for (std::vector<long long int>::const_iterator i = areas.begin(); i != areas.end(); ++i) {
914 NBDistrict* d = myShapeDistrictMap[*i];
915 if (d == nullptr) {
916 continue;
917 }
918 if (myDistrictShapes.find(d) == myDistrictShapes.end()) {
919 myDistrictShapes[d] = PositionVector();
920 }
921 if (dir.length() > 0 && dir[0] == '1') {
922 myDistrictShapes[d].push_back(myPoints[myEdges[edgeid].second]);
923 myDistrictShapes[d].push_back(myPoints[myEdges[edgeid].first]);
924 } else {
925 myDistrictShapes[d].push_back(myPoints[myEdges[edgeid].first]);
926 myDistrictShapes[d].push_back(myPoints[myEdges[edgeid].second]);
927 }
928 }
929 }
930
931
932 void
parse_Phases()933 NIImporter_VISUM::parse_Phases() {
934 // get the id
935 std::string phaseid = NBHelpers::normalIDRepresentation(myLineParser.get("Nr"));
936 std::string LSAid = NBHelpers::normalIDRepresentation(myLineParser.get("LsaNr"));
937 double startTime = getNamedFloat("GzStart", "GRUENANF");
938 double endTime = getNamedFloat("GzEnd", "GRUENENDE");
939 double yellowTime = myLineParser.know("GELB") ? getNamedFloat("GELB") : -1;
940 myTLS.find(LSAid)->second->addPhase(phaseid, (SUMOTime) startTime, (SUMOTime) endTime, (SUMOTime) yellowTime);
941 }
942
943
parse_SignalGroupsToPhases()944 void NIImporter_VISUM::parse_SignalGroupsToPhases() {
945 // get the id
946 std::string Phaseid = NBHelpers::normalIDRepresentation(myLineParser.get("PsNr"));
947 std::string LSAid = NBHelpers::normalIDRepresentation(myLineParser.get("LsaNr"));
948 std::string SGid = NBHelpers::normalIDRepresentation(myLineParser.get("SGNR"));
949 // insert
950 NIVisumTL* LSA = myTLS.find(LSAid)->second;
951 NIVisumTL::SignalGroup& SG = LSA->getSignalGroup(SGid);
952 NIVisumTL::Phase* PH = LSA->getPhases().find(Phaseid)->second;
953 SG.phases()[Phaseid] = PH;
954 }
955
956
parse_LanesConnections()957 void NIImporter_VISUM::parse_LanesConnections() {
958 NBNode* node = nullptr;
959 NBEdge* fromEdge = nullptr;
960 NBEdge* toEdge = nullptr;
961 // get the node and edges depending on network format
962 const std::string nodeID = getNamedString("KNOTNR", "KNOT");
963 if (nodeID == "0") {
964 fromEdge = getNamedEdge("VONSTRNR", "VONSTR");
965 toEdge = getNamedEdge("NACHSTRNR", "NACHSTR");
966 if (fromEdge == nullptr) {
967 return;
968 }
969 node = fromEdge->getToNode();
970 WRITE_WARNING("Ignoring lane-to-lane connection (not yet implemented for this format version)");
971 return;
972 } else {
973 node = getNamedNode("KNOTNR", "KNOT");
974 if (node == nullptr) {
975 return;
976 }
977 fromEdge = getNamedEdgeContinuating("VONSTRNR", "VONSTR", node);
978 toEdge = getNamedEdgeContinuating("NACHSTRNR", "NACHSTR", node);
979 }
980 if (fromEdge == nullptr || toEdge == nullptr) {
981 return;
982 }
983
984 int fromLaneOffset = 0;
985 if (!node->hasIncoming(fromEdge)) {
986 fromLaneOffset = fromEdge->getNumLanes();
987 fromEdge = getReversedContinuating(fromEdge, node);
988 } else {
989 fromEdge = getReversedContinuating(fromEdge, node);
990 NBEdge* tmp = myNetBuilder.getEdgeCont().retrieve(fromEdge->getID().substr(0, fromEdge->getID().find('_')));
991 fromLaneOffset = tmp->getNumLanes();
992 }
993
994 int toLaneOffset = 0;
995 if (!node->hasOutgoing(toEdge)) {
996 toLaneOffset = toEdge->getNumLanes();
997 toEdge = getReversedContinuating(toEdge, node);
998 } else {
999 NBEdge* tmp = myNetBuilder.getEdgeCont().retrieve(toEdge->getID().substr(0, toEdge->getID().find('_')));
1000 toLaneOffset = tmp->getNumLanes();
1001 }
1002 // get the from-lane
1003 std::string fromLaneS = NBHelpers::normalIDRepresentation(myLineParser.get("VONFSNR"));
1004 int fromLane = -1;
1005 try {
1006 fromLane = StringUtils::toInt(fromLaneS);
1007 } catch (NumberFormatException&) {
1008 WRITE_ERROR("A from-lane number for edge '" + fromEdge->getID() + "' is not numeric (" + fromLaneS + ").");
1009 return;
1010 }
1011 fromLane -= 1;
1012 if (fromLane < 0) {
1013 WRITE_ERROR("A from-lane number for edge '" + fromEdge->getID() + "' is not positive (" + fromLaneS + ").");
1014 return;
1015 }
1016 // get the from-lane
1017 std::string toLaneS = NBHelpers::normalIDRepresentation(myLineParser.get("NACHFSNR"));
1018 int toLane = -1;
1019 try {
1020 toLane = StringUtils::toInt(toLaneS);
1021 } catch (NumberFormatException&) {
1022 WRITE_ERROR("A to-lane number for edge '" + toEdge->getID() + "' is not numeric (" + toLaneS + ").");
1023 return;
1024 }
1025 toLane -= 1;
1026 if (toLane < 0) {
1027 WRITE_ERROR("A to-lane number for edge '" + toEdge->getID() + "' is not positive (" + toLaneS + ").");
1028 return;
1029 }
1030 // !!! the next is probably a hack
1031 if (fromLane - fromLaneOffset < 0) {
1032 //fromLaneOffset = 0;
1033 } else {
1034 fromLane = (int)fromEdge->getNumLanes() - (fromLane - fromLaneOffset) - 1;
1035 }
1036 if (toLane - toLaneOffset < 0) {
1037 //toLaneOffset = 0;
1038 } else {
1039 toLane = (int)toEdge->getNumLanes() - (toLane - toLaneOffset) - 1;
1040 }
1041 //
1042 if ((int) fromEdge->getNumLanes() <= fromLane) {
1043 WRITE_ERROR("A from-lane number for edge '" + fromEdge->getID() + "' is larger than the edge's lane number (" + fromLaneS + ").");
1044 return;
1045 }
1046 if ((int) toEdge->getNumLanes() <= toLane) {
1047 WRITE_ERROR("A to-lane number for edge '" + toEdge->getID() + "' is larger than the edge's lane number (" + toLaneS + ").");
1048 return;
1049 }
1050 //
1051 fromEdge->addLane2LaneConnection(fromLane, toEdge, toLane, NBEdge::L2L_VALIDATED);
1052 }
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066 double
getWeightedFloat(const std::string & name,const std::string & suffix)1067 NIImporter_VISUM::getWeightedFloat(const std::string& name, const std::string& suffix) {
1068 try {
1069 std::string val = myLineParser.get(name);
1070 if (val.find(suffix) != std::string::npos) {
1071 val = val.substr(0, val.find(suffix));
1072 }
1073 return StringUtils::toDouble(val);
1074 } catch (...) {}
1075 return -1;
1076 }
1077
1078
1079 double
getWeightedFloat2(const std::string & name,const std::string & name2,const std::string & suffix)1080 NIImporter_VISUM::getWeightedFloat2(const std::string& name, const std::string& name2, const std::string& suffix) {
1081 double result = getWeightedFloat(name, suffix);
1082 if (result != -1) {
1083 return result;
1084 } else {
1085 return getWeightedFloat(name2, suffix);
1086 }
1087 }
1088
1089 bool
getWeightedBool(const std::string & name)1090 NIImporter_VISUM::getWeightedBool(const std::string& name) {
1091 try {
1092 return StringUtils::toBool(myLineParser.get(name));
1093 } catch (...) {}
1094 try {
1095 return StringUtils::toBool(myLineParser.get((name + "(IV)")));
1096 } catch (...) {}
1097 return false;
1098 }
1099
1100 SVCPermissions
getPermissions(const std::string & name,bool warn,SVCPermissions unknown)1101 NIImporter_VISUM::getPermissions(const std::string& name, bool warn, SVCPermissions unknown) {
1102 SVCPermissions result = 0;
1103 for (std::string v : StringTokenizer(myLineParser.get(name), ",").getVector()) {
1104 // common values in english and german
1105 std::transform(v.begin(), v.end(), v.begin(), tolower);
1106 if (v == "bus") {
1107 result |= SVC_BUS;
1108 } else if (v == "walk" || v == "w" || v == "f") {
1109 result |= SVC_PEDESTRIAN;
1110 } else if (v == "l" || v == "lkw" || v == "h" || v == "hgv" || v == "lw" || v == "truck" || v == "tru") {
1111 result |= SVC_TRUCK;
1112 } else if (v == "b" || v == "bike") {
1113 result |= SVC_BICYCLE;
1114 } else if (v == "train") {
1115 result |= SVC_RAIL;
1116 } else if (v == "tram") {
1117 result |= SVC_TRAM;
1118 } else if (v == "p" || v == "pkw" || v == "car" || v == "c") {
1119 result |= SVC_PASSENGER;
1120 } else {
1121 if (warn) {
1122 WRITE_WARNING("Encountered unknown vehicle category '" + v + "' in type '" + myLineParser.get("Nr") + "'");
1123 }
1124 result |= unknown;
1125 }
1126 }
1127 return result;
1128 }
1129
1130 NBNode*
getNamedNode(const std::string & fieldName)1131 NIImporter_VISUM::getNamedNode(const std::string& fieldName) {
1132 std::string nodeS = NBHelpers::normalIDRepresentation(myLineParser.get(fieldName));
1133 NBNode* node = myNetBuilder.getNodeCont().retrieve(nodeS);
1134 if (node == nullptr) {
1135 WRITE_ERROR("The node '" + nodeS + "' is not known.");
1136 }
1137 return node;
1138 }
1139
1140 NBNode*
getNamedNodeSecure(const std::string & fieldName,NBNode * fallback)1141 NIImporter_VISUM::getNamedNodeSecure(const std::string& fieldName, NBNode* fallback) {
1142 std::string nodeS = NBHelpers::normalIDRepresentation(myLineParser.get(fieldName));
1143 NBNode* node = myNetBuilder.getNodeCont().retrieve(nodeS);
1144 if (node == nullptr) {
1145 return fallback;
1146 }
1147 return node;
1148 }
1149
1150
1151 NBNode*
getNamedNode(const std::string & fieldName1,const std::string & fieldName2)1152 NIImporter_VISUM::getNamedNode(const std::string& fieldName1, const std::string& fieldName2) {
1153 if (myLineParser.know(fieldName1)) {
1154 return getNamedNode(fieldName1);
1155 } else {
1156 return getNamedNode(fieldName2);
1157 }
1158 }
1159
1160
1161 NBEdge*
getNamedEdge(const std::string & fieldName)1162 NIImporter_VISUM::getNamedEdge(const std::string& fieldName) {
1163 std::string edgeS = NBHelpers::normalIDRepresentation(myLineParser.get(fieldName));
1164 NBEdge* edge = myNetBuilder.getEdgeCont().retrieve(edgeS);
1165 if (edge == nullptr) {
1166 WRITE_ERROR("The edge '" + edgeS + "' is not known.");
1167 }
1168 return edge;
1169 }
1170
1171
1172 NBEdge*
getNamedEdge(const std::string & fieldName1,const std::string & fieldName2)1173 NIImporter_VISUM::getNamedEdge(const std::string& fieldName1, const std::string& fieldName2) {
1174 if (myLineParser.know(fieldName1)) {
1175 return getNamedEdge(fieldName1);
1176 } else {
1177 return getNamedEdge(fieldName2);
1178 }
1179 }
1180
1181
1182
1183 NBEdge*
getReversedContinuating(NBEdge * edge,NBNode * node)1184 NIImporter_VISUM::getReversedContinuating(NBEdge* edge, NBNode* node) {
1185 std::string sid;
1186 if (edge->getID()[0] == '-') {
1187 sid = edge->getID().substr(1);
1188 } else {
1189 sid = "-" + edge->getID();
1190 }
1191 if (sid.find('_') != std::string::npos) {
1192 sid = sid.substr(0, sid.find('_'));
1193 }
1194 return getNamedEdgeContinuating(myNetBuilder.getEdgeCont().retrieve(sid), node);
1195 }
1196
1197
1198 NBEdge*
getNamedEdgeContinuating(NBEdge * begin,NBNode * node)1199 NIImporter_VISUM::getNamedEdgeContinuating(NBEdge* begin, NBNode* node) {
1200 if (begin == nullptr) {
1201 return nullptr;
1202 }
1203 NBEdge* ret = begin;
1204 std::string edgeID = ret->getID();
1205 // hangle forward
1206 while (ret != nullptr) {
1207 // ok, this is the edge we are looking for
1208 if (ret->getToNode() == node) {
1209 return ret;
1210 }
1211 const EdgeVector& nedges = ret->getToNode()->getOutgoingEdges();
1212 if (nedges.size() != 1) {
1213 // too many edges follow
1214 ret = nullptr;
1215 continue;
1216 }
1217 NBEdge* next = nedges[0];
1218 if (ret->getID().substr(0, edgeID.length()) != next->getID().substr(0, edgeID.length())) {
1219 // ok, another edge is next...
1220 ret = nullptr;
1221 continue;
1222 }
1223 if (next->getID().substr(next->getID().length() - node->getID().length()) != node->getID()) {
1224 ret = nullptr;
1225 continue;
1226 }
1227 ret = next;
1228 }
1229
1230 ret = begin;
1231 // hangle backward
1232 while (ret != nullptr) {
1233 // ok, this is the edge we are looking for
1234 if (ret->getFromNode() == node) {
1235 return ret;
1236 }
1237 const EdgeVector& nedges = ret->getFromNode()->getIncomingEdges();
1238 if (nedges.size() != 1) {
1239 // too many edges follow
1240 ret = nullptr;
1241 continue;
1242 }
1243 NBEdge* next = nedges[0];
1244 if (ret->getID().substr(0, edgeID.length()) != next->getID().substr(0, edgeID.length())) {
1245 // ok, another edge is next...
1246 ret = nullptr;
1247 continue;
1248 }
1249 if (next->getID().substr(next->getID().length() - node->getID().length()) != node->getID()) {
1250 ret = nullptr;
1251 continue;
1252 }
1253 ret = next;
1254 }
1255 return nullptr;
1256 }
1257
1258
1259 NBEdge*
getNamedEdgeContinuating(const std::string & fieldName,NBNode * node)1260 NIImporter_VISUM::getNamedEdgeContinuating(const std::string& fieldName, NBNode* node) {
1261 std::string edgeS = NBHelpers::normalIDRepresentation(myLineParser.get(fieldName));
1262 NBEdge* edge = myNetBuilder.getEdgeCont().retrieve(edgeS);
1263 if (edge == nullptr) {
1264 WRITE_ERROR("The edge '" + edgeS + "' is not known.");
1265 }
1266 return getNamedEdgeContinuating(edge, node);
1267 }
1268
1269
1270 NBEdge*
getNamedEdgeContinuating(const std::string & fieldName1,const std::string & fieldName2,NBNode * node)1271 NIImporter_VISUM::getNamedEdgeContinuating(const std::string& fieldName1, const std::string& fieldName2,
1272 NBNode* node) {
1273 if (myLineParser.know(fieldName1)) {
1274 return getNamedEdgeContinuating(fieldName1, node);
1275 } else {
1276 return getNamedEdgeContinuating(fieldName2, node);
1277 }
1278 }
1279
1280
1281 NBEdge*
getEdge(NBNode * FromNode,NBNode * ToNode)1282 NIImporter_VISUM::getEdge(NBNode* FromNode, NBNode* ToNode) {
1283 EdgeVector::const_iterator i;
1284 for (i = FromNode->getOutgoingEdges().begin(); i != FromNode->getOutgoingEdges().end(); i++) {
1285 if (ToNode == (*i)->getToNode()) {
1286 return (*i);
1287 }
1288 }
1289 //!!!
1290 return nullptr;
1291 }
1292
1293
1294 double
getNamedFloat(const std::string & fieldName)1295 NIImporter_VISUM::getNamedFloat(const std::string& fieldName) {
1296 std::string value = myLineParser.get(fieldName);
1297 if (StringUtils::endsWith(myLineParser.get(fieldName), "km/h")) {
1298 value = value.substr(0, value.length() - 4);
1299 }
1300 return StringUtils::toDouble(value);
1301 }
1302
1303
1304 double
getNamedFloat(const std::string & fieldName,double defaultValue)1305 NIImporter_VISUM::getNamedFloat(const std::string& fieldName, double defaultValue) {
1306 try {
1307 return StringUtils::toDouble(myLineParser.get(fieldName));
1308 } catch (...) {
1309 return defaultValue;
1310 }
1311 }
1312
1313
1314 double
getNamedFloat(const std::string & fieldName1,const std::string & fieldName2)1315 NIImporter_VISUM::getNamedFloat(const std::string& fieldName1, const std::string& fieldName2) {
1316 if (myLineParser.know(fieldName1)) {
1317 return getNamedFloat(fieldName1);
1318 } else {
1319 return getNamedFloat(fieldName2);
1320 }
1321 }
1322
1323
1324 double
getNamedFloat(const std::string & fieldName1,const std::string & fieldName2,double defaultValue)1325 NIImporter_VISUM::getNamedFloat(const std::string& fieldName1, const std::string& fieldName2,
1326 double defaultValue) {
1327 if (myLineParser.know(fieldName1)) {
1328 return getNamedFloat(fieldName1, defaultValue);
1329 } else {
1330 return getNamedFloat(fieldName2, defaultValue);
1331 }
1332 }
1333
1334
1335 std::string
getNamedString(const std::string & fieldName)1336 NIImporter_VISUM::getNamedString(const std::string& fieldName) {
1337 return NBHelpers::normalIDRepresentation(myLineParser.get(fieldName));
1338 }
1339
1340
1341 std::string
getNamedString(const std::string & fieldName1,const std::string & fieldName2)1342 NIImporter_VISUM::getNamedString(const std::string& fieldName1,
1343 const std::string& fieldName2) {
1344 if (myLineParser.know(fieldName1)) {
1345 return getNamedString(fieldName1);
1346 } else {
1347 return getNamedString(fieldName2);
1348 }
1349 }
1350
1351
1352
1353
1354
1355
1356 NBNode*
buildDistrictNode(const std::string & id,NBNode * dest,bool isSource)1357 NIImporter_VISUM::buildDistrictNode(const std::string& id, NBNode* dest,
1358 bool isSource) {
1359 // get the district
1360 NBDistrict* dist = myNetBuilder.getDistrictCont().retrieve(id);
1361 if (dist == nullptr) {
1362 return nullptr;
1363 }
1364 // build the id
1365 std::string nid;
1366 nid = id + "-" + dest->getID();
1367 if (!isSource) {
1368 nid = "-" + nid;
1369 }
1370 // insert the node
1371 if (!myNetBuilder.getNodeCont().insert(nid, dist->getPosition())) {
1372 WRITE_ERROR("Could not build connector node '" + nid + "'.");
1373 }
1374 // return the node
1375 return myNetBuilder.getNodeCont().retrieve(nid);
1376 }
1377
1378
1379 bool
checkNodes(NBNode * from,NBNode * to)1380 NIImporter_VISUM::checkNodes(NBNode* from, NBNode* to) {
1381 if (from == nullptr) {
1382 WRITE_ERROR(" The from-node was not found within the net");
1383 }
1384 if (to == nullptr) {
1385 WRITE_ERROR(" The to-node was not found within the net");
1386 }
1387 if (from == to) {
1388 WRITE_ERROR(" Both nodes are the same");
1389 }
1390 return from != nullptr && to != nullptr && from != to;
1391 }
1392
1393 bool
isSplitEdge(NBEdge * edge,NBNode * node)1394 NIImporter_VISUM::isSplitEdge(NBEdge* edge, NBNode* node) {
1395 return (edge->getID().length() > node->getID().length() + 1
1396 && (edge->getID().substr(edge->getID().length() - node->getID().length() - 1) == "_" + node->getID()));
1397 }
1398
1399 /****************************************************************************/
1400
1401