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