Eclipse SUMO - Simulation of Urban MObility
NIImporter_OpenStreetMap.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3// Copyright (C) 2001-2022 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/****************************************************************************/
22// Importer for networks stored in OpenStreetMap format
23/****************************************************************************/
24#include <config.h>
25#include <algorithm>
26#include <set>
27#include <functional>
28#include <sstream>
29#include <limits>
38#include <netbuild/NBEdge.h>
39#include <netbuild/NBEdgeCont.h>
40#include <netbuild/NBNode.h>
41#include <netbuild/NBNodeCont.h>
43#include <netbuild/NBOwnTLDef.h>
49#include <utils/xml/XMLSubSys.h>
50#include <netbuild/NBPTLine.h>
52#include "NILoader.h"
54
55#define KM_PER_MILE 1.609344
56
57//#define DEBUG_LAYER_ELEVATION
58
59// ---------------------------------------------------------------------------
60// static members
61// ---------------------------------------------------------------------------
63
64const long long int NIImporter_OpenStreetMap::INVALID_ID = std::numeric_limits<long long int>::max();
65
66// ===========================================================================
67// Private classes
68// ===========================================================================
69
73public:
74 bool operator()(const Edge* e1, const Edge* e2) const {
75 if (e1->myHighWayType != e2->myHighWayType) {
76 return e1->myHighWayType > e2->myHighWayType;
77 }
78 if (e1->myNoLanes != e2->myNoLanes) {
79 return e1->myNoLanes > e2->myNoLanes;
80 }
81 if (e1->myNoLanesForward != e2->myNoLanesForward) {
82 return e1->myNoLanesForward > e2->myNoLanesForward;
83 }
84 if (e1->myMaxSpeed != e2->myMaxSpeed) {
85 return e1->myMaxSpeed > e2->myMaxSpeed;
86 }
87 if (e1->myIsOneWay != e2->myIsOneWay) {
88 return e1->myIsOneWay > e2->myIsOneWay;
89 }
90 return e1->myCurrentNodes > e2->myCurrentNodes;
91 }
92};
93
94// ===========================================================================
95// method definitions
96// ===========================================================================
97// ---------------------------------------------------------------------------
98// static methods
99// ---------------------------------------------------------------------------
100const std::string NIImporter_OpenStreetMap::compoundTypeSeparator("|"); //clang-tidy says: "compundTypeSeparator with
101// static storage duration my throw an exception that cannot be caught
102
103void
106 importer.load(oc, nb);
107}
108
110
112 // delete nodes
113 for (auto myUniqueNode : myUniqueNodes) {
114 delete myUniqueNode;
115 }
116 // delete edges
117 for (auto& myEdge : myEdges) {
118 delete myEdge.second;
119 }
120 // delete platform shapes
121 for (auto& myPlatformShape : myPlatformShapes) {
122 delete myPlatformShape.second;
123 }
124}
125
126void
128 if (!oc.isSet("osm-files")) {
129 return;
130 }
131 const std::vector<std::string> files = oc.getStringVector("osm-files");
132 std::vector<SUMOSAXReader*> readers;
133
134 myImportLaneAccess = oc.getBool("osm.lane-access");
135 myImportTurnSigns = oc.getBool("osm.turn-lanes");
137
138 // load nodes, first
139 NodesHandler nodesHandler(myOSMNodes, myUniqueNodes, oc);
140 for (const std::string& file : files) {
141 if (!FileHelpers::isReadable(file)) {
142 WRITE_ERROR("Could not open osm-file '" + file + "'.");
143 return;
144 }
145 nodesHandler.setFileName(file);
146 nodesHandler.resetHierarchy();
147 const long before = PROGRESS_BEGIN_TIME_MESSAGE("Parsing nodes from osm-file '" + file + "'");
148 readers.push_back(XMLSubSys::getSAXReader(nodesHandler));
149 if (!readers.back()->parseFirst(file) || !readers.back()->parseSection(SUMO_TAG_NODE) ||
151 return;
152 }
153 if (nodesHandler.getDuplicateNodes() > 0) {
154 WRITE_MESSAGE("Found and substituted " + toString(nodesHandler.getDuplicateNodes()) + " osm nodes.");
155 }
156 PROGRESS_TIME_MESSAGE(before);
157 }
158
159 // load edges, then
161 int idx = 0;
162 for (const std::string& file : files) {
163 edgesHandler.setFileName(file);
164 readers[idx]->setHandler(edgesHandler);
165 const long before = PROGRESS_BEGIN_TIME_MESSAGE("Parsing edges from osm-file '" + file + "'");
166 if (!readers[idx]->parseSection(SUMO_TAG_WAY)) {
167 // eof already reached, no relations
168 delete readers[idx];
169 readers[idx] = nullptr;
170 }
171 PROGRESS_TIME_MESSAGE(before);
172 idx++;
173 }
174
175 /* Remove duplicate edges with the same shape and attributes */
176 if (!oc.getBool("osm.skip-duplicates-check")) {
177 int numRemoved = 0;
178 PROGRESS_BEGIN_MESSAGE("Removing duplicate edges");
179 if (myEdges.size() > 1) {
180 std::set<const Edge*, CompareEdges> dupsFinder;
181 for (auto it = myEdges.begin(); it != myEdges.end();) {
182 if (dupsFinder.count(it->second) > 0) {
183 numRemoved++;
184 delete it->second;
185 myEdges.erase(it++);
186 } else {
187 dupsFinder.insert(it->second);
188 it++;
189 }
190 }
191 }
192 if (numRemoved > 0) {
193 WRITE_MESSAGE("Removed " + toString(numRemoved) + " duplicate osm edges.");
194 }
196 }
197
198 /* Mark which nodes are used (by edges or traffic lights).
199 * This is necessary to detect which OpenStreetMap nodes are for
200 * geometry only */
201 std::map<long long int, int> nodeUsage;
202 // Mark which nodes are used by edges (begin and end)
203 for (std::map<long long int, Edge*>::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
204 Edge* e = (*i).second;
205 assert(e->myCurrentIsRoad);
206 for (std::vector<long long int>::const_iterator j = e->myCurrentNodes.begin();
207 j != e->myCurrentNodes.end();
208 ++j) {
209 if (nodeUsage.find(*j) == nodeUsage.end()) {
210 nodeUsage[*j] = 0;
211 }
212 nodeUsage[*j] = nodeUsage[*j] + 1;
213 }
214 }
215 // Mark which nodes are used by traffic lights
216 for (std::map<long long int, NIOSMNode*>::const_iterator nodesIt = myOSMNodes.begin();
217 nodesIt != myOSMNodes.end();
218 ++nodesIt) {
219 if (nodesIt->second->tlsControlled || nodesIt->second->railwaySignal /* || nodesIt->second->railwayCrossing*/) {
220 // If the key is not found in the map, the value is automatically
221 // initialized with 0.
222 nodeUsage[nodesIt->first] += 1;
223 }
224 }
225
226 /* Instantiate edges
227 * Only those nodes in the middle of an edge which are used by more than
228 * one edge are instantiated. Other nodes are considered as geometry nodes. */
229 NBNodeCont& nc = nb.getNodeCont();
231 for (auto& myEdge : myEdges) {
232 Edge* e = myEdge.second;
233 assert(e->myCurrentIsRoad);
234 if (e->myCurrentNodes.size() < 2) {
235 WRITE_WARNINGF(TL("Discarding way '%' because it has only % node(s)"), e->id, e->myCurrentNodes.size());
236 continue;
237 }
239 // build nodes;
240 // - the from- and to-nodes must be built in any case
241 // - the in-between nodes are only built if more than one edge references them
242 NBNode* first = insertNodeChecking(*e->myCurrentNodes.begin(), nc, tlsc);
243 NBNode* last = insertNodeChecking(*(e->myCurrentNodes.end() - 1), nc, tlsc);
244 NBNode* currentFrom = first;
245 int running = 0;
246 std::vector<long long int> passed;
247 for (auto j = e->myCurrentNodes.begin(); j != e->myCurrentNodes.end(); ++j) {
248 passed.push_back(*j);
249 if (nodeUsage[*j] > 1 && j != e->myCurrentNodes.end() - 1 && j != e->myCurrentNodes.begin()) {
250 NBNode* currentTo = insertNodeChecking(*j, nc, tlsc);
251 running = insertEdge(e, running, currentFrom, currentTo, passed, nb, first, last);
252 currentFrom = currentTo;
253 passed.clear();
254 passed.push_back(*j);
255 }
256 }
257 if (running == 0) {
258 running = -1;
259 }
260 insertEdge(e, running, currentFrom, last, passed, nb, first, last);
261 }
262
263 const double layerElevation = oc.getFloat("osm.layer-elevation");
264 if (layerElevation > 0) {
265 reconstructLayerElevation(layerElevation, nb);
266 }
267
268 // revise pt stops; remove stops on deleted edges
270
271 // load relations (after edges are built since we want to apply
272 // turn-restrictions directly to NBEdges)
274 &nb.getPTLineCont(), oc);
275 idx = 0;
276 for (const std::string& file : files) {
277 if (readers[idx] != nullptr) {
278 relationHandler.setFileName(file);
279 readers[idx]->setHandler(relationHandler);
280 const long before = PROGRESS_BEGIN_TIME_MESSAGE("Parsing relations from osm-file '" + file + "'");
281 readers[idx]->parseSection(SUMO_TAG_RELATION);
282 PROGRESS_TIME_MESSAGE(before);
283 delete readers[idx];
284 }
285 idx++;
286 }
287
288 // declare additional stops that are not anchored to a (road)-way or route relation
289 std::set<std::string> stopNames;
290 for (const auto& item : nb.getPTStopCont().getStops()) {
291 stopNames.insert(item.second->getName());
292 }
293 for (const auto& item : myOSMNodes) {
294 const NIOSMNode* n = item.second;
295 if (n->ptStopPosition && stopNames.count(n->name) == 0) {
296 Position ptPos(n->lon, n->lat, n->ele);
298 WRITE_ERROR("Unable to project coordinates for node '" + toString(n->id) + "'.");
299 }
300 NBPTStop* ptStop = new NBPTStop(toString(n->id), ptPos, "", "", n->ptStopLength, n->name, n->permissions);
301 nb.getPTStopCont().insert(ptStop, true);
302 }
303 }
304}
305
306
307NBNode*
309 NBNode* node = nc.retrieve(toString(id));
310 if (node == nullptr) {
311 NIOSMNode* n = myOSMNodes.find(id)->second;
312 Position pos(n->lon, n->lat, n->ele);
313 if (!NBNetBuilder::transformCoordinate(pos, true)) {
314 WRITE_ERROR("Unable to project coordinates for junction '" + toString(id) + "'.");
315 return nullptr;
316 }
317 node = new NBNode(toString(id), pos);
318 if (!nc.insert(node)) {
319 WRITE_ERROR("Could not insert junction '" + toString(id) + "'.");
320 delete node;
321 return nullptr;
322 }
323 n->node = node;
324 if (n->railwayCrossing) {
326 } else if (n->railwaySignal) {
328 } else if (n->tlsControlled) {
329 // ok, this node is a traffic light node where no other nodes
330 // participate
331 // @note: The OSM-community has not settled on a schema for differentiating between fixed and actuated lights
333 OptionsCont::getOptions().getString("tls.default-type"));
334 NBOwnTLDef* tlDef = new NBOwnTLDef(toString(id), node, 0, type);
335 if (!tlsc.insert(tlDef)) {
336 // actually, nothing should fail here
337 delete tlDef;
338 throw ProcessError("Could not allocate tls '" + toString(id) + "'.");
339 }
340 }
341 if (n->railwayBufferStop) {
342 node->setParameter("buffer_stop", "true");
344 }
345 }
346 return node;
347}
348
349
350int
352 const std::vector<long long int>& passed, NBNetBuilder& nb,
353 const NBNode* first, const NBNode* last) {
354 NBNodeCont& nc = nb.getNodeCont();
355 NBEdgeCont& ec = nb.getEdgeCont();
356 NBTypeCont& tc = nb.getTypeCont();
357 NBPTStopCont& sc = nb.getPTStopCont();
358
360 // patch the id
361 std::string id = toString(e->id);
362 if (from == nullptr || to == nullptr) {
363 WRITE_ERROR("Discarding edge '" + id + "' because the nodes could not be built.");
364 return index;
365 }
366 if (index >= 0) {
367 id = id + "#" + toString(index);
368 } else {
369 index = 0;
370 }
371 if (from == to) {
372 assert(passed.size() >= 2);
373 if (passed.size() == 2) {
374 WRITE_WARNINGF(TL("Discarding edge '%' which connects two identical nodes without geometry."), id);
375 return index;
376 }
377 // in the special case of a looped way split again using passed
378 int intermediateIndex = (int) passed.size() / 2;
379 NBNode* intermediate = insertNodeChecking(passed[intermediateIndex], nc, tlsc);
380 std::vector<long long int> part1(passed.begin(), passed.begin() + intermediateIndex + 1);
381 std::vector<long long int> part2(passed.begin() + intermediateIndex, passed.end());
382 index = insertEdge(e, index, from, intermediate, part1, nb, first, last);
383 return insertEdge(e, index, intermediate, to, part2, nb, first, last);
384 }
385 const int newIndex = index + 1;
386 const std::string type = usableType(e->myHighWayType, id, tc);
387 if (type == "") { // we do not want to import it
388 return newIndex;
389 }
390
391 int numLanesForward = tc.getEdgeTypeNumLanes(type);
392 int numLanesBackward = tc.getEdgeTypeNumLanes(type);
393 double speed = tc.getEdgeTypeSpeed(type);
394 bool defaultsToOneWay = tc.getEdgeTypeIsOneWay(type);
395 SVCPermissions defaultPermissions = tc.getEdgeTypePermissions(type);
396 SVCPermissions permissions = defaultPermissions | e->myExtraAllowed;
397 permissions &= ~e->myExtraDisallowed;
398 if (defaultsToOneWay && defaultPermissions == SVC_PEDESTRIAN && (permissions & (~SVC_PEDESTRIAN)) != 0) {
399 defaultsToOneWay = false;
400 }
401 if (e->myCurrentIsElectrified && (permissions & SVC_RAIL) != 0) {
402 permissions |= (SVC_RAIL_ELECTRIC | SVC_RAIL_FAST);
403 }
404
405 // convert the shape
406 PositionVector shape;
407 double distanceStart = myOSMNodes[passed.front()]->positionMeters;
408 double distanceEnd = myOSMNodes[passed.back()]->positionMeters;
409 const bool useDistance = distanceStart != std::numeric_limits<double>::max() && distanceEnd != std::numeric_limits<double>::max();
410 if (useDistance) {
411 // negative sign denotes counting in the other direction
412 if (distanceStart < distanceEnd) {
413 distanceStart *= -1;
414 } else {
415 distanceEnd *= -1;
416 }
417 } else {
418 distanceStart = 0;
419 distanceEnd = 0;
420 }
421 std::vector<NBPTStop*> ptStops;
422 for (long long i : passed) {
423 NIOSMNode* n = myOSMNodes.find(i)->second;
424 // recheck permissions, maybe they got assigned to a strange edge, see #11656
425 if (n->ptStopPosition && (n->permissions == 0 || (permissions & n->permissions) != 0)) {
426 NBPTStop* existingPtStop = sc.get(toString(n->id));
427 if (existingPtStop != nullptr) {
428 existingPtStop->registerAdditionalEdge(toString(e->id), id);
429 } else {
430 Position ptPos(n->lon, n->lat, n->ele);
432 WRITE_ERROR("Unable to project coordinates for node '" + toString(n->id) + "'.");
433 }
434 ptStops.push_back(new NBPTStop(toString(n->id), ptPos, id, toString(e->id), n->ptStopLength, n->name, n->permissions));
435 sc.insert(ptStops.back());
436 }
437 }
438 Position pos(n->lon, n->lat, n->ele);
439 shape.push_back(pos);
440 }
442 WRITE_ERROR("Unable to project coordinates for edge '" + id + "'.");
443 }
444
445 SVCPermissions forwardPermissions = permissions;
446 SVCPermissions backwardPermissions = permissions;
447 const std::string streetName = isRailway(permissions) && e->ref != "" ? e->ref : e->streetName;
448 if (streetName == e->ref) {
449 e->unsetParameter("ref"); // avoid superfluous param for railways
450 }
451 double forwardWidth = tc.getEdgeTypeWidth(type);
452 double backwardWidth = tc.getEdgeTypeWidth(type);
453 double sidewalkWidth = tc.getEdgeTypeSidewalkWidth(type);
454 bool addSidewalk = sidewalkWidth != NBEdge::UNSPECIFIED_WIDTH;
455 const bool addBikeLane = (tc.getEdgeTypeBikeLaneWidth(type) != NBEdge::UNSPECIFIED_WIDTH);
456 if (myImportSidewalks) {
457 if (addSidewalk) {
458 // only use sidewalk width from typemap but don't add sidewalks
459 // unless OSM specifies them
460 addSidewalk = false;
461 } else {
462 sidewalkWidth = OptionsCont::getOptions().getFloat("default.sidewalk-width");
463 }
464 }
465 // check directions
466 bool addForward = true;
467 bool addBackward = true;
468 if ((e->myIsOneWay == "true" || e->myIsOneWay == "yes" || e->myIsOneWay == "1"
469 || (defaultsToOneWay && e->myIsOneWay != "no" && e->myIsOneWay != "false" && e->myIsOneWay != "0"))
470 && e->myRailDirection != WAY_BOTH) {
471 addBackward = false;
472 }
473 if (e->myIsOneWay == "-1" || e->myIsOneWay == "reverse" || e->myRailDirection == WAY_BACKWARD) {
474 // one-way in reversed direction of way
475 addForward = false;
476 addBackward = true;
477 }
478 if (!e->myIsOneWay.empty() && e->myIsOneWay != "false" && e->myIsOneWay != "no" && e->myIsOneWay != "true"
479 && e->myIsOneWay != "yes" && e->myIsOneWay != "-1" && e->myIsOneWay != "1" && e->myIsOneWay != "reverse") {
480 WRITE_WARNINGF(TL("New value for oneway found: %"), e->myIsOneWay);
481 }
482 if (isBikepath(permissions) && e->myCyclewayType != WAY_UNKNOWN) {
483 if ((e->myCyclewayType & WAY_BACKWARD) == 0) {
484 addBackward = false;
485 }
486 if ((e->myCyclewayType & WAY_FORWARD) == 0) {
487 addForward = false;
488 }
489 }
490 bool ok = true;
491 // if we had been able to extract the number of lanes, override the highway type default
492 if (e->myNoLanes > 0) {
493 if (addForward && !addBackward) {
494 numLanesForward = e->myNoLanes;
495 } else if (!addForward && addBackward) {
496 numLanesBackward = e->myNoLanes;
497 } else {
498 if (e->myNoLanesForward > 0) {
499 numLanesForward = e->myNoLanesForward;
500 } else if (e->myNoLanesForward < 0) {
501 numLanesForward = e->myNoLanes + e->myNoLanesForward;
502 } else {
503 numLanesForward = (int) std::ceil(e->myNoLanes / 2.0);
504 }
505 numLanesBackward = e->myNoLanes - numLanesForward;
506 // sometimes ways are tagged according to their physical width of a single
507 // lane but they are intended for traffic in both directions
508 numLanesForward = MAX2(1, numLanesForward);
509 numLanesBackward = MAX2(1, numLanesBackward);
510 }
511 } else if (e->myNoLanes == 0) {
512 WRITE_WARNINGF(TL("Skipping edge '%' because it has zero lanes."), id);
513 ok = false;
514 } else {
515 // the total number of lanes is not known but at least one direction
516 if (e->myNoLanesForward > 0) {
517 numLanesForward = e->myNoLanesForward;
518 }
519 if (e->myNoLanesForward < 0) {
520 numLanesBackward = -e->myNoLanesForward;
521 }
522 }
523 // if we had been able to extract the maximum speed, override the type's default
524 if (e->myMaxSpeed != MAXSPEED_UNGIVEN) {
525 speed = e->myMaxSpeed / 3.6;
526 }
527 double speedBackward = speed;
529 speedBackward = e->myMaxSpeedBackward / 3.6;
530 }
531 if (speed <= 0 || speedBackward <= 0) {
532 WRITE_WARNINGF(TL("Skipping edge '%' because it has speed %."), id, speed);
533 ok = false;
534 }
535 // deal with cycleways that run in the opposite direction of a one-way street
536 WayType cyclewayType = e->myCyclewayType; // make a copy because we do some temporary modifications
537 if (addBikeLane) {
538 if (!addForward && (cyclewayType & WAY_FORWARD) != 0) {
539 addForward = true;
540 forwardPermissions = SVC_BICYCLE;
541 forwardWidth = tc.getEdgeTypeBikeLaneWidth(type);
542 numLanesForward = 1;
543 // do not add an additional cycle lane
544 cyclewayType = (WayType)(cyclewayType & ~WAY_FORWARD); //clang tidy thinks "!WAY_FORWARD" is always false
545 }
546 if (!addBackward && (cyclewayType & WAY_BACKWARD) != 0) {
547 addBackward = true;
548 backwardPermissions = SVC_BICYCLE;
549 backwardWidth = tc.getEdgeTypeBikeLaneWidth(type);
550 numLanesBackward = 1;
551 // do not add an additional cycle lane
552 cyclewayType = (WayType)(cyclewayType & ~WAY_BACKWARD); //clang tidy thinks "!WAY_BACKWARD" is always false
553 }
554 }
555 // deal with sidewalks that run in the opposite direction of a one-way street
556 WayType sidewalkType = e->mySidewalkType; // make a copy because we do some temporary modifications
557 if (sidewalkType == WAY_UNKNOWN && (e->myExtraAllowed & SVC_PEDESTRIAN) != 0 && (permissions & SVC_PASSENGER) != 0) {
558 // do not assume shared space unless sidewalk is actively disabled
559 sidewalkType = WAY_BOTH;
560 }
561 if (addSidewalk || (myImportSidewalks && (permissions & SVC_ROAD_CLASSES) != 0 && defaultPermissions != SVC_PEDESTRIAN)) {
562 if (!addForward && (sidewalkType & WAY_FORWARD) != 0) {
563 addForward = true;
564 forwardPermissions = SVC_PEDESTRIAN;
565 forwardWidth = tc.getEdgeTypeSidewalkWidth(type);
566 numLanesForward = 1;
567 // do not add an additional sidewalk
568 sidewalkType = (WayType)(sidewalkType & ~WAY_FORWARD); //clang tidy thinks "!WAY_FORWARD" is always false
569 } else if (addSidewalk && addForward && (sidewalkType & WAY_BOTH) == 0
570 && numLanesForward == 1 && numLanesBackward <= 1
571 && (e->myExtraDisallowed & SVC_PEDESTRIAN) == 0) {
572 // our typemap says pedestrians should walk here but the data says
573 // there is no sidewalk at all. If the road is small, pedestrians can just walk
574 // on the road
575 forwardPermissions |= SVC_PEDESTRIAN;
576 }
577 if (!addBackward && (sidewalkType & WAY_BACKWARD) != 0) {
578 addBackward = true;
579 backwardPermissions = SVC_PEDESTRIAN;
580 backwardWidth = tc.getEdgeTypeSidewalkWidth(type);
581 numLanesBackward = 1;
582 // do not add an additional cycle lane
583 sidewalkType = (WayType)(sidewalkType & ~WAY_BACKWARD); //clang tidy thinks "!WAY_BACKWARD" is always false
584 } else if (addSidewalk && addBackward && (sidewalkType & WAY_BOTH) == 0
585 && numLanesBackward == 1 && numLanesForward <= 1
586 && (e->myExtraDisallowed & SVC_PEDESTRIAN) == 0) {
587 // our typemap says pedestrians should walk here but the data says
588 // there is no sidewalk at all. If the road is small, pedestrians can just walk
589 // on the road
590 backwardPermissions |= SVC_PEDESTRIAN;
591 }
592 }
593 // deal with busways that run in the opposite direction of a one-way street
594 if (!addForward && (e->myBuswayType & WAY_FORWARD) != 0) {
595 addForward = true;
596 forwardPermissions = SVC_BUS;
597 numLanesForward = 1;
598 }
599 if (!addBackward && (e->myBuswayType & WAY_BACKWARD) != 0) {
600 addBackward = true;
601 backwardPermissions = SVC_BUS;
602 numLanesBackward = 1;
603 }
604
605 const std::string origID = OptionsCont::getOptions().getBool("output.original-names") ? toString(e->id) : "";
606 if (ok) {
607 const int offsetFactor = OptionsCont::getOptions().getBool("lefthand") ? -1 : 1;
608 LaneSpreadFunction lsf = (addBackward || OptionsCont::getOptions().getBool("osm.oneway-spread-right")) &&
610 if (addBackward && lsf == LaneSpreadFunction::RIGHT && OptionsCont::getOptions().getString("default.spreadtype") == toString(LaneSpreadFunction::ROADCENTER)) {
612 }
613
614 id = StringUtils::escapeXML(id);
615 const std::string reverseID = "-" + id;
616
617 if (addForward) {
618 assert(numLanesForward > 0);
619 NBEdge* nbe = new NBEdge(id, from, to, type, speed, NBEdge::UNSPECIFIED_FRICTION, numLanesForward, tc.getEdgeTypePriority(type),
620 forwardWidth, NBEdge::UNSPECIFIED_OFFSET, shape, lsf,
621 StringUtils::escapeXML(streetName), origID, true);
622 nbe->setPermissions(forwardPermissions);
623 if ((e->myBuswayType & WAY_FORWARD) != 0) {
624 nbe->setPermissions(SVC_BUS, 0);
625 }
629 nbe->setTurnSignTarget(last->getID());
630 if (addBikeLane && (cyclewayType == WAY_UNKNOWN || (cyclewayType & WAY_FORWARD) != 0)) {
631 nbe->addBikeLane(tc.getEdgeTypeBikeLaneWidth(type) * offsetFactor);
632 } else if (nbe->getPermissions(0) == SVC_BUS) {
633 // bikes drive on buslanes if no separate cycle lane is available
635 }
636 if ((addSidewalk && (sidewalkType == WAY_UNKNOWN || (sidewalkType & WAY_FORWARD) != 0))
637 || (myImportSidewalks && (sidewalkType & WAY_FORWARD) != 0 && defaultPermissions != SVC_PEDESTRIAN)) {
638 nbe->addSidewalk(sidewalkWidth * offsetFactor);
639 }
641 nbe->setDistance(distanceStart);
642 if (!ec.insert(nbe)) {
643 delete nbe;
644 throw ProcessError("Could not add edge '" + id + "'.");
645 }
646 }
647 if (addBackward) {
648 assert(numLanesBackward > 0);
649 NBEdge* nbe = new NBEdge(reverseID, to, from, type, speedBackward, NBEdge::UNSPECIFIED_FRICTION, numLanesBackward, tc.getEdgeTypePriority(type),
650 backwardWidth, NBEdge::UNSPECIFIED_OFFSET, shape.reverse(), lsf,
651 StringUtils::escapeXML(streetName), origID, true);
652 nbe->setPermissions(backwardPermissions);
653 if ((e->myBuswayType & WAY_BACKWARD) != 0) {
654 nbe->setPermissions(SVC_BUS, 0);
655 }
659 nbe->setTurnSignTarget(first->getID());
660 if (addBikeLane && (cyclewayType == WAY_UNKNOWN || (cyclewayType & WAY_BACKWARD) != 0)) {
661 nbe->addBikeLane(tc.getEdgeTypeBikeLaneWidth(type) * offsetFactor);
662 } else if (nbe->getPermissions(0) == SVC_BUS) {
663 // bikes drive on buslanes if no separate cycle lane is available
665 }
666 if ((addSidewalk && (sidewalkType == WAY_UNKNOWN || (sidewalkType & WAY_BACKWARD) != 0))
667 || (myImportSidewalks && (sidewalkType & WAY_BACKWARD) != 0 && defaultPermissions != SVC_PEDESTRIAN)) {
668 nbe->addSidewalk(sidewalkWidth * offsetFactor);
669 }
671 nbe->setDistance(distanceEnd);
672 if (!ec.insert(nbe)) {
673 delete nbe;
674 throw ProcessError("Could not add edge '-" + id + "'.");
675 }
676 }
677 if ((e->myParkingType & PARKING_BOTH) != 0 && OptionsCont::getOptions().isSet("parking-output")) {
678 if ((e->myParkingType & PARKING_RIGHT) != 0) {
679 if (addForward) {
680 nb.getParkingCont().push_back(NBParking(id, id));
681 } else {
683 if ((e->myParkingType & PARKING_LEFT) == 0 && !addBackward) {
685 nb.getParkingCont().push_back(NBParking(reverseID, reverseID));
686 }
687 }
688 }
689 if ((e->myParkingType & PARKING_LEFT) != 0) {
690 if (addBackward) {
691 nb.getParkingCont().push_back(NBParking(reverseID, reverseID));
692 } else {
694 if ((e->myParkingType & PARKING_RIGHT) == 0 && !addForward) {
696 nb.getParkingCont().push_back(NBParking(id, id));
697 }
698 }
699 }
700 }
701 }
702 return newIndex;
703}
704
705
706// ---------------------------------------------------------------------------
707// definitions of NIImporter_OpenStreetMap::NodesHandler-methods
708// ---------------------------------------------------------------------------
709NIImporter_OpenStreetMap::NodesHandler::NodesHandler(std::map<long long int, NIOSMNode*>& toFill,
710 std::set<NIOSMNode*, CompareNodes>& uniqueNodes, const OptionsCont& oc) :
711 SUMOSAXHandler("osm - file"),
712 myToFill(toFill),
713 myCurrentNode(nullptr),
714 myHierarchyLevel(0),
715 myUniqueNodes(uniqueNodes),
716 myImportElevation(oc.getBool("osm.elevation")),
717 myDuplicateNodes(0),
718 myOptionsCont(oc) {
719}
720
722
723void
725 ++myHierarchyLevel;
726 if (element == SUMO_TAG_NODE) {
727 bool ok = true;
728 myLastNodeID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
729 if (myHierarchyLevel != 2) {
730 WRITE_ERROR("Node element on wrong XML hierarchy level (id='" + myLastNodeID +
731 "', level='" + toString(myHierarchyLevel) + "').");
732 return;
733 }
734 const std::string& action = attrs.getOpt<std::string>(SUMO_ATTR_ACTION, myLastNodeID.c_str(), ok);
735 if (action == "delete" || !ok) {
736 return;
737 }
738 try {
739 // we do not use attrs.get here to save some time on parsing
740 const long long int id = StringUtils::toLong(myLastNodeID);
741 myCurrentNode = nullptr;
742 const auto insertionIt = myToFill.lower_bound(id);
743 if (insertionIt == myToFill.end() || insertionIt->first != id) {
744 // assume we are loading multiple files, so we won't report duplicate nodes
745 const double tlon = attrs.get<double>(SUMO_ATTR_LON, myLastNodeID.c_str(), ok);
746 const double tlat = attrs.get<double>(SUMO_ATTR_LAT, myLastNodeID.c_str(), ok);
747 if (!ok) {
748 return;
749 }
750 myCurrentNode = new NIOSMNode(id, tlon, tlat);
751 auto similarNode = myUniqueNodes.find(myCurrentNode);
752 if (similarNode == myUniqueNodes.end()) {
753 myUniqueNodes.insert(myCurrentNode);
754 } else {
755 delete myCurrentNode;
756 myCurrentNode = *similarNode;
757 myDuplicateNodes++;
758 }
759 myToFill.emplace_hint(insertionIt, id, myCurrentNode);
760 }
761 } catch (FormatException&) {
762 WRITE_ERROR(TL("Attribute 'id' in the definition of a node is not of type long long int."));
763 return;
764 }
765 }
766 if (element == SUMO_TAG_TAG && myCurrentNode != nullptr) {
767 if (myHierarchyLevel != 3) {
768 WRITE_ERROR(TL("Tag element on wrong XML hierarchy level."));
769 return;
770 }
771 bool ok = true;
772 const std::string& key = attrs.get<std::string>(SUMO_ATTR_K, myLastNodeID.c_str(), ok, false);
773 // we check whether the key is relevant (and we really need to transcode the value) to avoid hitting #1636
774 if (key == "highway" || key == "ele" || key == "crossing" || key == "railway" || key == "public_transport"
775 || key == "name" || key == "train" || key == "bus" || key == "tram" || key == "light_rail" || key == "subway" || key == "station" || key == "noexit"
776 || StringUtils::startsWith(key, "railway:signal")
777 || StringUtils::startsWith(key, "railway:position")
778 ) {
779 const std::string& value = attrs.get<std::string>(SUMO_ATTR_V, myLastNodeID.c_str(), ok, false);
780 if (key == "highway" && value.find("traffic_signal") != std::string::npos) {
781 myCurrentNode->tlsControlled = true;
782 } else if (key == "crossing" && value.find("traffic_signals") != std::string::npos) {
783 myCurrentNode->tlsControlled = true;
784 } else if ((key == "noexit" && value == "yes")
785 || (key == "railway" && value == "buffer_stop")) {
786 myCurrentNode->railwayBufferStop = true;
787 } else if (key == "railway" && value.find("crossing") != std::string::npos) {
788 myCurrentNode->railwayCrossing = true;
789 } else if (StringUtils::startsWith(key, "railway:signal") && (
790 value == "block" || value == "entry" || value == "exit" || value == "intermediate")) {
791 myCurrentNode->railwaySignal = true;
792 } else if (StringUtils::startsWith(key, "railway:position") && value.size() > myCurrentNode->position.size()) {
793 // use the entry with the highest precision (more digits)
794 myCurrentNode->position = value;
795 } else if ((key == "public_transport" && value == "stop_position") ||
796 (key == "highway" && value == "bus_stop")) {
797 myCurrentNode->ptStopPosition = true;
798 if (myCurrentNode->ptStopLength == 0) {
799 // default length
800 myCurrentNode->ptStopLength = myOptionsCont.getFloat("osm.stop-output.length");
801 }
802 } else if (key == "name") {
803 myCurrentNode->name = value;
804 } else if (myImportElevation && key == "ele") {
805 try {
806 const double elevation = StringUtils::toDouble(value);
807 if (ISNAN(elevation)) {
808 WRITE_WARNINGF(TL("Value of key '%' is invalid ('%') in node '%'."), key, value, myLastNodeID);
809 } else {
810 myCurrentNode->ele = elevation;
811 }
812 } catch (...) {
813 WRITE_WARNINGF(TL("Value of key '%' is not numeric ('%') in node '%'."), key, value, myLastNodeID);
814 }
815 } else if (key == "station") {
816 interpretTransportType(value, myCurrentNode);
817 } else {
818 // v="yes"
819 interpretTransportType(key, myCurrentNode);
820 }
821 }
822 }
823}
824
825
826void
828 if (element == SUMO_TAG_NODE && myHierarchyLevel == 2) {
829 myCurrentNode = nullptr;
830 }
831 --myHierarchyLevel;
832}
833
834
835// ---------------------------------------------------------------------------
836// definitions of NIImporter_OpenStreetMap::EdgesHandler-methods
837// ---------------------------------------------------------------------------
839 const std::map<long long int, NIOSMNode*>& osmNodes,
840 std::map<long long int, Edge*>& toFill, std::map<long long int, Edge*>& platformShapes):
841 SUMOSAXHandler("osm - file"),
842 myOSMNodes(osmNodes),
843 myEdgeMap(toFill),
844 myPlatformShapesMap(platformShapes) {
845
846 const double unlimitedSpeed = OptionsCont::getOptions().getFloat("osm.speedlimit-none") * 3.6;
847
850 mySpeedMap["signals"] = MAXSPEED_UNGIVEN;
851 mySpeedMap["none"] = unlimitedSpeed;
852 mySpeedMap["no"] = unlimitedSpeed;
853 mySpeedMap["walk"] = 5.;
854 // https://wiki.openstreetmap.org/wiki/Key:source:maxspeed#Commonly_used_values
855 mySpeedMap["AT:urban"] = 50;
856 mySpeedMap["AT:rural"] = 100;
857 mySpeedMap["AT:trunk"] = 100;
858 mySpeedMap["AT:motorway"] = 130;
859 mySpeedMap["AU:urban"] = 50;
860 mySpeedMap["BE:urban"] = 50;
861 mySpeedMap["BE:zone"] = 30;
862 mySpeedMap["BE:motorway"] = 120;
863 mySpeedMap["BE:zone30"] = 30;
864 mySpeedMap["BE-VLG:rural"] = 70;
865 mySpeedMap["BE-WAL:rural"] = 90;
866 mySpeedMap["BE:school"] = 30;
867 mySpeedMap["CZ:motorway"] = 130;
868 mySpeedMap["CZ:trunk"] = 110;
869 mySpeedMap["CZ:rural"] = 90;
870 mySpeedMap["CZ:urban_motorway"] = 80;
871 mySpeedMap["CZ:urban_trunk"] = 80;
872 mySpeedMap["CZ:urban"] = 50;
873 mySpeedMap["DE:motorway"] = unlimitedSpeed;
874 mySpeedMap["DE:rural"] = 100;
875 mySpeedMap["DE:urban"] = 50;
876 mySpeedMap["DE:bicycle_road"] = 30;
877 mySpeedMap["DK:motorway"] = 130;
878 mySpeedMap["DK:rural"] = 80;
879 mySpeedMap["DK:urban"] = 50;
880 mySpeedMap["EE:urban"] = 50;
881 mySpeedMap["EE:rural"] = 90;
882 mySpeedMap["ES:urban"] = 50;
883 mySpeedMap["ES:zone30"] = 30;
884 mySpeedMap["FR:motorway"] = 130; // 110 (raining)
885 mySpeedMap["FR:rural"] = 80;
886 mySpeedMap["FR:urban"] = 50;
887 mySpeedMap["FR:zone30"] = 30;
888 mySpeedMap["HU:living_street"] = 20;
889 mySpeedMap["HU:motorway"] = 130;
890 mySpeedMap["HU:rural"] = 90;
891 mySpeedMap["HU:trunk"] = 110;
892 mySpeedMap["HU:urban"] = 50;
893 mySpeedMap["IT:rural"] = 90;
894 mySpeedMap["IT:motorway"] = 130;
895 mySpeedMap["IT:urban"] = 50;
896 mySpeedMap["JP:nsl"] = 60;
897 mySpeedMap["JP:express"] = 100;
898 mySpeedMap["LT:rural"] = 90;
899 mySpeedMap["LT:urban"] = 50;
900 mySpeedMap["NO:rural"] = 80;
901 mySpeedMap["NO:urban"] = 50;
902 mySpeedMap["ON:urban"] = 50;
903 mySpeedMap["ON:rural"] = 80;
904 mySpeedMap["PT:motorway"] = 120;
905 mySpeedMap["PT:rural"] = 90;
906 mySpeedMap["PT:trunk"] = 100;
907 mySpeedMap["PT:urban"] = 50;
908 mySpeedMap["RO:motorway"] = 130;
909 mySpeedMap["RO:rural"] = 90;
910 mySpeedMap["RO:trunk"] = 100;
911 mySpeedMap["RO:urban"] = 50;
912 mySpeedMap["RS:living_street"] = 30;
913 mySpeedMap["RS:motorway"] = 130;
914 mySpeedMap["RS:rural"] = 80;
915 mySpeedMap["RS:trunk"] = 100;
916 mySpeedMap["RS:urban"] = 50;
917 mySpeedMap["RU:living_street"] = 20;
918 mySpeedMap["RU:urban"] = 60;
919 mySpeedMap["RU:rural"] = 90;
920 mySpeedMap["RU:motorway"] = 110;
921 mySpeedMap["GB:motorway"] = 70 * KM_PER_MILE;
922 mySpeedMap["GB:nsl_dual"] = 70 * KM_PER_MILE;
923 mySpeedMap["GB:nsl_single"] = 60 * KM_PER_MILE;
924 mySpeedMap["UK:motorway"] = 70 * KM_PER_MILE;
925 mySpeedMap["UK:nsl_dual"] = 70 * KM_PER_MILE;
926 mySpeedMap["UK:nsl_single"] = 60 * KM_PER_MILE;
927 mySpeedMap["UZ:living_street"] = 30;
928 mySpeedMap["UZ:urban"] = 70;
929 mySpeedMap["UZ:rural"] = 100;
930 mySpeedMap["UZ:motorway"] = 110;
931 myAllAttributes = OptionsCont::getOptions().getBool("osm.all-attributes");
932 std::vector<std::string> extra = OptionsCont::getOptions().getStringVector("osm.extra-attributes");
933 myExtraAttributes.insert(extra.begin(), extra.end());
934 if (myExtraAttributes.count("all") != 0) {
935 // import all
936 myExtraAttributes.clear();
937 }
939}
940
942
943void
945 if (element == SUMO_TAG_WAY) {
946 bool ok = true;
947 const long long int id = attrs.get<long long int>(SUMO_ATTR_ID, nullptr, ok);
948 const std::string& action = attrs.getOpt<std::string>(SUMO_ATTR_ACTION, nullptr, ok);
949 if (action == "delete" || !ok) {
950 myCurrentEdge = nullptr;
951 return;
952 }
953 myCurrentEdge = new Edge(id);
954 }
955 // parse "nd" (node) elements
956 if (element == SUMO_TAG_ND && myCurrentEdge != nullptr) {
957 bool ok = true;
958 long long int ref = attrs.get<long long int>(SUMO_ATTR_REF, nullptr, ok);
959 if (ok) {
960 auto node = myOSMNodes.find(ref);
961 if (node == myOSMNodes.end()) {
962 WRITE_WARNINGF(TL("The referenced geometry information (ref='%') is not known"), toString(ref));
963 return;
964 }
965
966 ref = node->second->id; // node may have been substituted
967 if (myCurrentEdge->myCurrentNodes.empty() ||
968 myCurrentEdge->myCurrentNodes.back() != ref) { // avoid consecutive duplicates
969 myCurrentEdge->myCurrentNodes.push_back(ref);
970 }
971
972 }
973 }
974 if (element == SUMO_TAG_TAG && myCurrentEdge != nullptr) {
975 bool ok = true;
976 std::string key = attrs.get<std::string>(SUMO_ATTR_K, toString(myCurrentEdge->id).c_str(), ok, false);
977 if (key.size() > 8 && StringUtils::startsWith(key, "cycleway:")) {
978 // handle special cycleway keys
979 const std::string cyclewaySpec = key.substr(9);
980 key = "cycleway";
981 if (cyclewaySpec == "right") {
982 myCurrentEdge->myCyclewayType = (WayType)(myCurrentEdge->myCyclewayType | WAY_FORWARD);
983 } else if (cyclewaySpec == "left") {
984 myCurrentEdge->myCyclewayType = (WayType)(myCurrentEdge->myCyclewayType | WAY_BACKWARD);
985 } else if (cyclewaySpec == "both") {
986 myCurrentEdge->myCyclewayType = (WayType)(myCurrentEdge->myCyclewayType | WAY_BOTH);
987 } else {
988 key = "ignore";
989 }
990 if ((myCurrentEdge->myCyclewayType & WAY_BOTH) != 0) {
991 // now we have some info on directionality
992 myCurrentEdge->myCyclewayType = (WayType)(myCurrentEdge->myCyclewayType & ~WAY_UNKNOWN);
993 }
994 } else if (key.size() > 6 && StringUtils::startsWith(key, "busway:")) {
995 // handle special busway keys
996 const std::string buswaySpec = key.substr(7);
997 key = "busway";
998 if (buswaySpec == "right") {
999 myCurrentEdge->myBuswayType = (WayType)(myCurrentEdge->myBuswayType | WAY_FORWARD);
1000 } else if (buswaySpec == "left") {
1001 myCurrentEdge->myBuswayType = (WayType)(myCurrentEdge->myBuswayType | WAY_BACKWARD);
1002 } else if (buswaySpec == "both") {
1003 myCurrentEdge->myBuswayType = (WayType)(myCurrentEdge->myBuswayType | WAY_BOTH);
1004 } else {
1005 key = "ignore";
1006 }
1007 }
1008 if (myAllAttributes && (myExtraAttributes.count(key) != 0 || myExtraAttributes.size() == 0)) {
1009 const std::string info = "way=" + toString(myCurrentEdge->id) + ", k=" + key;
1010 myCurrentEdge->setParameter(key, attrs.get<std::string>(SUMO_ATTR_V, info.c_str(), ok, false));
1011 }
1012 // we check whether the key is relevant (and we really need to transcode the value) to avoid hitting #1636
1013 if (!StringUtils::endsWith(key, "way") && !StringUtils::startsWith(key, "lanes")
1014 && key != "maxspeed" && key != "maxspeed:type"
1015 && key != "zone:maxspeed"
1016 && key != "maxspeed:forward" && key != "maxspeed:backward"
1017 && key != "junction" && key != "name" && key != "tracks" && key != "layer"
1018 && key != "route"
1019 && key != "sidewalk"
1020 && key != "ref"
1021 && key != "highspeed"
1022 && !StringUtils::startsWith(key, "parking")
1023 && !StringUtils::startsWith(key, "change")
1024 && !StringUtils::startsWith(key, "vehicle:lanes")
1025 && key != "postal_code"
1026 && key != "railway:preferred_direction"
1027 && key != "railway:bidirectional"
1028 && key != "railway:track_ref"
1029 && key != "usage"
1030 && key != "electrified"
1031 && key != "bus"
1032 && key != "psv"
1033 && key != "foot"
1034 && key != "bicycle"
1035 && key != "oneway:bicycle"
1036 && !StringUtils::startsWith(key, "turn:lanes")
1037 && key != "public_transport") {
1038 return;
1039 }
1040 std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentEdge->id).c_str(), ok, false);
1041
1042 if ((key == "highway" && value != "platform") || key == "railway" || key == "waterway" || key == "cycleway"
1043 || key == "busway" || key == "route" || key == "sidewalk" || key == "highspeed"
1044 || key == "aeroway" || key == "aerialway" || key == "usage") {
1045 // build type id
1046 std::string singleTypeID = key + "." + value;
1047 myCurrentEdge->myCurrentIsRoad = true;
1048 // special cycleway stuff
1049 if (key == "cycleway") {
1050 if (value == "no") {
1051 return;
1052 }
1053 if (value == "opposite_track") {
1054 myCurrentEdge->myCyclewayType = WAY_BACKWARD;
1055 } else if (value == "opposite_lane") {
1056 myCurrentEdge->myCyclewayType = WAY_BACKWARD;
1057 }
1058 }
1059 // special sidewalk stuff
1060 if (key == "sidewalk") {
1061 if (value == "no" || value == "none") {
1062 myCurrentEdge->mySidewalkType = WAY_NONE;
1063 } else if (value == "both") {
1064 myCurrentEdge->mySidewalkType = WAY_BOTH;
1065 } else if (value == "right") {
1066 myCurrentEdge->mySidewalkType = WAY_FORWARD;
1067 } else if (value == "left") {
1068 myCurrentEdge->mySidewalkType = WAY_BACKWARD;
1069 }
1070 // no need to extend the type id
1071 return;
1072 }
1073 // special busway stuff
1074 if (key == "busway") {
1075 if (value == "no") {
1076 return;
1077 }
1078 if (value == "opposite_track") {
1079 myCurrentEdge->myBuswayType = WAY_BACKWARD;
1080 } else if (value == "opposite_lane") {
1081 myCurrentEdge->myBuswayType = WAY_BACKWARD;
1082 }
1083 // no need to extend the type id
1084 return;
1085 }
1086 if (key == "highspeed") {
1087 if (value == "no") {
1088 return;
1089 }
1090 singleTypeID = "railway.highspeed";
1091 }
1092 // special case: never build compound type for highspeed rail
1093 if (!myCurrentEdge->myHighWayType.empty() && singleTypeID != "railway.highspeed") {
1094 if (myCurrentEdge->myHighWayType == "railway.highspeed") {
1095 return;
1096 }
1097 // osm-ways may be used by more than one mode (eg railway.tram + highway.residential. this is relevant for multimodal traffic)
1098 // we create a new type for this kind of situation which must then be resolved in insertEdge()
1099 std::vector<std::string> types = StringTokenizer(myCurrentEdge->myHighWayType,
1101 types.push_back(singleTypeID);
1102 myCurrentEdge->myHighWayType = joinToStringSorting(types, compoundTypeSeparator);
1103 } else {
1104 myCurrentEdge->myHighWayType = singleTypeID;
1105 }
1106 } else if (key == "bus" || key == "psv") {
1107 // 'psv' includes taxi in the UK but not in germany
1108 try {
1109 if (StringUtils::toBool(value)) {
1110 myCurrentEdge->myExtraAllowed |= SVC_BUS;
1111 } else {
1112 myCurrentEdge->myExtraDisallowed |= SVC_BUS;
1113 }
1114 } catch (const BoolFormatException&) {
1115 myCurrentEdge->myExtraAllowed |= SVC_BUS;
1116 }
1117 } else if (key == "foot") {
1118 if (value == "use_sidepath" || value == "no") {
1119 myCurrentEdge->myExtraDisallowed |= SVC_PEDESTRIAN;
1120 } else if (value == "yes" || value == "designated" || value == "permissive") {
1121 myCurrentEdge->myExtraAllowed |= SVC_PEDESTRIAN;
1122 }
1123 } else if (key == "bicycle") {
1124 if (myImportBikeAccess) {
1125 if (value == "use_sidepath" || value == "no") {
1126 myCurrentEdge->myExtraDisallowed |= SVC_BICYCLE;
1127 } else if (value == "yes" || value == "designated" || value == "permissive") {
1128 myCurrentEdge->myExtraAllowed |= SVC_BICYCLE;
1129 }
1130 }
1131 } else if (key == "oneway:bicycle") {
1132 if (myImportBikeAccess) {
1133 if (value == "true" || value == "yes" || value == "1") {
1134 myCurrentEdge->myCyclewayType = WAY_FORWARD;
1135 }
1136 if (value == "-1" || value == "reverse") {
1137 // one-way in reversed direction of way
1138 myCurrentEdge->myCyclewayType = WAY_BACKWARD;
1139 }
1140 if (value == "no" || value == "false" || value == "0") {
1141 myCurrentEdge->myCyclewayType = WAY_BOTH;
1142 }
1143 }
1144 } else if (key == "lanes") {
1145 try {
1146 myCurrentEdge->myNoLanes = StringUtils::toInt(value);
1147 } catch (NumberFormatException&) {
1148 // might be a list of values
1149 StringTokenizer st(value, ";", true);
1150 std::vector<std::string> list = st.getVector();
1151 if (list.size() >= 2) {
1152 int minLanes = std::numeric_limits<int>::max();
1153 try {
1154 for (auto& i : list) {
1155 const int numLanes = StringUtils::toInt(StringUtils::prune(i));
1156 minLanes = MIN2(minLanes, numLanes);
1157 }
1158 myCurrentEdge->myNoLanes = minLanes;
1159 WRITE_WARNINGF(TL("Using minimum lane number from list (%) for edge '%'."), value, toString(myCurrentEdge->id));
1160 } catch (NumberFormatException&) {
1161 WRITE_WARNINGF(TL("Value of key '%' is not numeric ('%') in edge '%'."), key, value, myCurrentEdge->id);
1162 }
1163 }
1164 } catch (EmptyData&) {
1165 WRITE_WARNINGF(TL("Value of key '%' is not numeric ('%') in edge '%'."), key, value, myCurrentEdge->id);
1166 }
1167 } else if (key == "lanes:forward") {
1168 try {
1169 const int numLanes = StringUtils::toInt(value);
1170 if (myCurrentEdge->myNoLanesForward < 0 && myCurrentEdge->myNoLanes < 0) {
1171 // fix lane count in case only lanes:forward and lanes:backward are set
1172 myCurrentEdge->myNoLanes = numLanes - myCurrentEdge->myNoLanesForward;
1173 }
1174 myCurrentEdge->myNoLanesForward = numLanes;
1175 } catch (...) {
1176 WRITE_WARNINGF(TL("Value of key '%' is not numeric ('%') in edge '%'."), key, value, myCurrentEdge->id);
1177 }
1178 } else if (key == "lanes:backward") {
1179 try {
1180 const int numLanes = StringUtils::toInt(value);
1181 if (myCurrentEdge->myNoLanesForward > 0 && myCurrentEdge->myNoLanes < 0) {
1182 // fix lane count in case only lanes:forward and lanes:backward are set
1183 myCurrentEdge->myNoLanes = numLanes + myCurrentEdge->myNoLanesForward;
1184 }
1185 // denote backwards count with a negative sign
1186 myCurrentEdge->myNoLanesForward = -numLanes;
1187 } catch (...) {
1188 WRITE_WARNINGF(TL("Value of key '%' is not numeric ('%') in edge '%'."), key, value, myCurrentEdge->id);
1189 }
1190 } else if (myCurrentEdge->myMaxSpeed == MAXSPEED_UNGIVEN &&
1191 (key == "maxspeed" || key == "maxspeed:type" || key == "maxspeed:forward" || key == "zone:maxspeed")) {
1192 // both 'maxspeed' and 'maxspeed:type' may be given so we must take care not to overwrite an already seen value
1193 myCurrentEdge->myMaxSpeed = interpretSpeed(key, value);
1194 } else if (key == "maxspeed:backward" && myCurrentEdge->myMaxSpeedBackward == MAXSPEED_UNGIVEN) {
1195 myCurrentEdge->myMaxSpeedBackward = interpretSpeed(key, value);
1196 } else if (key == "junction") {
1197 if ((value == "roundabout" || value == "circular") && (myCurrentEdge->myIsOneWay.empty())) {
1198 myCurrentEdge->myIsOneWay = "yes";
1199 }
1200 } else if (key == "oneway") {
1201 myCurrentEdge->myIsOneWay = value;
1202 } else if (key == "name") {
1203 myCurrentEdge->streetName = value;
1204 } else if (key == "ref") {
1205 myCurrentEdge->ref = value;
1206 myCurrentEdge->setParameter("ref", value);
1207 } else if (key == "layer") {
1208 try {
1209 myCurrentEdge->myLayer = StringUtils::toInt(value);
1210 } catch (...) {
1211 WRITE_WARNINGF(TL("Value of key '%' is not numeric ('%') in edge '%'."), key, value, myCurrentEdge->id);
1212 }
1213 } else if (key == "tracks") {
1214 try {
1215 if (StringUtils::toInt(value) == 1) {
1216 myCurrentEdge->myIsOneWay = "true";
1217 } else {
1218 WRITE_WARNINGF(TL("Ignoring track count % for edge '%'."), value, myCurrentEdge->id);
1219 }
1220 } catch (...) {
1221 WRITE_WARNINGF(TL("Value of key '%' is not numeric ('%') in edge '%'."), key, value, myCurrentEdge->id);
1222 }
1223 } else if (key == "railway:preferred_direction") {
1224 if (value == "both") {
1225 myCurrentEdge->myRailDirection = WAY_BOTH;
1226 } else if (value == "backward") {
1227 myCurrentEdge->myRailDirection = WAY_BACKWARD;
1228 }
1229 } else if (key == "railway:bidirectional") {
1230 if (value == "regular") {
1231 myCurrentEdge->myRailDirection = WAY_BOTH;
1232 }
1233 } else if (key == "electrified") {
1234 if (value != "no") {
1235 myCurrentEdge->myCurrentIsElectrified = true;
1236 }
1237 } else if (key == "railway:track_ref") {
1238 myCurrentEdge->setParameter(key, value);
1239 } else if (key == "public_transport" && value == "platform") {
1240 myCurrentEdge->myCurrentIsPlatform = true;
1241 } else if (key == "parking:lane:both" && !StringUtils::startsWith(value, "no")) {
1242 myCurrentEdge->myParkingType |= PARKING_BOTH;
1243 } else if (key == "parking:lane:left" && !StringUtils::startsWith(value, "no")) {
1244 myCurrentEdge->myParkingType |= PARKING_LEFT;
1245 } else if (key == "parking:lane:right" && !StringUtils::startsWith(value, "no")) {
1246 myCurrentEdge->myParkingType |= PARKING_RIGHT;
1247 } else if (key == "change" || key == "change:lanes") {
1248 myCurrentEdge->myChangeForward = myCurrentEdge->myChangeBackward = interpretChangeType(value);
1249 } else if (key == "change:forward" || key == "change:lanes:forward") {
1250 myCurrentEdge->myChangeForward = interpretChangeType(value);
1251 } else if (key == "change:backward" || key == "change:lanes:backward") {
1252 myCurrentEdge->myChangeBackward = interpretChangeType(value);
1253 } else if (key == "vehicle:lanes" || key == "vehicle:lanes:forward") {
1254 interpretLaneUse(value, SVC_PASSENGER, myCurrentEdge->myLaneUseForward);
1255 } else if (key == "vehicle:lanes:backward") {
1256 interpretLaneUse(value, SVC_PASSENGER, myCurrentEdge->myLaneUseBackward);
1257 } else if (StringUtils::startsWith(key, "turn:lanes")) {
1258 const std::vector<std::string> values = StringTokenizer(value, "|").getVector();
1259 std::vector<int> turnCodes;
1260 for (std::string codeList : values) {
1261 const std::vector<std::string> codes = StringTokenizer(codeList, ";").getVector();
1262 int turnCode = 0;
1263 for (std::string code : codes) {
1264 if (code == "" || code == "none" || code == "through") {
1265 turnCode |= (int)LinkDirection::STRAIGHT;
1266 } else if (code == "left" || code == "sharp_left") {
1267 turnCode |= (int)LinkDirection::LEFT;
1268 } else if (code == "right" || code == "sharp_right") {
1269 turnCode |= (int)LinkDirection::RIGHT;
1270 } else if (code == "slight_left") {
1271 turnCode |= (int)LinkDirection::PARTLEFT;
1272 } else if (code == "slight_right") {
1273 turnCode |= (int)LinkDirection::PARTRIGHT;
1274 } else if (code == "reverse") {
1275 turnCode |= (int)LinkDirection::TURN;
1276 } else if (code == "merge_to_left" || code == "merge_to_right") {
1277 turnCode |= (int)LinkDirection::NODIR;
1278 }
1279 }
1280 turnCodes.push_back(turnCode);
1281 }
1282 if (key == "turn:lanes" || key == "turn:lanes:forward") {
1283 myCurrentEdge->myTurnSignsForward = turnCodes;
1284 } else if (key == "turn:lanes:backward") {
1285 myCurrentEdge->myTurnSignsBackward = turnCodes;
1286 } else if (key == "turn:lanes:both_ways") {
1287 myCurrentEdge->myTurnSignsForward = turnCodes;
1288 myCurrentEdge->myTurnSignsBackward = turnCodes;
1289 }
1290 }
1291 }
1292}
1293
1294
1295double
1296NIImporter_OpenStreetMap::EdgesHandler::interpretSpeed(const std::string& key, std::string value) {
1297 if (mySpeedMap.find(value) != mySpeedMap.end()) {
1298 return mySpeedMap[value];
1299 } else {
1300 // handle symbolic names of the form DE:30 / DE:zone30
1301 if (value.size() > 3 && value[2] == ':') {
1302 if (value.substr(3, 4) == "zone") {
1303 value = value.substr(7);
1304 } else {
1305 value = value.substr(3);
1306 }
1307 }
1308 double conversion = 1; // OSM default is km/h
1309 if (StringUtils::to_lower_case(value).find("km/h") != std::string::npos) {
1310 value = StringUtils::prune(value.substr(0, value.find_first_not_of("0123456789")));
1311 } else if (StringUtils::to_lower_case(value).find("mph") != std::string::npos) {
1312 value = StringUtils::prune(value.substr(0, value.find_first_not_of("0123456789")));
1313 conversion = KM_PER_MILE;
1314 }
1315 try {
1316 return StringUtils::toDouble(value) * conversion;
1317 } catch (...) {
1318 WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" +
1319 toString(myCurrentEdge->id) + "'.");
1320 return MAXSPEED_UNGIVEN;
1321 }
1322 }
1323}
1324
1325
1326int
1328 int result = 0;
1329 const std::vector<std::string> values = StringTokenizer(value, "|").getVector();
1330 for (const std::string& val : values) {
1331 if (val == "no") {
1332 result += CHANGE_NO;
1333 } else if (val == "not_left") {
1334 result += CHANGE_NO_LEFT;
1335 } else if (val == "not_right") {
1336 result += CHANGE_NO_RIGHT;
1337 }
1338 result = result << 2;
1339 }
1340 // last shift was superfluous
1341 result = result >> 2;
1342
1343 if (values.size() > 1) {
1344 result += 2 << 29; // mark multi-value input
1345 }
1346 //std::cout << " way=" << myCurrentEdge->id << " value=" << value << " result=" << std::bitset<32>(result) << "\n";
1347 return result;
1348}
1349
1350
1351void
1352NIImporter_OpenStreetMap::EdgesHandler::interpretLaneUse(const std::string& value, SUMOVehicleClass svc, std::vector<SVCPermissions>& result) const {
1353 const std::vector<std::string> values = StringTokenizer(value, "|").getVector();
1354 int i = 0;
1355 for (const std::string& val : values) {
1357 if (val == "yes" || val == "lane" || val == "designated") {
1358 use = svc;
1359 } else if (val != "no") {
1360 WRITE_WARNINGF(TL("Unknown lane use specifier '%' treated as 'no' for way '%'"), val, myCurrentEdge->id);
1361 }
1362 if (i >= (int)result.size()) {
1363 result.push_back(use);
1364 } else {
1365 result[i] |= use;
1366 }
1367 i++;
1368 }
1369}
1370
1371
1372void
1374 if (element == SUMO_TAG_WAY && myCurrentEdge != nullptr) {
1375 if (myCurrentEdge->myCurrentIsRoad) {
1376 myEdgeMap[myCurrentEdge->id] = myCurrentEdge;
1377 } else if (myCurrentEdge->myCurrentIsPlatform) {
1378 myPlatformShapesMap[myCurrentEdge->id] = myCurrentEdge;
1379 } else {
1380 delete myCurrentEdge;
1381 }
1382 myCurrentEdge = nullptr;
1383 }
1384}
1385
1386
1387// ---------------------------------------------------------------------------
1388// definitions of NIImporter_OpenStreetMap::RelationHandler-methods
1389// ---------------------------------------------------------------------------
1391 const std::map<long long int, NIOSMNode*>& osmNodes,
1392 const std::map<long long int, Edge*>& osmEdges, NBPTStopCont* nbptStopCont,
1393 const std::map<long long int, Edge*>& platformShapes,
1394 NBPTLineCont* nbptLineCont,
1395 const OptionsCont& oc) :
1396 SUMOSAXHandler("osm - file"),
1397 myOSMNodes(osmNodes),
1398 myOSMEdges(osmEdges),
1399 myPlatformShapes(platformShapes),
1400 myNBPTStopCont(nbptStopCont),
1401 myNBPTLineCont(nbptLineCont),
1402 myOptionsCont(oc) {
1403 resetValues();
1404}
1405
1406
1408
1409
1410void
1412 myCurrentRelation = INVALID_ID;
1413 myIsRestriction = false;
1414 myFromWay = INVALID_ID;
1415 myToWay = INVALID_ID;
1416 myViaNode = INVALID_ID;
1417 myViaWay = INVALID_ID;
1418 myRestrictionType = RestrictionType::UNKNOWN;
1419 myPlatforms.clear();
1420 myStops.clear();
1421 myPlatformStops.clear();
1422 myWays.clear();
1423 myIsStopArea = false;
1424 myIsRoute = false;
1425 myPTRouteType = "";
1426 myRouteColor.setValid(false);
1427}
1428
1429
1430void
1432 if (element == SUMO_TAG_RELATION) {
1433 bool ok = true;
1434 myCurrentRelation = attrs.get<long long int>(SUMO_ATTR_ID, nullptr, ok);
1435 const std::string& action = attrs.getOpt<std::string>(SUMO_ATTR_ACTION, nullptr, ok);
1436 if (action == "delete" || !ok) {
1437 myCurrentRelation = INVALID_ID;
1438 }
1439 myName = "";
1440 myRef = "";
1441 myInterval = -1;
1442 myNightService = "";
1443 return;
1444 }
1445 if (myCurrentRelation == INVALID_ID) {
1446 return;
1447 }
1448 if (element == SUMO_TAG_MEMBER) {
1449 bool ok = true;
1450 std::string role = attrs.hasAttribute("role") ? attrs.getStringSecure("role", "") : "";
1451 const long long int ref = attrs.get<long long int>(SUMO_ATTR_REF, nullptr, ok);
1452 if (role == "via") {
1453 // u-turns for divided ways may be given with 2 via-nodes or 1 via-way
1454 std::string memberType = attrs.get<std::string>(SUMO_ATTR_TYPE, nullptr, ok);
1455 if (memberType == "way" && checkEdgeRef(ref)) {
1456 myViaWay = ref;
1457 } else if (memberType == "node") {
1458 if (myOSMNodes.find(ref) != myOSMNodes.end()) {
1459 myViaNode = ref;
1460 } else {
1461 WRITE_WARNINGF(TL("No node found for reference '%' in relation '%'."), toString(ref), toString(myCurrentRelation));
1462 }
1463 }
1464 } else if (role == "from" && checkEdgeRef(ref)) {
1465 myFromWay = ref;
1466 } else if (role == "to" && checkEdgeRef(ref)) {
1467 myToWay = ref;
1468 } else if (role == "stop") {
1469 myStops.push_back(ref);
1470 } else if (role == "platform") {
1471 std::string memberType = attrs.get<std::string>(SUMO_ATTR_TYPE, nullptr, ok);
1472 if (memberType == "way") {
1473 const std::map<long long int, NIImporter_OpenStreetMap::Edge*>::const_iterator& wayIt = myPlatformShapes.find(ref);
1474 if (wayIt != myPlatformShapes.end()) {
1475 NIIPTPlatform platform;
1476 platform.isWay = true;
1477 platform.ref = ref;
1478 myPlatforms.push_back(platform);
1479 }
1480 } else if (memberType == "node") {
1481 // myIsStopArea may not be set yet
1482 myStops.push_back(ref);
1483 myPlatformStops.insert(ref);
1484 NIIPTPlatform platform;
1485 platform.isWay = false;
1486 platform.ref = ref;
1487 myPlatforms.push_back(platform);
1488 }
1489
1490 } else if (role.empty()) {
1491 std::string memberType = attrs.get<std::string>(SUMO_ATTR_TYPE, nullptr, ok);
1492 if (memberType == "way") {
1493 myWays.push_back(ref);
1494 } else if (memberType == "node") {
1495 myStops.push_back(ref);
1496 }
1497 }
1498 return;
1499 }
1500 // parse values
1501 if (element == SUMO_TAG_TAG) {
1502 bool ok = true;
1503 std::string key = attrs.get<std::string>(SUMO_ATTR_K, toString(myCurrentRelation).c_str(), ok, false);
1504 // we check whether the key is relevant (and we really need to transcode the value) to avoid hitting #1636
1505 if (key == "type" || key == "restriction") {
1506 std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1507 if (key == "type" && value == "restriction") {
1508 myIsRestriction = true;
1509 return;
1510 }
1511 if (key == "type" && value == "route") {
1512 myIsRoute = true;
1513 return;
1514 }
1515 if (key == "restriction") {
1516 // @note: the 'right/left/straight' part is ignored since the information is
1517 // redundantly encoded in the 'from', 'to' and 'via' members
1518 if (value.substr(0, 5) == "only_") {
1519 myRestrictionType = RestrictionType::ONLY;
1520 } else if (value.substr(0, 3) == "no_") {
1521 myRestrictionType = RestrictionType::NO;
1522 } else {
1523 WRITE_WARNINGF(TL("Found unknown restriction type '%' in relation '%'"), value, toString(myCurrentRelation));
1524 }
1525 return;
1526 }
1527 } else if (key == "public_transport") {
1528 std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1529 if (value == "stop_area") {
1530 myIsStopArea = true;
1531 }
1532 } else if (key == "route") {
1533 std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1534 if (value == "train" || value == "subway" || value == "light_rail" || value == "monorail" || value == "tram" || value == "bus"
1535 || value == "trolleybus" || value == "aerialway" || value == "ferry" || value == "share_taxi" || value == "minibus") {
1536 myPTRouteType = value;
1537 }
1538
1539 } else if (key == "name") {
1540 myName = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1541 } else if (key == "colour") {
1542 std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1543 try {
1544 myRouteColor = RGBColor::parseColor(value);
1545 } catch (...) {
1546 WRITE_WARNINGF(TL("Invalid color value '%' in relation %"), value, myCurrentRelation);
1547 }
1548 } else if (key == "ref") {
1549 myRef = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1550 } else if (key == "interval" || key == "headway") {
1551 myInterval = attrs.get<int>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1552 } else if (key == "by_night") {
1553 myNightService = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
1554 }
1555 }
1556}
1557
1558
1559bool
1561 if (myOSMEdges.find(ref) != myOSMEdges.end()) {
1562 return true;
1563 }
1564 WRITE_WARNINGF(TL("No way found for reference '%' in relation '%'"), toString(ref), toString(myCurrentRelation));
1565 return false;
1566}
1567
1568
1569void
1571 if (element == SUMO_TAG_RELATION) {
1572 if (myIsRestriction) {
1573 assert(myCurrentRelation != INVALID_ID);
1574 bool ok = true;
1575 if (myRestrictionType == RestrictionType::UNKNOWN) {
1576 WRITE_WARNINGF(TL("Ignoring restriction relation '%' with unknown type."), toString(myCurrentRelation));
1577 ok = false;
1578 }
1579 if (myFromWay == INVALID_ID) {
1580 WRITE_WARNINGF(TL("Ignoring restriction relation '%' with unknown from-way."), toString(myCurrentRelation));
1581 ok = false;
1582 }
1583 if (myToWay == INVALID_ID) {
1584 WRITE_WARNINGF(TL("Ignoring restriction relation '%' with unknown to-way."), toString(myCurrentRelation));
1585 ok = false;
1586 }
1587 if (myViaNode == INVALID_ID && myViaWay == INVALID_ID) {
1588 WRITE_WARNINGF(TL("Ignoring restriction relation '%' with unknown via."), toString(myCurrentRelation));
1589 ok = false;
1590 }
1591 if (ok && !applyRestriction()) {
1592 WRITE_WARNINGF(TL("Ignoring restriction relation '%'."), toString(myCurrentRelation));
1593 }
1594 } else if (myIsStopArea) {
1595 for (long long ref : myStops) {
1596 myStopAreas[ref] = myCurrentRelation;
1597 if (myOSMNodes.find(ref) == myOSMNodes.end()) {
1598 //WRITE_WARNING(
1599 // "Referenced node: '" + toString(ref) + "' in relation: '" + toString(myCurrentRelation)
1600 // + "' does not exist. Probably OSM file is incomplete.");
1601 continue;
1602 }
1603
1604 NIOSMNode* n = myOSMNodes.find(ref)->second;
1605 NBPTStop* ptStop = myNBPTStopCont->get(toString(n->id));
1606 if (ptStop == nullptr) {
1607 //WRITE_WARNING(
1608 // "Relation '" + toString(myCurrentRelation) + "' refers to a non existing pt stop at node: '"
1609 // + toString(n->id) + "'. Probably OSM file is incomplete.");
1610 continue;
1611 }
1612 for (NIIPTPlatform& myPlatform : myPlatforms) {
1613 if (myPlatform.isWay) {
1614 assert(myPlatformShapes.find(myPlatform.ref) != myPlatformShapes.end()); //already tested earlier
1615 Edge* edge = (*myPlatformShapes.find(myPlatform.ref)).second;
1616 if (edge->myCurrentNodes[0] == *(edge->myCurrentNodes.end() - 1)) {
1617 WRITE_WARNINGF(TL("Platform '%' in relation: '%' is given as polygon, which currently is not supported."), myPlatform.ref, myCurrentRelation);
1618 continue;
1619
1620 }
1622 for (auto nodeRef : edge->myCurrentNodes) {
1623 if (myOSMNodes.find(nodeRef) == myOSMNodes.end()) {
1624 //WRITE_WARNING(
1625 // "Referenced node: '" + toString(ref) + "' in relation: '" + toString(myCurrentRelation)
1626 // + "' does not exist. Probably OSM file is incomplete.");
1627 continue;
1628 }
1629 NIOSMNode* pNode = myOSMNodes.find(nodeRef)->second;
1630 Position pNodePos(pNode->lon, pNode->lat, pNode->ele);
1631 if (!NBNetBuilder::transformCoordinate(pNodePos)) {
1632 WRITE_ERROR("Unable to project coordinates for node '" + toString(pNode->id) + "'.");
1633 continue;
1634 }
1635 p.push_back(pNodePos);
1636 }
1637 if (p.size() == 0) {
1638 WRITE_WARNINGF(TL("Referenced platform: '%' in relation: '%' is corrupt. Probably OSM file is incomplete."),
1639 toString(myPlatform.ref), toString(myCurrentRelation));
1640 continue;
1641 }
1642 NBPTPlatform platform(p[(int)p.size() / 2], p.length());
1643 ptStop->addPlatformCand(platform);
1644 } else {
1645 if (myOSMNodes.find(myPlatform.ref) == myOSMNodes.end()) {
1646 //WRITE_WARNING(
1647 // "Referenced node: '" + toString(ref) + "' in relation: '" + toString(myCurrentRelation)
1648 // + "' does not exist. Probably OSM file is incomplete.");
1649 continue;
1650 }
1651 NIOSMNode* pNode = myOSMNodes.find(myPlatform.ref)->second;
1652 Position platformPos(pNode->lon, pNode->lat, pNode->ele);
1653 if (!NBNetBuilder::transformCoordinate(platformPos)) {
1654 WRITE_ERROR("Unable to project coordinates for node '" + toString(pNode->id) + "'.");
1655 }
1656 NBPTPlatform platform(platformPos, myOptionsCont.getFloat("osm.stop-output.length"));
1657 ptStop->addPlatformCand(platform);
1658
1659 }
1660 }
1661 ptStop->setIsMultipleStopPositions(myStops.size() > 1, myCurrentRelation);
1662 }
1663 } else if (myPTRouteType != "" && myIsRoute) {
1664 NBPTLine* ptLine = new NBPTLine(toString(myCurrentRelation), myName, myPTRouteType, myRef, myInterval, myNightService,
1665 interpretTransportType(myPTRouteType), myRouteColor);
1666 ptLine->setMyNumOfStops((int)myStops.size());
1667 bool hadGap = false;
1668 for (long long ref : myStops) {
1669 const auto& nodeIt = myOSMNodes.find(ref);
1670 if (nodeIt == myOSMNodes.end()) {
1671 if (!ptLine->getStops().empty() && !hadGap) {
1672 hadGap = true;
1673 }
1674 continue;
1675 }
1676 if (hadGap) {
1677 WRITE_WARNINGF(TL("PT line '%' in relation % seems to be split, only keeping first part."), myName, myCurrentRelation);
1678 break;
1679 }
1680
1681 const NIOSMNode* const n = nodeIt->second;
1682 NBPTStop* ptStop = myNBPTStopCont->get(toString(n->id));
1683 if (ptStop == nullptr) {
1684 // loose stop, which must later be mapped onto a line way
1685 Position ptPos(n->lon, n->lat, n->ele);
1687 WRITE_ERROR("Unable to project coordinates for node '" + toString(n->id) + "'.");
1688 }
1689 ptStop = new NBPTStop(toString(n->id), ptPos, "", "", n->ptStopLength, n->name, n->permissions);
1690 myNBPTStopCont->insert(ptStop);
1691 if (myStopAreas.count(n->id)) {
1692 ptStop->setIsMultipleStopPositions(false, myStopAreas[n->id]);
1693 }
1694 if (myPlatformStops.count(n->id) > 0) {
1695 ptStop->setIsPlatform();
1696 }
1697 }
1698 ptLine->addPTStop(ptStop);
1699 }
1700 for (long long& myWay : myWays) {
1701 auto entr = myOSMEdges.find(myWay);
1702 if (entr != myOSMEdges.end()) {
1703 Edge* edge = entr->second;
1704 for (long long& myCurrentNode : edge->myCurrentNodes) {
1705 ptLine->addWayNode(myWay, myCurrentNode);
1706 }
1707 }
1708 }
1709 if (ptLine->getStops().empty()) {
1710 WRITE_WARNINGF(TL("PT line in relation % with no stops ignored. Probably OSM file is incomplete."), myCurrentRelation);
1711 resetValues();
1712 return;
1713 }
1714 if (myNBPTLineCont->getLines().count(ptLine->getLineID()) == 0) {
1715 myNBPTLineCont->insert(ptLine);
1716 } else {
1717 WRITE_WARNINGF(TL("Ignoring duplicate PT line '%'."), myCurrentRelation);
1718 delete ptLine;
1719 }
1720 }
1721 // other relations might use similar subelements so reset in any case
1722 resetValues();
1723 }
1724}
1725
1726bool
1728 // since OSM ways are bidirectional we need the via to figure out which direction was meant
1729 if (myViaNode != INVALID_ID) {
1730 NBNode* viaNode = myOSMNodes.find(myViaNode)->second->node;
1731 if (viaNode == nullptr) {
1732 WRITE_WARNINGF(TL("Via-node '%' was not instantiated"), toString(myViaNode));
1733 return false;
1734 }
1735 NBEdge* from = findEdgeRef(myFromWay, viaNode->getIncomingEdges());
1736 NBEdge* to = findEdgeRef(myToWay, viaNode->getOutgoingEdges());
1737 if (from == nullptr) {
1738 WRITE_WARNINGF(TL("from-edge '%' of restriction relation could not be determined"), toString(myFromWay));
1739 return false;
1740 }
1741 if (to == nullptr) {
1742 WRITE_WARNINGF(TL("to-edge '%' of restriction relation could not be determined"), toString(myToWay));
1743 return false;
1744 }
1745 if (myRestrictionType == RestrictionType::ONLY) {
1746 from->addEdge2EdgeConnection(to, true);
1747 // make sure that these connections remain disabled even if network
1748 // modifications (ramps.guess) reset existing connections
1749 for (NBEdge* cand : from->getToNode()->getOutgoingEdges()) {
1750 if (!from->isConnectedTo(cand)) {
1751 from->removeFromConnections(cand, -1, -1, true);
1752 }
1753 }
1754 } else {
1755 from->removeFromConnections(to, -1, -1, true);
1756 }
1757 } else {
1758 // XXX interpreting via-ways or via-node lists not yet implemented
1759 WRITE_WARNINGF(TL("direction of restriction relation could not be determined%"), "");
1760 return false;
1761 }
1762 return true;
1763}
1764
1765NBEdge*
1767 const std::vector<NBEdge*>& candidates) const {
1768 const std::string prefix = toString(wayRef);
1769 const std::string backPrefix = "-" + prefix;
1770 NBEdge* result = nullptr;
1771 int found = 0;
1772 for (auto candidate : candidates) {
1773 if ((candidate->getID().substr(0, prefix.size()) == prefix) ||
1774 (candidate->getID().substr(0, backPrefix.size()) == backPrefix)) {
1775 result = candidate;
1776 found++;
1777 }
1778 }
1779 if (found > 1) {
1780 WRITE_WARNINGF(TL("Ambiguous way reference '%' in restriction relation"), prefix);
1781 result = nullptr;
1782 }
1783 return result;
1784}
1785
1786
1787void
1789 NBNodeCont& nc = nb.getNodeCont();
1790 NBEdgeCont& ec = nb.getEdgeCont();
1791 // reconstruct elevation from layer info
1792 // build a map of raising and lowering forces (attractor and distance)
1793 // for all nodes unknownElevation
1794 std::map<NBNode*, std::vector<std::pair<double, double> > > layerForces;
1795
1796 // collect all nodes that belong to a way with layer information
1797 std::set<NBNode*> knownElevation;
1798 for (auto& myEdge : myEdges) {
1799 Edge* e = myEdge.second;
1800 if (e->myLayer != 0) {
1801 for (auto j = e->myCurrentNodes.begin(); j != e->myCurrentNodes.end(); ++j) {
1802 NBNode* node = nc.retrieve(toString(*j));
1803 if (node != nullptr) {
1804 knownElevation.insert(node);
1805 layerForces[node].emplace_back(e->myLayer * layerElevation, POSITION_EPS);
1806 }
1807 }
1808 }
1809 }
1810#ifdef DEBUG_LAYER_ELEVATION
1811 std::cout << "known elevations:\n";
1812 for (std::set<NBNode*>::iterator it = knownElevation.begin(); it != knownElevation.end(); ++it) {
1813 const std::vector<std::pair<double, double> >& primaryLayers = layerForces[*it];
1814 std::cout << " node=" << (*it)->getID() << " ele=";
1815 for (std::vector<std::pair<double, double> >::const_iterator it_ele = primaryLayers.begin(); it_ele != primaryLayers.end(); ++it_ele) {
1816 std::cout << it_ele->first << " ";
1817 }
1818 std::cout << "\n";
1819 }
1820#endif
1821 // layer data only provides a lower bound on elevation since it is used to
1822 // resolve the relation among overlapping ways.
1823 // Perform a sanity check for steep inclines and raise the knownElevation if necessary
1824 std::map<NBNode*, double> knownEleMax;
1825 for (auto it : knownElevation) {
1826 double eleMax = -std::numeric_limits<double>::max();
1827 const std::vector<std::pair<double, double> >& primaryLayers = layerForces[it];
1828 for (const auto& primaryLayer : primaryLayers) {
1829 eleMax = MAX2(eleMax, primaryLayer.first);
1830 }
1831 knownEleMax[it] = eleMax;
1832 }
1833 const double gradeThreshold = OptionsCont::getOptions().getFloat("osm.layer-elevation.max-grade") / 100;
1834 bool changed = true;
1835 while (changed) {
1836 changed = false;
1837 for (auto it = knownElevation.begin(); it != knownElevation.end(); ++it) {
1838 std::map<NBNode*, std::pair<double, double> > neighbors = getNeighboringNodes(*it,
1839 knownEleMax[*it]
1840 / gradeThreshold * 3,
1841 knownElevation);
1842 for (auto& neighbor : neighbors) {
1843 if (knownElevation.count(neighbor.first) != 0) {
1844 const double grade = fabs(knownEleMax[*it] - knownEleMax[neighbor.first])
1845 / MAX2(POSITION_EPS, neighbor.second.first);
1846#ifdef DEBUG_LAYER_ELEVATION
1847 std::cout << " grade at node=" << (*it)->getID() << " ele=" << knownEleMax[*it] << " neigh=" << it_neigh->first->getID() << " neighEle=" << knownEleMax[it_neigh->first] << " grade=" << grade << " dist=" << it_neigh->second.first << " speed=" << it_neigh->second.second << "\n";
1848#endif
1849 if (grade > gradeThreshold * 50 / 3.6 / neighbor.second.second) {
1850 // raise the lower node to the higher level
1851 const double eleMax = MAX2(knownEleMax[*it], knownEleMax[neighbor.first]);
1852 if (knownEleMax[*it] < eleMax) {
1853 knownEleMax[*it] = eleMax;
1854 } else {
1855 knownEleMax[neighbor.first] = eleMax;
1856 }
1857 changed = true;
1858 }
1859 }
1860 }
1861 }
1862 }
1863
1864 // collect all nodes within a grade-dependent range around knownElevation-nodes and apply knowElevation forces
1865 std::set<NBNode*> unknownElevation;
1866 for (auto it = knownElevation.begin(); it != knownElevation.end(); ++it) {
1867 const double eleMax = knownEleMax[*it];
1868 const double maxDist = fabs(eleMax) * 100 / layerElevation;
1869 std::map<NBNode*, std::pair<double, double> > neighbors = getNeighboringNodes(*it, maxDist, knownElevation);
1870 for (auto& neighbor : neighbors) {
1871 if (knownElevation.count(neighbor.first) == 0) {
1872 unknownElevation.insert(neighbor.first);
1873 layerForces[neighbor.first].emplace_back(eleMax, neighbor.second.first);
1874 }
1875 }
1876 }
1877
1878 // apply forces to ground-level nodes (neither in knownElevation nor unknownElevation)
1879 for (auto it = unknownElevation.begin(); it != unknownElevation.end(); ++it) {
1880 double eleMax = -std::numeric_limits<double>::max();
1881 const std::vector<std::pair<double, double> >& primaryLayers = layerForces[*it];
1882 for (const auto& primaryLayer : primaryLayers) {
1883 eleMax = MAX2(eleMax, primaryLayer.first);
1884 }
1885 const double maxDist = fabs(eleMax) * 100 / layerElevation;
1886 std::map<NBNode*, std::pair<double, double> > neighbors = getNeighboringNodes(*it, maxDist, knownElevation);
1887 for (auto& neighbor : neighbors) {
1888 if (knownElevation.count(neighbor.first) == 0 && unknownElevation.count(neighbor.first) == 0) {
1889 layerForces[*it].emplace_back(0, neighbor.second.first);
1890 }
1891 }
1892 }
1893 // compute the elevation for each node as the weighted average of all forces
1894#ifdef DEBUG_LAYER_ELEVATION
1895 std::cout << "summation of forces\n";
1896#endif
1897 std::map<NBNode*, double> nodeElevation;
1898 for (auto& layerForce : layerForces) {
1899 const std::vector<std::pair<double, double> >& forces = layerForce.second;
1900 if (knownElevation.count(layerForce.first) != 0) {
1901 // use the maximum value
1902 /*
1903 double eleMax = -std::numeric_limits<double>::max();
1904 for (std::vector<std::pair<double, double> >::const_iterator it_force = forces.begin(); it_force != forces.end(); ++it_force) {
1905 eleMax = MAX2(eleMax, it_force->first);
1906 }
1907 */
1908#ifdef DEBUG_LAYER_ELEVATION
1909 std::cout << " node=" << it->first->getID() << " knownElevation=" << knownEleMax[it->first] << "\n";
1910#endif
1911 nodeElevation[layerForce.first] = knownEleMax[layerForce.first];
1912 } else if (forces.size() == 1) {
1913 nodeElevation[layerForce.first] = forces.front().first;
1914 } else {
1915 // use the weighted sum
1916 double distSum = 0;
1917 for (const auto& force : forces) {
1918 distSum += force.second;
1919 }
1920 double weightSum = 0;
1921 double elevation = 0;
1922#ifdef DEBUG_LAYER_ELEVATION
1923 std::cout << " node=" << it->first->getID() << " distSum=" << distSum << "\n";
1924#endif
1925 for (const auto& force : forces) {
1926 const double weight = (distSum - force.second) / distSum;
1927 weightSum += weight;
1928 elevation += force.first * weight;
1929
1930#ifdef DEBUG_LAYER_ELEVATION
1931 std::cout << " force=" << it_force->first << " dist=" << it_force->second << " weight=" << weight << " ele=" << elevation << "\n";
1932#endif
1933 }
1934 nodeElevation[layerForce.first] = elevation / weightSum;
1935 }
1936 }
1937#ifdef DEBUG_LAYER_ELEVATION
1938 std::cout << "final elevations:\n";
1939 for (std::map<NBNode*, double>::iterator it = nodeElevation.begin(); it != nodeElevation.end(); ++it) {
1940 std::cout << " node=" << (it->first)->getID() << " ele=" << it->second << "\n";
1941 }
1942#endif
1943 // apply node elevations
1944 for (auto& it : nodeElevation) {
1945 NBNode* n = it.first;
1946 Position pos = n->getPosition();
1947 n->reinit(n->getPosition() + Position(0, 0, it.second), n->getType());
1948 }
1949
1950 // apply way elevation to all edges that had layer information
1951 for (const auto& it : ec) {
1952 NBEdge* edge = it.second;
1953 const PositionVector& geom = edge->getGeometry();
1954 const double length = geom.length2D();
1955 const double zFrom = nodeElevation[edge->getFromNode()];
1956 const double zTo = nodeElevation[edge->getToNode()];
1957 // XXX if the from- or to-node was part of multiple ways with
1958 // different layers, reconstruct the layer value from origID
1959 double dist = 0;
1960 PositionVector newGeom;
1961 for (auto it_pos = geom.begin(); it_pos != geom.end(); ++it_pos) {
1962 if (it_pos != geom.begin()) {
1963 dist += (*it_pos).distanceTo2D(*(it_pos - 1));
1964 }
1965 newGeom.push_back((*it_pos) + Position(0, 0, zFrom + (zTo - zFrom) * dist / length));
1966 }
1967 edge->setGeometry(newGeom);
1968 }
1969}
1970
1971std::map<NBNode*, std::pair<double, double> >
1972NIImporter_OpenStreetMap::getNeighboringNodes(NBNode* node, double maxDist, const std::set<NBNode*>& knownElevation) {
1973 std::map<NBNode*, std::pair<double, double> > result;
1974 std::set<NBNode*> visited;
1975 std::vector<NBNode*> open;
1976 open.push_back(node);
1977 result[node] = std::make_pair(0, 0);
1978 while (!open.empty()) {
1979 NBNode* n = open.back();
1980 open.pop_back();
1981 if (visited.count(n) != 0) {
1982 continue;
1983 }
1984 visited.insert(n);
1985 const EdgeVector& edges = n->getEdges();
1986 for (auto e : edges) {
1987 NBNode* s = nullptr;
1988 if (n->hasIncoming(e)) {
1989 s = e->getFromNode();
1990 } else {
1991 s = e->getToNode();
1992 }
1993 const double dist = result[n].first + e->getGeometry().length2D();
1994 const double speed = MAX2(e->getSpeed(), result[n].second);
1995 if (result.count(s) == 0) {
1996 result[s] = std::make_pair(dist, speed);
1997 } else {
1998 result[s] = std::make_pair(MIN2(dist, result[s].first), MAX2(speed, result[s].second));
1999 }
2000 if (dist < maxDist && knownElevation.count(s) == 0) {
2001 open.push_back(s);
2002 }
2003 }
2004 }
2005 result.erase(node);
2006 return result;
2007}
2008
2009
2010std::string
2011NIImporter_OpenStreetMap::usableType(const std::string& type, const std::string& id, NBTypeCont& tc) {
2012 if (tc.knows(type)) {
2013 return type;
2014 }
2015 if (myUnusableTypes.count(type) > 0) {
2016 return "";
2017 }
2018 if (myKnownCompoundTypes.count(type) > 0) {
2019 return myKnownCompoundTypes[type];
2020 }
2021 // this edge has a type which does not yet exist in the TypeContainer
2023 std::vector<std::string> types;
2024 while (tok.hasNext()) {
2025 std::string t = tok.next();
2026 if (tc.knows(t)) {
2027 if (std::find(types.begin(), types.end(), t) == types.end()) {
2028 types.push_back(t);
2029 }
2030 } else if (tok.size() > 1) {
2031 WRITE_WARNINGF(TL("Discarding unknown compound '%' in type '%' (first occurence for edge '%')."), t, type, id);
2032 }
2033 }
2034 if (types.empty()) {
2035 WRITE_WARNINGF(TL("Discarding unusable type '%' (first occurence for edge '%')."), type, id);
2036 myUnusableTypes.insert(type);
2037 return "";
2038 }
2039 const std::string newType = joinToString(types, "|");
2040 if (tc.knows(newType)) {
2041 myKnownCompoundTypes[type] = newType;
2042 return newType;
2043 } else if (myKnownCompoundTypes.count(newType) > 0) {
2044 return myKnownCompoundTypes[newType];
2045 } else {
2046 // build a new type by merging all values
2047 int numLanes = 0;
2048 double maxSpeed = 0;
2049 int prio = 0;
2050 double width = NBEdge::UNSPECIFIED_WIDTH;
2051 double sidewalkWidth = NBEdge::UNSPECIFIED_WIDTH;
2052 double bikelaneWidth = NBEdge::UNSPECIFIED_WIDTH;
2053 bool defaultIsOneWay = true;
2054 SVCPermissions permissions = 0;
2056 bool discard = true;
2057 for (auto& type2 : types) {
2058 if (!tc.getEdgeTypeShallBeDiscarded(type2)) {
2059 numLanes = MAX2(numLanes, tc.getEdgeTypeNumLanes(type2));
2060 maxSpeed = MAX2(maxSpeed, tc.getEdgeTypeSpeed(type2));
2061 prio = MAX2(prio, tc.getEdgeTypePriority(type2));
2062 defaultIsOneWay &= tc.getEdgeTypeIsOneWay(type2);
2063 //std::cout << "merging component " << type2 << " into type " << newType << " allows=" << getVehicleClassNames(tc.getPermissions(type2)) << " oneway=" << defaultIsOneWay << "\n";
2064 permissions |= tc.getEdgeTypePermissions(type2);
2065 spreadType = tc.getEdgeTypeSpreadType(type2);
2066 width = MAX2(width, tc.getEdgeTypeWidth(type2));
2067 sidewalkWidth = MAX2(sidewalkWidth, tc.getEdgeTypeSidewalkWidth(type2));
2068 bikelaneWidth = MAX2(bikelaneWidth, tc.getEdgeTypeBikeLaneWidth(type2));
2069 discard = false;
2070 }
2071 }
2072 if (width != NBEdge::UNSPECIFIED_WIDTH) {
2073 width = MAX2(width, SUMO_const_laneWidth);
2074 }
2075 // ensure pedestrians don't run into trains
2076 if (sidewalkWidth == NBEdge::UNSPECIFIED_WIDTH
2077 && (permissions & SVC_PEDESTRIAN) != 0
2078 && (permissions & SVC_RAIL_CLASSES) != 0) {
2079 //std::cout << "patching sidewalk for type '" << newType << "' which allows=" << getVehicleClassNames(permissions) << "\n";
2080 sidewalkWidth = OptionsCont::getOptions().getFloat("default.sidewalk-width");
2081 }
2082
2083 if (discard) {
2084 WRITE_WARNINGF(TL("Discarding compound type '%' (first occurence for edge '%')."), newType, id);
2085 myUnusableTypes.insert(newType);
2086 return "";
2087 }
2088
2089 WRITE_MESSAGE("Adding new type '" + type + "' (first occurence for edge '" + id + "').");
2090 tc.insertEdgeType(newType, numLanes, maxSpeed, prio, permissions, spreadType, width,
2091 defaultIsOneWay, sidewalkWidth, bikelaneWidth, 0, 0, 0);
2092 for (auto& type3 : types) {
2093 if (!tc.getEdgeTypeShallBeDiscarded(type3)) {
2094 tc.copyEdgeTypeRestrictionsAndAttrs(type3, newType);
2095 }
2096 }
2097 myKnownCompoundTypes[type] = newType;
2098 return newType;
2099 }
2100}
2101
2102void
2104 const std::string id = toString(e->id);
2105 std::string type = usableType(e->myHighWayType, id, tc);
2106 if (type != "" && isRailway(tc.getEdgeTypePermissions(type))) {
2107 std::vector<NIOSMNode*> nodes;
2108 std::vector<double> usablePositions;
2109 std::vector<int> usableIndex;
2110 for (long long int n : e->myCurrentNodes) {
2111 NIOSMNode* node = myOSMNodes[n];
2112 node->positionMeters = interpretDistance(node);
2113 if (node->positionMeters != std::numeric_limits<double>::max()) {
2114 usablePositions.push_back(node->positionMeters);
2115 usableIndex.push_back((int)nodes.size());
2116 }
2117 nodes.push_back(node);
2118 }
2119 if (usablePositions.size() == 0) {
2120 return;
2121 } else {
2122 bool forward = true;
2123 if (usablePositions.size() == 1) {
2124 WRITE_WARNINGF(TL("Ambiguous railway kilometrage direction for way '%' (assuming forward)"), id);
2125 } else {
2126 forward = usablePositions.front() < usablePositions.back();
2127 }
2128 // check for consistency
2129 for (int i = 1; i < (int)usablePositions.size(); i++) {
2130 if ((usablePositions[i - 1] < usablePositions[i]) != forward) {
2131 WRITE_WARNINGF(TL("Inconsistent railway kilometrage direction for way '%': % (skipping)"), id, toString(usablePositions));
2132 return;
2133 }
2134 }
2135 if (nodes.size() > usablePositions.size()) {
2136 // complete missing values
2137 PositionVector shape;
2138 for (NIOSMNode* node : nodes) {
2139 shape.push_back(Position(node->lon, node->lat, 0));
2140 }
2142 return; // error will be given later
2143 }
2144 double sign = forward ? 1 : -1;
2145 // extend backward before first usable value
2146 for (int i = usableIndex.front() - 1; i >= 0; i--) {
2147 nodes[i]->positionMeters = nodes[i + 1]->positionMeters - sign * shape[i].distanceTo2D(shape[i + 1]);
2148 }
2149 // extend forward
2150 for (int i = usableIndex.front() + 1; i < (int)nodes.size(); i++) {
2151 if (nodes[i]->positionMeters == std::numeric_limits<double>::max()) {
2152 nodes[i]->positionMeters = nodes[i - 1]->positionMeters + sign * shape[i].distanceTo2D(shape[i - 1]);
2153 }
2154 }
2155 //std::cout << " way=" << id << " usable=" << toString(usablePositions) << "\n indices=" << toString(usableIndex)
2156 // << " final:\n";
2157 //for (auto n : nodes) {
2158 // std::cout << " " << n->id << " " << n->positionMeters << " " << n->position<< "\n";
2159 //}
2160 }
2161 }
2162 }
2163}
2164
2165
2166double
2168 if (node->position.size() > 0) {
2169 try {
2170 if (StringUtils::startsWith(node->position, "mi:")) {
2171 return StringUtils::toDouble(node->position.substr(3)) * 1609.344; // meters per mile
2172 } else {
2173 return StringUtils::toDouble(node->position) * 1000;
2174 }
2175 } catch (...) {
2176 WRITE_WARNINGF(TL("Value of railway:position is not numeric ('%') in node '%'."), node->position, toString(node->id));
2177 }
2178 }
2179 return std::numeric_limits<double>::max();
2180}
2181
2185 if (type == "train") {
2186 result = SVC_RAIL;
2187 } else if (type == "subway" || type == "light_rail" || type == "monorail" || type == "aerialway") {
2188 result = SVC_RAIL_URBAN;
2189 } else if (type == "share_taxi") {
2190 result = SVC_TAXI;
2191 } else if (type == "minibus") {
2192 result = SVC_BUS;
2193 } else if (SumoVehicleClassStrings.hasString(type)) {
2194 result = SumoVehicleClassStrings.get(type);
2195 }
2196 std::string stop = "";
2197 if (result == SVC_TRAM) {
2198 stop = ".tram";
2199 } else if (result == SVC_BUS) {
2200 stop = ".bus";
2201 } else if (isRailway(result)) {
2202 stop = ".train";
2203 }
2204 if (toSet != nullptr && result != SVC_IGNORING) {
2205 toSet->permissions |= result;
2206 toSet->ptStopLength = OptionsCont::getOptions().getFloat("osm.stop-output.length" + stop);
2207 }
2208 return result;
2209}
2210
2211void
2213 bool multiLane = changeProhibition > 3;
2214 //std::cout << "applyChangeProhibition e=" << e->getID() << " changeProhibition=" << std::bitset<32>(changeProhibition) << " val=" << changeProhibition << "\n";
2215 for (int lane = 0; changeProhibition > 0 && lane < e->getNumLanes(); lane++) {
2216 int code = changeProhibition % 4; // only look at the last 2 bits
2217 SVCPermissions changeLeft = (code & CHANGE_NO_LEFT) == 0 ? SVCAll : SVC_AUTHORITY;
2218 SVCPermissions changeRight = (code & CHANGE_NO_RIGHT) == 0 ? SVCAll : SVC_AUTHORITY;
2219 e->setPermittedChanging(lane, changeLeft, changeRight);
2220 if (multiLane) {
2221 changeProhibition = changeProhibition >> 2;
2222 }
2223 }
2224}
2225
2226void
2227NIImporter_OpenStreetMap::applyLaneUseInformation(NBEdge* e, const std::vector<SVCPermissions>& laneUse) {
2228 if (myImportLaneAccess && laneUse.size() > 0) {
2229 if ((int)laneUse.size() == e->getNumLanes()) {
2230 const bool lefthand = OptionsCont::getOptions().getBool("lefthand");
2231 for (int lane = 0; lane < (int)laneUse.size(); lane++) {
2232 // laneUse stores from left to right
2233 const int i = lefthand ? lane : e->getNumLanes() - 1 - lane;
2234 SVCPermissions svc = e->getPermissions(lane);
2235 if (laneUse[i] == 0) {
2236 svc = SVC_IGNORING;
2237 } else if ((laneUse[i] & SVC_PASSENGER) == 0) {
2238 svc &= ~SVC_PASSENGER;
2239 }
2240 e->setPermissions(svc, lane);
2241 }
2242 } else {
2243 WRITE_WARNINGF(TL("Ignoring lane use information for % lanes on edge % with % lanes"), laneUse.size(), e->getID(), e->getNumLanes());
2244 }
2245 }
2246}
2247
2248void
2249NIImporter_OpenStreetMap::applyTurnSigns(NBEdge* e, const std::vector<int>& turnSigns) {
2250 if (myImportTurnSigns && turnSigns.size() > 0) {
2251 // no sidewalks and bike lanes have been added yet
2252 if ((int)turnSigns.size() == e->getNumLanes()) {
2253 const bool lefthand = OptionsCont::getOptions().getBool("lefthand");
2254 //std::cout << "apply turnSigns for " << e->getID() << " turnSigns=" << toString(turnSigns) << "\n";
2255 for (int i = 0; i < (int)turnSigns.size(); i++) {
2256 // laneUse stores from left to right
2257 const int laneIndex = lefthand ? i : e->getNumLanes() - 1 - i;
2258 NBEdge::Lane& lane = e->getLaneStruct(laneIndex);
2259 lane.turnSigns = turnSigns[i];
2260 }
2261 } else {
2262 WRITE_WARNINGF(TL("Ignoring turn sign information for % lanes on edge % with % driving lanes"), turnSigns.size(), e->getID(), e->getNumLanes());
2263 }
2264 }
2265}
2266
2267/****************************************************************************/
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:266
#define WRITE_MESSAGE(msg)
Definition: MsgHandler.h:267
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:274
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:265
#define PROGRESS_BEGIN_TIME_MESSAGE(msg)
Definition: MsgHandler.h:271
#define TL(string)
Definition: MsgHandler.h:282
#define PROGRESS_TIME_MESSAGE(before)
Definition: MsgHandler.h:272
#define PROGRESS_DONE_MESSAGE()
Definition: MsgHandler.h:270
#define PROGRESS_BEGIN_MESSAGE(msg)
Definition: MsgHandler.h:269
std::vector< NBEdge * > EdgeVector
container for (sorted) edges
Definition: NBCont.h:42
#define KM_PER_MILE
const SVCPermissions SVCAll
all VClasses are allowed
bool isRailway(SVCPermissions permissions)
Returns whether an edge with the given permission is a railway edge.
bool isBikepath(SVCPermissions permissions)
Returns whether an edge with the given permission is a bicycle edge.
StringBijection< SUMOVehicleClass > SumoVehicleClassStrings(sumoVehicleClassStringInitializer, SVC_CUSTOM2, false)
SUMOVehicleClass
Definition of vehicle classes to differ between different lane usage and authority types.
@ SVC_ROAD_CLASSES
classes which drive on roads
@ SVC_IGNORING
vehicles ignoring classes
@ SVC_RAIL
vehicle is a not electrified rail
@ SVC_RAIL_CLASSES
classes which drive on tracks
@ SVC_PASSENGER
vehicle is a passenger car (a "normal" car)
@ SVC_BICYCLE
vehicle is a bicycle
@ SVC_RAIL_FAST
vehicle that is allowed to drive on high-speed rail tracks
@ SVC_RAIL_ELECTRIC
rail vehicle that requires electrified tracks
@ SVC_RAIL_URBAN
vehicle is a city rail
@ SVC_AUTHORITY
authorities vehicles
@ SVC_TRAM
vehicle is a light rail
@ SVC_TAXI
vehicle is a taxi
@ SVC_BUS
vehicle is a bus
@ SVC_PEDESTRIAN
pedestrian
int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
TrafficLightType
@ SUMO_TAG_MEMBER
@ SUMO_TAG_ND
@ SUMO_TAG_WAY
@ SUMO_TAG_NODE
alternative definition for junction
@ SUMO_TAG_RELATION
@ SUMO_TAG_TAG
LaneSpreadFunction
Numbers representing special SUMO-XML-attribute values Information how the edge's lateral offset shal...
@ PARTLEFT
The link is a partial left direction.
@ RIGHT
The link is a (hard) right direction.
@ TURN
The link is a 180 degree turn.
@ LEFT
The link is a (hard) left direction.
@ STRAIGHT
The link is a straight direction.
@ PARTRIGHT
The link is a partial right direction.
@ NODIR
The link has no direction (is a dead end link)
@ SUMO_ATTR_LON
@ SUMO_ATTR_V
@ SUMO_ATTR_REF
@ SUMO_ATTR_LAT
@ SUMO_ATTR_TYPE
@ SUMO_ATTR_ID
@ SUMO_ATTR_ACTION
@ SUMO_ATTR_K
const double SUMO_const_laneWidth
Definition: StdDefs.h:48
T MIN2(T a, T b)
Definition: StdDefs.h:71
T ISNAN(T a)
Definition: StdDefs.h:112
T MAX2(T a, T b)
Definition: StdDefs.h:77
std::string joinToStringSorting(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition: ToString.h:298
std::string joinToString(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition: ToString.h:282
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:46
static bool isReadable(std::string path)
Checks whether the given file is readable.
Definition: FileHelpers.cpp:51
void setFileName(const std::string &name)
Sets the current file name.
bool wasInformed() const
Returns the information whether any messages were added.
Definition: MsgHandler.cpp:321
static MsgHandler * getErrorInstance()
Returns the instance to add errors to.
Definition: MsgHandler.cpp:79
Storage for edges, including some functionality operating on multiple edges.
Definition: NBEdgeCont.h:59
bool insert(NBEdge *edge, bool ignorePrunning=false)
Adds an edge to the dictionary.
Definition: NBEdgeCont.cpp:177
The representation of a single edge during network building.
Definition: NBEdge.h:92
bool addEdge2EdgeConnection(NBEdge *dest, bool overrideRemoval=false)
Adds a connection to another edge.
Definition: NBEdge.cpp:1058
void setPermittedChanging(int lane, SVCPermissions changeLeft, SVCPermissions changeRight)
set allowed classes for changing to the left and right from the given lane
Definition: NBEdge.cpp:4128
SVCPermissions getPermissions(int lane=-1) const
get the union of allowed classes over all lanes or for a specific lane
Definition: NBEdge.cpp:4137
void setPermissions(SVCPermissions permissions, int lane=-1)
set allowed/disallowed classes for the given lane or for all lanes if -1 is given
Definition: NBEdge.cpp:4100
void addBikeLane(double width)
add a bicycle lane of the given width and shift existing connctions
Definition: NBEdge.cpp:4342
NBNode * getToNode() const
Returns the destination node of the edge.
Definition: NBEdge.h:552
static const double UNSPECIFIED_FRICTION
unspecified lane friction
Definition: NBEdge.h:366
Lane & getLaneStruct(int lane)
Definition: NBEdge.h:1426
const PositionVector & getGeometry() const
Returns the geometry of the edge.
Definition: NBEdge.h:787
void setTurnSignTarget(const std::string &target)
Definition: NBEdge.h:1555
void setDistance(double distance)
set kilometrage at start of edge (negative value implies couting down along the edge)
Definition: NBEdge.h:1416
const std::string & getID() const
Definition: NBEdge.h:1526
void addSidewalk(double width)
add a pedestrian sidewalk of the given width and shift existing connctions
Definition: NBEdge.cpp:4330
int getNumLanes() const
Returns the number of lanes.
Definition: NBEdge.h:526
void removeFromConnections(NBEdge *toEdge, int fromLane=-1, int toLane=-1, bool tryLater=false, const bool adaptToLaneRemoval=false, const bool keepPossibleTurns=false)
Removes the specified connection(s)
Definition: NBEdge.cpp:1402
bool isConnectedTo(const NBEdge *e, const bool ignoreTurnaround=false) const
Returns the information whethe a connection to the given edge has been added (or computed)
Definition: NBEdge.cpp:1285
NBNode * getFromNode() const
Returns the origin node of the edge.
Definition: NBEdge.h:545
static const double UNSPECIFIED_WIDTH
unspecified lane width
Definition: NBEdge.h:357
static const double UNSPECIFIED_OFFSET
unspecified lane offset
Definition: NBEdge.h:360
void setGeometry(const PositionVector &g, bool inner=false)
(Re)sets the edge's geometry
Definition: NBEdge.cpp:650
Instance responsible for building networks.
Definition: NBNetBuilder.h:107
static bool transformCoordinates(PositionVector &from, bool includeInBoundary=true, GeoConvHelper *from_srs=nullptr)
NBPTLineCont & getPTLineCont()
Returns a reference to the pt line container.
Definition: NBNetBuilder.h:169
NBParkingCont & getParkingCont()
Definition: NBNetBuilder.h:173
NBPTStopCont & getPTStopCont()
Returns a reference to the pt stop container.
Definition: NBNetBuilder.h:164
NBNodeCont & getNodeCont()
Returns a reference to the node container.
Definition: NBNetBuilder.h:144
NBEdgeCont & getEdgeCont()
Definition: NBNetBuilder.h:139
NBTypeCont & getTypeCont()
Returns a reference to the type container.
Definition: NBNetBuilder.h:149
NBTrafficLightLogicCont & getTLLogicCont()
Returns a reference to the traffic light logics container.
Definition: NBNetBuilder.h:154
static bool transformCoordinate(Position &from, bool includeInBoundary=true, GeoConvHelper *from_srs=nullptr)
transforms loaded coordinates handles projections, offsets (using GeoConvHelper) and import of height...
Container for nodes during the netbuilding process.
Definition: NBNodeCont.h:58
bool insert(const std::string &id, const Position &position, NBDistrict *district=0)
Inserts a node into the map.
Definition: NBNodeCont.cpp:91
NBNode * retrieve(const std::string &id) const
Returns the node with the given name.
Definition: NBNodeCont.cpp:120
Represents a single node (junction) during network building.
Definition: NBNode.h:66
bool hasIncoming(const NBEdge *const e) const
Returns whether the given edge ends at this node.
Definition: NBNode.cpp:1746
void reinit(const Position &position, SumoXMLNodeType type, bool updateEdgeGeometries=false)
Resets initial values.
Definition: NBNode.cpp:307
SumoXMLNodeType getType() const
Returns the type of this node.
Definition: NBNode.h:275
const EdgeVector & getIncomingEdges() const
Returns this node's incoming edges (The edges which yield in this node)
Definition: NBNode.h:258
const EdgeVector & getOutgoingEdges() const
Returns this node's outgoing edges (The edges which start at this node)
Definition: NBNode.h:263
const Position & getPosition() const
Definition: NBNode.h:250
const EdgeVector & getEdges() const
Returns all edges which participate in this node (Edges that start or end at this node)
Definition: NBNode.h:268
void setFringeType(FringeType fringeType)
set method for computing right-of-way
Definition: NBNode.h:550
A traffic light logics which must be computed (only nodes/edges are given)
Definition: NBOwnTLDef.h:44
void addPTStop(NBPTStop *pStop)
Definition: NBPTLine.cpp:46
const std::vector< NBPTStop * > & getStops()
Definition: NBPTLine.cpp:60
const std::string & getLineID() const
Definition: NBPTLine.h:47
void addWayNode(long long int way, long long int node)
Definition: NBPTLine.cpp:107
void setMyNumOfStops(int numStops)
Definition: NBPTLine.cpp:152
bool insert(NBPTStop *ptStop, bool floating=false)
Inserts a node into the map.
int cleanupDeleted(NBEdgeCont &cont)
remove stops on non existing (removed) edges
NBPTStop * get(std::string id) const
Retrieve a previously inserted pt stop.
const std::map< std::string, NBPTStop * > & getStops() const
Definition: NBPTStopCont.h:66
The representation of a single pt stop.
Definition: NBPTStop.h:46
void registerAdditionalEdge(std::string wayId, std::string edgeId)
Definition: NBPTStop.cpp:189
void addPlatformCand(NBPTPlatform platform)
Definition: NBPTStop.cpp:151
void setIsPlatform()
Definition: NBPTStop.h:109
void setIsMultipleStopPositions(bool multipleStopPositions, long long int areaID)
Definition: NBPTStop.cpp:169
The representation of an imported parking area.
Definition: NBParking.h:42
A container for traffic light definitions and built programs.
bool insert(NBTrafficLightDefinition *logic, bool forceInsert=false)
Adds a logic definition to the dictionary.
A storage for available edgeTypes of edges.
Definition: NBTypeCont.h:52
bool getEdgeTypeShallBeDiscarded(const std::string &edgeType) const
Returns the information whether edges of this edgeType shall be discarded.
Definition: NBTypeCont.cpp:523
void insertEdgeType(const std::string &id, int numLanes, double maxSpeed, int prio, SVCPermissions permissions, LaneSpreadFunction spreadType, double width, bool oneWayIsDefault, double sidewalkWidth, double bikeLaneWidth, double widthResolution, double maxWidth, double minWidth)
Adds a edgeType into the list.
Definition: NBTypeCont.cpp:204
bool copyEdgeTypeRestrictionsAndAttrs(const std::string &fromId, const std::string &toId)
Copy restrictions to a edgeType.
Definition: NBTypeCont.cpp:342
double getEdgeTypeSpeed(const std::string &edgeType) const
Returns the maximal velocity for the given edgeType [m/s].
Definition: NBTypeCont.cpp:500
int getEdgeTypePriority(const std::string &edgeType) const
Returns the priority for the given edgeType.
Definition: NBTypeCont.cpp:511
int getEdgeTypeNumLanes(const std::string &edgeType) const
Returns the number of lanes for the given edgeType.
Definition: NBTypeCont.cpp:494
double getEdgeTypeWidth(const std::string &edgeType) const
Returns the lane width for the given edgeType [m].
Definition: NBTypeCont.cpp:561
SVCPermissions getEdgeTypePermissions(const std::string &edgeType) const
Returns allowed vehicle classes for the given edgeType.
Definition: NBTypeCont.cpp:549
bool knows(const std::string &edgeType) const
Returns whether the named edgeType is in the container.
Definition: NBTypeCont.cpp:303
double getEdgeTypeSidewalkWidth(const std::string &edgeType) const
Returns the lane width for a sidewalk to be added [m].
Definition: NBTypeCont.cpp:567
LaneSpreadFunction getEdgeTypeSpreadType(const std::string &edgeType) const
Returns spreadType for the given edgeType.
Definition: NBTypeCont.cpp:555
double getEdgeTypeBikeLaneWidth(const std::string &edgeType) const
Returns the lane width for a bike lane to be added [m].
Definition: NBTypeCont.cpp:573
bool getEdgeTypeIsOneWay(const std::string &edgeType) const
Returns whether edges are one-way per default for the given edgeType.
Definition: NBTypeCont.cpp:517
bool operator()(const Edge *e1, const Edge *e2) const
An internal definition of a loaded edge.
WayType mySidewalkType
Information about the kind of sidwalk along this road.
std::vector< SVCPermissions > myLaneUseForward
(optional) information about the permitted vehicle classes on each lane
bool myCurrentIsRoad
Information whether this is a road.
WayType myCyclewayType
Information about the kind of cycleway along this road.
int myNoLanesForward
number of lanes in forward direction or 0 if unknown, negative if backwards lanes are meant
double myMaxSpeed
maximum speed in km/h, or MAXSPEED_UNGIVEN
bool myCurrentIsElectrified
Information whether this is railway is electrified.
std::string ref
The edge's track name.
std::string myHighWayType
The type, stored in "highway" key.
const long long int id
The edge's id.
int myLayer
Information about the relative z-ordering of ways.
SVCPermissions myExtraDisallowed
Extra permissions prohibited from tags instead of highway type.
std::vector< SVCPermissions > myLaneUseBackward
int myNoLanes
number of lanes, or -1 if unknown
std::vector< int > myTurnSignsForward
turning direction (arrows printed on the road)
std::vector< long long int > myCurrentNodes
The list of nodes this edge is made of.
int myParkingType
Information about road-side parking.
double myMaxSpeedBackward
maximum speed in km/h, or MAXSPEED_UNGIVEN
WayType myBuswayType
Information about the kind of busway along this road.
int myChangeForward
Information about change prohibitions (forward direction.
SVCPermissions myExtraAllowed
Extra permissions added from tags instead of highway type.
int myChangeBackward
Information about change prohibitions (backward direction.
std::string streetName
The edge's street name.
WayType myRailDirection
Information about the direction(s) of railway usage.
std::string myIsOneWay
Information whether this is an one-way road.
A class which extracts OSM-edges from a parsed OSM-file.
std::set< std::string > myExtraAttributes
extra attributes to import
EdgesHandler(const std::map< long long int, NIOSMNode * > &osmNodes, std::map< long long int, Edge * > &toFill, std::map< long long int, Edge * > &platformShapes)
Constructor.
int interpretChangeType(const std::string &value) const
bool myAllAttributes
whether additional way attributes shall be added to the edge
bool myImportBikeAccess
import bike path specific permissions and directions
void myEndElement(int element) override
Called when a closing tag occurs.
double interpretSpeed(const std::string &key, std::string value)
std::map< std::string, double > mySpeedMap
A map of non-numeric speed descriptions to their numeric values.
void myStartElement(int element, const SUMOSAXAttributes &attrs) override
Called on the opening of a tag;.
void interpretLaneUse(const std::string &value, SUMOVehicleClass svc, std::vector< SVCPermissions > &result) const
A class which extracts OSM-nodes from a parsed OSM-file.
void myStartElement(int element, const SUMOSAXAttributes &attrs) override
Called on the opening of a tag;.
NodesHandler(std::map< long long int, NIOSMNode * > &toFill, std::set< NIOSMNode *, CompareNodes > &uniqueNodes, const OptionsCont &cont)
Contructor.
void myEndElement(int element) override
Called when a closing tag occurs.
A class which extracts relevant relation information from a parsed OSM-file.
void myEndElement(int element) override
Called when a closing tag occurs.
void resetValues()
reset members to their defaults for parsing a new relation
void myStartElement(int element, const SUMOSAXAttributes &attrs) override
Called on the opening of a tag;.
RelationHandler(const std::map< long long int, NIOSMNode * > &osmNodes, const std::map< long long int, Edge * > &osmEdges, NBPTStopCont *nbptStopCont, const std::map< long long int, Edge * > &platfromShapes, NBPTLineCont *nbptLineCont, const OptionsCont &oc)
Constructor.
bool checkEdgeRef(long long int ref) const
check whether a referenced way has a corresponding edge
bool applyRestriction() const
try to apply the parsed restriction and return whether successful
NBEdge * findEdgeRef(long long int wayRef, const std::vector< NBEdge * > &candidates) const
try to find the way segment among candidates
Importer for networks stored in OpenStreetMap format.
int insertEdge(Edge *e, int index, NBNode *from, NBNode *to, const std::vector< long long int > &passed, NBNetBuilder &nb, const NBNode *first, const NBNode *last)
Builds an NBEdge.
std::map< long long int, Edge * > myEdges
the map from OSM way ids to edge objects
std::map< long long int, NIOSMNode * > myOSMNodes
the map from OSM node ids to actual nodes
static void loadNetwork(const OptionsCont &oc, NBNetBuilder &nb)
Loads content of the optionally given OSM file.
static const long long int INVALID_ID
static const double MAXSPEED_UNGIVEN
std::map< long long int, Edge * > myPlatformShapes
the map from OSM way ids to platform shapes
void load(const OptionsCont &oc, NBNetBuilder &nb)
void applyTurnSigns(NBEdge *e, const std::vector< int > &turnSigns)
bool myImportSidewalks
import sidewalks
std::set< NIOSMNode *, CompareNodes > myUniqueNodes
the set of unique nodes used in NodesHandler, used when freeing memory
void reconstructLayerElevation(double layerElevation, NBNetBuilder &nb)
reconstruct elevation from layer info
static SUMOVehicleClass interpretTransportType(const std::string &type, NIOSMNode *toSet=nullptr)
translate osm transport designations into sumo vehicle class
bool myImportLaneAccess
import lane specific access restrictions
bool myImportTurnSigns
import turning signals (turn:lanes) to guide connection building
std::map< std::string, std::string > myKnownCompoundTypes
The compound types that have already been mapped to other known types.
static const std::string compoundTypeSeparator
The separator within newly created compound type names.
std::set< std::string > myUnusableTypes
The compounds types that do not contain known types.
std::map< NBNode *, std::pair< double, double > > getNeighboringNodes(NBNode *node, double maxDist, const std::set< NBNode * > &knownElevation)
collect neighboring nodes with their road distance and maximum between-speed. Search does not continu...
static double interpretDistance(NIOSMNode *node)
read distance value from node and return value in m
NBNode * insertNodeChecking(long long int id, NBNodeCont &nc, NBTrafficLightLogicCont &tlsc)
Builds an NBNode.
void extendRailwayDistances(Edge *e, NBTypeCont &tc)
extend kilometrage data for all nodes along railway
std::string usableType(const std::string &type, const std::string &id, NBTypeCont &tc)
check whether the type is known or consists of known type compounds. return empty string otherwise
void applyLaneUseInformation(NBEdge *e, const std::vector< SVCPermissions > &laneUse)
static void applyChangeProhibition(NBEdge *e, int changeProhibition)
const std::string & getID() const
Returns the id.
Definition: Named.h:74
A storage for options typed value containers)
Definition: OptionsCont.h:89
bool isSet(const std::string &name, bool failOnNonExistant=true) const
Returns the information whether the named option is set.
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
std::string getString(const std::string &name) const
Returns the string-value of the named option (only for Option_String)
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
const StringVector & getStringVector(const std::string &name) const
Returns the list of string-value of the named option (only for Option_StringVector)
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:59
void unsetParameter(const std::string &key)
Removes a parameter.
const Parameterised::Map & getParametersMap() const
Returns the inner key/value map.
virtual void setParameter(const std::string &key, const std::string &value)
Sets a parameter.
void updateParameters(const Parameterised::Map &mapArg)
Adds or updates all given parameters from the map.
A point in 2D or 3D with translation and scaling methods.
Definition: Position.h:37
A list of positions.
double length2D() const
Returns the length.
double length() const
Returns the length.
PositionVector reverse() const
reverse position vector
static RGBColor parseColor(std::string coldef)
Parses a color information.
Definition: RGBColor.cpp:239
Encapsulated SAX-Attributes.
T getOpt(int attr, const char *objectid, bool &ok, T defaultValue=T(), bool report=true) const
Tries to read given attribute assuming it is an int.
virtual std::string getStringSecure(int id, const std::string &def) const =0
Returns the string-value of the named (by its enum-value) attribute.
T get(int attr, const char *objectid, bool &ok, bool report=true) const
Tries to read given attribute assuming it is an int.
virtual bool hasAttribute(int id) const =0
Returns the information whether the named (by its enum-value) attribute is within the current list.
SAX-handler base for SUMO-files.
static StringBijection< TrafficLightType > TrafficLightTypes
traffic light types
T get(const std::string &str) const
int size() const
returns the number of existing substrings
std::vector< std::string > getVector()
return vector of strings
bool hasNext()
returns the information whether further substrings exist
std::string next()
returns the next substring when it exists. Otherwise the behaviour is undefined
static long long int toLong(const std::string &sData)
converts a string into the long value described by it by calling the char-type converter,...
static std::string to_lower_case(const std::string &str)
Transfers the content to lower case.
Definition: StringUtils.cpp:76
static double toDouble(const std::string &sData)
converts a string into the double value described by it by calling the char-type converter
static std::string escapeXML(const std::string &orig, const bool maskDoubleHyphen=false)
Replaces the standard escapes by their XML entities.
static std::string prune(const std::string &str)
Removes trailing and leading whitechars.
Definition: StringUtils.cpp:55
static bool startsWith(const std::string &str, const std::string prefix)
Checks whether a given string starts with the prefix.
static bool endsWith(const std::string &str, const std::string suffix)
Checks whether a given string ends with the suffix.
static int toInt(const std::string &sData)
converts a string into the integer value described by it by calling the char-type converter,...
static bool toBool(const std::string &sData)
converts a string into the bool value described by it by calling the char-type converter
static SUMOSAXReader * getSAXReader(SUMOSAXHandler &handler, const bool isNet=false, const bool isRoute=false)
Builds a reader and assigns the handler to it.
Definition: XMLSubSys.cpp:121
An (internal) definition of a single lane of an edge.
Definition: NBEdge.h:143
int turnSigns
turning signs printed on the road, bitset of LinkDirection (imported from OSM)
Definition: NBEdge.h:195
An internal representation of an OSM-node.
SVCPermissions permissions
type of pt stop
NBNode * node
the NBNode that was instantiated
double positionMeters
position converted to m (using highest precision available)
std::string position
kilometrage/mileage
const long long int id
The node's id.
bool tlsControlled
Whether this is a tls controlled junction.
double ptStopLength
The length of the pt stop.
bool ptStopPosition
Whether this is a public transport stop position.
std::string name
The name of the node.
bool railwayCrossing
Whether this is a railway crossing.
double ele
The elevation of this node.
bool railwayBufferStop
Whether this is a railway buffer stop.
const double lon
The longitude the node is located at.
const double lat
The latitude the node is located at.
bool railwaySignal
Whether this is a railway (main) signal.