Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
NIImporter_OpenStreetMap.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3// Copyright (C) 2001-2026 German Aerospace Center (DLR) and others.
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// https://www.eclipse.org/legal/epl-2.0/
7// This Source Code may also be made available under the following Secondary
8// Licenses when the conditions for such availability set forth in the Eclipse
9// Public License 2.0 are satisfied: GNU General Public License, version 2
10// or later which is available at
11// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13/****************************************************************************/
23// Importer for networks stored in OpenStreetMap format
24/****************************************************************************/
25#include <config.h>
26#include <algorithm>
27#include <set>
28#include <functional>
29#include <sstream>
30#include <limits>
44#include <utils/xml/XMLSubSys.h>
45#include <netbuild/NBEdge.h>
46#include <netbuild/NBEdgeCont.h>
47#include <netbuild/NBNode.h>
48#include <netbuild/NBNodeCont.h>
50#include <netbuild/NBOwnTLDef.h>
51#include <netbuild/NBPTLine.h>
54#include <netbuild/NBPTStop.h>
55#include "NILoader.h"
57
58//#define DEBUG_LAYER_ELEVATION
59//#define DEBUG_RAIL_DIRECTION
60
61// ---------------------------------------------------------------------------
62// static members
63// ---------------------------------------------------------------------------
65
66const long long int NIImporter_OpenStreetMap::INVALID_ID = std::numeric_limits<long long int>::max();
69
70// ===========================================================================
71// Private classes
72// ===========================================================================
73
77public:
78 bool operator()(const Edge* e1, const Edge* e2) const {
79 if (e1->myHighWayType != e2->myHighWayType) {
80 return e1->myHighWayType > e2->myHighWayType;
81 }
82 if (e1->myNoLanes != e2->myNoLanes) {
83 return e1->myNoLanes > e2->myNoLanes;
84 }
85 if (e1->myNoLanesForward != e2->myNoLanesForward) {
86 return e1->myNoLanesForward > e2->myNoLanesForward;
87 }
88 if (e1->myMaxSpeed != e2->myMaxSpeed) {
89 return e1->myMaxSpeed > e2->myMaxSpeed;
90 }
91 if (e1->myIsOneWay != e2->myIsOneWay) {
92 return e1->myIsOneWay > e2->myIsOneWay;
93 }
94 return e1->myCurrentNodes > e2->myCurrentNodes;
95 }
96};
97
98// ===========================================================================
99// method definitions
100// ===========================================================================
101// ---------------------------------------------------------------------------
102// static methods
103// ---------------------------------------------------------------------------
104const std::string NIImporter_OpenStreetMap::compoundTypeSeparator("|"); //clang-tidy says: "compundTypeSeparator with
105// static storage duration my throw an exception that cannot be caught
106
107void
110 importer.load(oc, nb);
111}
112
114
116 // delete nodes
117 for (auto myUniqueNode : myUniqueNodes) {
118 delete myUniqueNode;
119 }
120 // delete edges
121 for (auto& myEdge : myEdges) {
122 delete myEdge.second;
123 }
124 // delete platform shapes
125 for (auto& myPlatformShape : myPlatformShapes) {
126 delete myPlatformShape.second;
127 }
128}
129
130void
132 if (!oc.isSet("osm-files")) {
133 return;
134 }
135 const std::vector<std::string> files = oc.getStringVector("osm-files");
136 std::vector<SUMOSAXReader*> readers;
137
138 myImportLaneAccess = oc.getBool("osm.lane-access");
139 myImportTurnSigns = oc.getBool("osm.turn-lanes");
140 myImportSidewalks = oc.getBool("osm.sidewalks");
141 myImportBikeAccess = oc.getBool("osm.bike-access");
142 myImportCrossings = oc.getBool("osm.crossings");
143 myOnewayDualSidewalk = oc.getBool("osm.oneway-reverse-sidewalk");
144 myAnnotateDefaults = oc.getBool("osm.annotate-defaults");
145
146 myAllAttributes = OptionsCont::getOptions().getBool("osm.all-attributes");
147 std::vector<std::string> extra = OptionsCont::getOptions().getStringVector("osm.extra-attributes");
148 myExtraAttributes.insert(extra.begin(), extra.end());
149 if (myExtraAttributes.count("all") != 0) {
150 // import all
151 myExtraAttributes.clear();
152 }
153
154 // load nodes, first
155 NodesHandler nodesHandler(myOSMNodes, myUniqueNodes, oc);
156 for (const std::string& file : files) {
157 if (!FileHelpers::isReadable(file)) {
158 WRITE_ERRORF(TL("Could not open osm-file '%'."), file);
159 return;
160 }
161 nodesHandler.setFileName(file);
162 nodesHandler.resetHierarchy();
163 const long before = PROGRESS_BEGIN_TIME_MESSAGE("Parsing nodes from osm-file '" + file + "'");
164 readers.push_back(XMLSubSys::getSAXReader(nodesHandler));
165 if (!readers.back()->parseFirst(file) || !readers.back()->parseSection(SUMO_TAG_NODE) ||
167 return;
168 }
169 if (nodesHandler.getDuplicateNodes() > 0) {
170 WRITE_MESSAGEF(TL("Found and substituted % osm nodes."), toString(nodesHandler.getDuplicateNodes()));
171 }
172 PROGRESS_TIME_MESSAGE(before);
173 }
174
175 // load edges, then
177 int idx = 0;
178 for (const std::string& file : files) {
179 edgesHandler.setFileName(file);
180 readers[idx]->setHandler(edgesHandler);
181 const long before = PROGRESS_BEGIN_TIME_MESSAGE("Parsing edges from osm-file '" + file + "'");
182 if (!readers[idx]->parseSection(SUMO_TAG_WAY)) {
183 // eof already reached, no relations
184 delete readers[idx];
185 readers[idx] = nullptr;
186 }
187 PROGRESS_TIME_MESSAGE(before);
188 idx++;
189 }
190
191 /* Remove duplicate edges with the same shape and attributes */
192 if (!oc.getBool("osm.skip-duplicates-check")) {
193 int numRemoved = 0;
194 PROGRESS_BEGIN_MESSAGE(TL("Removing duplicate edges"));
195 if (myEdges.size() > 1) {
196 std::set<const Edge*, CompareEdges> dupsFinder;
197 for (auto it = myEdges.begin(); it != myEdges.end();) {
198 if (dupsFinder.count(it->second) > 0) {
199 numRemoved++;
200 delete it->second;
201 myEdges.erase(it++);
202 } else {
203 dupsFinder.insert(it->second);
204 it++;
205 }
206 }
207 }
208 if (numRemoved > 0) {
209 WRITE_MESSAGEF(TL("Removed % duplicate osm edges."), toString(numRemoved));
210 }
212 }
213
214 /* Mark which nodes are used (by edges or traffic lights).
215 * This is necessary to detect which OpenStreetMap nodes are for
216 * geometry only */
217 std::map<long long int, int> nodeUsage;
218 // Mark which nodes are used by edges (begin and end)
219 for (const auto& edgeIt : myEdges) {
220 assert(edgeIt.second->myCurrentIsRoad);
221 for (const long long int node : edgeIt.second->myCurrentNodes) {
222 nodeUsage[node]++;
223 }
224 }
225 // Mark which nodes are used by traffic lights or are pedestrian crossings
226 for (const auto& nodesIt : myOSMNodes) {
227 if (nodesIt.second->tlsControlled || nodesIt.second->railwaySignal || (nodesIt.second->pedestrianCrossing && myImportCrossings) /* || nodesIt->second->railwayCrossing*/) {
228 // If the key is not found in the map, the value is automatically
229 // initialized with 0.
230 nodeUsage[nodesIt.first]++;
231 }
232 }
233
234 /* Instantiate edges
235 * Only those nodes in the middle of an edge which are used by more than
236 * one edge are instantiated. Other nodes are considered as geometry nodes. */
237 NBNodeCont& nc = nb.getNodeCont();
239 for (const auto& edgeIt : myEdges) {
240 Edge* const e = edgeIt.second;
241 if (!e->myCurrentIsRoad) {
242 continue;
243 }
244 if (e->myCurrentNodes.size() < 2) {
245 WRITE_WARNINGF(TL("Discarding way '%' because it has only % node(s)"), e->id, e->myCurrentNodes.size());
246 continue;
247 }
249 // build nodes;
250 // - the from- and to-nodes must be built in any case
251 // - the in-between nodes are only built if more than one edge references them
252 NBNode* first = insertNodeChecking(e->myCurrentNodes.front(), nc, tlsc);
253 NBNode* last = insertNodeChecking(e->myCurrentNodes.back(), nc, tlsc);
254 NBNode* currentFrom = first;
255 int running = 0;
256 std::vector<long long int> passed;
257 for (auto j = e->myCurrentNodes.begin(); j != e->myCurrentNodes.end(); ++j) {
258 passed.push_back(*j);
259 if (nodeUsage[*j] > 1 && j != e->myCurrentNodes.end() - 1 && j != e->myCurrentNodes.begin()) {
260 NBNode* currentTo = insertNodeChecking(*j, nc, tlsc);
261 running = insertEdge(e, running, currentFrom, currentTo, passed, nb, first, last);
262 currentFrom = currentTo;
263 passed.clear();
264 passed.push_back(*j);
265 }
266 }
267 if (running == 0) {
268 running = -1;
269 }
270 insertEdge(e, running, currentFrom, last, passed, nb, first, last);
271 }
272
273 /* Collect edges which explicitly are part of a roundabout and store the edges of each
274 * detected roundabout */
276
277 if (myImportCrossings) {
278 /* After edges are instantiated
279 * nodes are parsed again to add pedestrian crossings to them
280 * This is only executed if crossings are imported and not guessed */
281 const double crossingWidth = OptionsCont::getOptions().getFloat("default.crossing-width");
282
283 for (auto item : nodeUsage) {
284 NIOSMNode* osmNode = myOSMNodes.find(item.first)->second;
285 if (osmNode->pedestrianCrossing) {
286 NBNode* n = osmNode->node;
287 EdgeVector incomingEdges = n->getIncomingEdges();
288 EdgeVector outgoingEdges = n->getOutgoingEdges();
289 size_t incomingEdgesNo = incomingEdges.size();
290 size_t outgoingEdgesNo = outgoingEdges.size();
291
292 for (size_t i = 0; i < incomingEdgesNo; i++) {
293 /* Check if incoming edge has driving lanes(and sidewalks)
294 * if not, ignore
295 * if yes, check if there is a corresponding outgoing edge for the opposite direction
296 * -> if yes, check if it has driving lanes
297 * --> if yes, do the crossing
298 * --> if no, only do the crossing with the incoming edge (usually one lane roads with two sidewalks)
299 * -> if not, do nothing as we don't have a sidewalk in the opposite direction */
300 auto const iEdge = incomingEdges[i];
301
302 if (iEdge->getFirstNonPedestrianLaneIndex(NBNode::FORWARD) > -1
303 && iEdge->getSpecialLane(SVC_PEDESTRIAN) > -1) {
304 std::string const& iEdgeId = iEdge->getID();
305 std::size_t const m = iEdgeId.find_first_of("#");
306 std::string const& iWayId = iEdgeId.substr(0, m);
307 for (size_t j = 0; j < outgoingEdgesNo; j++) {
308 auto const oEdge = outgoingEdges[j];
309 // Searching for a corresponding outgoing edge (based on OSM way identifier)
310 // with at least a pedestrian lane, going in the opposite direction
311 if (oEdge->getID().find(iWayId) != std::string::npos
312 && oEdge->getSpecialLane(SVC_PEDESTRIAN) > -1
313 && oEdge->getID().rfind(iWayId, 0) != 0) {
314 EdgeVector edgeVector = EdgeVector{ iEdge };
315 if (oEdge->getFirstNonPedestrianLaneIndex(NBNode::FORWARD) > -1) {
316 edgeVector.push_back(oEdge);
317 }
318
319 if (!n->checkCrossingDuplicated(edgeVector)) {
320 n->addCrossing(edgeVector, crossingWidth, false);
321 }
322 }
323 }
324 }
325 }
326 for (size_t i = 0; i < outgoingEdgesNo; i++) {
327 // Same checks as above for loop, but for outgoing edges
328 auto const oEdge = outgoingEdges[i];
329
330 if (oEdge->getFirstNonPedestrianLaneIndex(NBNode::FORWARD) > -1
331 && oEdge->getSpecialLane(SVC_PEDESTRIAN) > -1) {
332 std::string const& oEdgeId = oEdge->getID();
333 std::size_t const m = oEdgeId.find_first_of("#");
334 std::string const& iWayId = oEdgeId.substr(0, m);
335 for (size_t j = 0; j < incomingEdgesNo; j++) {
336 auto const iEdge = incomingEdges[j];
337 if (iEdge->getID().find(iWayId) != std::string::npos
338 && iEdge->getSpecialLane(SVC_PEDESTRIAN) > -1
339 && iEdge->getID().rfind(iWayId, 0) != 0) {
340 EdgeVector edgeVector = EdgeVector{ oEdge };
341 if (iEdge->getFirstNonPedestrianLaneIndex(NBNode::FORWARD) > -1) {
342 edgeVector.push_back(iEdge);
343 }
344
345 if (!n->checkCrossingDuplicated(edgeVector)) {
346 n->addCrossing(edgeVector, crossingWidth, false);
347 }
348 }
349 }
350 }
351 }
352 }
353 }
354 }
355
356 const double layerElevation = oc.getFloat("osm.layer-elevation");
357 if (layerElevation > 0) {
358 reconstructLayerElevation(layerElevation, nb);
359 }
360
361 // revise pt stops; remove stops on deleted edges
363
364 // load relations (after edges are built since we want to apply
365 // turn-restrictions directly to NBEdges)
367 &nb.getPTLineCont(), oc);
368 idx = 0;
369 for (const std::string& file : files) {
370 if (readers[idx] != nullptr) {
371 relationHandler.setFileName(file);
372 readers[idx]->setHandler(relationHandler);
373 const long before = PROGRESS_BEGIN_TIME_MESSAGE("Parsing relations from osm-file '" + file + "'");
374 readers[idx]->parseSection(SUMO_TAG_RELATION);
375 PROGRESS_TIME_MESSAGE(before);
376 delete readers[idx];
377 }
378 idx++;
379 }
380
381 // declare additional stops that are not anchored to a (road)-way or route relation
382 std::set<std::string> stopNames;
383 for (const auto& item : nb.getPTStopCont().getStops()) {
384 stopNames.insert(item.second->getName());
385 }
386 for (const auto& item : myOSMNodes) {
387 const NIOSMNode* n = item.second;
388 if (n->ptStopPosition && stopNames.count(n->name) == 0) {
389 Position ptPos(n->lon, n->lat, n->ele);
391 WRITE_ERRORF("Unable to project coordinates for node '%'.", n->id);
392 }
394 std::shared_ptr<NBPTStop> ptStop = std::make_shared<NBPTStop>(element, toString(n->id), ptPos, "", "", n->ptStopLength, n->name, n->permissions);
395 nb.getPTStopCont().insert(ptStop, true);
396 }
397 }
398}
399
400// ---------------------------------------------------------------------------
401// definitions of NIImporter_OpenStreetMap-methods
402// ---------------------------------------------------------------------------
403
404NBNode*
406 NBNode* node = nc.retrieve(toString(id));
407 if (node == nullptr) {
408 NIOSMNode* n = myOSMNodes.find(id)->second;
409 Position pos(n->lon, n->lat, n->ele);
410 if (!NBNetBuilder::transformCoordinate(pos, true)) {
411 WRITE_ERRORF("Unable to project coordinates for junction '%'.", id);
412 return nullptr;
413 }
414 node = new NBNode(toString(id), pos);
415 if (!nc.insert(node)) {
416 WRITE_ERRORF(TL("Could not insert junction '%'."), toString(id));
417 delete node;
418 return nullptr;
419 }
420 n->node = node;
421 if (n->railwayCrossing) {
422 if (n->getParameter("crossing:barrier") != "no") {
424 } else if (n->getParameter("crossing.light") == "yes") {
426 }
427 } else if (n->railwaySignal) {
429 } else if (n->tlsControlled) {
430 // ok, this node is a traffic light node where no other nodes
431 // participate
432 // @note: The OSM-community has not settled on a schema for differentiating between fixed and actuated lights
434 OptionsCont::getOptions().getString("tls.default-type"));
435 NBOwnTLDef* tlDef = new NBOwnTLDef(toString(id), node, 0, type);
436 if (!tlsc.insert(tlDef)) {
437 // actually, nothing should fail here
438 delete tlDef;
439 throw ProcessError(TLF("Could not allocate tls '%'.", toString(id)));
440 }
441 }
442 if (n->railwayBufferStop) {
443 node->setParameter("buffer_stop", "true");
445 }
446 if (n->railwaySignal) {
447 if (n->myRailDirection == WAY_FORWARD) {
449 } else if (n->myRailDirection == WAY_BACKWARD) {
451 }
452 }
454 }
455 return node;
456}
457
458
459int
461 const std::vector<long long int>& passed, NBNetBuilder& nb,
462 const NBNode* first, const NBNode* last) {
463 NBNodeCont& nc = nb.getNodeCont();
464 NBEdgeCont& ec = nb.getEdgeCont();
465 NBTypeCont& tc = nb.getTypeCont();
466 NBPTStopCont& sc = nb.getPTStopCont();
467
469 // patch the id
470 std::string id = toString(e->id);
471 if (from == nullptr || to == nullptr) {
472 WRITE_ERRORF("Discarding edge '%' because the nodes could not be built.", id);
473 return index;
474 }
475 if (index >= 0) {
476 id = id + "#" + toString(index);
477 } else {
478 index = 0;
479 }
480 if (from == to) {
481 assert(passed.size() >= 2);
482 if (passed.size() == 2) {
483 WRITE_WARNINGF(TL("Discarding edge '%' which connects two identical nodes without geometry."), id);
484 return index;
485 }
486 // in the special case of a looped way split again using passed
487 int intermediateIndex = (int) passed.size() / 2;
488 NBNode* intermediate = insertNodeChecking(passed[intermediateIndex], nc, tlsc);
489 std::vector<long long int> part1(passed.begin(), passed.begin() + intermediateIndex + 1);
490 std::vector<long long int> part2(passed.begin() + intermediateIndex, passed.end());
491 index = insertEdge(e, index, from, intermediate, part1, nb, first, last);
492 return insertEdge(e, index, intermediate, to, part2, nb, first, last);
493 }
494 const int newIndex = index + 1;
495 const std::string type = usableType(e->myHighWayType, id, tc);
496 if (type == "") { // we do not want to import it
497 return newIndex;
498 }
499 std::string routingType = "";
500 int numLanesForward = tc.getEdgeTypeNumLanes(type);
501 int numLanesBackward = tc.getEdgeTypeNumLanes(type);
502 double speed = tc.getEdgeTypeSpeed(type);
503 bool defaultsToOneWay = tc.getEdgeTypeIsOneWay(type);
504 const SVCPermissions defaultPermissions = tc.getEdgeTypePermissions(type);
505 SVCPermissions extra = myImportBikeAccess ? e->myExtraAllowed : (e->myExtraAllowed & ~SVC_BICYCLE);
506 const SVCPermissions extraDis = myImportBikeAccess ? e->myExtraDisallowed : (e->myExtraDisallowed & ~SVC_BICYCLE);
507 std::vector<SumoXMLAttr> defaults;
508 // extra permissions are more specific than extra prohibitions except for buses (which come from the less specific psv tag)
509 if ((extraDis & SVC_BUS) && (extra & SVC_BUS)) {
510 extra = extra & ~SVC_BUS;
511 }
512 SVCPermissions permissions = (defaultPermissions & ~extraDis) | extra;
513 if (!myImportBikeAccess && permissions == (SVC_PEDESTRIAN | SVC_BICYCLE)
514 && (e->myExtraDisallowed & SVC_BICYCLE) != 0
515 && (e->myExtraAllowed & SVC_BICYCLE) == 0) {
516 // remove bicyle permissions where they affect network building the most
517 permissions = SVC_PEDESTRIAN;
518 defaultsToOneWay = true;
519 }
520 if (defaultPermissions == SVC_SHIP) {
521 // extra permission apply to the ships operating on the route rather than the waterway
522 permissions = defaultPermissions;
523 }
524 if (defaultsToOneWay && defaultPermissions == SVC_PEDESTRIAN && (permissions & (~SVC_PEDESTRIAN)) != 0) {
525 defaultsToOneWay = false;
526 }
527 if ((permissions & SVC_RAIL) != 0 && e->myExtraTags.count("electrified") != 0) {
528 permissions |= (SVC_RAIL_ELECTRIC | SVC_RAIL_FAST);
529 }
530
531 // convert the shape
532 PositionVector shape;
533 double distanceStart = myOSMNodes[passed.front()]->positionMeters;
534 double distanceEnd = myOSMNodes[passed.back()]->positionMeters;
535 const bool useDistance = distanceStart != std::numeric_limits<double>::max() && distanceEnd != std::numeric_limits<double>::max();
536 if (useDistance) {
537 // negative sign denotes counting in the other direction
538 if (distanceStart < distanceEnd) {
539 distanceStart *= -1;
540 } else {
541 distanceEnd *= -1;
542 }
543 } else {
544 distanceStart = 0;
545 distanceEnd = 0;
546 }
547 // get additional direction information
548 int nodeDirection = myOSMNodes.find(StringUtils::toLong(from->getID()))->second->myRailDirection |
549 myOSMNodes.find(StringUtils::toLong(to->getID()))->second->myRailDirection;
550
551 std::vector<std::shared_ptr<NBPTStop> > ptStops;
552 for (long long i : passed) {
553 NIOSMNode* n = myOSMNodes.find(i)->second;
554 // recheck permissions, maybe they got assigned to a strange edge, see #11656
555 if (n->ptStopPosition && (n->permissions == 0 || (permissions & n->permissions) != 0)) {
556 std::shared_ptr<NBPTStop> existingPtStop = sc.get(toString(n->id));
557 if (existingPtStop != nullptr) {
558 existingPtStop->registerAdditionalEdge(toString(e->id), id);
559 } else {
560 Position ptPos(n->lon, n->lat, n->ele);
562 WRITE_ERRORF("Unable to project coordinates for node '%'.", n->id);
563 }
565 ptStops.push_back(std::make_shared<NBPTStop>(element, toString(n->id), ptPos, id, toString(e->id), n->ptStopLength, n->name, n->permissions));
566 sc.insert(ptStops.back());
567 }
568 }
569 if (n->railwaySignal) {
570 nodeDirection |= n->myRailDirection;
571 }
572 Position pos(n->lon, n->lat, n->ele);
573 shape.push_back(pos);
574 }
575#ifdef DEBUG_LAYER_ELEVATION
576 if (e->id == "DEBUGID") {
577 std::cout
578 << " id=" << id << " from=" << from->getID() << " fromRailDirection=" << myOSMNodes.find(StringUtils::toLong(from->getID()))->second->myRailDirection
579 << " to=" << to->getID() << " toRailDirection=" << myOSMNodes.find(StringUtils::toLong(to->getID()))->second->myRailDirection
580 << " origRailDirection=" << e->myRailDirection
581 << " nodeDirection=" << nodeDirection
582 << "\n";
583 }
584#endif
585 if (e->myRailDirection == WAY_UNKNOWN && nodeDirection != WAY_UNKNOWN && nodeDirection != WAY_FORWARD
586 && nodeDirection != (WAY_FORWARD | WAY_UNKNOWN)) {
587 //std::cout << "way " << e->id << " nodeDirection=" << nodeDirection << " origDirection=" << e->myRailDirection << "\n";
588 // heuristic: assume that the mapped way direction indicates
589 // potential driving direction
591 }
593 WRITE_ERRORF("Unable to project coordinates for edge '%'.", id);
594 }
595
596 SVCPermissions forwardPermissions = permissions;
597 SVCPermissions backwardPermissions = permissions;
598 const std::string streetName = isRailway(permissions) && e->ref != "" ? e->ref : e->streetName;
599 if (streetName == e->ref) {
600 e->unsetParameter("ref"); // avoid superfluous param for railways
601 }
602 double forwardWidth = tc.getEdgeTypeWidth(type);
603 double backwardWidth = tc.getEdgeTypeWidth(type);
604 double sidewalkWidth = tc.getEdgeTypeSidewalkWidth(type);
605 bool addSidewalk = sidewalkWidth != NBEdge::UNSPECIFIED_WIDTH;
606 if (myImportSidewalks) {
607 if (addSidewalk) {
608 // only use sidewalk width from typemap but don't add sidewalks
609 // unless OSM specifies them
610 addSidewalk = false;
611 } else {
612 sidewalkWidth = OptionsCont::getOptions().getFloat("default.sidewalk-width");
613 }
614 }
615 double bikeLaneWidth = tc.getEdgeTypeBikeLaneWidth(type);
616 const std::string& onewayBike = e->myExtraTags["oneway:bicycle"];
617 if (onewayBike == "false" || onewayBike == "no" || onewayBike == "0") {
619 }
620
621 const bool addBikeLane = bikeLaneWidth != NBEdge::UNSPECIFIED_WIDTH ||
622 (myImportBikeAccess && (((e->myCyclewayType & WAY_BOTH) != 0 || e->myExtraTags.count("segregated") != 0) &&
623 !(e->myCyclewayType == WAY_BACKWARD && (e->myBuswayType & WAY_BOTH) != 0)));
624 if (addBikeLane && bikeLaneWidth == NBEdge::UNSPECIFIED_WIDTH) {
625 bikeLaneWidth = OptionsCont::getOptions().getFloat("default.bikelane-width");
626 }
627 // check directions
628 bool addForward = true;
629 bool addBackward = true;
630 const bool explicitTwoWay = e->myIsOneWay == "no";
631 if ((e->myIsOneWay == "true" || e->myIsOneWay == "yes" || e->myIsOneWay == "1"
632 || (defaultsToOneWay && e->myIsOneWay != "no" && e->myIsOneWay != "false" && e->myIsOneWay != "0"))
633 && e->myRailDirection != WAY_BOTH) {
634 addBackward = false;
635 }
636 if (e->myIsOneWay == "-1" || e->myIsOneWay == "reverse" || e->myRailDirection == WAY_BACKWARD) {
637 // one-way in reversed direction of way
638 addForward = false;
639 addBackward = true;
640 }
641 if (!e->myIsOneWay.empty() && e->myIsOneWay != "false" && e->myIsOneWay != "no" && e->myIsOneWay != "true"
642 && e->myIsOneWay != "yes" && e->myIsOneWay != "-1" && e->myIsOneWay != "1" && e->myIsOneWay != "reverse") {
643 WRITE_WARNINGF(TL("New value for oneway found: %"), e->myIsOneWay);
644 }
645 if ((permissions == SVC_BICYCLE || permissions == (SVC_BICYCLE | SVC_PEDESTRIAN) || permissions == SVC_PEDESTRIAN)) {
646 if (addBackward && (onewayBike == "true" || onewayBike == "yes" || onewayBike == "1")) {
647 addBackward = false;
648 }
649 if (addForward && (onewayBike == "reverse" || onewayBike == "-1")) {
650 addForward = false;
651 }
652 if (!addBackward && (onewayBike == "false" || onewayBike == "no" || onewayBike == "0")) {
653 addBackward = true;
654 }
655 }
656 bool ok = true;
657 // if we had been able to extract the number of lanes, override the highway type default
658 if (e->myNoLanes > 0) {
659 if (addForward && !addBackward) {
660 numLanesForward = e->myNoLanesForward > 0 ? e->myNoLanesForward : e->myNoLanes;
661 } else if (!addForward && addBackward) {
662 numLanesBackward = e->myNoLanesForward < 0 ? -e->myNoLanesForward : e->myNoLanes;
663 } else {
664 if (e->myNoLanesForward > 0) {
665 numLanesForward = e->myNoLanesForward;
666 } else if (e->myNoLanesForward < 0) {
667 numLanesForward = e->myNoLanes + e->myNoLanesForward;
668 } else {
669 numLanesForward = (int) std::ceil(e->myNoLanes / 2.0);
670 }
671 numLanesBackward = e->myNoLanes - numLanesForward;
672 // sometimes ways are tagged according to their physical width of a single
673 // lane but they are intended for traffic in both directions
674 numLanesForward = MAX2(1, numLanesForward);
675 numLanesBackward = MAX2(1, numLanesBackward);
676 }
677 } else if (e->myNoLanes == 0) {
678 WRITE_WARNINGF(TL("Skipping edge '%' because it has zero lanes."), id);
679 ok = false;
680 } else {
681 // the total number of lanes is not known but at least one direction
682 if (e->myNoLanesForward > 0) {
683 numLanesForward = e->myNoLanesForward;
684 } else if ((e->myBuswayType & WAY_FORWARD) != 0 && (extraDis & SVC_PASSENGER) == 0) {
685 // if we have a busway lane, yet cars may drive this implies at least two lanes
686 numLanesForward = MAX2(numLanesForward, 2);
687 }
688 if (e->myNoLanesForward < 0) {
689 numLanesBackward = -e->myNoLanesForward;
690 } else if ((e->myBuswayType & WAY_BACKWARD) != 0 && (extraDis & SVC_PASSENGER) == 0) {
691 // if we have a busway lane, yet cars may drive this implies at least two lanes
692 numLanesBackward = MAX2(numLanesForward, 2);
693 }
694 if (myAnnotateDefaults && e->myNoLanesForward == 0) {
695 defaults.push_back(SUMO_ATTR_NUMLANES);
696 }
697 }
698 // deal with busways that run in the opposite direction of a one-way street
699 if (!addForward && (e->myBuswayType & WAY_FORWARD) != 0) {
700 addForward = true;
701 forwardPermissions = SVC_BUS;
702 numLanesForward = 1;
703 }
704 if (!addBackward && (e->myBuswayType & WAY_BACKWARD) != 0) {
705 addBackward = true;
706 backwardPermissions = SVC_BUS;
707 numLanesBackward = 1;
708 }
709 // width is meant for raw lane count before adding sidewalks or cycleways
710 const int taggedLanes = (addForward ? numLanesForward : 0) + (addBackward ? numLanesBackward : 0);
711 if (e->myWidth > 0 && e->myWidthLanesForward.size() == 0 && e->myWidthLanesBackward.size() == 0 && taggedLanes != 0
712 && !OptionsCont::getOptions().getBool("ignore-widths")) {
713 // width is tagged excluding sidewalks and cycleways
714 forwardWidth = e->myWidth / taggedLanes;
715 backwardWidth = forwardWidth;
716 }
717
718 // if we had been able to extract the maximum speed, override the type's default
719 if (e->myMaxSpeed != MAXSPEED_UNGIVEN) {
720 speed = e->myMaxSpeed;
721 } else if (myAnnotateDefaults) {
722 defaults.push_back(SUMO_ATTR_SPEED);
723 }
724 double speedBackward = speed;
726 speedBackward = e->myMaxSpeedBackward;
727 }
728 if (speed <= 0 || speedBackward <= 0) {
729 WRITE_WARNINGF(TL("Skipping edge '%' because it has speed %."), id, speed);
730 ok = false;
731 }
732 if (e->myNoLanes == 1 && addForward && addBackward) {
733 // narrow road which now receives a total of 2 lanes but has less capacity than implied
734 if (e->myWidth < 0 && e->myWidthLanesForward.size() == 0 && e->myWidthLanesBackward.size() == 0) {
735 if (forwardWidth == NBEdge::UNSPECIFIED_WIDTH) {
736 forwardWidth = SUMO_const_laneWidth;
737 }
738 if (backwardWidth == NBEdge::UNSPECIFIED_WIDTH) {
739 backwardWidth = SUMO_const_laneWidth;
740 }
741 forwardWidth /= 2;
742 backwardWidth /= 2;
743 }
744 if (e->myWidth < 5) {
745 routingType = "narrow";
746 }
747 }
748 // deal with cycleways that run in the opposite direction of a one-way street
749 WayType cyclewayType = e->myCyclewayType; // make a copy because we do some temporary modifications
750 if (addBikeLane) {
751 if (!addForward && (cyclewayType & WAY_FORWARD) != 0) {
752 addForward = true;
753 forwardPermissions = SVC_BICYCLE;
754 forwardWidth = bikeLaneWidth;
755 numLanesForward = 1;
756 // do not add an additional cycle lane
757 cyclewayType = (WayType)(cyclewayType & ~WAY_FORWARD);
758 }
759 if (!addBackward && (cyclewayType & WAY_BACKWARD) != 0) {
760 addBackward = true;
761 backwardPermissions = SVC_BICYCLE;
762 backwardWidth = bikeLaneWidth;
763 numLanesBackward = 1;
764 // do not add an additional cycle lane
765 cyclewayType = (WayType)(cyclewayType & ~WAY_BACKWARD);
766 }
767 }
768 // deal with sidewalks that run in the opposite direction of a one-way street
769 WayType sidewalkType = e->mySidewalkType; // make a copy because we do some temporary modifications
770 if (sidewalkType == WAY_UNKNOWN && (e->myExtraAllowed & SVC_PEDESTRIAN) != 0 && (permissions & SVC_PASSENGER) != 0) {
771 // do not assume shared space unless sidewalk is actively disabled
773 sidewalkType = WAY_BOTH;
774 }
775 }
776 if (addSidewalk || (myImportSidewalks && (permissions & SVC_ROAD_CLASSES) != 0 && defaultPermissions != SVC_PEDESTRIAN)) {
777 if (!addForward && (sidewalkType & WAY_FORWARD) != 0) {
778 addForward = true;
779 forwardPermissions = SVC_PEDESTRIAN;
780 forwardWidth = tc.getEdgeTypeSidewalkWidth(type);
781 numLanesForward = 1;
782 // do not add an additional sidewalk
783 sidewalkType = (WayType)(sidewalkType & ~WAY_FORWARD); //clang tidy thinks "!WAY_FORWARD" is always false
784 } else if (addSidewalk && addForward && (sidewalkType & WAY_BOTH) == 0
785 && numLanesForward == 1 && numLanesBackward <= 1
786 && (e->myExtraDisallowed & SVC_PEDESTRIAN) == 0) {
787 // our typemap says pedestrians should walk here but the data says
788 // there is no sidewalk at all. If the road is small, pedestrians can just walk
789 // on the road
790 forwardPermissions |= SVC_PEDESTRIAN;
791 }
792 if (!addBackward && (sidewalkType & WAY_BACKWARD) != 0) {
793 addBackward = true;
794 backwardPermissions = SVC_PEDESTRIAN;
795 backwardWidth = tc.getEdgeTypeSidewalkWidth(type);
796 numLanesBackward = 1;
797 // do not add an additional cycle lane
798 sidewalkType = (WayType)(sidewalkType & ~WAY_BACKWARD); //clang tidy thinks "!WAY_BACKWARD" is always false
799 } else if (addSidewalk && addBackward && (sidewalkType & WAY_BOTH) == 0
800 && numLanesBackward == 1 && numLanesForward <= 1
801 && (e->myExtraDisallowed & SVC_PEDESTRIAN) == 0) {
802 // our typemap says pedestrians should walk here but the data says
803 // there is no sidewalk at all. If the road is small, pedestrians can just walk
804 // on the road
805 backwardPermissions |= SVC_PEDESTRIAN;
806 }
807 }
808
809 const std::string origID = OptionsCont::getOptions().getBool("output.original-names") ? toString(e->id) : "";
810 if (ok) {
811 const bool lefthand = OptionsCont::getOptions().getBool("lefthand");
812 const int offsetFactor = lefthand ? -1 : 1;
813 LaneSpreadFunction lsf = (addBackward || OptionsCont::getOptions().getBool("osm.oneway-spread-right")) &&
815 if (addBackward && lsf == LaneSpreadFunction::RIGHT && OptionsCont::getOptions().getString("default.spreadtype") == toString(LaneSpreadFunction::ROADCENTER)) {
817 }
819 // user defined value overrides defaults
820 lsf = tc.getEdgeTypeSpreadType(type);
821 }
822 if (defaults.size() > 0) {
823 e->setParameter("osmDefaults", joinToString(defaults, " "));
824 }
825
826 id = StringUtils::escapeXML(id);
827 const std::string reverseID = "-" + id;
828 const bool markOSMDirection = from->getType() == SumoXMLNodeType::RAIL_SIGNAL || to->getType() == SumoXMLNodeType::RAIL_SIGNAL;
829 if (addForward) {
830 assert(numLanesForward > 0);
831 NBEdge* nbe = new NBEdge(id, from, to, type, speed, NBEdge::UNSPECIFIED_FRICTION, numLanesForward, tc.getEdgeTypePriority(type),
832 forwardWidth, NBEdge::UNSPECIFIED_OFFSET, shape, lsf,
833 StringUtils::escapeXML(streetName), origID, true);
834 if (markOSMDirection) {
836 }
837 nbe->setPermissions(forwardPermissions, -1);
838 if ((e->myBuswayType & WAY_FORWARD) != 0) {
839 nbe->setPermissions(SVC_BUS, 0);
840 }
842 applyLaneUse(nbe, e, true);
844 nbe->setTurnSignTarget(last->getID());
845 if (addBikeLane && (cyclewayType == WAY_UNKNOWN || (cyclewayType & WAY_FORWARD) != 0)) {
846 nbe->addBikeLane(bikeLaneWidth * offsetFactor);
847 } else if (nbe->getPermissions(0) == SVC_BUS) {
848 // bikes drive on buslanes if no separate cycle lane is available
850 }
851 if ((addSidewalk && (sidewalkType == WAY_UNKNOWN || (sidewalkType & WAY_FORWARD) != 0))
852 || (myImportSidewalks && (sidewalkType & WAY_FORWARD) != 0 && defaultPermissions != SVC_PEDESTRIAN)) {
853 nbe->addSidewalk(sidewalkWidth * offsetFactor);
854 }
855 if (!addBackward && (e->myExtraAllowed & SVC_PEDESTRIAN) != 0 && (nbe->getPermissions(0) & SVC_PEDESTRIAN) == 0) {
856 // Pedestrians are explicitly allowed (maybe through foot="yes") but did not get a sidewalk (maybe through sidewalk="no").
857 // Since we do not have a backward edge, we need to make sure they can at least walk somewhere, see #14124
859 }
861 nbe->setDistance(distanceStart);
862 if (e->myAmInRoundabout) {
863 // ensure roundabout edges have the precedence
866 }
867
868 // process forward lanes width
869 const int numForwardLanesFromWidthKey = (int)e->myWidthLanesForward.size();
870 if (numForwardLanesFromWidthKey > 0 && !OptionsCont::getOptions().getBool("ignore-widths")) {
871 if ((int)nbe->getLanes().size() != numForwardLanesFromWidthKey) {
872 WRITE_WARNINGF(TL("Forward lanes count for edge '%' ('%') is not matching the number of lanes defined in width:lanes:forward key ('%'). Using default width values."),
873 id, nbe->getLanes().size(), numForwardLanesFromWidthKey);
874 } else {
875 for (int i = 0; i < numForwardLanesFromWidthKey; i++) {
876 const double actualWidth = e->myWidthLanesForward[i] <= 0 ? forwardWidth : e->myWidthLanesForward[i];
877 const int laneIndex = lefthand ? i : numForwardLanesFromWidthKey - i - 1;
878 nbe->setLaneWidth(laneIndex, actualWidth);
879 }
880 }
881 }
882 nbe->setRoutingType(routingType);
883
884 if (!ec.insert(nbe)) {
885 delete nbe;
886 throw ProcessError(TLF("Could not add edge '%'.", id));
887 }
888 }
889 if (addBackward) {
890 assert(numLanesBackward > 0);
891 NBEdge* nbe = new NBEdge(reverseID, to, from, type, speedBackward, NBEdge::UNSPECIFIED_FRICTION, numLanesBackward, tc.getEdgeTypePriority(type),
892 backwardWidth, NBEdge::UNSPECIFIED_OFFSET, shape.reverse(), lsf,
893 StringUtils::escapeXML(streetName), origID, true);
894 if (markOSMDirection) {
896 }
897 nbe->setPermissions(backwardPermissions);
898 if ((e->myBuswayType & WAY_BACKWARD) != 0) {
899 nbe->setPermissions(SVC_BUS, 0);
900 }
902 applyLaneUse(nbe, e, false);
904 nbe->setTurnSignTarget(first->getID());
905 if (addBikeLane && (cyclewayType == WAY_UNKNOWN || (cyclewayType & WAY_BACKWARD) != 0)) {
906 nbe->addBikeLane(bikeLaneWidth * offsetFactor);
907 } else if (nbe->getPermissions(0) == SVC_BUS) {
908 // bikes drive on buslanes if no separate cycle lane is available
910 }
911 if ((addSidewalk && (sidewalkType == WAY_UNKNOWN || (sidewalkType & WAY_BACKWARD) != 0))
912 || (myImportSidewalks && (sidewalkType & WAY_BACKWARD) != 0 && defaultPermissions != SVC_PEDESTRIAN)) {
913 nbe->addSidewalk(sidewalkWidth * offsetFactor);
914 }
916 nbe->setDistance(distanceEnd);
917 if (e->myAmInRoundabout) {
918 // ensure roundabout edges have the precedence
921 }
922 // process backward lanes width
923 const int numBackwardLanesFromWidthKey = (int)e->myWidthLanesBackward.size();
924 if (numBackwardLanesFromWidthKey > 0 && !OptionsCont::getOptions().getBool("ignore-widths")) {
925 if ((int)nbe->getLanes().size() != numBackwardLanesFromWidthKey) {
926 WRITE_WARNINGF(TL("Backward lanes count for edge '%' ('%') is not matching the number of lanes defined in width:lanes:backward key ('%'). Using default width values."),
927 id, nbe->getLanes().size(), numBackwardLanesFromWidthKey);
928 } else {
929 for (int i = 0; i < numBackwardLanesFromWidthKey; i++) {
930 const double actualWidth = e->myWidthLanesBackward[i] <= 0 ? backwardWidth : e->myWidthLanesBackward[i];
931 const int laneIndex = lefthand ? i : numBackwardLanesFromWidthKey - i - 1;
932 nbe->setLaneWidth(laneIndex, actualWidth);
933 }
934 }
935 }
936 nbe->setRoutingType(routingType);
937
938 if (!ec.insert(nbe)) {
939 delete nbe;
940 throw ProcessError(TLF("Could not add edge '-%'.", id));
941 }
942 }
943 if ((e->myParkingType & PARKING_BOTH) != 0 && OptionsCont::getOptions().isSet("parking-output")) {
944 if ((e->myParkingType & PARKING_RIGHT) != 0) {
945 if (addForward) {
946 nb.getParkingCont().push_back(NBParking(id, id));
947 } else {
949 if ((e->myParkingType & PARKING_LEFT) == 0 && !addBackward) {
951 nb.getParkingCont().push_back(NBParking(reverseID, reverseID));
952 }
953 }
954 }
955 if ((e->myParkingType & PARKING_LEFT) != 0) {
956 if (addBackward) {
957 nb.getParkingCont().push_back(NBParking(reverseID, reverseID));
958 } else {
960 if ((e->myParkingType & PARKING_RIGHT) == 0 && !addForward) {
962 nb.getParkingCont().push_back(NBParking(id, id));
963 }
964 }
965 }
966 }
967 }
968 return newIndex;
969}
970
971
972void
974 NBNodeCont& nc = nb.getNodeCont();
975 NBEdgeCont& ec = nb.getEdgeCont();
976 // reconstruct elevation from layer info
977 // build a map of raising and lowering forces (attractor and distance)
978 // for all nodes unknownElevation
979 std::map<NBNode*, std::vector<std::pair<double, double> > > layerForces;
980
981 // collect all nodes that belong to a way with layer information
982 std::set<NBNode*> knownElevation;
983 for (auto& myEdge : myEdges) {
984 Edge* e = myEdge.second;
985 if (e->myLayer != 0) {
986 for (auto j = e->myCurrentNodes.begin(); j != e->myCurrentNodes.end(); ++j) {
987 NBNode* node = nc.retrieve(toString(*j));
988 if (node != nullptr) {
989 knownElevation.insert(node);
990 layerForces[node].emplace_back(e->myLayer * layerElevation, POSITION_EPS);
991 }
992 }
993 }
994 }
995#ifdef DEBUG_LAYER_ELEVATION
996 std::cout << "known elevations:\n";
997 for (std::set<NBNode*>::iterator it = knownElevation.begin(); it != knownElevation.end(); ++it) {
998 const std::vector<std::pair<double, double> >& primaryLayers = layerForces[*it];
999 std::cout << " node=" << (*it)->getID() << " ele=";
1000 for (std::vector<std::pair<double, double> >::const_iterator it_ele = primaryLayers.begin(); it_ele != primaryLayers.end(); ++it_ele) {
1001 std::cout << it_ele->first << " ";
1002 }
1003 std::cout << "\n";
1004 }
1005#endif
1006 // layer data only provides a lower bound on elevation since it is used to
1007 // resolve the relation among overlapping ways.
1008 // Perform a sanity check for steep inclines and raise the knownElevation if necessary
1009 std::map<NBNode*, double> knownEleMax;
1010 for (auto it : knownElevation) {
1011 double eleMax = -std::numeric_limits<double>::max();
1012 const std::vector<std::pair<double, double> >& primaryLayers = layerForces[it];
1013 for (const auto& primaryLayer : primaryLayers) {
1014 eleMax = MAX2(eleMax, primaryLayer.first);
1015 }
1016 knownEleMax[it] = eleMax;
1017 }
1018 const double gradeThreshold = OptionsCont::getOptions().getFloat("osm.layer-elevation.max-grade") / 100;
1019 bool changed = true;
1020 while (changed) {
1021 changed = false;
1022 for (auto it = knownElevation.begin(); it != knownElevation.end(); ++it) {
1023 std::map<NBNode*, std::pair<double, double> > neighbors = getNeighboringNodes(*it,
1024 knownEleMax[*it]
1025 / gradeThreshold * 3,
1026 knownElevation);
1027 for (auto& neighbor : neighbors) {
1028 if (knownElevation.count(neighbor.first) != 0) {
1029 const double grade = fabs(knownEleMax[*it] - knownEleMax[neighbor.first])
1030 / MAX2(POSITION_EPS, neighbor.second.first);
1031#ifdef DEBUG_LAYER_ELEVATION
1032 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";
1033#endif
1034 if (grade > gradeThreshold * 50 / 3.6 / neighbor.second.second) {
1035 // raise the lower node to the higher level
1036 const double eleMax = MAX2(knownEleMax[*it], knownEleMax[neighbor.first]);
1037 if (knownEleMax[*it] < eleMax) {
1038 knownEleMax[*it] = eleMax;
1039 } else {
1040 knownEleMax[neighbor.first] = eleMax;
1041 }
1042 changed = true;
1043 }
1044 }
1045 }
1046 }
1047 }
1048
1049 // collect all nodes within a grade-dependent range around knownElevation-nodes and apply knowElevation forces
1050 std::set<NBNode*> unknownElevation;
1051 for (auto it = knownElevation.begin(); it != knownElevation.end(); ++it) {
1052 const double eleMax = knownEleMax[*it];
1053 const double maxDist = fabs(eleMax) * 100 / layerElevation;
1054 std::map<NBNode*, std::pair<double, double> > neighbors = getNeighboringNodes(*it, maxDist, knownElevation);
1055 for (auto& neighbor : neighbors) {
1056 if (knownElevation.count(neighbor.first) == 0) {
1057 unknownElevation.insert(neighbor.first);
1058 layerForces[neighbor.first].emplace_back(eleMax, neighbor.second.first);
1059 }
1060 }
1061 }
1062
1063 // apply forces to ground-level nodes (neither in knownElevation nor unknownElevation)
1064 for (auto it = unknownElevation.begin(); it != unknownElevation.end(); ++it) {
1065 double eleMax = -std::numeric_limits<double>::max();
1066 const std::vector<std::pair<double, double> >& primaryLayers = layerForces[*it];
1067 for (const auto& primaryLayer : primaryLayers) {
1068 eleMax = MAX2(eleMax, primaryLayer.first);
1069 }
1070 const double maxDist = fabs(eleMax) * 100 / layerElevation;
1071 std::map<NBNode*, std::pair<double, double> > neighbors = getNeighboringNodes(*it, maxDist, knownElevation);
1072 for (auto& neighbor : neighbors) {
1073 if (knownElevation.count(neighbor.first) == 0 && unknownElevation.count(neighbor.first) == 0) {
1074 layerForces[*it].emplace_back(0, neighbor.second.first);
1075 }
1076 }
1077 }
1078 // compute the elevation for each node as the weighted average of all forces
1079#ifdef DEBUG_LAYER_ELEVATION
1080 std::cout << "summation of forces\n";
1081#endif
1082 std::map<NBNode*, double> nodeElevation;
1083 for (auto& layerForce : layerForces) {
1084 const std::vector<std::pair<double, double> >& forces = layerForce.second;
1085 if (knownElevation.count(layerForce.first) != 0) {
1086 // use the maximum value
1087 /*
1088 double eleMax = -std::numeric_limits<double>::max();
1089 for (std::vector<std::pair<double, double> >::const_iterator it_force = forces.begin(); it_force != forces.end(); ++it_force) {
1090 eleMax = MAX2(eleMax, it_force->first);
1091 }
1092 */
1093#ifdef DEBUG_LAYER_ELEVATION
1094 std::cout << " node=" << it->first->getID() << " knownElevation=" << knownEleMax[it->first] << "\n";
1095#endif
1096 nodeElevation[layerForce.first] = knownEleMax[layerForce.first];
1097 } else if (forces.size() == 1) {
1098 nodeElevation[layerForce.first] = forces.front().first;
1099 } else {
1100 // use the weighted sum
1101 double distSum = 0;
1102 for (const auto& force : forces) {
1103 distSum += force.second;
1104 }
1105 double weightSum = 0;
1106 double elevation = 0;
1107#ifdef DEBUG_LAYER_ELEVATION
1108 std::cout << " node=" << it->first->getID() << " distSum=" << distSum << "\n";
1109#endif
1110 for (const auto& force : forces) {
1111 const double weight = (distSum - force.second) / distSum;
1112 weightSum += weight;
1113 elevation += force.first * weight;
1114
1115#ifdef DEBUG_LAYER_ELEVATION
1116 std::cout << " force=" << it_force->first << " dist=" << it_force->second << " weight=" << weight << " ele=" << elevation << "\n";
1117#endif
1118 }
1119 nodeElevation[layerForce.first] = elevation / weightSum;
1120 }
1121 }
1122#ifdef DEBUG_LAYER_ELEVATION
1123 std::cout << "final elevations:\n";
1124 for (std::map<NBNode*, double>::iterator it = nodeElevation.begin(); it != nodeElevation.end(); ++it) {
1125 std::cout << " node=" << (it->first)->getID() << " ele=" << it->second << "\n";
1126 }
1127#endif
1128 // apply node elevations
1129 for (auto& it : nodeElevation) {
1130 NBNode* n = it.first;
1131 n->reinit(n->getPosition() + Position(0, 0, it.second), n->getType());
1132 }
1133
1134 // apply way elevation to all edges that had layer information
1135 for (const auto& it : ec) {
1136 NBEdge* edge = it.second;
1137 const PositionVector& geom = edge->getGeometry();
1138 const double length = geom.length2D();
1139 const double zFrom = nodeElevation[edge->getFromNode()];
1140 const double zTo = nodeElevation[edge->getToNode()];
1141 // XXX if the from- or to-node was part of multiple ways with
1142 // different layers, reconstruct the layer value from origID
1143 double dist = 0;
1144 PositionVector newGeom;
1145 for (auto it_pos = geom.begin(); it_pos != geom.end(); ++it_pos) {
1146 if (it_pos != geom.begin()) {
1147 dist += (*it_pos).distanceTo2D(*(it_pos - 1));
1148 }
1149 newGeom.push_back((*it_pos) + Position(0, 0, zFrom + (zTo - zFrom) * dist / length));
1150 }
1151 edge->setGeometry(newGeom);
1152 }
1153}
1154
1155std::map<NBNode*, std::pair<double, double> >
1156NIImporter_OpenStreetMap::getNeighboringNodes(NBNode* node, double maxDist, const std::set<NBNode*>& knownElevation) {
1157 std::map<NBNode*, std::pair<double, double> > result;
1158 std::set<NBNode*> visited;
1159 std::vector<NBNode*> open;
1160 open.push_back(node);
1161 result[node] = std::make_pair(0, 0);
1162 while (!open.empty()) {
1163 NBNode* n = open.back();
1164 open.pop_back();
1165 if (visited.count(n) != 0) {
1166 continue;
1167 }
1168 visited.insert(n);
1169 const EdgeVector& edges = n->getEdges();
1170 for (auto e : edges) {
1171 NBNode* s = nullptr;
1172 if (n->hasIncoming(e)) {
1173 s = e->getFromNode();
1174 } else {
1175 s = e->getToNode();
1176 }
1177 const double dist = result[n].first + e->getGeometry().length2D();
1178 const double speed = MAX2(e->getSpeed(), result[n].second);
1179 if (result.count(s) == 0) {
1180 result[s] = std::make_pair(dist, speed);
1181 } else {
1182 result[s] = std::make_pair(MIN2(dist, result[s].first), MAX2(speed, result[s].second));
1183 }
1184 if (dist < maxDist && knownElevation.count(s) == 0) {
1185 open.push_back(s);
1186 }
1187 }
1188 }
1189 result.erase(node);
1190 return result;
1191}
1192
1193
1194std::string
1195NIImporter_OpenStreetMap::usableType(const std::string& type, const std::string& id, NBTypeCont& tc) {
1196 if (tc.knows(type)) {
1197 return type;
1198 }
1199 if (myUnusableTypes.count(type) > 0) {
1200 return "";
1201 }
1202 if (myKnownCompoundTypes.count(type) > 0) {
1203 return myKnownCompoundTypes[type];
1204 }
1205 // this edge has a type which does not yet exist in the TypeContainer
1207 std::vector<std::string> types;
1208 while (tok.hasNext()) {
1209 std::string t = tok.next();
1210 if (tc.knows(t)) {
1211 if (std::find(types.begin(), types.end(), t) == types.end()) {
1212 types.push_back(t);
1213 }
1214 } else if (tok.size() > 1) {
1215 if (!StringUtils::startsWith(t, "service.")) {
1216 WRITE_WARNINGF(TL("Discarding unknown compound '%' in type '%' (first occurrence for edge '%')."), t, type, id);
1217 }
1218 }
1219 }
1220 if (types.empty()) {
1221 if (!StringUtils::startsWith(type, "service.")) {
1222 WRITE_WARNINGF(TL("Discarding unusable type '%' (first occurrence for edge '%')."), type, id);
1223 }
1224 myUnusableTypes.insert(type);
1225 return "";
1226 }
1227 const std::string newType = joinToString(types, "|");
1228 if (tc.knows(newType)) {
1229 myKnownCompoundTypes[type] = newType;
1230 return newType;
1231 } else if (myKnownCompoundTypes.count(newType) > 0) {
1232 return myKnownCompoundTypes[newType];
1233 } else {
1234 // build a new type by merging all values
1235 int numLanes = 0;
1236 double maxSpeed = 0;
1237 int prio = 0;
1238 double width = NBEdge::UNSPECIFIED_WIDTH;
1239 double sidewalkWidth = NBEdge::UNSPECIFIED_WIDTH;
1240 double bikelaneWidth = NBEdge::UNSPECIFIED_WIDTH;
1241 bool defaultIsOneWay = true;
1242 SVCPermissions permissions = 0;
1244 bool discard = true;
1245 bool hadDiscard = false;
1246 for (auto& type2 : types) {
1247 if (!tc.getEdgeTypeShallBeDiscarded(type2)) {
1248 numLanes = MAX2(numLanes, tc.getEdgeTypeNumLanes(type2));
1249 maxSpeed = MAX2(maxSpeed, tc.getEdgeTypeSpeed(type2));
1250 prio = MAX2(prio, tc.getEdgeTypePriority(type2));
1251 defaultIsOneWay &= tc.getEdgeTypeIsOneWay(type2);
1252 //std::cout << "merging component " << type2 << " into type " << newType << " allows=" << getVehicleClassNames(tc.getPermissions(type2)) << " oneway=" << defaultIsOneWay << "\n";
1253 permissions |= tc.getEdgeTypePermissions(type2);
1254 spreadType = tc.getEdgeTypeSpreadType(type2);
1255 width = MAX2(width, tc.getEdgeTypeWidth(type2));
1256 sidewalkWidth = MAX2(sidewalkWidth, tc.getEdgeTypeSidewalkWidth(type2));
1257 bikelaneWidth = MAX2(bikelaneWidth, tc.getEdgeTypeBikeLaneWidth(type2));
1258 discard = false;
1259 } else {
1260 hadDiscard = true;
1261 }
1262 }
1263 if (hadDiscard && permissions == 0) {
1264 discard = true;
1265 }
1266 if (discard) {
1267 WRITE_WARNINGF(TL("Discarding compound type '%' (first occurrence for edge '%')."), newType, id);
1268 myUnusableTypes.insert(newType);
1269 return "";
1270 }
1271 if (width != NBEdge::UNSPECIFIED_WIDTH) {
1272 width = MAX2(width, SUMO_const_laneWidth);
1273 }
1274 // ensure pedestrians don't run into trains
1275 if (sidewalkWidth == NBEdge::UNSPECIFIED_WIDTH
1276 && (permissions & SVC_PEDESTRIAN) != 0
1277 && (permissions & SVC_RAIL_CLASSES) != 0) {
1278 //std::cout << "patching sidewalk for type '" << newType << "' which allows=" << getVehicleClassNames(permissions) << "\n";
1279 sidewalkWidth = OptionsCont::getOptions().getFloat("default.sidewalk-width");
1280 }
1281
1282 WRITE_MESSAGEF(TL("Adding new type '%' (first occurrence for edge '%')."), type, id);
1283 tc.insertEdgeType(newType, numLanes, maxSpeed, prio, permissions, spreadType, width,
1284 defaultIsOneWay, sidewalkWidth, bikelaneWidth, 0, 0, 0);
1285 for (auto& type3 : types) {
1286 if (!tc.getEdgeTypeShallBeDiscarded(type3)) {
1287 tc.copyEdgeTypeRestrictionsAndAttrs(type3, newType);
1288 }
1289 }
1290 myKnownCompoundTypes[type] = newType;
1291 return newType;
1292 }
1293}
1294
1295void
1297 const std::string id = toString(e->id);
1298 std::string type = usableType(e->myHighWayType, id, tc);
1299 if (type != "" && isRailway(tc.getEdgeTypePermissions(type))) {
1300 std::vector<NIOSMNode*> nodes;
1301 std::vector<double> usablePositions;
1302 std::vector<int> usableIndex;
1303 for (long long int n : e->myCurrentNodes) {
1304 NIOSMNode* node = myOSMNodes[n];
1305 node->positionMeters = interpretDistance(node);
1306 if (node->positionMeters != std::numeric_limits<double>::max()) {
1307 usablePositions.push_back(node->positionMeters);
1308 usableIndex.push_back((int)nodes.size());
1309 }
1310 nodes.push_back(node);
1311 }
1312 if (usablePositions.size() == 0) {
1313 return;
1314 } else {
1315 bool forward = true;
1316 if (usablePositions.size() == 1) {
1317 WRITE_WARNINGF(TL("Ambiguous railway kilometrage direction for way '%' (assuming forward)"), id);
1318 } else {
1319 forward = usablePositions.front() < usablePositions.back();
1320 }
1321 // check for consistency
1322 for (int i = 1; i < (int)usablePositions.size(); i++) {
1323 if ((usablePositions[i - 1] < usablePositions[i]) != forward) {
1324 WRITE_WARNINGF(TL("Inconsistent railway kilometrage direction for way '%': % (skipping)"), id, toString(usablePositions));
1325 return;
1326 }
1327 }
1328 if (nodes.size() > usablePositions.size()) {
1329 // complete missing values
1330 PositionVector shape;
1331 for (NIOSMNode* node : nodes) {
1332 shape.push_back(Position(node->lon, node->lat, 0));
1333 }
1335 return; // error will be given later
1336 }
1337 double sign = forward ? 1 : -1;
1338 // extend backward before first usable value
1339 for (int i = usableIndex.front() - 1; i >= 0; i--) {
1340 nodes[i]->positionMeters = nodes[i + 1]->positionMeters - sign * shape[i].distanceTo2D(shape[i + 1]);
1341 }
1342 // extend forward
1343 for (int i = usableIndex.front() + 1; i < (int)nodes.size(); i++) {
1344 if (nodes[i]->positionMeters == std::numeric_limits<double>::max()) {
1345 nodes[i]->positionMeters = nodes[i - 1]->positionMeters + sign * shape[i].distanceTo2D(shape[i - 1]);
1346 }
1347 }
1348 //std::cout << " way=" << id << " usable=" << toString(usablePositions) << "\n indices=" << toString(usableIndex)
1349 // << " final:\n";
1350 //for (auto n : nodes) {
1351 // std::cout << " " << n->id << " " << n->positionMeters << " " << n->position<< "\n";
1352 //}
1353 }
1354 }
1355 }
1356}
1357
1358
1359double
1361 if (node->position.size() > 0) {
1362 try {
1363 if (StringUtils::startsWith(node->position, "mi:")) {
1364 return StringUtils::toDouble(node->position.substr(3)) * 1609.344; // meters per mile
1365 } else {
1366 return StringUtils::toDouble(node->position) * 1000;
1367 }
1368 } catch (...) {
1369 WRITE_WARNINGF(TL("Value of railway:position is not numeric ('%') in node '%'."), node->position, toString(node->id));
1370 }
1371 }
1372 return std::numeric_limits<double>::max();
1373}
1374
1378 if (type == "train") {
1379 result = SVC_RAIL;
1380 } else if (type == "subway") {
1381 result = SVC_SUBWAY;
1382 } else if (type == "aerialway") {
1383 result = SVC_CABLE_CAR;
1384 } else if (type == "light_rail" || type == "monorail") {
1385 result = SVC_RAIL_URBAN;
1386 } else if (type == "share_taxi") {
1387 result = SVC_TAXI;
1388 } else if (type == "minibus") {
1389 result = SVC_BUS;
1390 } else if (type == "trolleybus") {
1391 result = SVC_BUS;
1392 } else if (SumoVehicleClassStrings.hasString(type)) {
1393 result = SumoVehicleClassStrings.get(type);
1394 }
1395 std::string stop = "";
1396 if (result == SVC_TRAM) {
1397 stop = ".tram";
1398 } else if (result == SVC_BUS) {
1399 stop = ".bus";
1400 } else if (isRailway(result)) {
1401 stop = ".train";
1402 }
1403 if (toSet != nullptr && result != SVC_IGNORING) {
1404 toSet->permissions |= result;
1405 toSet->ptStopLength = OptionsCont::getOptions().getFloat("osm.stop-output.length" + stop);
1406 }
1407 return result;
1408}
1409
1410
1411void
1413 bool multiLane = changeProhibition > 3;
1414 //std::cout << "applyChangeProhibition e=" << e->getID() << " changeProhibition=" << std::bitset<32>(changeProhibition) << " val=" << changeProhibition << "\n";
1415 for (int lane = 0; changeProhibition > 0 && lane < e->getNumLanes(); lane++) {
1416 int code = changeProhibition % 4; // only look at the last 2 bits
1417 SVCPermissions changeLeft = (code & CHANGE_NO_LEFT) == 0 ? SVCAll : (SVCPermissions)SVC_AUTHORITY;
1418 SVCPermissions changeRight = (code & CHANGE_NO_RIGHT) == 0 ? SVCAll : (SVCPermissions)SVC_AUTHORITY;
1419 e->setPermittedChanging(lane, changeLeft, changeRight);
1420 if (multiLane) {
1421 changeProhibition = changeProhibition >> 2;
1422 }
1423 }
1424}
1425
1426
1427void
1429 if (myImportLaneAccess) {
1430 const int numLanes = e->getNumLanes();
1431 const bool lefthand = OptionsCont::getOptions().getBool("lefthand");
1432 const std::vector<bool>& designated = forward ? nie->myDesignatedLaneForward : nie->myDesignatedLaneBackward;
1433 const std::vector<SVCPermissions>& allowed = forward ? nie->myAllowedLaneForward : nie->myAllowedLaneBackward;
1434 const std::vector<SVCPermissions>& disallowed = forward ? nie->myDisallowedLaneForward : nie->myDisallowedLaneBackward;
1435 for (int lane = 0; lane < numLanes; lane++) {
1436 // laneUse stores from left to right
1437 const int i = lefthand ? lane : numLanes - 1 - lane;
1438 // Extra allowed SVCs for this lane or none if no info was present for the lane
1439 const SVCPermissions extraAllowed = i < (int)allowed.size() ? allowed[i] : (SVCPermissions)SVC_IGNORING;
1440 // Extra disallowed SVCs for this lane or none if no info was present for the lane
1441 const SVCPermissions extraDisallowed = i < (int)disallowed.size() ? disallowed[i] : (SVCPermissions)SVC_IGNORING;
1442 if (i < (int)designated.size() && designated[i]) {
1443 // if designated, delete all permissions
1444 e->setPermissions(SVC_IGNORING, lane);
1445 e->preferVehicleClass(lane, extraAllowed);
1446 }
1447 e->setPermissions((e->getPermissions(lane) | extraAllowed) & (~extraDisallowed), lane);
1448 }
1449 }
1450}
1451
1452void
1453NIImporter_OpenStreetMap::mergeTurnSigns(std::vector<int>& signs, std::vector<int> signs2) {
1454 if (signs.empty()) {
1455 signs.insert(signs.begin(), signs2.begin(), signs2.end());
1456 } else {
1457 for (int i = 0; i < (int)MIN2(signs.size(), signs2.size()); i++) {
1458 signs[i] |= signs2[i];
1459 }
1460 }
1461}
1462
1463
1464void
1465NIImporter_OpenStreetMap::applyTurnSigns(NBEdge* e, const std::vector<int>& turnSigns) {
1466 if (myImportTurnSigns && turnSigns.size() > 0) {
1467 // no sidewalks and bike lanes have been added yet
1468 if ((int)turnSigns.size() == e->getNumLanes()) {
1469 //std::cout << "apply turnSigns for " << e->getID() << " turnSigns=" << toString(turnSigns) << "\n";
1470 for (int i = 0; i < (int)turnSigns.size(); i++) {
1471 // laneUse stores from left to right
1472 const int laneIndex = e->getNumLanes() - 1 - i;
1473 NBEdge::Lane& lane = e->getLaneStruct(laneIndex);
1474 lane.turnSigns = turnSigns[i];
1475 }
1476 } else {
1477 WRITE_WARNINGF(TL("Ignoring turn sign information for % lanes on edge % with % driving lanes"), turnSigns.size(), e->getID(), e->getNumLanes());
1478 }
1479 }
1480}
1481
1482
1483// ---------------------------------------------------------------------------
1484// definitions of NIImporter_OpenStreetMap::NodesHandler-methods
1485// ---------------------------------------------------------------------------
1486NIImporter_OpenStreetMap::NodesHandler::NodesHandler(std::map<long long int, NIOSMNode*>& toFill,
1487 std::set<NIOSMNode*, CompareNodes>& uniqueNodes, const OptionsCont& oc) :
1488 SUMOSAXHandler("osm - file"),
1489 myToFill(toFill),
1490 myCurrentNode(nullptr),
1491 myIsStation(false),
1492 myHierarchyLevel(0),
1493 myUniqueNodes(uniqueNodes),
1494 myImportElevation(oc.getBool("osm.elevation")),
1495 myDuplicateNodes(0),
1496 myOptionsCont(oc) {
1497 // init rail signal rules
1498 for (std::string kv : oc.getStringVector("osm.railsignals")) {
1499 if (kv == "DEFAULT") {
1500 myRailSignalRules.push_back("railway:signal:main=");
1501 myRailSignalRules.push_back("railway:signal:combined=");
1502 } else if (kv == "ALL") {
1503 myRailSignalRules.push_back("railway=signal");
1504 } else {
1505 myRailSignalRules.push_back("railway:signal:" + kv);
1506 }
1507 }
1508}
1509
1510
1512
1513void
1515 ++myHierarchyLevel;
1516 if (element == SUMO_TAG_NODE) {
1517 bool ok = true;
1518 myLastNodeID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
1519 if (myHierarchyLevel != 2) {
1520 WRITE_ERROR("Node element on wrong XML hierarchy level (id='" + myLastNodeID +
1521 "', level='" + toString(myHierarchyLevel) + "').");
1522 return;
1523 }
1524 const std::string& action = attrs.getOpt<std::string>(SUMO_ATTR_ACTION, myLastNodeID.c_str(), ok);
1525 if (action == "delete" || !ok) {
1526 return;
1527 }
1528 try {
1529 // we do not use attrs.get here to save some time on parsing
1530 const long long int id = StringUtils::toLong(myLastNodeID);
1531 myCurrentNode = nullptr;
1532 const auto insertionIt = myToFill.lower_bound(id);
1533 if (insertionIt == myToFill.end() || insertionIt->first != id) {
1534 // assume we are loading multiple files, so we won't report duplicate nodes
1535 const double tlon = attrs.get<double>(SUMO_ATTR_LON, myLastNodeID.c_str(), ok);
1536 const double tlat = attrs.get<double>(SUMO_ATTR_LAT, myLastNodeID.c_str(), ok);
1537 if (!ok) {
1538 return;
1539 }
1540 myCurrentNode = new NIOSMNode(id, tlon, tlat);
1541 auto similarNode = myUniqueNodes.find(myCurrentNode);
1542 if (similarNode == myUniqueNodes.end()) {
1543 myUniqueNodes.insert(myCurrentNode);
1544 } else {
1545 delete myCurrentNode;
1546 myCurrentNode = *similarNode;
1547 myDuplicateNodes++;
1548 }
1549 myToFill.emplace_hint(insertionIt, id, myCurrentNode);
1550 }
1551 } catch (FormatException&) {
1552 WRITE_ERROR(TL("Attribute 'id' in the definition of a node is not of type long long int."));
1553 return;
1554 }
1555 }
1556 if (element == SUMO_TAG_TAG && myCurrentNode != nullptr) {
1557 if (myHierarchyLevel != 3) {
1558 WRITE_ERROR(TL("Tag element on wrong XML hierarchy level."));
1559 return;
1560 }
1561 bool ok = true;
1562 const std::string& key = attrs.get<std::string>(SUMO_ATTR_K, myLastNodeID.c_str(), ok, false);
1563 // we check whether the key is relevant (and we really need to transcode the value) to avoid hitting #1636
1564 if (key == "highway" || key == "ele" || key == "crossing" || key == "railway" || key == "public_transport"
1565 || key == "name" || key == "train" || key == "bus" || key == "tram" || key == "light_rail" || key == "subway" || key == "station" || key == "noexit"
1566 || key == "crossing:barrier"
1567 || key == "crossing:light"
1568 || key == "railway:ref"
1569 || StringUtils::startsWith(key, "railway:signal")
1570 || StringUtils::startsWith(key, "railway:position")
1571 ) {
1572 const std::string& value = attrs.get<std::string>(SUMO_ATTR_V, myLastNodeID.c_str(), ok, false);
1573 if (key == "highway" && value.find("traffic_signal") != std::string::npos) {
1574 myCurrentNode->tlsControlled = true;
1575 } else if (key == "crossing" && value.find("traffic_signals") != std::string::npos) {
1576 myCurrentNode->tlsControlled = true;
1577 } else if (key == "highway" && value.find("crossing") != std::string::npos) {
1578 myCurrentNode->pedestrianCrossing = true;
1579 } else if ((key == "noexit" && value == "yes")
1580 || (key == "railway" && value == "buffer_stop")) {
1581 myCurrentNode->railwayBufferStop = true;
1582 } else if (key == "railway" && value.find("crossing") != std::string::npos) {
1583 myCurrentNode->railwayCrossing = true;
1584 } else if (key == "crossing:barrier") {
1585 myCurrentNode->setParameter("crossing:barrier", value);
1586 } else if (key == "crossing:light") {
1587 myCurrentNode->setParameter("crossing:light", value);
1588 } else if (key == "railway:signal:direction") {
1589 if (value == "both") {
1590 myCurrentNode->myRailDirection = WAY_BOTH;
1591 } else if (value == "backward") {
1592 myCurrentNode->myRailDirection = WAY_BACKWARD;
1593 } else if (value == "forward") {
1594 myCurrentNode->myRailDirection = WAY_FORWARD;
1595 }
1596 } else if (StringUtils::startsWith(key, "railway:signal") || (key == "railway" && value == "signal")) {
1597 std::string kv = key + "=" + value;
1598 std::string kglob = key + "=";
1599 if ((std::find(myRailSignalRules.begin(), myRailSignalRules.end(), kv) != myRailSignalRules.end())
1600 || (std::find(myRailSignalRules.begin(), myRailSignalRules.end(), kglob) != myRailSignalRules.end())) {
1601 myCurrentNode->railwaySignal = true;
1602 }
1603 } else if (StringUtils::startsWith(key, "railway:position") && value.size() > myCurrentNode->position.size()) {
1604 // use the entry with the highest precision (more digits)
1605 myCurrentNode->position = value;
1606 } else if ((key == "public_transport" && value == "stop_position") ||
1607 (key == "highway" && value == "bus_stop")) {
1608 myCurrentNode->ptStopPosition = true;
1609 if (myCurrentNode->ptStopLength == 0) {
1610 // default length
1611 myCurrentNode->ptStopLength = myOptionsCont.getFloat("osm.stop-output.length");
1612 }
1613 } else if (key == "name") {
1614 myCurrentNode->name = value;
1615 } else if (myImportElevation && key == "ele") {
1616 try {
1617 const double elevation = StringUtils::parseDist(value);
1618 if (std::isnan(elevation)) {
1619 WRITE_WARNINGF(TL("Value of key '%' is invalid ('%') in node '%'."), key, value, myLastNodeID);
1620 } else {
1621 myCurrentNode->ele = elevation;
1622 }
1623 } catch (...) {
1624 WRITE_WARNINGF(TL("Value of key '%' is not numeric ('%') in node '%'."), key, value, myLastNodeID);
1625 }
1626 } else if (key == "station") {
1627 interpretTransportType(value, myCurrentNode);
1628 myIsStation = true;
1629 } else if (key == "railway:ref") {
1630 myRailwayRef = value;
1631 } else {
1632 // v="yes"
1633 interpretTransportType(key, myCurrentNode);
1634 }
1635 }
1636 if (myAllAttributes && (myExtraAttributes.count(key) != 0 || myExtraAttributes.size() == 0)) {
1637 const std::string info = "node=" + toString(myCurrentNode->id) + ", k=" + key;
1638 myCurrentNode->setParameter(key, attrs.get<std::string>(SUMO_ATTR_V, info.c_str(), ok, false));
1639 }
1640 }
1641}
1642
1643
1644void
1646 if (element == SUMO_TAG_NODE && myHierarchyLevel == 2) {
1647 if (myIsStation && myRailwayRef != "") {
1648 myCurrentNode->setParameter("railway:ref", myRailwayRef);
1649 }
1650 myCurrentNode = nullptr;
1651 myIsStation = false;
1652 myRailwayRef = "";
1653 }
1654 --myHierarchyLevel;
1655}
1656
1657
1658// ---------------------------------------------------------------------------
1659// definitions of NIImporter_OpenStreetMap::EdgesHandler-methods
1660// ---------------------------------------------------------------------------
1662 const std::map<long long int, NIOSMNode*>& osmNodes,
1663 std::map<long long int, Edge*>& toFill, std::map<long long int, Edge*>& platformShapes,
1664 const NBTypeCont& tc):
1665 SUMOSAXHandler("osm - file"),
1666 myOSMNodes(osmNodes),
1667 myEdgeMap(toFill),
1668 myPlatformShapesMap(platformShapes),
1669 myTypeCont(tc) {
1670
1671 const double unlimitedSpeed = OptionsCont::getOptions().getFloat("osm.speedlimit-none");
1672
1674 mySpeedMap["sign"] = MAXSPEED_UNGIVEN;
1675 mySpeedMap["signals"] = MAXSPEED_UNGIVEN;
1676 mySpeedMap["none"] = unlimitedSpeed;
1677 mySpeedMap["no"] = unlimitedSpeed;
1678 mySpeedMap["walk"] = 5. / 3.6;
1679 // https://wiki.openstreetmap.org/wiki/Key:source:maxspeed#Commonly_used_values
1680 mySpeedMap["AT:urban"] = 50. / 3.6;
1681 mySpeedMap["AT:rural"] = 100. / 3.6;
1682 mySpeedMap["AT:trunk"] = 100. / 3.6;
1683 mySpeedMap["AT:motorway"] = 130. / 3.6;
1684 mySpeedMap["AU:urban"] = 50. / 3.6;
1685 mySpeedMap["BE:urban"] = 50. / 3.6;
1686 mySpeedMap["BE:zone"] = 30. / 3.6;
1687 mySpeedMap["BE:motorway"] = 120. / 3.6;
1688 mySpeedMap["BE:zone30"] = 30. / 3.6;
1689 mySpeedMap["BE-VLG:rural"] = 70. / 3.6;
1690 mySpeedMap["BE-WAL:rural"] = 90. / 3.6;
1691 mySpeedMap["BE:school"] = 30. / 3.6;
1692 mySpeedMap["CZ:motorway"] = 130. / 3.6;
1693 mySpeedMap["CZ:trunk"] = 110. / 3.6;
1694 mySpeedMap["CZ:rural"] = 90. / 3.6;
1695 mySpeedMap["CZ:urban_motorway"] = 80. / 3.6;
1696 mySpeedMap["CZ:urban_trunk"] = 80. / 3.6;
1697 mySpeedMap["CZ:urban"] = 50. / 3.6;
1698 mySpeedMap["DE:motorway"] = unlimitedSpeed;
1699 mySpeedMap["DE:rural"] = 100. / 3.6;
1700 mySpeedMap["DE:urban"] = 50. / 3.6;
1701 mySpeedMap["DE:bicycle_road"] = 30. / 3.6;
1702 mySpeedMap["DK:motorway"] = 130. / 3.6;
1703 mySpeedMap["DK:rural"] = 80. / 3.6;
1704 mySpeedMap["DK:urban"] = 50. / 3.6;
1705 mySpeedMap["EE:urban"] = 50. / 3.6;
1706 mySpeedMap["EE:rural"] = 90. / 3.6;
1707 mySpeedMap["ES:urban"] = 50. / 3.6;
1708 mySpeedMap["ES:zone30"] = 30. / 3.6;
1709 mySpeedMap["FR:motorway"] = 130. / 3.6; // 110 (raining)
1710 mySpeedMap["FR:rural"] = 80. / 3.6;
1711 mySpeedMap["FR:urban"] = 50. / 3.6;
1712 mySpeedMap["FR:zone30"] = 30. / 3.6;
1713 mySpeedMap["HU:living_street"] = 20. / 3.6;
1714 mySpeedMap["HU:motorway"] = 130. / 3.6;
1715 mySpeedMap["HU:rural"] = 90. / 3.6;
1716 mySpeedMap["HU:trunk"] = 110. / 3.6;
1717 mySpeedMap["HU:urban"] = 50. / 3.6;
1718 mySpeedMap["IT:rural"] = 90. / 3.6;
1719 mySpeedMap["IT:motorway"] = 130. / 3.6;
1720 mySpeedMap["IT:urban"] = 50. / 3.6;
1721 mySpeedMap["JP:nsl"] = 60. / 3.6;
1722 mySpeedMap["JP:express"] = 100. / 3.6;
1723 mySpeedMap["LT:rural"] = 90. / 3.6;
1724 mySpeedMap["LT:urban"] = 50. / 3.6;
1725 mySpeedMap["NO:rural"] = 80. / 3.6;
1726 mySpeedMap["NO:urban"] = 50. / 3.6;
1727 mySpeedMap["ON:urban"] = 50. / 3.6;
1728 mySpeedMap["ON:rural"] = 80. / 3.6;
1729 mySpeedMap["PT:motorway"] = 120. / 3.6;
1730 mySpeedMap["PT:rural"] = 90. / 3.6;
1731 mySpeedMap["PT:trunk"] = 100. / 3.6;
1732 mySpeedMap["PT:urban"] = 50. / 3.6;
1733 mySpeedMap["RO:motorway"] = 130. / 3.6;
1734 mySpeedMap["RO:rural"] = 90. / 3.6;
1735 mySpeedMap["RO:trunk"] = 100. / 3.6;
1736 mySpeedMap["RO:urban"] = 50. / 3.6;
1737 mySpeedMap["RS:living_street"] = 30. / 3.6;
1738 mySpeedMap["RS:motorway"] = 130. / 3.6;
1739 mySpeedMap["RS:rural"] = 80. / 3.6;
1740 mySpeedMap["RS:trunk"] = 100. / 3.6;
1741 mySpeedMap["RS:urban"] = 50. / 3.6;
1742 mySpeedMap["RU:living_street"] = 20. / 3.6;
1743 mySpeedMap["RU:urban"] = 60. / 3.6;
1744 mySpeedMap["RU:rural"] = 90. / 3.6;
1745 mySpeedMap["RU:motorway"] = 110. / 3.6;
1746 const double seventy = StringUtils::parseSpeed("70mph");
1747 const double sixty = StringUtils::parseSpeed("60mph");
1748 mySpeedMap["GB:motorway"] = seventy;
1749 mySpeedMap["GB:nsl_dual"] = seventy;
1750 mySpeedMap["GB:nsl_single"] = sixty;
1751 mySpeedMap["UK:motorway"] = seventy;
1752 mySpeedMap["UK:nsl_dual"] = seventy;
1753 mySpeedMap["UK:nsl_single"] = sixty;
1754 mySpeedMap["UZ:living_street"] = 30. / 3.6;
1755 mySpeedMap["UZ:urban"] = 70. / 3.6;
1756 mySpeedMap["UZ:rural"] = 100. / 3.6;
1757 mySpeedMap["UZ:motorway"] = 110. / 3.6;
1758}
1759
1761
1762void
1764 if (element == SUMO_TAG_WAY) {
1765 bool ok = true;
1766 const long long int id = attrs.get<long long int>(SUMO_ATTR_ID, nullptr, ok);
1767 const std::string& action = attrs.getOpt<std::string>(SUMO_ATTR_ACTION, nullptr, ok);
1768 if (action == "delete" || !ok) {
1769 myCurrentEdge = nullptr;
1770 return;
1771 }
1772 myCurrentEdge = new Edge(id);
1773 }
1774 // parse "nd" (node) elements
1775 if (element == SUMO_TAG_ND && myCurrentEdge != nullptr) {
1776 bool ok = true;
1777 long long int ref = attrs.get<long long int>(SUMO_ATTR_REF, nullptr, ok);
1778 if (ok) {
1779 auto node = myOSMNodes.find(ref);
1780 if (node == myOSMNodes.end()) {
1781 WRITE_WARNINGF(TL("The referenced geometry information (ref='%') is not known"), toString(ref));
1782 return;
1783 }
1784
1785 ref = node->second->id; // node may have been substituted
1786 if (myCurrentEdge->myCurrentNodes.empty() ||
1787 myCurrentEdge->myCurrentNodes.back() != ref) { // avoid consecutive duplicates
1788 myCurrentEdge->myCurrentNodes.push_back(ref);
1789 }
1790
1791 }
1792 }
1793 if (element == SUMO_TAG_TAG && myCurrentEdge != nullptr) {
1794 bool ok = true;
1795 std::string key = attrs.get<std::string>(SUMO_ATTR_K, toString(myCurrentEdge->id).c_str(), ok, false);
1796 if (key.size() > 6 && StringUtils::startsWith(key, "busway:")) {
1797 // handle special busway keys
1798 const std::string buswaySpec = key.substr(7);
1799 key = "busway";
1800 if (buswaySpec == "right") {
1801 myCurrentEdge->myBuswayType = (WayType)(myCurrentEdge->myBuswayType | WAY_FORWARD);
1802 } else if (buswaySpec == "left") {
1803 myCurrentEdge->myBuswayType = (WayType)(myCurrentEdge->myBuswayType | WAY_BACKWARD);
1804 } else if (buswaySpec == "both") {
1805 myCurrentEdge->myBuswayType = (WayType)(myCurrentEdge->myBuswayType | WAY_BOTH);
1806 } else {
1807 key = "ignore";
1808 }
1809 }
1810 if (myAllAttributes && (myExtraAttributes.count(key) != 0 || myExtraAttributes.size() == 0)) {
1811 const std::string info = "way=" + toString(myCurrentEdge->id) + ", k=" + key;
1812 myCurrentEdge->setParameter(key, attrs.get<std::string>(SUMO_ATTR_V, info.c_str(), ok, false));
1813 }
1814 // we check whether the key is relevant (and we really need to transcode the value) to avoid hitting #1636
1815 if (!StringUtils::endsWith(key, "way")
1816 && !StringUtils::startsWith(key, "lanes")
1817 && key != "maxspeed" && key != "maxspeed:type"
1818 && key != "zone:maxspeed"
1819 && key != "maxspeed:forward" && key != "maxspeed:backward"
1820 && key != "junction" && key != "name" && key != "tracks" && key != "layer"
1821 && key != "route"
1822 && !StringUtils::startsWith(key, "cycleway")
1823 && !StringUtils::startsWith(key, "sidewalk")
1824 && key != "ref"
1825 && key != "highspeed"
1826 && !StringUtils::startsWith(key, "parking")
1827 && !StringUtils::startsWith(key, "change")
1828 && !StringUtils::startsWith(key, "vehicle:lanes")
1829 && key != "postal_code"
1830 && key != "railway:preferred_direction"
1831 && key != "railway:bidirectional"
1832 && key != "railway:track_ref"
1833 && key != "usage"
1834 && key != "access"
1835 && key != "emergency"
1836 && key != "service"
1837 && key != "electrified"
1838 && key != "segregated"
1839 && key != "bus"
1840 && key != "psv"
1841 && key != "foot"
1842 && key != "bicycle"
1843 && key != "oneway:bicycle"
1844 && key != "oneway:bus"
1845 && key != "oneway:psv"
1846 && key != "bus:lanes"
1847 && key != "bus:lanes:forward"
1848 && key != "bus:lanes:backward"
1849 && key != "psv:lanes"
1850 && key != "psv:lanes:forward"
1851 && key != "psv:lanes:backward"
1852 && key != "bicycle:lanes"
1853 && key != "bicycle:lanes:forward"
1854 && key != "bicycle:lanes:backward"
1855 && !StringUtils::startsWith(key, "width")
1856 && !(StringUtils::startsWith(key, "turn:") && key.find(":lanes") != std::string::npos)
1857 && key != "public_transport") {
1858 return;
1859 }
1860 const std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentEdge->id).c_str(), ok, false);
1861
1862 if (key == "highway" || key == "railway" || key == "waterway" || StringUtils::startsWith(key, "cycleway")
1863 || key == "busway" || key == "route" || StringUtils::startsWith(key, "sidewalk") || key == "highspeed"
1864 || key == "aeroway" || key == "aerialway" || key == "usage" || key == "service") {
1865 // build type id
1866 if (key != "highway" || myTypeCont.knows(key + "." + value)) {
1867 myCurrentEdge->myCurrentIsRoad = true;
1868 }
1869 // special cycleway stuff https://wiki.openstreetmap.org/wiki/Key:cycleway
1870 if (key == "cycleway") {
1871 if (value == "no" || value == "none" || value == "separate") {
1872 myCurrentEdge->myCyclewayType = WAY_NONE;
1873 } else if (value == "both") {
1874 myCurrentEdge->myCyclewayType = WAY_BOTH;
1875 } else if (value == "right") {
1876 myCurrentEdge->myCyclewayType = WAY_FORWARD;
1877 } else if (value == "left") {
1878 myCurrentEdge->myCyclewayType = WAY_BACKWARD;
1879 } else if (value == "opposite_track") {
1880 myCurrentEdge->myCyclewayType = WAY_BACKWARD;
1881 } else if (value == "opposite_lane") {
1882 myCurrentEdge->myCyclewayType = WAY_BACKWARD;
1883 } else if (value == "opposite") {
1884 // according to the wiki ref above, this should rather be a bidi lane, see #13438
1885 myCurrentEdge->myCyclewayType = WAY_BACKWARD;
1886 }
1887 }
1888 if (key == "cycleway:left") {
1889 if (myCurrentEdge->myCyclewayType == WAY_UNKNOWN) {
1890 myCurrentEdge->myCyclewayType = WAY_NONE;
1891 }
1892 if (value == "yes" || value == "lane" || value == "track") {
1893 myCurrentEdge->myCyclewayType = (WayType)(myCurrentEdge->myCyclewayType | WAY_BACKWARD);
1894 }
1895 key = "cycleway"; // for type adaption
1896 }
1897 if (key == "cycleway:right") {
1898 if (myCurrentEdge->myCyclewayType == WAY_UNKNOWN) {
1899 myCurrentEdge->myCyclewayType = WAY_NONE;
1900 }
1901 if (value == "yes" || value == "lane" || value == "track") {
1902 myCurrentEdge->myCyclewayType = (WayType)(myCurrentEdge->myCyclewayType | WAY_FORWARD);
1903 }
1904 key = "cycleway"; // for type adaption
1905 }
1906 if (key == "cycleway:both") {
1907 if (myCurrentEdge->myCyclewayType == WAY_UNKNOWN) {
1908 if (value == "no" || value == "none" || value == "separate") {
1909 myCurrentEdge->myCyclewayType = WAY_NONE;
1910 }
1911 if (value == "yes" || value == "lane" || value == "track") {
1912 myCurrentEdge->myCyclewayType = WAY_BOTH;
1913 }
1914 }
1915 key = "cycleway"; // for type adaption
1916 }
1917 if (key == "cycleway" && value != "lane" && value != "track" && value != "opposite_track" && value != "opposite_lane") {
1918 // typemap covers only the lane and track cases
1919 return;
1920 }
1921 if (StringUtils::startsWith(key, "cycleway:")) {
1922 // no need to extend the type id for other cycleway sub tags
1923 return;
1924 }
1925 // special sidewalk stuff
1926 if (key == "sidewalk") {
1927 if (value == "no" || value == "none" || value == "separate") {
1928 myCurrentEdge->mySidewalkType = WAY_NONE;
1929 } else if (value == "both") {
1930 myCurrentEdge->mySidewalkType = WAY_BOTH;
1931 } else if (value == "right") {
1932 myCurrentEdge->mySidewalkType = WAY_FORWARD;
1933 } else if (value == "left") {
1934 myCurrentEdge->mySidewalkType = WAY_BACKWARD;
1935 }
1936 }
1937 if (key == "sidewalk:left") {
1938 if (myCurrentEdge->mySidewalkType == WAY_UNKNOWN) {
1939 myCurrentEdge->mySidewalkType = WAY_NONE;
1940 }
1941 if (value == "yes") {
1942 myCurrentEdge->mySidewalkType = (WayType)(myCurrentEdge->mySidewalkType | WAY_BACKWARD);
1943 }
1944 }
1945 if (key == "sidewalk:right") {
1946 if (myCurrentEdge->mySidewalkType == WAY_UNKNOWN) {
1947 myCurrentEdge->mySidewalkType = WAY_NONE;
1948 }
1949 if (value == "yes") {
1950 myCurrentEdge->mySidewalkType = (WayType)(myCurrentEdge->mySidewalkType | WAY_FORWARD);
1951 }
1952 }
1953 if (key == "sidewalk:both") {
1954 if (myCurrentEdge->mySidewalkType == WAY_UNKNOWN) {
1955 if (value == "no" || value == "none" || value == "separate") {
1956 myCurrentEdge->mySidewalkType = WAY_NONE;
1957 }
1958 if (value == "yes") {
1959 myCurrentEdge->mySidewalkType = WAY_BOTH;
1960 }
1961 }
1962 }
1963 if (StringUtils::startsWith(key, "sidewalk")) {
1964 // no need to extend the type id
1965 return;
1966 }
1967 // special busway stuff
1968 if (key == "busway") {
1969 if (value == "no") {
1970 return;
1971 }
1972 if (value == "opposite_track") {
1973 myCurrentEdge->myBuswayType = WAY_BACKWARD;
1974 } else if (value == "opposite_lane") {
1975 myCurrentEdge->myBuswayType = WAY_BACKWARD;
1976 }
1977 // no need to extend the type id
1978 return;
1979 }
1980 std::string singleTypeID = key + "." + value;
1981 if (key == "highspeed") {
1982 if (value == "no") {
1983 return;
1984 }
1985 singleTypeID = "railway.highspeed";
1986 }
1987 addType(singleTypeID);
1988
1989 } else if (key == "bus" || key == "psv") {
1990 // 'psv' includes taxi in the UK but not in germany
1991 try {
1992 if (StringUtils::toBool(value)) {
1993 myCurrentEdge->myExtraAllowed |= SVC_BUS;
1994 addType(key);
1995 } else {
1996 myCurrentEdge->myExtraDisallowed |= SVC_BUS;
1997 }
1998 } catch (const BoolFormatException&) {
1999 myCurrentEdge->myExtraAllowed |= SVC_BUS;
2000 addType(key);
2001 }
2002 } else if (key == "emergency") {
2003 try {
2004 if (StringUtils::toBool(value)) {
2005 myCurrentEdge->myExtraAllowed |= SVC_AUTHORITY | SVC_EMERGENCY;
2006 }
2007 } catch (const BoolFormatException&) {
2008 myCurrentEdge->myExtraAllowed |= SVC_AUTHORITY | SVC_EMERGENCY;
2009 }
2010 } else if (key == "access") {
2011 if (value == "no") {
2012 myCurrentEdge->myExtraDisallowed |= ~(SVC_PUBLIC_CLASSES | SVC_EMERGENCY | SVC_AUTHORITY);
2013 }
2014 } else if (StringUtils::startsWith(key, "width:lanes")) {
2015 try {
2016 const std::vector<std::string> values = StringTokenizer(value, "|").getVector();
2017 std::vector<double> widthLanes;
2018 for (std::string width : values) {
2019 const double parsedWidth = width == "" ? -1 : StringUtils::parseDist(width);
2020 widthLanes.push_back(parsedWidth);
2021 }
2022
2023 if (key == "width:lanes" || key == "width:lanes:forward") {
2024 myCurrentEdge->myWidthLanesForward = widthLanes;
2025 } else if (key == "width:lanes:backward") {
2026 myCurrentEdge->myWidthLanesBackward = widthLanes;
2027 } else {
2028 WRITE_WARNINGF(TL("Using default lane width for edge '%' as key '%' could not be parsed."), toString(myCurrentEdge->id), key);
2029 }
2030 } catch (const NumberFormatException&) {
2031 WRITE_WARNINGF(TL("Using default lane width for edge '%' as value '%' could not be parsed."), toString(myCurrentEdge->id), value);
2032 }
2033 } else if (key == "width") {
2034 try {
2035 myCurrentEdge->myWidth = StringUtils::parseDist(value);
2036 } catch (const NumberFormatException&) {
2037 WRITE_WARNINGF(TL("Using default width for edge '%' as value '%' could not be parsed."), toString(myCurrentEdge->id), value);
2038 }
2039 } else if (key == "foot") {
2040 if (value == "use_sidepath" || value == "no") {
2041 myCurrentEdge->myExtraDisallowed |= SVC_PEDESTRIAN;
2042 } else if (value == "yes" || value == "designated" || value == "permissive") {
2043 myCurrentEdge->myExtraAllowed |= SVC_PEDESTRIAN;
2044 }
2045 } else if (key == "bicycle") {
2046 if (value == "use_sidepath" || value == "no") {
2047 myCurrentEdge->myExtraDisallowed |= SVC_BICYCLE;
2048 } else if (value == "yes" || value == "designated" || value == "permissive") {
2049 myCurrentEdge->myExtraAllowed |= SVC_BICYCLE;
2050 }
2051 } else if (key == "oneway:bicycle") {
2052 myCurrentEdge->myExtraTags["oneway:bicycle"] = value;
2053 } else if (key == "oneway:bus" || key == "oneway:psv") {
2054 if (value == "no") {
2055 // need to add a bus way in reversed direction of way
2056 myCurrentEdge->myBuswayType = WAY_BACKWARD;
2057 }
2058 } else if (key == "lanes") {
2059 try {
2060 myCurrentEdge->myNoLanes = StringUtils::toInt(value);
2061 } catch (NumberFormatException&) {
2062 // might be a list of values
2063 StringTokenizer st(value, ";", true);
2064 std::vector<std::string> list = st.getVector();
2065 if (list.size() >= 2) {
2066 int minLanes = std::numeric_limits<int>::max();
2067 try {
2068 for (auto& i : list) {
2069 const int numLanes = StringUtils::toInt(StringUtils::prune(i));
2070 minLanes = MIN2(minLanes, numLanes);
2071 }
2072 myCurrentEdge->myNoLanes = minLanes;
2073 WRITE_WARNINGF(TL("Using minimum lane number from list (%) for edge '%'."), value, toString(myCurrentEdge->id));
2074 } catch (NumberFormatException&) {
2075 WRITE_WARNINGF(TL("Value of key '%' is not numeric ('%') in edge '%'."), key, value, myCurrentEdge->id);
2076 }
2077 }
2078 } catch (EmptyData&) {
2079 WRITE_WARNINGF(TL("Value of key '%' is not numeric ('%') in edge '%'."), key, value, myCurrentEdge->id);
2080 }
2081 } else if (key == "lanes:forward") {
2082 try {
2083 const int numLanes = StringUtils::toInt(value);
2084 if (myCurrentEdge->myNoLanesForward < 0 && myCurrentEdge->myNoLanes < 0) {
2085 // fix lane count in case only lanes:forward and lanes:backward are set
2086 myCurrentEdge->myNoLanes = numLanes - myCurrentEdge->myNoLanesForward;
2087 }
2088 myCurrentEdge->myNoLanesForward = numLanes;
2089 } catch (...) {
2090 WRITE_WARNINGF(TL("Value of key '%' is not numeric ('%') in edge '%'."), key, value, myCurrentEdge->id);
2091 }
2092 } else if (key == "lanes:backward") {
2093 try {
2094 const int numLanes = StringUtils::toInt(value);
2095 if (myCurrentEdge->myNoLanesForward > 0 && myCurrentEdge->myNoLanes < 0) {
2096 // fix lane count in case only lanes:forward and lanes:backward are set
2097 myCurrentEdge->myNoLanes = numLanes + myCurrentEdge->myNoLanesForward;
2098 }
2099 // denote backwards count with a negative sign
2100 myCurrentEdge->myNoLanesForward = -numLanes;
2101 } catch (...) {
2102 WRITE_WARNINGF(TL("Value of key '%' is not numeric ('%') in edge '%'."), key, value, myCurrentEdge->id);
2103 }
2104 } else if (myCurrentEdge->myMaxSpeed == MAXSPEED_UNGIVEN &&
2105 (key == "maxspeed" || key == "maxspeed:type" || key == "maxspeed:forward" || key == "zone:maxspeed")) {
2106 // both 'maxspeed' and 'maxspeed:type' may be given so we must take care not to overwrite an already seen value
2107 myCurrentEdge->myMaxSpeed = interpretSpeed(key, value);
2108 } else if (key == "maxspeed:backward" && myCurrentEdge->myMaxSpeedBackward == MAXSPEED_UNGIVEN) {
2109 myCurrentEdge->myMaxSpeedBackward = interpretSpeed(key, value);
2110 } else if (key == "junction") {
2111 if ((value == "roundabout" || value == "circular") && myCurrentEdge->myIsOneWay.empty()) {
2112 myCurrentEdge->myIsOneWay = "yes";
2113 }
2114 if (value == "roundabout") {
2115 myCurrentEdge->myAmInRoundabout = true;
2116 }
2117 } else if (key == "oneway") {
2118 myCurrentEdge->myIsOneWay = value;
2119 } else if (key == "name") {
2120 myCurrentEdge->streetName = value;
2121 } else if (key == "ref") {
2122 myCurrentEdge->ref = value;
2123 myCurrentEdge->setParameter("ref", value);
2124 } else if (key == "layer") {
2125 try {
2126 myCurrentEdge->myLayer = StringUtils::toInt(value);
2127 } catch (...) {
2128 WRITE_WARNINGF(TL("Value of key '%' is not numeric ('%') in edge '%'."), key, value, myCurrentEdge->id);
2129 }
2130 } else if (key == "tracks") {
2131 try {
2132 if (StringUtils::toInt(value) == 1) {
2133 myCurrentEdge->myIsOneWay = "true";
2134 } else {
2135 WRITE_WARNINGF(TL("Ignoring track count % for edge '%'."), value, myCurrentEdge->id);
2136 }
2137 } catch (...) {
2138 WRITE_WARNINGF(TL("Value of key '%' is not numeric ('%') in edge '%'."), key, value, myCurrentEdge->id);
2139 }
2140 } else if (key == "railway:preferred_direction") {
2141 if (value == "both") {
2142 myCurrentEdge->myRailDirection = WAY_BOTH;
2143 } else if (myCurrentEdge->myRailDirection == WAY_UNKNOWN) {
2144 if (value == "backward") {
2145 myCurrentEdge->myRailDirection = WAY_BACKWARD;
2146 } else if (value == "forward") {
2147 myCurrentEdge->myRailDirection = WAY_FORWARD;
2148 }
2149 }
2150 } else if (key == "railway:bidirectional") {
2151 if (value == "regular") {
2152 myCurrentEdge->myRailDirection = WAY_BOTH;
2153 }
2154 } else if (key == "electrified" || key == "segregated") {
2155 if (value != "no") {
2156 myCurrentEdge->myExtraTags[key] = value;
2157 }
2158 } else if (key == "railway:track_ref") {
2159 myCurrentEdge->setParameter(key, value);
2160 } else if (key == "public_transport" && value == "platform") {
2161 myCurrentEdge->myExtraTags["platform"] = "yes";
2162 } else if ((key == "parking:both" || key == "parking:lane:both") && !StringUtils::startsWith(value, "no")) {
2163 myCurrentEdge->myParkingType |= PARKING_BOTH;
2164 } else if ((key == "parking:left" || key == "parking:lane:left") && !StringUtils::startsWith(value, "no")) {
2165 myCurrentEdge->myParkingType |= PARKING_LEFT;
2166 } else if ((key == "parking:right" || key == "parking:lane:right") && !StringUtils::startsWith(value, "no")) {
2167 myCurrentEdge->myParkingType |= PARKING_RIGHT;
2168 } else if (key == "change" || key == "change:lanes") {
2169 myCurrentEdge->myChangeForward = myCurrentEdge->myChangeBackward = interpretChangeType(value);
2170 } else if (key == "change:forward" || key == "change:lanes:forward") {
2171 myCurrentEdge->myChangeForward = interpretChangeType(value);
2172 } else if (key == "change:backward" || key == "change:lanes:backward") {
2173 myCurrentEdge->myChangeBackward = interpretChangeType(value);
2174 } else if (key == "vehicle:lanes" || key == "vehicle:lanes:forward") {
2175 interpretLaneUse(value, SVC_PASSENGER, true);
2176 interpretLaneUse(value, SVC_PRIVATE, true);
2177 } else if (key == "vehicle:lanes:backward") {
2178 interpretLaneUse(value, SVC_PASSENGER, false);
2179 interpretLaneUse(value, SVC_PRIVATE, false);
2180 } else if (key == "bus:lanes" || key == "bus:lanes:forward") {
2181 interpretLaneUse(value, SVC_BUS, true);
2182 } else if (key == "bus:lanes:backward") {
2183 interpretLaneUse(value, SVC_BUS, false);
2184 } else if (key == "psv:lanes" || key == "psv:lanes:forward") {
2185 interpretLaneUse(value, SVC_BUS, true);
2186 interpretLaneUse(value, SVC_TAXI, true);
2187 } else if (key == "psv:lanes:backward") {
2188 interpretLaneUse(value, SVC_BUS, false);
2189 interpretLaneUse(value, SVC_TAXI, false);
2190 } else if (key == "bicycle:lanes" || key == "bicycle:lanes:forward") {
2191 interpretLaneUse(value, SVC_BICYCLE, true);
2192 } else if (key == "bicycle:lanes:backward") {
2193 interpretLaneUse(value, SVC_BICYCLE, false);
2194 } else if (StringUtils::startsWith(key, "turn:") && key.find(":lanes") != std::string::npos) {
2195 int shift = 0;
2196 // use the first 8 bit to encode permitted directions for all classes
2197 // and the successive 8 bit blocks for selected classes
2198 if (StringUtils::startsWith(key, "turn:bus") || StringUtils::startsWith(key, "turn:psv:")) {
2200 } else if (StringUtils::startsWith(key, "turn:taxi")) {
2202 } else if (StringUtils::startsWith(key, "turn:bicycle")) {
2204 }
2205 const std::vector<std::string> values = StringTokenizer(value, "|").getVector();
2206 std::vector<int> turnCodes;
2207 for (std::string codeList : values) {
2208 const std::vector<std::string> codes = StringTokenizer(codeList, ";").getVector();
2209 int turnCode = 0;
2210 if (codes.size() == 0) {
2211 turnCode = (int)LinkDirection::STRAIGHT;
2212 }
2213 for (std::string code : codes) {
2214 if (code == "" || code == "none" || code == "through") {
2215 turnCode |= (int)LinkDirection::STRAIGHT << shift ;
2216 } else if (code == "left" || code == "sharp_left") {
2217 turnCode |= (int)LinkDirection::LEFT << shift;
2218 } else if (code == "right" || code == "sharp_right") {
2219 turnCode |= (int)LinkDirection::RIGHT << shift;
2220 } else if (code == "slight_left") {
2221 turnCode |= (int)LinkDirection::PARTLEFT << shift;
2222 } else if (code == "slight_right") {
2223 turnCode |= (int)LinkDirection::PARTRIGHT << shift;
2224 } else if (code == "reverse") {
2225 turnCode |= (int)LinkDirection::TURN << shift;
2226 } else if (code == "merge_to_left" || code == "merge_to_right") {
2227 turnCode |= (int)LinkDirection::NODIR << shift;
2228 }
2229 }
2230 turnCodes.push_back(turnCode);
2231 }
2232 if (StringUtils::endsWith(key, "lanes") || StringUtils::endsWith(key, "lanes:forward")) {
2233 mergeTurnSigns(myCurrentEdge->myTurnSignsForward, turnCodes);
2234 } else if (StringUtils::endsWith(key, "lanes:backward")) {
2235 mergeTurnSigns(myCurrentEdge->myTurnSignsBackward, turnCodes);
2236 } else if (StringUtils::endsWith(key, "lanes:both_ways")) {
2237 mergeTurnSigns(myCurrentEdge->myTurnSignsForward, turnCodes);
2238 mergeTurnSigns(myCurrentEdge->myTurnSignsBackward, turnCodes);
2239 }
2240 }
2241 }
2242}
2243
2244
2245void
2246NIImporter_OpenStreetMap::EdgesHandler::addType(const std::string& singleTypeID) {
2247 // special case: never build compound type for highspeed rail
2248 if (!myCurrentEdge->myHighWayType.empty() && singleTypeID != "railway.highspeed") {
2249 if (myCurrentEdge->myHighWayType == "railway.highspeed") {
2250 return;
2251 }
2252 // osm-ways may be used by more than one mode (eg railway.tram + highway.residential. this is relevant for multimodal traffic)
2253 // we create a new type for this kind of situation which must then be resolved in insertEdge()
2254 std::vector<std::string> types = StringTokenizer(myCurrentEdge->myHighWayType,
2256 types.push_back(singleTypeID);
2257 myCurrentEdge->myHighWayType = joinToStringSorting(types, compoundTypeSeparator);
2258 } else {
2259 myCurrentEdge->myHighWayType = singleTypeID;
2260 }
2261}
2262
2263
2264double
2265NIImporter_OpenStreetMap::EdgesHandler::interpretSpeed(const std::string& key, std::string value) {
2266 if (mySpeedMap.find(value) != mySpeedMap.end()) {
2267 return mySpeedMap[value];
2268 } else {
2269 // handle symbolic names of the form DE:30 / DE:zone30
2270 if (value.size() > 3 && value[2] == ':') {
2271 if (value.substr(3, 4) == "zone") {
2272 value = value.substr(7);
2273 } else {
2274 value = value.substr(3);
2275 }
2276 }
2277 try {
2278 return StringUtils::parseSpeed(value);
2279 } catch (...) {
2280 WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" +
2281 toString(myCurrentEdge->id) + "'.");
2282 return MAXSPEED_UNGIVEN;
2283 }
2284 }
2285}
2286
2287
2288int
2290 int result = 0;
2291 const std::vector<std::string> values = StringTokenizer(value, "|").getVector();
2292 for (const std::string& val : values) {
2293 if (val == "no") {
2294 result += CHANGE_NO;
2295 } else if (val == "not_left") {
2296 result += CHANGE_NO_LEFT;
2297 } else if (val == "not_right") {
2298 result += CHANGE_NO_RIGHT;
2299 }
2300 result = result << 2;
2301 }
2302 // last shift was superfluous
2303 result = result >> 2;
2304
2305 if (values.size() > 1) {
2306 result += 2 << 29; // mark multi-value input
2307 }
2308 //std::cout << " way=" << myCurrentEdge->id << " value=" << value << " result=" << std::bitset<32>(result) << "\n";
2309 return result;
2310}
2311
2312
2313void
2314NIImporter_OpenStreetMap::EdgesHandler::interpretLaneUse(const std::string& value, SUMOVehicleClass svc, const bool forward) const {
2315 const std::vector<std::string> values = StringTokenizer(value, "|").getVector();
2316 std::vector<bool>& designated = forward ? myCurrentEdge->myDesignatedLaneForward : myCurrentEdge->myDesignatedLaneBackward;
2317 std::vector<SVCPermissions>& allowed = forward ? myCurrentEdge->myAllowedLaneForward : myCurrentEdge->myAllowedLaneBackward;
2318 std::vector<SVCPermissions>& disallowed = forward ? myCurrentEdge->myDisallowedLaneForward : myCurrentEdge->myDisallowedLaneBackward;
2319 designated.resize(MAX2(designated.size(), values.size()), false);
2320 allowed.resize(MAX2(allowed.size(), values.size()), SVC_IGNORING);
2321 disallowed.resize(MAX2(disallowed.size(), values.size()), SVC_IGNORING);
2322 int i = 0;
2323 for (const std::string& val : values) {
2324 if (val == "yes" || val == "permissive") {
2325 allowed[i] |= svc;
2326 } else if (val == "lane" || val == "designated") {
2327 allowed[i] |= svc;
2328 designated[i] = true;
2329 } else if (val == "no") {
2330 disallowed[i] |= svc;
2331 } else {
2332 WRITE_WARNINGF(TL("Unknown lane use specifier '%' ignored for way '%'"), val, myCurrentEdge->id);
2333 }
2334 i++;
2335 }
2336}
2337
2338
2339void
2341 if (element == SUMO_TAG_WAY && myCurrentEdge != nullptr) {
2342 if (myCurrentEdge->myCurrentIsRoad) {
2343 const auto insertionIt = myEdgeMap.lower_bound(myCurrentEdge->id);
2344 if (insertionIt == myEdgeMap.end() || insertionIt->first != myCurrentEdge->id) {
2345 // assume we are loading multiple files, so we won't report duplicate edges
2346 myEdgeMap.emplace_hint(insertionIt, myCurrentEdge->id, myCurrentEdge);
2347 } else {
2348 delete myCurrentEdge;
2349 }
2350 } else if (myCurrentEdge->myExtraTags.count("platform") != 0) {
2351 const auto insertionIt = myPlatformShapesMap.lower_bound(myCurrentEdge->id);
2352 if (insertionIt == myPlatformShapesMap.end() || insertionIt->first != myCurrentEdge->id) {
2353 // assume we are loading multiple files, so we won't report duplicate platforms
2354 myPlatformShapesMap.emplace_hint(insertionIt, myCurrentEdge->id, myCurrentEdge);
2355 } else {
2356 delete myCurrentEdge;
2357 }
2358 } else {
2359 delete myCurrentEdge;
2360 }
2361 myCurrentEdge = nullptr;
2362 }
2363}
2364
2365
2366// ---------------------------------------------------------------------------
2367// definitions of NIImporter_OpenStreetMap::RelationHandler-methods
2368// ---------------------------------------------------------------------------
2370 const std::map<long long int, NIOSMNode*>& osmNodes,
2371 const std::map<long long int, Edge*>& osmEdges, NBPTStopCont* nbptStopCont,
2372 const std::map<long long int, Edge*>& platformShapes,
2373 NBPTLineCont* nbptLineCont,
2374 const OptionsCont& oc) :
2375 SUMOSAXHandler("osm - file"),
2376 myOSMNodes(osmNodes),
2377 myOSMEdges(osmEdges),
2378 myPlatformShapes(platformShapes),
2379 myNBPTStopCont(nbptStopCont),
2380 myNBPTLineCont(nbptLineCont),
2381 myOptionsCont(oc) {
2382 resetValues();
2383}
2384
2385
2387
2388
2389void
2391 myCurrentRelation = INVALID_ID;
2392 myIsRestriction = false;
2393 myRestrictionException = SVC_IGNORING;
2394 myFromWay = INVALID_ID;
2395 myToWay = INVALID_ID;
2396 myViaNode = INVALID_ID;
2397 myViaWay = INVALID_ID;
2398 myStation = INVALID_ID;
2399 myRestrictionType = RestrictionType::UNKNOWN;
2400 myPlatforms.clear();
2401 myStops.clear();
2402 myPlatformStops.clear();
2403 myWays.clear();
2404 myIsStopArea = false;
2405 myIsRoute = false;
2406 myPTRouteType = "";
2407 myRouteColor.setValid(false);
2408}
2409
2410
2411void
2413 if (element == SUMO_TAG_RELATION) {
2414 bool ok = true;
2415 myCurrentRelation = attrs.get<long long int>(SUMO_ATTR_ID, nullptr, ok);
2416 const std::string& action = attrs.getOpt<std::string>(SUMO_ATTR_ACTION, nullptr, ok);
2417 if (action == "delete" || !ok) {
2418 myCurrentRelation = INVALID_ID;
2419 }
2420 myName = "";
2421 myRef = "";
2422 myInterval = -1;
2423 myNightService = "";
2424 return;
2425 }
2426 if (myCurrentRelation == INVALID_ID) {
2427 return;
2428 }
2429 if (element == SUMO_TAG_MEMBER) {
2430 bool ok = true;
2431 std::string role = attrs.hasAttribute("role") ? attrs.getStringSecure("role", "") : "";
2432 const long long int ref = attrs.get<long long int>(SUMO_ATTR_REF, nullptr, ok);
2433 if (role == "via") {
2434 // u-turns for divided ways may be given with 2 via-nodes or 1 via-way
2435 std::string memberType = attrs.get<std::string>(SUMO_ATTR_TYPE, nullptr, ok);
2436 if (memberType == "way" && checkEdgeRef(ref)) {
2437 myViaWay = ref;
2438 } else if (memberType == "node") {
2439 if (myOSMNodes.find(ref) != myOSMNodes.end()) {
2440 myViaNode = ref;
2441 } else {
2442 WRITE_WARNINGF(TL("No node found for reference '%' in relation '%'."), toString(ref), toString(myCurrentRelation));
2443 }
2444 }
2445 } else if (role == "from" && checkEdgeRef(ref)) {
2446 myFromWay = ref;
2447 } else if (role == "to" && checkEdgeRef(ref)) {
2448 myToWay = ref;
2449 } else if (StringUtils::startsWith(role, "stop")) {
2450 // permit _entry_only and _exit_only variants
2451 myStops.push_back(ref);
2452 } else if (StringUtils::startsWith(role, "platform")) {
2453 // permit _entry_only and _exit_only variants
2454 std::string memberType = attrs.get<std::string>(SUMO_ATTR_TYPE, nullptr, ok);
2455 if (memberType == "way") {
2456 const std::map<long long int, NIImporter_OpenStreetMap::Edge*>::const_iterator& wayIt = myPlatformShapes.find(ref);
2457 if (wayIt != myPlatformShapes.end()) {
2458 NIIPTPlatform platform;
2459 platform.isWay = true;
2460 platform.ref = ref;
2461 myPlatforms.push_back(platform);
2462 }
2463 } else if (memberType == "node") {
2464 // myIsStopArea may not be set yet
2465 myStops.push_back(ref);
2466 myPlatformStops.insert(ref);
2467 NIIPTPlatform platform;
2468 platform.isWay = false;
2469 platform.ref = ref;
2470 myPlatforms.push_back(platform);
2471 }
2472
2473 } else if (role == "station") {
2474 myStation = ref;
2475 } else if (role.empty()) {
2476 std::string memberType = attrs.get<std::string>(SUMO_ATTR_TYPE, nullptr, ok);
2477 if (memberType == "way") {
2478 myWays.push_back(ref);
2479 } else if (memberType == "node") {
2480 auto it = myOSMNodes.find(ref);
2481 if (it != myOSMNodes.end() && it->second->hasParameter("railway:ref")) {
2482 myStation = ref;
2483 } else {
2484 myStops.push_back(ref);
2485 }
2486 }
2487 }
2488 return;
2489 }
2490 // parse values
2491 if (element == SUMO_TAG_TAG) {
2492 bool ok = true;
2493 std::string key = attrs.get<std::string>(SUMO_ATTR_K, toString(myCurrentRelation).c_str(), ok, false);
2494 // we check whether the key is relevant (and we really need to transcode the value) to avoid hitting #1636
2495 if (key == "type" || key == "restriction") {
2496 std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
2497 if (key == "type" && value == "restriction") {
2498 myIsRestriction = true;
2499 return;
2500 }
2501 if (key == "type" && value == "route") {
2502 myIsRoute = true;
2503 return;
2504 }
2505 if (key == "restriction") {
2506 // @note: the 'right/left/straight' part is ignored since the information is
2507 // redundantly encoded in the 'from', 'to' and 'via' members
2508 if (value.substr(0, 5) == "only_") {
2509 myRestrictionType = RestrictionType::ONLY;
2510 } else if (value.substr(0, 3) == "no_") {
2511 myRestrictionType = RestrictionType::NO;
2512 } else {
2513 WRITE_WARNINGF(TL("Found unknown restriction type '%' in relation '%'"), value, toString(myCurrentRelation));
2514 }
2515 return;
2516 }
2517 } else if (key == "except") {
2518 std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
2519 for (const std::string& v : StringTokenizer(value, ";").getVector()) {
2520 if (v == "psv") {
2521 myRestrictionException |= SVC_BUS;
2522 } else if (v == "bicycle") {
2523 myRestrictionException |= SVC_BICYCLE;
2524 } else if (v == "hgv") {
2525 myRestrictionException |= SVC_TRUCK | SVC_TRAILER;
2526 } else if (v == "motorcar") {
2527 myRestrictionException |= SVC_PASSENGER | SVC_TAXI;
2528 } else if (v == "emergency") {
2529 myRestrictionException |= SVC_EMERGENCY;
2530 }
2531 }
2532 } else if (key == "public_transport") {
2533 std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
2534 if (value == "stop_area") {
2535 myIsStopArea = true;
2536 }
2537 } else if (key == "route") {
2538 std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
2539 if (value == "train" || value == "subway" || value == "light_rail" || value == "monorail" || value == "tram" || value == "bus"
2540 || value == "trolleybus" || value == "aerialway" || value == "ferry" || value == "share_taxi" || value == "minibus") {
2541 myPTRouteType = value;
2542 }
2543
2544 } else if (key == "name") {
2545 myName = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
2546 } else if (key == "colour") {
2547 std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
2548 try {
2549 myRouteColor = RGBColor::parseColor(value);
2550 } catch (...) {
2551 WRITE_WARNINGF(TL("Invalid color value '%' in relation %"), value, myCurrentRelation);
2552 }
2553 } else if (key == "ref") {
2554 myRef = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
2555 } else if (key == "interval" || key == "headway") {
2556 myInterval = attrs.get<int>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
2557 } else if (key == "by_night") {
2558 myNightService = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
2559 }
2560 }
2561}
2562
2563
2564bool
2566 if (myOSMEdges.find(ref) != myOSMEdges.end()) {
2567 return true;
2568 }
2569 WRITE_WARNINGF(TL("No way found for reference '%' in relation '%'"), toString(ref), toString(myCurrentRelation));
2570 return false;
2571}
2572
2573
2574void
2576 if (element == SUMO_TAG_RELATION) {
2577 if (myIsRestriction) {
2578 assert(myCurrentRelation != INVALID_ID);
2579 bool ok = true;
2580 if (myRestrictionType == RestrictionType::UNKNOWN) {
2581 WRITE_WARNINGF(TL("Ignoring restriction relation '%' with unknown type."), toString(myCurrentRelation));
2582 ok = false;
2583 }
2584 if (myFromWay == INVALID_ID) {
2585 WRITE_WARNINGF(TL("Ignoring restriction relation '%' with unknown from-way."), toString(myCurrentRelation));
2586 ok = false;
2587 }
2588 if (myToWay == INVALID_ID) {
2589 WRITE_WARNINGF(TL("Ignoring restriction relation '%' with unknown to-way."), toString(myCurrentRelation));
2590 ok = false;
2591 }
2592 if (myViaNode == INVALID_ID && myViaWay == INVALID_ID) {
2593 WRITE_WARNINGF(TL("Ignoring restriction relation '%' with unknown via."), toString(myCurrentRelation));
2594 ok = false;
2595 }
2596 if (ok && !applyRestriction()) {
2597 WRITE_WARNINGF(TL("Ignoring restriction relation '%'."), toString(myCurrentRelation));
2598 }
2599 } else if (myIsStopArea) {
2600 for (long long ref : myStops) {
2601 myStopAreas[ref] = myCurrentRelation;
2602 if (myOSMNodes.find(ref) == myOSMNodes.end()) {
2603 //WRITE_WARNING(
2604 // "Referenced node: '" + toString(ref) + "' in relation: '" + toString(myCurrentRelation)
2605 // + "' does not exist. Probably OSM file is incomplete.");
2606 continue;
2607 }
2608
2609 NIOSMNode* n = myOSMNodes.find(ref)->second;
2610 std::shared_ptr<NBPTStop> ptStop = myNBPTStopCont->get(toString(n->id));
2611 if (ptStop == nullptr) {
2612 //WRITE_WARNING(
2613 // "Relation '" + toString(myCurrentRelation) + "' refers to a non existing pt stop at node: '"
2614 // + toString(n->id) + "'. Probably OSM file is incomplete.");
2615 continue;
2616 }
2617 for (NIIPTPlatform& myPlatform : myPlatforms) {
2618 if (myPlatform.isWay) {
2619 assert(myPlatformShapes.find(myPlatform.ref) != myPlatformShapes.end()); //already tested earlier
2620 Edge* edge = (*myPlatformShapes.find(myPlatform.ref)).second;
2621 if (edge->myCurrentNodes.size() > 1 && edge->myCurrentNodes[0] == *(edge->myCurrentNodes.end() - 1)) {
2622 WRITE_WARNINGF(TL("Platform '%' in relation: '%' is given as polygon, which currently is not supported."), myPlatform.ref, myCurrentRelation);
2623 continue;
2624
2625 }
2627 for (auto nodeRef : edge->myCurrentNodes) {
2628 if (myOSMNodes.find(nodeRef) == myOSMNodes.end()) {
2629 //WRITE_WARNING(
2630 // "Referenced node: '" + toString(ref) + "' in relation: '" + toString(myCurrentRelation)
2631 // + "' does not exist. Probably OSM file is incomplete.");
2632 continue;
2633 }
2634 NIOSMNode* pNode = myOSMNodes.find(nodeRef)->second;
2635 Position pNodePos(pNode->lon, pNode->lat, pNode->ele);
2636 if (!NBNetBuilder::transformCoordinate(pNodePos)) {
2637 WRITE_ERRORF("Unable to project coordinates for node '%'.", pNode->id);
2638 continue;
2639 }
2640 p.push_back(pNodePos);
2641 }
2642 if (p.size() == 0) {
2643 WRITE_WARNINGF(TL("Referenced platform: '%' in relation: '%' is corrupt. Probably OSM file is incomplete."),
2644 toString(myPlatform.ref), toString(myCurrentRelation));
2645 continue;
2646 }
2647 NBPTPlatform platform(p[(int)p.size() / 2], p.length());
2648 ptStop->addPlatformCand(platform);
2649 } else {
2650 if (myOSMNodes.find(myPlatform.ref) == myOSMNodes.end()) {
2651 //WRITE_WARNING(
2652 // "Referenced node: '" + toString(ref) + "' in relation: '" + toString(myCurrentRelation)
2653 // + "' does not exist. Probably OSM file is incomplete.");
2654 continue;
2655 }
2656 NIOSMNode* pNode = myOSMNodes.find(myPlatform.ref)->second;
2657 Position platformPos(pNode->lon, pNode->lat, pNode->ele);
2658 if (!NBNetBuilder::transformCoordinate(platformPos)) {
2659 WRITE_ERRORF("Unable to project coordinates for node '%'.", pNode->id);
2660 }
2661 NBPTPlatform platform(platformPos, myOptionsCont.getFloat("osm.stop-output.length"));
2662 ptStop->addPlatformCand(platform);
2663
2664 }
2665 }
2666 ptStop->setIsMultipleStopPositions(myStops.size() > 1, myCurrentRelation);
2667 if (myStation != INVALID_ID) {
2668 const auto& nodeIt = myOSMNodes.find(myStation);
2669 if (nodeIt != myOSMNodes.end()) {
2670 NIOSMNode* station = nodeIt->second;
2671 if (station != nullptr) {
2672 if (station->hasParameter("railway:ref")) {
2673 ptStop->setParameter("stationRef", station->getParameter("railway:ref"));
2674 }
2675 }
2676 }
2677 }
2678 }
2679 } else if (myPTRouteType != "" && myIsRoute) {
2680 NBPTLine* ptLine = new NBPTLine(toString(myCurrentRelation), myName, myPTRouteType, myRef, myInterval, myNightService,
2681 interpretTransportType(myPTRouteType), myRouteColor);
2682 int consecutiveGap = false;
2683 int missingBefore = 0;
2684 int missingAfter = 0;
2685 for (long long ref : myStops) {
2686 const auto& nodeIt = myOSMNodes.find(ref);
2687 if (nodeIt == myOSMNodes.end()) {
2688 if (ptLine->getStops().empty()) {
2689 missingBefore++;
2690 } else {
2691 missingAfter++;
2692 consecutiveGap++;
2693 }
2694 continue;
2695 }
2696 // give some slack for single missing stops
2697 if (consecutiveGap > 1) {
2698 WRITE_WARNINGF(TL("PT line '%' in relation % has a gap of % stops, only keeping first part."), myName, myCurrentRelation, consecutiveGap);
2699 missingAfter = (int)myStops.size() - missingBefore - (int)ptLine->getStops().size();
2700 break;
2701 }
2702 // reset gap
2703 consecutiveGap = 0;
2704
2705 const NIOSMNode* const n = nodeIt->second;
2706 std::shared_ptr<NBPTStop> ptStop = myNBPTStopCont->get(toString(n->id));
2707 if (ptStop == nullptr) {
2708 // loose stop, which must later be mapped onto a line way
2709 Position ptPos(n->lon, n->lat, n->ele);
2711 WRITE_ERRORF("Unable to project coordinates for node '%'.", n->id);
2712 }
2714 ptStop = std::make_shared<NBPTStop>(stopElement, toString(n->id), ptPos, "", "", n->ptStopLength, n->name, n->permissions);
2715 myNBPTStopCont->insert(ptStop);
2716 if (myStopAreas.count(n->id)) {
2717 ptStop->setIsMultipleStopPositions(false, myStopAreas[n->id]);
2718 }
2719 if (myPlatformStops.count(n->id) > 0) {
2720 ptStop->setIsPlatform();
2721 }
2722 }
2723 ptLine->addPTStop(ptStop);
2724 }
2725 for (long long& myWay : myWays) {
2726 auto entr = myOSMEdges.find(myWay);
2727 if (entr != myOSMEdges.end()) {
2728 Edge* edge = entr->second;
2729 for (long long& myCurrentNode : edge->myCurrentNodes) {
2730 ptLine->addWayNode(myWay, myCurrentNode);
2731 }
2732 }
2733 }
2734 ptLine->setNumOfStops((int)myStops.size(), missingBefore, missingAfter);
2735 if (ptLine->getStops().empty()) {
2736 WRITE_WARNINGF(TL("PT line in relation % with no stops ignored. Probably OSM file is incomplete."), myCurrentRelation);
2737 delete ptLine;
2738 resetValues();
2739 return;
2740 }
2741 if (!myNBPTLineCont->insert(ptLine)) {
2742 WRITE_WARNINGF(TL("Ignoring duplicate PT line '%'."), myCurrentRelation);
2743 delete ptLine;
2744 }
2745 }
2746 // other relations might use similar subelements so reset in any case
2747 resetValues();
2748 }
2749}
2750
2751bool
2753 // since OSM ways are bidirectional we need the via to figure out which direction was meant
2754 if (myViaNode != INVALID_ID) {
2755 NBNode* viaNode = myOSMNodes.find(myViaNode)->second->node;
2756 if (viaNode == nullptr) {
2757 WRITE_WARNINGF(TL("Via-node '%' was not instantiated"), toString(myViaNode));
2758 return false;
2759 }
2760 NBEdge* from = findEdgeRef(myFromWay, viaNode->getIncomingEdges());
2761 NBEdge* to = findEdgeRef(myToWay, viaNode->getOutgoingEdges());
2762 if (from == nullptr) {
2763 WRITE_WARNINGF(TL("from-edge '%' of restriction relation could not be determined"), toString(myFromWay));
2764 return false;
2765 }
2766 if (to == nullptr) {
2767 WRITE_WARNINGF(TL("to-edge '%' of restriction relation could not be determined"), toString(myToWay));
2768 return false;
2769 }
2770 if (myRestrictionType == RestrictionType::ONLY) {
2771 from->addEdge2EdgeConnection(to, true);
2772 // make sure that these connections remain disabled even if network
2773 // modifications (ramps.guess) reset existing connections
2774 for (NBEdge* cand : from->getToNode()->getOutgoingEdges()) {
2775 if (!from->isConnectedTo(cand)) {
2776 if (myRestrictionException == SVC_IGNORING) {
2777 from->removeFromConnections(cand, -1, -1, true);
2778 } else {
2779 from->addEdge2EdgeConnection(cand, true, myRestrictionException);
2780 }
2781 }
2782 }
2783 } else {
2784 if (myRestrictionException == SVC_IGNORING) {
2785 from->removeFromConnections(to, -1, -1, true);
2786 } else {
2787 from->addEdge2EdgeConnection(to, true, myRestrictionException);
2788 for (NBEdge* cand : from->getToNode()->getOutgoingEdges()) {
2789 if (!from->isConnectedTo(cand)) {
2790 from->addEdge2EdgeConnection(cand, true);
2791 }
2792 }
2793 }
2794 }
2795 } else {
2796 // XXX interpreting via-ways or via-node lists not yet implemented
2797 WRITE_WARNINGF(TL("direction of restriction relation could not be determined%"), "");
2798 return false;
2799 }
2800 return true;
2801}
2802
2803NBEdge*
2805 const std::vector<NBEdge*>& candidates) const {
2806 const std::string prefix = toString(wayRef);
2807 const std::string backPrefix = "-" + prefix;
2808 NBEdge* result = nullptr;
2809 int found = 0;
2810 for (auto candidate : candidates) {
2811 if ((candidate->getID().substr(0, prefix.size()) == prefix) ||
2812 (candidate->getID().substr(0, backPrefix.size()) == backPrefix)) {
2813 result = candidate;
2814 found++;
2815 }
2816 }
2817 if (found > 1) {
2818 WRITE_WARNINGF(TL("Ambiguous way reference '%' in restriction relation"), prefix);
2819 result = nullptr;
2820 }
2821 return result;
2822}
2823
2824
2825/****************************************************************************/
#define WRITE_WARNINGF(...)
Definition MsgHandler.h:287
#define WRITE_MESSAGEF(...)
Definition MsgHandler.h:289
#define WRITE_ERRORF(...)
Definition MsgHandler.h:296
#define WRITE_ERROR(msg)
Definition MsgHandler.h:295
#define WRITE_WARNING(msg)
Definition MsgHandler.h:286
#define PROGRESS_BEGIN_TIME_MESSAGE(msg)
Definition MsgHandler.h:292
#define TL(string)
Definition MsgHandler.h:304
#define PROGRESS_TIME_MESSAGE(before)
Definition MsgHandler.h:293
#define PROGRESS_DONE_MESSAGE()
Definition MsgHandler.h:291
#define TLF(string,...)
Definition MsgHandler.h:306
#define PROGRESS_BEGIN_MESSAGE(msg)
Definition MsgHandler.h:290
std::vector< NBEdge * > EdgeVector
container for (sorted) edges
Definition NBCont.h:42
SVCPermissions extraDisallowed(SVCPermissions disallowed, const MMVersion &networkVersion)
Interprets disallowed vehicles depending on network version.
const SVCPermissions SVCAll
all VClasses are allowed
bool isRailway(SVCPermissions permissions)
Returns whether an edge with the given permissions is a (exclusive) railway edge.
StringBijection< SUMOVehicleClass > SumoVehicleClassStrings(sumoVehicleClassStringInitializer, SVC_CUSTOM2, false)
long long int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
SUMOVehicleClass
Definition of vehicle classes to differ between different lane usage and authority types.
@ SVC_SHIP
is an arbitrary ship
@ SVC_PRIVATE
private vehicles
@ SVC_TRUCK
vehicle is a large transport vehicle
@ SVC_ROAD_CLASSES
@ SVC_IGNORING
vehicles ignoring classes
@ SVC_RAIL
vehicle is a not electrified rail
@ SVC_RAIL_CLASSES
classes which drive on tracks
@ SVC_CABLE_CAR
@ 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_TRAILER
vehicle is a large transport vehicle
@ SVC_RAIL_ELECTRIC
rail vehicle that requires electrified tracks
@ SVC_RAIL_URBAN
vehicle is a city rail
@ SVC_EMERGENCY
public emergency vehicles
@ SVC_AUTHORITY
authorities vehicles
@ SVC_TRAM
vehicle is a light rail
@ SVC_PUBLIC_CLASSES
public transport
@ SVC_TAXI
vehicle is a taxi
@ SVC_BUS
vehicle is a bus
@ SVC_SUBWAY
@ SVC_PEDESTRIAN
pedestrian
SumoXMLTag
Numbers representing SUMO-XML - element names.
@ SUMO_TAG_MEMBER
@ SUMO_TAG_BUS_STOP
A bus stop.
@ SUMO_TAG_ND
@ SUMO_TAG_WAY
@ SUMO_TAG_TRAIN_STOP
A train stop (alias for bus stop)
@ 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_SPEED
@ SUMO_ATTR_V
@ SUMO_ATTR_NUMLANES
@ 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:52
T MIN2(T a, T b)
Definition StdDefs.h:80
T MAX2(T a, T b)
Definition StdDefs.h:86
std::string joinToStringSorting(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition ToString.h:305
std::string joinToString(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition ToString.h:289
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.
void setFileName(const std::string &name)
Sets the current file name.
bool wasInformed() const
Returns the information whether any messages were added.
static MsgHandler * getErrorInstance()
Returns the instance to add errors to.
Storage for edges, including some functionality operating on multiple edges.
Definition NBEdgeCont.h:59
int extractRoundabouts()
Determines which edges have been marked as roundabouts and stores them internally.
bool insert(NBEdge *edge, bool ignorePrunning=false)
Adds an edge to the dictionary.
The representation of a single edge during network building.
Definition NBEdge.h:92
static const int TURN_SIGN_SHIFT_BUS
shift values for decoding turn signs
Definition NBEdge.h:379
static const int TURN_SIGN_SHIFT_BICYCLE
Definition NBEdge.h:381
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:4531
SVCPermissions getPermissions(int lane=-1) const
get the union of allowed classes over all lanes or for a specific lane
Definition NBEdge.cpp:4540
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:4503
@ ROUNDABOUT
Definition NBEdge.h:387
void addBikeLane(double width)
add a bicycle lane of the given width and shift existing connctions
Definition NBEdge.cpp:4746
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:355
Lane & getLaneStruct(int lane)
Definition NBEdge.h:1451
const PositionVector & getGeometry() const
Returns the geometry of the edge.
Definition NBEdge.h:789
bool addEdge2EdgeConnection(NBEdge *dest, bool overrideRemoval=false, SVCPermissions permission=SVC_UNSPECIFIED)
Adds a connection to another edge.
Definition NBEdge.cpp:1120
void setTurnSignTarget(const std::string &target)
Definition NBEdge.h:1580
void setDistance(double distance)
set kilometrage at start of edge (negative value implies couting down along the edge)
Definition NBEdge.h:1425
const std::vector< NBEdge::Lane > & getLanes() const
Returns the lane definitions.
Definition NBEdge.h:736
const std::string & getID() const
Definition NBEdge.h:1551
void setLaneWidth(int lane, double width)
set lane specific width (negative lane implies set for all lanes)
Definition NBEdge.cpp:4326
void addSidewalk(double width)
add a pedestrian sidewalk of the given width and shift existing connctions
Definition NBEdge.cpp:4734
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:1471
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:1354
static const int TURN_SIGN_SHIFT_TAXI
Definition NBEdge.h:380
void preferVehicleClass(int lane, SVCPermissions vclasses)
prefer certain vehicle classes for the given lane or for all lanes if -1 is given (ensures also permi...
Definition NBEdge.cpp:4312
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:346
void setRoutingType(const std::string &routingType)
set the routingType for this edge
Definition NBEdge.h:1441
static const double UNSPECIFIED_OFFSET
unspecified lane offset
Definition NBEdge.h:349
void setJunctionPriority(const NBNode *const node, int prio)
Sets the junction priority of the edge.
Definition NBEdge.cpp:2167
void setGeometry(const PositionVector &g, bool inner=false)
(Re)sets the edge's geometry
Definition NBEdge.cpp:660
Instance responsible for building networks.
static bool transformCoordinates(PositionVector &from, bool includeInBoundary=true, GeoConvHelper *from_srs=nullptr)
NBPTLineCont & getPTLineCont()
Returns a reference to the pt line container.
NBParkingCont & getParkingCont()
NBPTStopCont & getPTStopCont()
Returns a reference to the pt stop container.
NBNodeCont & getNodeCont()
Returns a reference to the node container.
NBEdgeCont & getEdgeCont()
NBTypeCont & getTypeCont()
Returns a reference to the type container.
NBTrafficLightLogicCont & getTLLogicCont()
Returns a reference to the traffic light logics container.
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:57
bool insert(const std::string &id, const Position &position, NBDistrict *district=0)
Inserts a node into the map.
NBNode * retrieve(const std::string &id) const
Returns the node with the given name.
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:1995
NBNode::Crossing * addCrossing(EdgeVector edges, double width, bool priority, int tlIndex=-1, int tlIndex2=-1, const PositionVector &customShape=PositionVector::EMPTY, bool fromSumoNet=false, const Parameterised *params=nullptr)
add a pedestrian crossing to this node
Definition NBNode.cpp:4083
void reinit(const Position &position, SumoXMLNodeType type, bool updateEdgeGeometries=false)
Resets initial values.
Definition NBNode.cpp:353
SumoXMLNodeType getType() const
Returns the type of this node.
Definition NBNode.h:285
const EdgeVector & getIncomingEdges() const
Returns this node's incoming edges (The edges which yield in this node)
Definition NBNode.h:268
const EdgeVector & getOutgoingEdges() const
Returns this node's outgoing edges (The edges which start at this node)
Definition NBNode.h:273
bool checkCrossingDuplicated(EdgeVector edges)
return true if there already exist a crossing with the same edges as the input
Definition NBNode.cpp:3022
const Position & getPosition() const
Definition NBNode.h:260
const EdgeVector & getEdges() const
Returns all edges which participate in this node (Edges that start or end at this node)
Definition NBNode.h:278
static const int FORWARD
edge directions (for pedestrian related stuff)
Definition NBNode.h:216
void setFringeType(FringeType fringeType)
set fringe type
Definition NBNode.h:586
A traffic light logics which must be computed (only nodes/edges are given)
Definition NBOwnTLDef.h:44
void setNumOfStops(int numStops, int missingBefore, int missingAfter)
Definition NBPTLine.cpp:166
void addWayNode(long long int way, long long int node)
Definition NBPTLine.cpp:121
const std::vector< std::shared_ptr< NBPTStop > > & getStops()
Definition NBPTLine.cpp:68
void addPTStop(std::shared_ptr< NBPTStop > pStop)
Definition NBPTLine.cpp:54
Container for public transport stops during the net building process.
int cleanupDeleted(NBEdgeCont &cont)
remove stops on non existing (removed) edges
const std::map< std::string, std::shared_ptr< NBPTStop > > & getStops() const
Returns an unmodifiable reference to the stored pt stops.
std::shared_ptr< NBPTStop > get(std::string id) const
Retrieve a previously inserted pt stop.
bool insert(std::shared_ptr< NBPTStop > ptStop, bool floating=false)
Inserts a node into the map.
The representation of an imported parking area.
Definition NBParking.h:42
static const std::string OSM_DIRECTION
processing parameter for rail signal edges and nodes
static const std::string OSM_SIGNAL_DIRECTION
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.
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.
bool copyEdgeTypeRestrictionsAndAttrs(const std::string &fromId, const std::string &toId)
Copy restrictions to a edgeType.
double getEdgeTypeSpeed(const std::string &edgeType) const
Returns the maximal velocity for the given edgeType [m/s].
int getEdgeTypePriority(const std::string &edgeType) const
Returns the priority for the given edgeType.
int getEdgeTypeNumLanes(const std::string &edgeType) const
Returns the number of lanes for the given edgeType.
double getEdgeTypeWidth(const std::string &edgeType) const
Returns the lane width for the given edgeType [m].
SVCPermissions getEdgeTypePermissions(const std::string &edgeType) const
Returns allowed vehicle classes for the given edgeType.
bool knows(const std::string &edgeType) const
Returns whether the named edgeType is in the container.
double getEdgeTypeSidewalkWidth(const std::string &edgeType) const
Returns the lane width for a sidewalk to be added [m].
LaneSpreadFunction getEdgeTypeSpreadType(const std::string &edgeType) const
Returns spreadType for the given edgeType.
double getEdgeTypeBikeLaneWidth(const std::string &edgeType) const
Returns the lane width for a bike lane to be added [m].
bool getEdgeTypeIsOneWay(const std::string &edgeType) const
Returns whether edges are one-way per default for the given edgeType.
bool operator()(const Edge *e1, const Edge *e2) const
An internal definition of a loaded edge.
std::vector< SVCPermissions > myDisallowedLaneBackward
(optional) information about additional disallowed SVCs on backward lane(s)
std::map< std::string, std::string > myExtraTags
Additionally tagged information.
std::vector< double > myWidthLanesForward
Information on lane width.
WayType mySidewalkType
Information about the kind of sidwalk along this road.
std::vector< SVCPermissions > myDisallowedLaneForward
(optional) information about additional disallowed SVCs on forward lane(s)
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
std::string ref
The edge's track name.
std::vector< SVCPermissions > myAllowedLaneForward
(optional) information about additional allowed SVCs on forward lane(s)
std::string myHighWayType
The type, stored in "highway" key.
const long long int id
The edge's id.
bool myAmInRoundabout
Information whether this road is part of a roundabout.
int myLayer
Information about the relative z-ordering of ways.
std::vector< bool > myDesignatedLaneBackward
(optional) information about whether the backward lanes are designated to some SVCs
SVCPermissions myExtraDisallowed
Extra permissions prohibited from tags instead of highway type.
std::vector< SVCPermissions > myAllowedLaneBackward
(optional) information about additional allowed SVCs on backward lane(s)
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::vector< bool > myDesignatedLaneForward
(optional) information about whether the forward lanes are designated to some SVCs
std::string myIsOneWay
Information whether this is an one-way road.
A class which extracts OSM-edges from a parsed OSM-file.
void addType(const std::string &singleTypeID)
void interpretLaneUse(const std::string &value, SUMOVehicleClass svc, const bool forward) const
int interpretChangeType(const std::string &value) const
EdgesHandler(const std::map< long long int, NIOSMNode * > &osmNodes, std::map< long long int, Edge * > &toFill, std::map< long long int, Edge * > &platformShapes, const NBTypeCont &tc)
Constructor.
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;.
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)
Constructor.
void myEndElement(int element) override
Called when a closing tag occurs.
StringVector myRailSignalRules
custom requirements for rail signal tagging
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
bool myImportCrossings
import crossings
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
void applyLaneUse(NBEdge *e, NIImporter_OpenStreetMap::Edge *nie, const bool forward)
Applies lane use information from nie to e.
bool myOnewayDualSidewalk
import sidewalks
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
static bool myAllAttributes
whether additional way and node attributes shall be imported
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 std::set< std::string > myExtraAttributes
extra attributes to import
bool myImportBikeAccess
import bike path specific permissions and directions
bool myAnnotateDefaults
whether edges should carry information on the use of typemap defaults
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.
static void mergeTurnSigns(std::vector< int > &signs, std::vector< int > signs2)
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
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.
void unsetParameter(const std::string &key)
Removes a parameter.
bool hasParameter(const std::string &key) const
Returns whether the parameter is set.
virtual const std::string getParameter(const std::string &key, const std::string defaultValue="") const
Returns the value for a given key.
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
get key
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 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.
static double parseDist(const std::string &sData)
parse a distance, length or width value with a unit
static bool startsWith(const std::string &str, const std::string prefix)
Checks whether a given string starts with the prefix.
static double parseSpeed(const std::string &sData, const bool defaultKmph=true)
parse a speed value with a unit
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.
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 pedestrianCrossing
Whether this is a pedestrian crossing.
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.
WayType myRailDirection
Information about the direction(s) of railway usage.