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
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 (defaultPermissions == SVC_SHIP) {
514 // extra permission apply to the ships operating on the route rather than the waterway
515 permissions = defaultPermissions;
516 }
517 if (defaultsToOneWay && defaultPermissions == SVC_PEDESTRIAN && (permissions & (~SVC_PEDESTRIAN)) != 0) {
518 defaultsToOneWay = false;
519 }
520 if ((permissions & SVC_RAIL) != 0 && e->myExtraTags.count("electrified") != 0) {
521 permissions |= (SVC_RAIL_ELECTRIC | SVC_RAIL_FAST);
522 }
523
524 // convert the shape
525 PositionVector shape;
526 double distanceStart = myOSMNodes[passed.front()]->positionMeters;
527 double distanceEnd = myOSMNodes[passed.back()]->positionMeters;
528 const bool useDistance = distanceStart != std::numeric_limits<double>::max() && distanceEnd != std::numeric_limits<double>::max();
529 if (useDistance) {
530 // negative sign denotes counting in the other direction
531 if (distanceStart < distanceEnd) {
532 distanceStart *= -1;
533 } else {
534 distanceEnd *= -1;
535 }
536 } else {
537 distanceStart = 0;
538 distanceEnd = 0;
539 }
540 // get additional direction information
541 int nodeDirection = myOSMNodes.find(StringUtils::toLong(from->getID()))->second->myRailDirection |
542 myOSMNodes.find(StringUtils::toLong(to->getID()))->second->myRailDirection;
543
544 std::vector<std::shared_ptr<NBPTStop> > ptStops;
545 for (long long i : passed) {
546 NIOSMNode* n = myOSMNodes.find(i)->second;
547 // recheck permissions, maybe they got assigned to a strange edge, see #11656
548 if (n->ptStopPosition && (n->permissions == 0 || (permissions & n->permissions) != 0)) {
549 std::shared_ptr<NBPTStop> existingPtStop = sc.get(toString(n->id));
550 if (existingPtStop != nullptr) {
551 existingPtStop->registerAdditionalEdge(toString(e->id), id);
552 } else {
553 Position ptPos(n->lon, n->lat, n->ele);
555 WRITE_ERRORF("Unable to project coordinates for node '%'.", n->id);
556 }
558 ptStops.push_back(std::make_shared<NBPTStop>(element, toString(n->id), ptPos, id, toString(e->id), n->ptStopLength, n->name, n->permissions));
559 sc.insert(ptStops.back());
560 }
561 }
562 if (n->railwaySignal) {
563 nodeDirection |= n->myRailDirection;
564 }
565 Position pos(n->lon, n->lat, n->ele);
566 shape.push_back(pos);
567 }
568#ifdef DEBUG_LAYER_ELEVATION
569 if (e->id == "DEBUGID") {
570 std::cout
571 << " id=" << id << " from=" << from->getID() << " fromRailDirection=" << myOSMNodes.find(StringUtils::toLong(from->getID()))->second->myRailDirection
572 << " to=" << to->getID() << " toRailDirection=" << myOSMNodes.find(StringUtils::toLong(to->getID()))->second->myRailDirection
573 << " origRailDirection=" << e->myRailDirection
574 << " nodeDirection=" << nodeDirection
575 << "\n";
576 }
577#endif
578 if (e->myRailDirection == WAY_UNKNOWN && nodeDirection != WAY_UNKNOWN && nodeDirection != WAY_FORWARD
579 && nodeDirection != (WAY_FORWARD | WAY_UNKNOWN)) {
580 //std::cout << "way " << e->id << " nodeDirection=" << nodeDirection << " origDirection=" << e->myRailDirection << "\n";
581 // heuristic: assume that the mapped way direction indicates
582 // potential driving direction
584 }
586 WRITE_ERRORF("Unable to project coordinates for edge '%'.", id);
587 }
588
589 SVCPermissions forwardPermissions = permissions;
590 SVCPermissions backwardPermissions = permissions;
591 const std::string streetName = isRailway(permissions) && e->ref != "" ? e->ref : e->streetName;
592 if (streetName == e->ref) {
593 e->unsetParameter("ref"); // avoid superfluous param for railways
594 }
595 double forwardWidth = tc.getEdgeTypeWidth(type);
596 double backwardWidth = tc.getEdgeTypeWidth(type);
597 double sidewalkWidth = tc.getEdgeTypeSidewalkWidth(type);
598 bool addSidewalk = sidewalkWidth != NBEdge::UNSPECIFIED_WIDTH;
599 if (myImportSidewalks) {
600 if (addSidewalk) {
601 // only use sidewalk width from typemap but don't add sidewalks
602 // unless OSM specifies them
603 addSidewalk = false;
604 } else {
605 sidewalkWidth = OptionsCont::getOptions().getFloat("default.sidewalk-width");
606 }
607 }
608 double bikeLaneWidth = tc.getEdgeTypeBikeLaneWidth(type);
609 const std::string& onewayBike = e->myExtraTags["oneway:bicycle"];
610 if (onewayBike == "false" || onewayBike == "no" || onewayBike == "0") {
612 }
613
614 const bool addBikeLane = bikeLaneWidth != NBEdge::UNSPECIFIED_WIDTH ||
615 (myImportBikeAccess && (((e->myCyclewayType & WAY_BOTH) != 0 || e->myExtraTags.count("segregated") != 0) &&
616 !(e->myCyclewayType == WAY_BACKWARD && (e->myBuswayType & WAY_BOTH) != 0)));
617 if (addBikeLane && bikeLaneWidth == NBEdge::UNSPECIFIED_WIDTH) {
618 bikeLaneWidth = OptionsCont::getOptions().getFloat("default.bikelane-width");
619 }
620 // check directions
621 bool addForward = true;
622 bool addBackward = true;
623 const bool explicitTwoWay = e->myIsOneWay == "no";
624 if ((e->myIsOneWay == "true" || e->myIsOneWay == "yes" || e->myIsOneWay == "1"
625 || (defaultsToOneWay && e->myIsOneWay != "no" && e->myIsOneWay != "false" && e->myIsOneWay != "0"))
626 && e->myRailDirection != WAY_BOTH) {
627 addBackward = false;
628 }
629 if (e->myIsOneWay == "-1" || e->myIsOneWay == "reverse" || e->myRailDirection == WAY_BACKWARD) {
630 // one-way in reversed direction of way
631 addForward = false;
632 addBackward = true;
633 }
634 if (!e->myIsOneWay.empty() && e->myIsOneWay != "false" && e->myIsOneWay != "no" && e->myIsOneWay != "true"
635 && e->myIsOneWay != "yes" && e->myIsOneWay != "-1" && e->myIsOneWay != "1" && e->myIsOneWay != "reverse") {
636 WRITE_WARNINGF(TL("New value for oneway found: %"), e->myIsOneWay);
637 }
638 if ((permissions == SVC_BICYCLE || permissions == (SVC_BICYCLE | SVC_PEDESTRIAN) || permissions == SVC_PEDESTRIAN)) {
639 if (addBackward && (onewayBike == "true" || onewayBike == "yes" || onewayBike == "1")) {
640 addBackward = false;
641 }
642 if (addForward && (onewayBike == "reverse" || onewayBike == "-1")) {
643 addForward = false;
644 }
645 if (!addBackward && (onewayBike == "false" || onewayBike == "no" || onewayBike == "0")) {
646 addBackward = true;
647 }
648 }
649 bool ok = true;
650 // if we had been able to extract the number of lanes, override the highway type default
651 if (e->myNoLanes > 0) {
652 if (addForward && !addBackward) {
653 numLanesForward = e->myNoLanesForward > 0 ? e->myNoLanesForward : e->myNoLanes;
654 } else if (!addForward && addBackward) {
655 numLanesBackward = e->myNoLanesForward < 0 ? -e->myNoLanesForward : e->myNoLanes;
656 } else {
657 if (e->myNoLanesForward > 0) {
658 numLanesForward = e->myNoLanesForward;
659 } else if (e->myNoLanesForward < 0) {
660 numLanesForward = e->myNoLanes + e->myNoLanesForward;
661 } else {
662 numLanesForward = (int) std::ceil(e->myNoLanes / 2.0);
663 }
664 numLanesBackward = e->myNoLanes - numLanesForward;
665 // sometimes ways are tagged according to their physical width of a single
666 // lane but they are intended for traffic in both directions
667 numLanesForward = MAX2(1, numLanesForward);
668 numLanesBackward = MAX2(1, numLanesBackward);
669 }
670 } else if (e->myNoLanes == 0) {
671 WRITE_WARNINGF(TL("Skipping edge '%' because it has zero lanes."), id);
672 ok = false;
673 } else {
674 // the total number of lanes is not known but at least one direction
675 if (e->myNoLanesForward > 0) {
676 numLanesForward = e->myNoLanesForward;
677 } else if ((e->myBuswayType & WAY_FORWARD) != 0 && (extraDis & SVC_PASSENGER) == 0) {
678 // if we have a busway lane, yet cars may drive this implies at least two lanes
679 numLanesForward = MAX2(numLanesForward, 2);
680 }
681 if (e->myNoLanesForward < 0) {
682 numLanesBackward = -e->myNoLanesForward;
683 } else if ((e->myBuswayType & WAY_BACKWARD) != 0 && (extraDis & SVC_PASSENGER) == 0) {
684 // if we have a busway lane, yet cars may drive this implies at least two lanes
685 numLanesBackward = MAX2(numLanesForward, 2);
686 }
687 if (myAnnotateDefaults && e->myNoLanesForward == 0) {
688 defaults.push_back(SUMO_ATTR_NUMLANES);
689 }
690 }
691 // deal with busways that run in the opposite direction of a one-way street
692 if (!addForward && (e->myBuswayType & WAY_FORWARD) != 0) {
693 addForward = true;
694 forwardPermissions = SVC_BUS;
695 numLanesForward = 1;
696 }
697 if (!addBackward && (e->myBuswayType & WAY_BACKWARD) != 0) {
698 addBackward = true;
699 backwardPermissions = SVC_BUS;
700 numLanesBackward = 1;
701 }
702 // with is meant for raw lane count before adding sidewalks or cycleways
703 const int taggedLanes = (addForward ? numLanesForward : 0) + (addBackward ? numLanesBackward : 0);
704 if (e->myWidth > 0 && e->myWidthLanesForward.size() == 0 && e->myWidthLanesBackward.size() == 0 && taggedLanes != 0
705 && !OptionsCont::getOptions().getBool("ignore-widths")) {
706 // width is tagged excluding sidewalks and cycleways
707 forwardWidth = e->myWidth / taggedLanes;
708 backwardWidth = forwardWidth;
709 }
710
711 // if we had been able to extract the maximum speed, override the type's default
712 if (e->myMaxSpeed != MAXSPEED_UNGIVEN) {
713 speed = e->myMaxSpeed;
714 } else if (myAnnotateDefaults) {
715 defaults.push_back(SUMO_ATTR_SPEED);
716 }
717 double speedBackward = speed;
719 speedBackward = e->myMaxSpeedBackward;
720 }
721 if (speed <= 0 || speedBackward <= 0) {
722 WRITE_WARNINGF(TL("Skipping edge '%' because it has speed %."), id, speed);
723 ok = false;
724 }
725 // deal with cycleways that run in the opposite direction of a one-way street
726 WayType cyclewayType = e->myCyclewayType; // make a copy because we do some temporary modifications
727 if (addBikeLane) {
728 if (!addForward && (cyclewayType & WAY_FORWARD) != 0) {
729 addForward = true;
730 forwardPermissions = SVC_BICYCLE;
731 forwardWidth = bikeLaneWidth;
732 numLanesForward = 1;
733 // do not add an additional cycle lane
734 cyclewayType = (WayType)(cyclewayType & ~WAY_FORWARD);
735 }
736 if (!addBackward && (cyclewayType & WAY_BACKWARD) != 0) {
737 addBackward = true;
738 backwardPermissions = SVC_BICYCLE;
739 backwardWidth = bikeLaneWidth;
740 numLanesBackward = 1;
741 // do not add an additional cycle lane
742 cyclewayType = (WayType)(cyclewayType & ~WAY_BACKWARD);
743 }
744 }
745 // deal with sidewalks that run in the opposite direction of a one-way street
746 WayType sidewalkType = e->mySidewalkType; // make a copy because we do some temporary modifications
747 if (sidewalkType == WAY_UNKNOWN && (e->myExtraAllowed & SVC_PEDESTRIAN) != 0 && (permissions & SVC_PASSENGER) != 0) {
748 // do not assume shared space unless sidewalk is actively disabled
750 sidewalkType = WAY_BOTH;
751 }
752 }
753 if (addSidewalk || (myImportSidewalks && (permissions & SVC_ROAD_CLASSES) != 0 && defaultPermissions != SVC_PEDESTRIAN)) {
754 if (!addForward && (sidewalkType & WAY_FORWARD) != 0) {
755 addForward = true;
756 forwardPermissions = SVC_PEDESTRIAN;
757 forwardWidth = tc.getEdgeTypeSidewalkWidth(type);
758 numLanesForward = 1;
759 // do not add an additional sidewalk
760 sidewalkType = (WayType)(sidewalkType & ~WAY_FORWARD); //clang tidy thinks "!WAY_FORWARD" is always false
761 } else if (addSidewalk && addForward && (sidewalkType & WAY_BOTH) == 0
762 && numLanesForward == 1 && numLanesBackward <= 1
763 && (e->myExtraDisallowed & SVC_PEDESTRIAN) == 0) {
764 // our typemap says pedestrians should walk here but the data says
765 // there is no sidewalk at all. If the road is small, pedestrians can just walk
766 // on the road
767 forwardPermissions |= SVC_PEDESTRIAN;
768 }
769 if (!addBackward && (sidewalkType & WAY_BACKWARD) != 0) {
770 addBackward = true;
771 backwardPermissions = SVC_PEDESTRIAN;
772 backwardWidth = tc.getEdgeTypeSidewalkWidth(type);
773 numLanesBackward = 1;
774 // do not add an additional cycle lane
775 sidewalkType = (WayType)(sidewalkType & ~WAY_BACKWARD); //clang tidy thinks "!WAY_BACKWARD" is always false
776 } else if (addSidewalk && addBackward && (sidewalkType & WAY_BOTH) == 0
777 && numLanesBackward == 1 && numLanesForward <= 1
778 && (e->myExtraDisallowed & SVC_PEDESTRIAN) == 0) {
779 // our typemap says pedestrians should walk here but the data says
780 // there is no sidewalk at all. If the road is small, pedestrians can just walk
781 // on the road
782 backwardPermissions |= SVC_PEDESTRIAN;
783 }
784 }
785
786 const std::string origID = OptionsCont::getOptions().getBool("output.original-names") ? toString(e->id) : "";
787 if (ok) {
788 const bool lefthand = OptionsCont::getOptions().getBool("lefthand");
789 const int offsetFactor = lefthand ? -1 : 1;
790 LaneSpreadFunction lsf = (addBackward || OptionsCont::getOptions().getBool("osm.oneway-spread-right")) &&
792 if (addBackward && lsf == LaneSpreadFunction::RIGHT && OptionsCont::getOptions().getString("default.spreadtype") == toString(LaneSpreadFunction::ROADCENTER)) {
794 }
796 // user defined value overrides defaults
797 lsf = tc.getEdgeTypeSpreadType(type);
798 }
799 if (defaults.size() > 0) {
800 e->setParameter("osmDefaults", joinToString(defaults, " "));
801 }
802
803 id = StringUtils::escapeXML(id);
804 const std::string reverseID = "-" + id;
805 const bool markOSMDirection = from->getType() == SumoXMLNodeType::RAIL_SIGNAL || to->getType() == SumoXMLNodeType::RAIL_SIGNAL;
806 if (addForward) {
807 assert(numLanesForward > 0);
808 NBEdge* nbe = new NBEdge(id, from, to, type, speed, NBEdge::UNSPECIFIED_FRICTION, numLanesForward, tc.getEdgeTypePriority(type),
809 forwardWidth, NBEdge::UNSPECIFIED_OFFSET, shape, lsf,
810 StringUtils::escapeXML(streetName), origID, true);
811 if (markOSMDirection) {
813 }
814 nbe->setPermissions(forwardPermissions, -1);
815 if ((e->myBuswayType & WAY_FORWARD) != 0) {
816 nbe->setPermissions(SVC_BUS, 0);
817 }
819 applyLaneUse(nbe, e, true);
821 nbe->setTurnSignTarget(last->getID());
822 if (addBikeLane && (cyclewayType == WAY_UNKNOWN || (cyclewayType & WAY_FORWARD) != 0)) {
823 nbe->addBikeLane(bikeLaneWidth * offsetFactor);
824 } else if (nbe->getPermissions(0) == SVC_BUS) {
825 // bikes drive on buslanes if no separate cycle lane is available
827 }
828 if ((addSidewalk && (sidewalkType == WAY_UNKNOWN || (sidewalkType & WAY_FORWARD) != 0))
829 || (myImportSidewalks && (sidewalkType & WAY_FORWARD) != 0 && defaultPermissions != SVC_PEDESTRIAN)) {
830 nbe->addSidewalk(sidewalkWidth * offsetFactor);
831 }
832 if (!addBackward && (e->myExtraAllowed & SVC_PEDESTRIAN) != 0 && (nbe->getPermissions(0) & SVC_PEDESTRIAN) == 0) {
833 // Pedestrians are explicitly allowed (maybe through foot="yes") but did not get a sidewalk (maybe through sidewalk="no").
834 // Since we do not have a backward edge, we need to make sure they can at least walk somewhere, see #14124
836 }
838 nbe->setDistance(distanceStart);
839 if (e->myAmInRoundabout) {
840 // ensure roundabout edges have the precedence
843 }
844
845 // process forward lanes width
846 const int numForwardLanesFromWidthKey = (int)e->myWidthLanesForward.size();
847 if (numForwardLanesFromWidthKey > 0 && !OptionsCont::getOptions().getBool("ignore-widths")) {
848 if ((int)nbe->getLanes().size() != numForwardLanesFromWidthKey) {
849 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."),
850 id, nbe->getLanes().size(), numForwardLanesFromWidthKey);
851 } else {
852 for (int i = 0; i < numForwardLanesFromWidthKey; i++) {
853 const double actualWidth = e->myWidthLanesForward[i] <= 0 ? forwardWidth : e->myWidthLanesForward[i];
854 const int laneIndex = lefthand ? i : numForwardLanesFromWidthKey - i - 1;
855 nbe->setLaneWidth(laneIndex, actualWidth);
856 }
857 }
858 }
859
860 if (!ec.insert(nbe)) {
861 delete nbe;
862 throw ProcessError(TLF("Could not add edge '%'.", id));
863 }
864 }
865 if (addBackward) {
866 assert(numLanesBackward > 0);
867 NBEdge* nbe = new NBEdge(reverseID, to, from, type, speedBackward, NBEdge::UNSPECIFIED_FRICTION, numLanesBackward, tc.getEdgeTypePriority(type),
868 backwardWidth, NBEdge::UNSPECIFIED_OFFSET, shape.reverse(), lsf,
869 StringUtils::escapeXML(streetName), origID, true);
870 if (markOSMDirection) {
872 }
873 nbe->setPermissions(backwardPermissions);
874 if ((e->myBuswayType & WAY_BACKWARD) != 0) {
875 nbe->setPermissions(SVC_BUS, 0);
876 }
878 applyLaneUse(nbe, e, false);
880 nbe->setTurnSignTarget(first->getID());
881 if (addBikeLane && (cyclewayType == WAY_UNKNOWN || (cyclewayType & WAY_BACKWARD) != 0)) {
882 nbe->addBikeLane(bikeLaneWidth * offsetFactor);
883 } else if (nbe->getPermissions(0) == SVC_BUS) {
884 // bikes drive on buslanes if no separate cycle lane is available
886 }
887 if ((addSidewalk && (sidewalkType == WAY_UNKNOWN || (sidewalkType & WAY_BACKWARD) != 0))
888 || (myImportSidewalks && (sidewalkType & WAY_BACKWARD) != 0 && defaultPermissions != SVC_PEDESTRIAN)) {
889 nbe->addSidewalk(sidewalkWidth * offsetFactor);
890 }
892 nbe->setDistance(distanceEnd);
893 if (e->myAmInRoundabout) {
894 // ensure roundabout edges have the precedence
897 }
898 // process backward lanes width
899 const int numBackwardLanesFromWidthKey = (int)e->myWidthLanesBackward.size();
900 if (numBackwardLanesFromWidthKey > 0 && !OptionsCont::getOptions().getBool("ignore-widths")) {
901 if ((int)nbe->getLanes().size() != numBackwardLanesFromWidthKey) {
902 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."),
903 id, nbe->getLanes().size(), numBackwardLanesFromWidthKey);
904 } else {
905 for (int i = 0; i < numBackwardLanesFromWidthKey; i++) {
906 const double actualWidth = e->myWidthLanesBackward[i] <= 0 ? backwardWidth : e->myWidthLanesBackward[i];
907 const int laneIndex = lefthand ? i : numBackwardLanesFromWidthKey - i - 1;
908 nbe->setLaneWidth(laneIndex, actualWidth);
909 }
910 }
911 }
912
913 if (!ec.insert(nbe)) {
914 delete nbe;
915 throw ProcessError(TLF("Could not add edge '-%'.", id));
916 }
917 }
918 if ((e->myParkingType & PARKING_BOTH) != 0 && OptionsCont::getOptions().isSet("parking-output")) {
919 if ((e->myParkingType & PARKING_RIGHT) != 0) {
920 if (addForward) {
921 nb.getParkingCont().push_back(NBParking(id, id));
922 } else {
924 if ((e->myParkingType & PARKING_LEFT) == 0 && !addBackward) {
926 nb.getParkingCont().push_back(NBParking(reverseID, reverseID));
927 }
928 }
929 }
930 if ((e->myParkingType & PARKING_LEFT) != 0) {
931 if (addBackward) {
932 nb.getParkingCont().push_back(NBParking(reverseID, reverseID));
933 } else {
935 if ((e->myParkingType & PARKING_RIGHT) == 0 && !addForward) {
937 nb.getParkingCont().push_back(NBParking(id, id));
938 }
939 }
940 }
941 }
942 }
943 return newIndex;
944}
945
946
947void
949 NBNodeCont& nc = nb.getNodeCont();
950 NBEdgeCont& ec = nb.getEdgeCont();
951 // reconstruct elevation from layer info
952 // build a map of raising and lowering forces (attractor and distance)
953 // for all nodes unknownElevation
954 std::map<NBNode*, std::vector<std::pair<double, double> > > layerForces;
955
956 // collect all nodes that belong to a way with layer information
957 std::set<NBNode*> knownElevation;
958 for (auto& myEdge : myEdges) {
959 Edge* e = myEdge.second;
960 if (e->myLayer != 0) {
961 for (auto j = e->myCurrentNodes.begin(); j != e->myCurrentNodes.end(); ++j) {
962 NBNode* node = nc.retrieve(toString(*j));
963 if (node != nullptr) {
964 knownElevation.insert(node);
965 layerForces[node].emplace_back(e->myLayer * layerElevation, POSITION_EPS);
966 }
967 }
968 }
969 }
970#ifdef DEBUG_LAYER_ELEVATION
971 std::cout << "known elevations:\n";
972 for (std::set<NBNode*>::iterator it = knownElevation.begin(); it != knownElevation.end(); ++it) {
973 const std::vector<std::pair<double, double> >& primaryLayers = layerForces[*it];
974 std::cout << " node=" << (*it)->getID() << " ele=";
975 for (std::vector<std::pair<double, double> >::const_iterator it_ele = primaryLayers.begin(); it_ele != primaryLayers.end(); ++it_ele) {
976 std::cout << it_ele->first << " ";
977 }
978 std::cout << "\n";
979 }
980#endif
981 // layer data only provides a lower bound on elevation since it is used to
982 // resolve the relation among overlapping ways.
983 // Perform a sanity check for steep inclines and raise the knownElevation if necessary
984 std::map<NBNode*, double> knownEleMax;
985 for (auto it : knownElevation) {
986 double eleMax = -std::numeric_limits<double>::max();
987 const std::vector<std::pair<double, double> >& primaryLayers = layerForces[it];
988 for (const auto& primaryLayer : primaryLayers) {
989 eleMax = MAX2(eleMax, primaryLayer.first);
990 }
991 knownEleMax[it] = eleMax;
992 }
993 const double gradeThreshold = OptionsCont::getOptions().getFloat("osm.layer-elevation.max-grade") / 100;
994 bool changed = true;
995 while (changed) {
996 changed = false;
997 for (auto it = knownElevation.begin(); it != knownElevation.end(); ++it) {
998 std::map<NBNode*, std::pair<double, double> > neighbors = getNeighboringNodes(*it,
999 knownEleMax[*it]
1000 / gradeThreshold * 3,
1001 knownElevation);
1002 for (auto& neighbor : neighbors) {
1003 if (knownElevation.count(neighbor.first) != 0) {
1004 const double grade = fabs(knownEleMax[*it] - knownEleMax[neighbor.first])
1005 / MAX2(POSITION_EPS, neighbor.second.first);
1006#ifdef DEBUG_LAYER_ELEVATION
1007 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";
1008#endif
1009 if (grade > gradeThreshold * 50 / 3.6 / neighbor.second.second) {
1010 // raise the lower node to the higher level
1011 const double eleMax = MAX2(knownEleMax[*it], knownEleMax[neighbor.first]);
1012 if (knownEleMax[*it] < eleMax) {
1013 knownEleMax[*it] = eleMax;
1014 } else {
1015 knownEleMax[neighbor.first] = eleMax;
1016 }
1017 changed = true;
1018 }
1019 }
1020 }
1021 }
1022 }
1023
1024 // collect all nodes within a grade-dependent range around knownElevation-nodes and apply knowElevation forces
1025 std::set<NBNode*> unknownElevation;
1026 for (auto it = knownElevation.begin(); it != knownElevation.end(); ++it) {
1027 const double eleMax = knownEleMax[*it];
1028 const double maxDist = fabs(eleMax) * 100 / layerElevation;
1029 std::map<NBNode*, std::pair<double, double> > neighbors = getNeighboringNodes(*it, maxDist, knownElevation);
1030 for (auto& neighbor : neighbors) {
1031 if (knownElevation.count(neighbor.first) == 0) {
1032 unknownElevation.insert(neighbor.first);
1033 layerForces[neighbor.first].emplace_back(eleMax, neighbor.second.first);
1034 }
1035 }
1036 }
1037
1038 // apply forces to ground-level nodes (neither in knownElevation nor unknownElevation)
1039 for (auto it = unknownElevation.begin(); it != unknownElevation.end(); ++it) {
1040 double eleMax = -std::numeric_limits<double>::max();
1041 const std::vector<std::pair<double, double> >& primaryLayers = layerForces[*it];
1042 for (const auto& primaryLayer : primaryLayers) {
1043 eleMax = MAX2(eleMax, primaryLayer.first);
1044 }
1045 const double maxDist = fabs(eleMax) * 100 / layerElevation;
1046 std::map<NBNode*, std::pair<double, double> > neighbors = getNeighboringNodes(*it, maxDist, knownElevation);
1047 for (auto& neighbor : neighbors) {
1048 if (knownElevation.count(neighbor.first) == 0 && unknownElevation.count(neighbor.first) == 0) {
1049 layerForces[*it].emplace_back(0, neighbor.second.first);
1050 }
1051 }
1052 }
1053 // compute the elevation for each node as the weighted average of all forces
1054#ifdef DEBUG_LAYER_ELEVATION
1055 std::cout << "summation of forces\n";
1056#endif
1057 std::map<NBNode*, double> nodeElevation;
1058 for (auto& layerForce : layerForces) {
1059 const std::vector<std::pair<double, double> >& forces = layerForce.second;
1060 if (knownElevation.count(layerForce.first) != 0) {
1061 // use the maximum value
1062 /*
1063 double eleMax = -std::numeric_limits<double>::max();
1064 for (std::vector<std::pair<double, double> >::const_iterator it_force = forces.begin(); it_force != forces.end(); ++it_force) {
1065 eleMax = MAX2(eleMax, it_force->first);
1066 }
1067 */
1068#ifdef DEBUG_LAYER_ELEVATION
1069 std::cout << " node=" << it->first->getID() << " knownElevation=" << knownEleMax[it->first] << "\n";
1070#endif
1071 nodeElevation[layerForce.first] = knownEleMax[layerForce.first];
1072 } else if (forces.size() == 1) {
1073 nodeElevation[layerForce.first] = forces.front().first;
1074 } else {
1075 // use the weighted sum
1076 double distSum = 0;
1077 for (const auto& force : forces) {
1078 distSum += force.second;
1079 }
1080 double weightSum = 0;
1081 double elevation = 0;
1082#ifdef DEBUG_LAYER_ELEVATION
1083 std::cout << " node=" << it->first->getID() << " distSum=" << distSum << "\n";
1084#endif
1085 for (const auto& force : forces) {
1086 const double weight = (distSum - force.second) / distSum;
1087 weightSum += weight;
1088 elevation += force.first * weight;
1089
1090#ifdef DEBUG_LAYER_ELEVATION
1091 std::cout << " force=" << it_force->first << " dist=" << it_force->second << " weight=" << weight << " ele=" << elevation << "\n";
1092#endif
1093 }
1094 nodeElevation[layerForce.first] = elevation / weightSum;
1095 }
1096 }
1097#ifdef DEBUG_LAYER_ELEVATION
1098 std::cout << "final elevations:\n";
1099 for (std::map<NBNode*, double>::iterator it = nodeElevation.begin(); it != nodeElevation.end(); ++it) {
1100 std::cout << " node=" << (it->first)->getID() << " ele=" << it->second << "\n";
1101 }
1102#endif
1103 // apply node elevations
1104 for (auto& it : nodeElevation) {
1105 NBNode* n = it.first;
1106 n->reinit(n->getPosition() + Position(0, 0, it.second), n->getType());
1107 }
1108
1109 // apply way elevation to all edges that had layer information
1110 for (const auto& it : ec) {
1111 NBEdge* edge = it.second;
1112 const PositionVector& geom = edge->getGeometry();
1113 const double length = geom.length2D();
1114 const double zFrom = nodeElevation[edge->getFromNode()];
1115 const double zTo = nodeElevation[edge->getToNode()];
1116 // XXX if the from- or to-node was part of multiple ways with
1117 // different layers, reconstruct the layer value from origID
1118 double dist = 0;
1119 PositionVector newGeom;
1120 for (auto it_pos = geom.begin(); it_pos != geom.end(); ++it_pos) {
1121 if (it_pos != geom.begin()) {
1122 dist += (*it_pos).distanceTo2D(*(it_pos - 1));
1123 }
1124 newGeom.push_back((*it_pos) + Position(0, 0, zFrom + (zTo - zFrom) * dist / length));
1125 }
1126 edge->setGeometry(newGeom);
1127 }
1128}
1129
1130std::map<NBNode*, std::pair<double, double> >
1131NIImporter_OpenStreetMap::getNeighboringNodes(NBNode* node, double maxDist, const std::set<NBNode*>& knownElevation) {
1132 std::map<NBNode*, std::pair<double, double> > result;
1133 std::set<NBNode*> visited;
1134 std::vector<NBNode*> open;
1135 open.push_back(node);
1136 result[node] = std::make_pair(0, 0);
1137 while (!open.empty()) {
1138 NBNode* n = open.back();
1139 open.pop_back();
1140 if (visited.count(n) != 0) {
1141 continue;
1142 }
1143 visited.insert(n);
1144 const EdgeVector& edges = n->getEdges();
1145 for (auto e : edges) {
1146 NBNode* s = nullptr;
1147 if (n->hasIncoming(e)) {
1148 s = e->getFromNode();
1149 } else {
1150 s = e->getToNode();
1151 }
1152 const double dist = result[n].first + e->getGeometry().length2D();
1153 const double speed = MAX2(e->getSpeed(), result[n].second);
1154 if (result.count(s) == 0) {
1155 result[s] = std::make_pair(dist, speed);
1156 } else {
1157 result[s] = std::make_pair(MIN2(dist, result[s].first), MAX2(speed, result[s].second));
1158 }
1159 if (dist < maxDist && knownElevation.count(s) == 0) {
1160 open.push_back(s);
1161 }
1162 }
1163 }
1164 result.erase(node);
1165 return result;
1166}
1167
1168
1169std::string
1170NIImporter_OpenStreetMap::usableType(const std::string& type, const std::string& id, NBTypeCont& tc) {
1171 if (tc.knows(type)) {
1172 return type;
1173 }
1174 if (myUnusableTypes.count(type) > 0) {
1175 return "";
1176 }
1177 if (myKnownCompoundTypes.count(type) > 0) {
1178 return myKnownCompoundTypes[type];
1179 }
1180 // this edge has a type which does not yet exist in the TypeContainer
1182 std::vector<std::string> types;
1183 while (tok.hasNext()) {
1184 std::string t = tok.next();
1185 if (tc.knows(t)) {
1186 if (std::find(types.begin(), types.end(), t) == types.end()) {
1187 types.push_back(t);
1188 }
1189 } else if (tok.size() > 1) {
1190 if (!StringUtils::startsWith(t, "service.")) {
1191 WRITE_WARNINGF(TL("Discarding unknown compound '%' in type '%' (first occurrence for edge '%')."), t, type, id);
1192 }
1193 }
1194 }
1195 if (types.empty()) {
1196 if (!StringUtils::startsWith(type, "service.")) {
1197 WRITE_WARNINGF(TL("Discarding unusable type '%' (first occurrence for edge '%')."), type, id);
1198 }
1199 myUnusableTypes.insert(type);
1200 return "";
1201 }
1202 const std::string newType = joinToString(types, "|");
1203 if (tc.knows(newType)) {
1204 myKnownCompoundTypes[type] = newType;
1205 return newType;
1206 } else if (myKnownCompoundTypes.count(newType) > 0) {
1207 return myKnownCompoundTypes[newType];
1208 } else {
1209 // build a new type by merging all values
1210 int numLanes = 0;
1211 double maxSpeed = 0;
1212 int prio = 0;
1213 double width = NBEdge::UNSPECIFIED_WIDTH;
1214 double sidewalkWidth = NBEdge::UNSPECIFIED_WIDTH;
1215 double bikelaneWidth = NBEdge::UNSPECIFIED_WIDTH;
1216 bool defaultIsOneWay = true;
1217 SVCPermissions permissions = 0;
1219 bool discard = true;
1220 bool hadDiscard = false;
1221 for (auto& type2 : types) {
1222 if (!tc.getEdgeTypeShallBeDiscarded(type2)) {
1223 numLanes = MAX2(numLanes, tc.getEdgeTypeNumLanes(type2));
1224 maxSpeed = MAX2(maxSpeed, tc.getEdgeTypeSpeed(type2));
1225 prio = MAX2(prio, tc.getEdgeTypePriority(type2));
1226 defaultIsOneWay &= tc.getEdgeTypeIsOneWay(type2);
1227 //std::cout << "merging component " << type2 << " into type " << newType << " allows=" << getVehicleClassNames(tc.getPermissions(type2)) << " oneway=" << defaultIsOneWay << "\n";
1228 permissions |= tc.getEdgeTypePermissions(type2);
1229 spreadType = tc.getEdgeTypeSpreadType(type2);
1230 width = MAX2(width, tc.getEdgeTypeWidth(type2));
1231 sidewalkWidth = MAX2(sidewalkWidth, tc.getEdgeTypeSidewalkWidth(type2));
1232 bikelaneWidth = MAX2(bikelaneWidth, tc.getEdgeTypeBikeLaneWidth(type2));
1233 discard = false;
1234 } else {
1235 hadDiscard = true;
1236 }
1237 }
1238 if (hadDiscard && permissions == 0) {
1239 discard = true;
1240 }
1241 if (discard) {
1242 WRITE_WARNINGF(TL("Discarding compound type '%' (first occurrence for edge '%')."), newType, id);
1243 myUnusableTypes.insert(newType);
1244 return "";
1245 }
1246 if (width != NBEdge::UNSPECIFIED_WIDTH) {
1247 width = MAX2(width, SUMO_const_laneWidth);
1248 }
1249 // ensure pedestrians don't run into trains
1250 if (sidewalkWidth == NBEdge::UNSPECIFIED_WIDTH
1251 && (permissions & SVC_PEDESTRIAN) != 0
1252 && (permissions & SVC_RAIL_CLASSES) != 0) {
1253 //std::cout << "patching sidewalk for type '" << newType << "' which allows=" << getVehicleClassNames(permissions) << "\n";
1254 sidewalkWidth = OptionsCont::getOptions().getFloat("default.sidewalk-width");
1255 }
1256
1257 WRITE_MESSAGEF(TL("Adding new type '%' (first occurrence for edge '%')."), type, id);
1258 tc.insertEdgeType(newType, numLanes, maxSpeed, prio, permissions, spreadType, width,
1259 defaultIsOneWay, sidewalkWidth, bikelaneWidth, 0, 0, 0);
1260 for (auto& type3 : types) {
1261 if (!tc.getEdgeTypeShallBeDiscarded(type3)) {
1262 tc.copyEdgeTypeRestrictionsAndAttrs(type3, newType);
1263 }
1264 }
1265 myKnownCompoundTypes[type] = newType;
1266 return newType;
1267 }
1268}
1269
1270void
1272 const std::string id = toString(e->id);
1273 std::string type = usableType(e->myHighWayType, id, tc);
1274 if (type != "" && isRailway(tc.getEdgeTypePermissions(type))) {
1275 std::vector<NIOSMNode*> nodes;
1276 std::vector<double> usablePositions;
1277 std::vector<int> usableIndex;
1278 for (long long int n : e->myCurrentNodes) {
1279 NIOSMNode* node = myOSMNodes[n];
1280 node->positionMeters = interpretDistance(node);
1281 if (node->positionMeters != std::numeric_limits<double>::max()) {
1282 usablePositions.push_back(node->positionMeters);
1283 usableIndex.push_back((int)nodes.size());
1284 }
1285 nodes.push_back(node);
1286 }
1287 if (usablePositions.size() == 0) {
1288 return;
1289 } else {
1290 bool forward = true;
1291 if (usablePositions.size() == 1) {
1292 WRITE_WARNINGF(TL("Ambiguous railway kilometrage direction for way '%' (assuming forward)"), id);
1293 } else {
1294 forward = usablePositions.front() < usablePositions.back();
1295 }
1296 // check for consistency
1297 for (int i = 1; i < (int)usablePositions.size(); i++) {
1298 if ((usablePositions[i - 1] < usablePositions[i]) != forward) {
1299 WRITE_WARNINGF(TL("Inconsistent railway kilometrage direction for way '%': % (skipping)"), id, toString(usablePositions));
1300 return;
1301 }
1302 }
1303 if (nodes.size() > usablePositions.size()) {
1304 // complete missing values
1305 PositionVector shape;
1306 for (NIOSMNode* node : nodes) {
1307 shape.push_back(Position(node->lon, node->lat, 0));
1308 }
1310 return; // error will be given later
1311 }
1312 double sign = forward ? 1 : -1;
1313 // extend backward before first usable value
1314 for (int i = usableIndex.front() - 1; i >= 0; i--) {
1315 nodes[i]->positionMeters = nodes[i + 1]->positionMeters - sign * shape[i].distanceTo2D(shape[i + 1]);
1316 }
1317 // extend forward
1318 for (int i = usableIndex.front() + 1; i < (int)nodes.size(); i++) {
1319 if (nodes[i]->positionMeters == std::numeric_limits<double>::max()) {
1320 nodes[i]->positionMeters = nodes[i - 1]->positionMeters + sign * shape[i].distanceTo2D(shape[i - 1]);
1321 }
1322 }
1323 //std::cout << " way=" << id << " usable=" << toString(usablePositions) << "\n indices=" << toString(usableIndex)
1324 // << " final:\n";
1325 //for (auto n : nodes) {
1326 // std::cout << " " << n->id << " " << n->positionMeters << " " << n->position<< "\n";
1327 //}
1328 }
1329 }
1330 }
1331}
1332
1333
1334double
1336 if (node->position.size() > 0) {
1337 try {
1338 if (StringUtils::startsWith(node->position, "mi:")) {
1339 return StringUtils::toDouble(node->position.substr(3)) * 1609.344; // meters per mile
1340 } else {
1341 return StringUtils::toDouble(node->position) * 1000;
1342 }
1343 } catch (...) {
1344 WRITE_WARNINGF(TL("Value of railway:position is not numeric ('%') in node '%'."), node->position, toString(node->id));
1345 }
1346 }
1347 return std::numeric_limits<double>::max();
1348}
1349
1353 if (type == "train") {
1354 result = SVC_RAIL;
1355 } else if (type == "subway") {
1356 result = SVC_SUBWAY;
1357 } else if (type == "aerialway") {
1358 result = SVC_CABLE_CAR;
1359 } else if (type == "light_rail" || type == "monorail") {
1360 result = SVC_RAIL_URBAN;
1361 } else if (type == "share_taxi") {
1362 result = SVC_TAXI;
1363 } else if (type == "minibus") {
1364 result = SVC_BUS;
1365 } else if (type == "trolleybus") {
1366 result = SVC_BUS;
1367 } else if (SumoVehicleClassStrings.hasString(type)) {
1368 result = SumoVehicleClassStrings.get(type);
1369 }
1370 std::string stop = "";
1371 if (result == SVC_TRAM) {
1372 stop = ".tram";
1373 } else if (result == SVC_BUS) {
1374 stop = ".bus";
1375 } else if (isRailway(result)) {
1376 stop = ".train";
1377 }
1378 if (toSet != nullptr && result != SVC_IGNORING) {
1379 toSet->permissions |= result;
1380 toSet->ptStopLength = OptionsCont::getOptions().getFloat("osm.stop-output.length" + stop);
1381 }
1382 return result;
1383}
1384
1385
1386void
1388 bool multiLane = changeProhibition > 3;
1389 //std::cout << "applyChangeProhibition e=" << e->getID() << " changeProhibition=" << std::bitset<32>(changeProhibition) << " val=" << changeProhibition << "\n";
1390 for (int lane = 0; changeProhibition > 0 && lane < e->getNumLanes(); lane++) {
1391 int code = changeProhibition % 4; // only look at the last 2 bits
1392 SVCPermissions changeLeft = (code & CHANGE_NO_LEFT) == 0 ? SVCAll : (SVCPermissions)SVC_AUTHORITY;
1393 SVCPermissions changeRight = (code & CHANGE_NO_RIGHT) == 0 ? SVCAll : (SVCPermissions)SVC_AUTHORITY;
1394 e->setPermittedChanging(lane, changeLeft, changeRight);
1395 if (multiLane) {
1396 changeProhibition = changeProhibition >> 2;
1397 }
1398 }
1399}
1400
1401
1402void
1404 if (myImportLaneAccess) {
1405 const int numLanes = e->getNumLanes();
1406 const bool lefthand = OptionsCont::getOptions().getBool("lefthand");
1407 const std::vector<bool>& designated = forward ? nie->myDesignatedLaneForward : nie->myDesignatedLaneBackward;
1408 const std::vector<SVCPermissions>& allowed = forward ? nie->myAllowedLaneForward : nie->myAllowedLaneBackward;
1409 const std::vector<SVCPermissions>& disallowed = forward ? nie->myDisallowedLaneForward : nie->myDisallowedLaneBackward;
1410 for (int lane = 0; lane < numLanes; lane++) {
1411 // laneUse stores from left to right
1412 const int i = lefthand ? lane : numLanes - 1 - lane;
1413 // Extra allowed SVCs for this lane or none if no info was present for the lane
1414 const SVCPermissions extraAllowed = i < (int)allowed.size() ? allowed[i] : (SVCPermissions)SVC_IGNORING;
1415 // Extra disallowed SVCs for this lane or none if no info was present for the lane
1416 const SVCPermissions extraDisallowed = i < (int)disallowed.size() ? disallowed[i] : (SVCPermissions)SVC_IGNORING;
1417 if (i < (int)designated.size() && designated[i]) {
1418 // if designated, delete all permissions
1419 e->setPermissions(SVC_IGNORING, lane);
1420 e->preferVehicleClass(lane, extraAllowed);
1421 }
1422 e->setPermissions((e->getPermissions(lane) | extraAllowed) & (~extraDisallowed), lane);
1423 }
1424 }
1425}
1426
1427void
1428NIImporter_OpenStreetMap::mergeTurnSigns(std::vector<int>& signs, std::vector<int> signs2) {
1429 if (signs.empty()) {
1430 signs.insert(signs.begin(), signs2.begin(), signs2.end());
1431 } else {
1432 for (int i = 0; i < (int)MIN2(signs.size(), signs2.size()); i++) {
1433 signs[i] |= signs2[i];
1434 }
1435 }
1436}
1437
1438
1439void
1440NIImporter_OpenStreetMap::applyTurnSigns(NBEdge* e, const std::vector<int>& turnSigns) {
1441 if (myImportTurnSigns && turnSigns.size() > 0) {
1442 // no sidewalks and bike lanes have been added yet
1443 if ((int)turnSigns.size() == e->getNumLanes()) {
1444 //std::cout << "apply turnSigns for " << e->getID() << " turnSigns=" << toString(turnSigns) << "\n";
1445 for (int i = 0; i < (int)turnSigns.size(); i++) {
1446 // laneUse stores from left to right
1447 const int laneIndex = e->getNumLanes() - 1 - i;
1448 NBEdge::Lane& lane = e->getLaneStruct(laneIndex);
1449 lane.turnSigns = turnSigns[i];
1450 }
1451 } else {
1452 WRITE_WARNINGF(TL("Ignoring turn sign information for % lanes on edge % with % driving lanes"), turnSigns.size(), e->getID(), e->getNumLanes());
1453 }
1454 }
1455}
1456
1457
1458// ---------------------------------------------------------------------------
1459// definitions of NIImporter_OpenStreetMap::NodesHandler-methods
1460// ---------------------------------------------------------------------------
1461NIImporter_OpenStreetMap::NodesHandler::NodesHandler(std::map<long long int, NIOSMNode*>& toFill,
1462 std::set<NIOSMNode*, CompareNodes>& uniqueNodes, const OptionsCont& oc) :
1463 SUMOSAXHandler("osm - file"),
1464 myToFill(toFill),
1465 myCurrentNode(nullptr),
1466 myIsStation(false),
1467 myHierarchyLevel(0),
1468 myUniqueNodes(uniqueNodes),
1469 myImportElevation(oc.getBool("osm.elevation")),
1470 myDuplicateNodes(0),
1471 myOptionsCont(oc) {
1472 // init rail signal rules
1473 for (std::string kv : oc.getStringVector("osm.railsignals")) {
1474 if (kv == "DEFAULT") {
1475 myRailSignalRules.push_back("railway:signal:main=");
1476 myRailSignalRules.push_back("railway:signal:combined=");
1477 } else if (kv == "ALL") {
1478 myRailSignalRules.push_back("railway=signal");
1479 } else {
1480 myRailSignalRules.push_back("railway:signal:" + kv);
1481 }
1482 }
1483}
1484
1485
1487
1488void
1490 ++myHierarchyLevel;
1491 if (element == SUMO_TAG_NODE) {
1492 bool ok = true;
1493 myLastNodeID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
1494 if (myHierarchyLevel != 2) {
1495 WRITE_ERROR("Node element on wrong XML hierarchy level (id='" + myLastNodeID +
1496 "', level='" + toString(myHierarchyLevel) + "').");
1497 return;
1498 }
1499 const std::string& action = attrs.getOpt<std::string>(SUMO_ATTR_ACTION, myLastNodeID.c_str(), ok);
1500 if (action == "delete" || !ok) {
1501 return;
1502 }
1503 try {
1504 // we do not use attrs.get here to save some time on parsing
1505 const long long int id = StringUtils::toLong(myLastNodeID);
1506 myCurrentNode = nullptr;
1507 const auto insertionIt = myToFill.lower_bound(id);
1508 if (insertionIt == myToFill.end() || insertionIt->first != id) {
1509 // assume we are loading multiple files, so we won't report duplicate nodes
1510 const double tlon = attrs.get<double>(SUMO_ATTR_LON, myLastNodeID.c_str(), ok);
1511 const double tlat = attrs.get<double>(SUMO_ATTR_LAT, myLastNodeID.c_str(), ok);
1512 if (!ok) {
1513 return;
1514 }
1515 myCurrentNode = new NIOSMNode(id, tlon, tlat);
1516 auto similarNode = myUniqueNodes.find(myCurrentNode);
1517 if (similarNode == myUniqueNodes.end()) {
1518 myUniqueNodes.insert(myCurrentNode);
1519 } else {
1520 delete myCurrentNode;
1521 myCurrentNode = *similarNode;
1522 myDuplicateNodes++;
1523 }
1524 myToFill.emplace_hint(insertionIt, id, myCurrentNode);
1525 }
1526 } catch (FormatException&) {
1527 WRITE_ERROR(TL("Attribute 'id' in the definition of a node is not of type long long int."));
1528 return;
1529 }
1530 }
1531 if (element == SUMO_TAG_TAG && myCurrentNode != nullptr) {
1532 if (myHierarchyLevel != 3) {
1533 WRITE_ERROR(TL("Tag element on wrong XML hierarchy level."));
1534 return;
1535 }
1536 bool ok = true;
1537 const std::string& key = attrs.get<std::string>(SUMO_ATTR_K, myLastNodeID.c_str(), ok, false);
1538 // we check whether the key is relevant (and we really need to transcode the value) to avoid hitting #1636
1539 if (key == "highway" || key == "ele" || key == "crossing" || key == "railway" || key == "public_transport"
1540 || key == "name" || key == "train" || key == "bus" || key == "tram" || key == "light_rail" || key == "subway" || key == "station" || key == "noexit"
1541 || key == "crossing:barrier"
1542 || key == "crossing:light"
1543 || key == "railway:ref"
1544 || StringUtils::startsWith(key, "railway:signal")
1545 || StringUtils::startsWith(key, "railway:position")
1546 ) {
1547 const std::string& value = attrs.get<std::string>(SUMO_ATTR_V, myLastNodeID.c_str(), ok, false);
1548 if (key == "highway" && value.find("traffic_signal") != std::string::npos) {
1549 myCurrentNode->tlsControlled = true;
1550 } else if (key == "crossing" && value.find("traffic_signals") != std::string::npos) {
1551 myCurrentNode->tlsControlled = true;
1552 } else if (key == "highway" && value.find("crossing") != std::string::npos) {
1553 myCurrentNode->pedestrianCrossing = true;
1554 } else if ((key == "noexit" && value == "yes")
1555 || (key == "railway" && value == "buffer_stop")) {
1556 myCurrentNode->railwayBufferStop = true;
1557 } else if (key == "railway" && value.find("crossing") != std::string::npos) {
1558 myCurrentNode->railwayCrossing = true;
1559 } else if (key == "crossing:barrier") {
1560 myCurrentNode->setParameter("crossing:barrier", value);
1561 } else if (key == "crossing:light") {
1562 myCurrentNode->setParameter("crossing:light", value);
1563 } else if (key == "railway:signal:direction") {
1564 if (value == "both") {
1565 myCurrentNode->myRailDirection = WAY_BOTH;
1566 } else if (value == "backward") {
1567 myCurrentNode->myRailDirection = WAY_BACKWARD;
1568 } else if (value == "forward") {
1569 myCurrentNode->myRailDirection = WAY_FORWARD;
1570 }
1571 } else if (StringUtils::startsWith(key, "railway:signal") || (key == "railway" && value == "signal")) {
1572 std::string kv = key + "=" + value;
1573 std::string kglob = key + "=";
1574 if ((std::find(myRailSignalRules.begin(), myRailSignalRules.end(), kv) != myRailSignalRules.end())
1575 || (std::find(myRailSignalRules.begin(), myRailSignalRules.end(), kglob) != myRailSignalRules.end())) {
1576 myCurrentNode->railwaySignal = true;
1577 }
1578 } else if (StringUtils::startsWith(key, "railway:position") && value.size() > myCurrentNode->position.size()) {
1579 // use the entry with the highest precision (more digits)
1580 myCurrentNode->position = value;
1581 } else if ((key == "public_transport" && value == "stop_position") ||
1582 (key == "highway" && value == "bus_stop")) {
1583 myCurrentNode->ptStopPosition = true;
1584 if (myCurrentNode->ptStopLength == 0) {
1585 // default length
1586 myCurrentNode->ptStopLength = myOptionsCont.getFloat("osm.stop-output.length");
1587 }
1588 } else if (key == "name") {
1589 myCurrentNode->name = value;
1590 } else if (myImportElevation && key == "ele") {
1591 try {
1592 const double elevation = StringUtils::parseDist(value);
1593 if (std::isnan(elevation)) {
1594 WRITE_WARNINGF(TL("Value of key '%' is invalid ('%') in node '%'."), key, value, myLastNodeID);
1595 } else {
1596 myCurrentNode->ele = elevation;
1597 }
1598 } catch (...) {
1599 WRITE_WARNINGF(TL("Value of key '%' is not numeric ('%') in node '%'."), key, value, myLastNodeID);
1600 }
1601 } else if (key == "station") {
1602 interpretTransportType(value, myCurrentNode);
1603 myIsStation = true;
1604 } else if (key == "railway:ref") {
1605 myRailwayRef = value;
1606 } else {
1607 // v="yes"
1608 interpretTransportType(key, myCurrentNode);
1609 }
1610 }
1611 if (myAllAttributes && (myExtraAttributes.count(key) != 0 || myExtraAttributes.size() == 0)) {
1612 const std::string info = "node=" + toString(myCurrentNode->id) + ", k=" + key;
1613 myCurrentNode->setParameter(key, attrs.get<std::string>(SUMO_ATTR_V, info.c_str(), ok, false));
1614 }
1615 }
1616}
1617
1618
1619void
1621 if (element == SUMO_TAG_NODE && myHierarchyLevel == 2) {
1622 if (myIsStation && myRailwayRef != "") {
1623 myCurrentNode->setParameter("railway:ref", myRailwayRef);
1624 }
1625 myCurrentNode = nullptr;
1626 myIsStation = false;
1627 myRailwayRef = "";
1628 }
1629 --myHierarchyLevel;
1630}
1631
1632
1633// ---------------------------------------------------------------------------
1634// definitions of NIImporter_OpenStreetMap::EdgesHandler-methods
1635// ---------------------------------------------------------------------------
1637 const std::map<long long int, NIOSMNode*>& osmNodes,
1638 std::map<long long int, Edge*>& toFill, std::map<long long int, Edge*>& platformShapes,
1639 const NBTypeCont& tc):
1640 SUMOSAXHandler("osm - file"),
1641 myOSMNodes(osmNodes),
1642 myEdgeMap(toFill),
1643 myPlatformShapesMap(platformShapes),
1644 myTypeCont(tc) {
1645
1646 const double unlimitedSpeed = OptionsCont::getOptions().getFloat("osm.speedlimit-none");
1647
1649 mySpeedMap["sign"] = MAXSPEED_UNGIVEN;
1650 mySpeedMap["signals"] = MAXSPEED_UNGIVEN;
1651 mySpeedMap["none"] = unlimitedSpeed;
1652 mySpeedMap["no"] = unlimitedSpeed;
1653 mySpeedMap["walk"] = 5. / 3.6;
1654 // https://wiki.openstreetmap.org/wiki/Key:source:maxspeed#Commonly_used_values
1655 mySpeedMap["AT:urban"] = 50. / 3.6;
1656 mySpeedMap["AT:rural"] = 100. / 3.6;
1657 mySpeedMap["AT:trunk"] = 100. / 3.6;
1658 mySpeedMap["AT:motorway"] = 130. / 3.6;
1659 mySpeedMap["AU:urban"] = 50. / 3.6;
1660 mySpeedMap["BE:urban"] = 50. / 3.6;
1661 mySpeedMap["BE:zone"] = 30. / 3.6;
1662 mySpeedMap["BE:motorway"] = 120. / 3.6;
1663 mySpeedMap["BE:zone30"] = 30. / 3.6;
1664 mySpeedMap["BE-VLG:rural"] = 70. / 3.6;
1665 mySpeedMap["BE-WAL:rural"] = 90. / 3.6;
1666 mySpeedMap["BE:school"] = 30. / 3.6;
1667 mySpeedMap["CZ:motorway"] = 130. / 3.6;
1668 mySpeedMap["CZ:trunk"] = 110. / 3.6;
1669 mySpeedMap["CZ:rural"] = 90. / 3.6;
1670 mySpeedMap["CZ:urban_motorway"] = 80. / 3.6;
1671 mySpeedMap["CZ:urban_trunk"] = 80. / 3.6;
1672 mySpeedMap["CZ:urban"] = 50. / 3.6;
1673 mySpeedMap["DE:motorway"] = unlimitedSpeed;
1674 mySpeedMap["DE:rural"] = 100. / 3.6;
1675 mySpeedMap["DE:urban"] = 50. / 3.6;
1676 mySpeedMap["DE:bicycle_road"] = 30. / 3.6;
1677 mySpeedMap["DK:motorway"] = 130. / 3.6;
1678 mySpeedMap["DK:rural"] = 80. / 3.6;
1679 mySpeedMap["DK:urban"] = 50. / 3.6;
1680 mySpeedMap["EE:urban"] = 50. / 3.6;
1681 mySpeedMap["EE:rural"] = 90. / 3.6;
1682 mySpeedMap["ES:urban"] = 50. / 3.6;
1683 mySpeedMap["ES:zone30"] = 30. / 3.6;
1684 mySpeedMap["FR:motorway"] = 130. / 3.6; // 110 (raining)
1685 mySpeedMap["FR:rural"] = 80. / 3.6;
1686 mySpeedMap["FR:urban"] = 50. / 3.6;
1687 mySpeedMap["FR:zone30"] = 30. / 3.6;
1688 mySpeedMap["HU:living_street"] = 20. / 3.6;
1689 mySpeedMap["HU:motorway"] = 130. / 3.6;
1690 mySpeedMap["HU:rural"] = 90. / 3.6;
1691 mySpeedMap["HU:trunk"] = 110. / 3.6;
1692 mySpeedMap["HU:urban"] = 50. / 3.6;
1693 mySpeedMap["IT:rural"] = 90. / 3.6;
1694 mySpeedMap["IT:motorway"] = 130. / 3.6;
1695 mySpeedMap["IT:urban"] = 50. / 3.6;
1696 mySpeedMap["JP:nsl"] = 60. / 3.6;
1697 mySpeedMap["JP:express"] = 100. / 3.6;
1698 mySpeedMap["LT:rural"] = 90. / 3.6;
1699 mySpeedMap["LT:urban"] = 50. / 3.6;
1700 mySpeedMap["NO:rural"] = 80. / 3.6;
1701 mySpeedMap["NO:urban"] = 50. / 3.6;
1702 mySpeedMap["ON:urban"] = 50. / 3.6;
1703 mySpeedMap["ON:rural"] = 80. / 3.6;
1704 mySpeedMap["PT:motorway"] = 120. / 3.6;
1705 mySpeedMap["PT:rural"] = 90. / 3.6;
1706 mySpeedMap["PT:trunk"] = 100. / 3.6;
1707 mySpeedMap["PT:urban"] = 50. / 3.6;
1708 mySpeedMap["RO:motorway"] = 130. / 3.6;
1709 mySpeedMap["RO:rural"] = 90. / 3.6;
1710 mySpeedMap["RO:trunk"] = 100. / 3.6;
1711 mySpeedMap["RO:urban"] = 50. / 3.6;
1712 mySpeedMap["RS:living_street"] = 30. / 3.6;
1713 mySpeedMap["RS:motorway"] = 130. / 3.6;
1714 mySpeedMap["RS:rural"] = 80. / 3.6;
1715 mySpeedMap["RS:trunk"] = 100. / 3.6;
1716 mySpeedMap["RS:urban"] = 50. / 3.6;
1717 mySpeedMap["RU:living_street"] = 20. / 3.6;
1718 mySpeedMap["RU:urban"] = 60. / 3.6;
1719 mySpeedMap["RU:rural"] = 90. / 3.6;
1720 mySpeedMap["RU:motorway"] = 110. / 3.6;
1721 const double seventy = StringUtils::parseSpeed("70mph");
1722 const double sixty = StringUtils::parseSpeed("60mph");
1723 mySpeedMap["GB:motorway"] = seventy;
1724 mySpeedMap["GB:nsl_dual"] = seventy;
1725 mySpeedMap["GB:nsl_single"] = sixty;
1726 mySpeedMap["UK:motorway"] = seventy;
1727 mySpeedMap["UK:nsl_dual"] = seventy;
1728 mySpeedMap["UK:nsl_single"] = sixty;
1729 mySpeedMap["UZ:living_street"] = 30. / 3.6;
1730 mySpeedMap["UZ:urban"] = 70. / 3.6;
1731 mySpeedMap["UZ:rural"] = 100. / 3.6;
1732 mySpeedMap["UZ:motorway"] = 110. / 3.6;
1733}
1734
1736
1737void
1739 if (element == SUMO_TAG_WAY) {
1740 bool ok = true;
1741 const long long int id = attrs.get<long long int>(SUMO_ATTR_ID, nullptr, ok);
1742 const std::string& action = attrs.getOpt<std::string>(SUMO_ATTR_ACTION, nullptr, ok);
1743 if (action == "delete" || !ok) {
1744 myCurrentEdge = nullptr;
1745 return;
1746 }
1747 myCurrentEdge = new Edge(id);
1748 }
1749 // parse "nd" (node) elements
1750 if (element == SUMO_TAG_ND && myCurrentEdge != nullptr) {
1751 bool ok = true;
1752 long long int ref = attrs.get<long long int>(SUMO_ATTR_REF, nullptr, ok);
1753 if (ok) {
1754 auto node = myOSMNodes.find(ref);
1755 if (node == myOSMNodes.end()) {
1756 WRITE_WARNINGF(TL("The referenced geometry information (ref='%') is not known"), toString(ref));
1757 return;
1758 }
1759
1760 ref = node->second->id; // node may have been substituted
1761 if (myCurrentEdge->myCurrentNodes.empty() ||
1762 myCurrentEdge->myCurrentNodes.back() != ref) { // avoid consecutive duplicates
1763 myCurrentEdge->myCurrentNodes.push_back(ref);
1764 }
1765
1766 }
1767 }
1768 if (element == SUMO_TAG_TAG && myCurrentEdge != nullptr) {
1769 bool ok = true;
1770 std::string key = attrs.get<std::string>(SUMO_ATTR_K, toString(myCurrentEdge->id).c_str(), ok, false);
1771 if (key.size() > 6 && StringUtils::startsWith(key, "busway:")) {
1772 // handle special busway keys
1773 const std::string buswaySpec = key.substr(7);
1774 key = "busway";
1775 if (buswaySpec == "right") {
1776 myCurrentEdge->myBuswayType = (WayType)(myCurrentEdge->myBuswayType | WAY_FORWARD);
1777 } else if (buswaySpec == "left") {
1778 myCurrentEdge->myBuswayType = (WayType)(myCurrentEdge->myBuswayType | WAY_BACKWARD);
1779 } else if (buswaySpec == "both") {
1780 myCurrentEdge->myBuswayType = (WayType)(myCurrentEdge->myBuswayType | WAY_BOTH);
1781 } else {
1782 key = "ignore";
1783 }
1784 }
1785 if (myAllAttributes && (myExtraAttributes.count(key) != 0 || myExtraAttributes.size() == 0)) {
1786 const std::string info = "way=" + toString(myCurrentEdge->id) + ", k=" + key;
1787 myCurrentEdge->setParameter(key, attrs.get<std::string>(SUMO_ATTR_V, info.c_str(), ok, false));
1788 }
1789 // we check whether the key is relevant (and we really need to transcode the value) to avoid hitting #1636
1790 if (!StringUtils::endsWith(key, "way")
1791 && !StringUtils::startsWith(key, "lanes")
1792 && key != "maxspeed" && key != "maxspeed:type"
1793 && key != "zone:maxspeed"
1794 && key != "maxspeed:forward" && key != "maxspeed:backward"
1795 && key != "junction" && key != "name" && key != "tracks" && key != "layer"
1796 && key != "route"
1797 && !StringUtils::startsWith(key, "cycleway")
1798 && !StringUtils::startsWith(key, "sidewalk")
1799 && key != "ref"
1800 && key != "highspeed"
1801 && !StringUtils::startsWith(key, "parking")
1802 && !StringUtils::startsWith(key, "change")
1803 && !StringUtils::startsWith(key, "vehicle:lanes")
1804 && key != "postal_code"
1805 && key != "railway:preferred_direction"
1806 && key != "railway:bidirectional"
1807 && key != "railway:track_ref"
1808 && key != "usage"
1809 && key != "access"
1810 && key != "emergency"
1811 && key != "service"
1812 && key != "electrified"
1813 && key != "segregated"
1814 && key != "bus"
1815 && key != "psv"
1816 && key != "foot"
1817 && key != "bicycle"
1818 && key != "oneway:bicycle"
1819 && key != "oneway:bus"
1820 && key != "oneway:psv"
1821 && key != "bus:lanes"
1822 && key != "bus:lanes:forward"
1823 && key != "bus:lanes:backward"
1824 && key != "psv:lanes"
1825 && key != "psv:lanes:forward"
1826 && key != "psv:lanes:backward"
1827 && key != "bicycle:lanes"
1828 && key != "bicycle:lanes:forward"
1829 && key != "bicycle:lanes:backward"
1830 && !StringUtils::startsWith(key, "width")
1831 && !(StringUtils::startsWith(key, "turn:") && key.find(":lanes") != std::string::npos)
1832 && key != "public_transport") {
1833 return;
1834 }
1835 const std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentEdge->id).c_str(), ok, false);
1836
1837 if (key == "highway" || key == "railway" || key == "waterway" || StringUtils::startsWith(key, "cycleway")
1838 || key == "busway" || key == "route" || StringUtils::startsWith(key, "sidewalk") || key == "highspeed"
1839 || key == "aeroway" || key == "aerialway" || key == "usage" || key == "service") {
1840 // build type id
1841 if (key != "highway" || myTypeCont.knows(key + "." + value)) {
1842 myCurrentEdge->myCurrentIsRoad = true;
1843 }
1844 // special cycleway stuff https://wiki.openstreetmap.org/wiki/Key:cycleway
1845 if (key == "cycleway") {
1846 if (value == "no" || value == "none" || value == "separate") {
1847 myCurrentEdge->myCyclewayType = WAY_NONE;
1848 } else if (value == "both") {
1849 myCurrentEdge->myCyclewayType = WAY_BOTH;
1850 } else if (value == "right") {
1851 myCurrentEdge->myCyclewayType = WAY_FORWARD;
1852 } else if (value == "left") {
1853 myCurrentEdge->myCyclewayType = WAY_BACKWARD;
1854 } else if (value == "opposite_track") {
1855 myCurrentEdge->myCyclewayType = WAY_BACKWARD;
1856 } else if (value == "opposite_lane") {
1857 myCurrentEdge->myCyclewayType = WAY_BACKWARD;
1858 } else if (value == "opposite") {
1859 // according to the wiki ref above, this should rather be a bidi lane, see #13438
1860 myCurrentEdge->myCyclewayType = WAY_BACKWARD;
1861 }
1862 }
1863 if (key == "cycleway:left") {
1864 if (myCurrentEdge->myCyclewayType == WAY_UNKNOWN) {
1865 myCurrentEdge->myCyclewayType = WAY_NONE;
1866 }
1867 if (value == "yes" || value == "lane" || value == "track") {
1868 myCurrentEdge->myCyclewayType = (WayType)(myCurrentEdge->myCyclewayType | WAY_BACKWARD);
1869 }
1870 key = "cycleway"; // for type adaption
1871 }
1872 if (key == "cycleway:right") {
1873 if (myCurrentEdge->myCyclewayType == WAY_UNKNOWN) {
1874 myCurrentEdge->myCyclewayType = WAY_NONE;
1875 }
1876 if (value == "yes" || value == "lane" || value == "track") {
1877 myCurrentEdge->myCyclewayType = (WayType)(myCurrentEdge->myCyclewayType | WAY_FORWARD);
1878 }
1879 key = "cycleway"; // for type adaption
1880 }
1881 if (key == "cycleway:both") {
1882 if (myCurrentEdge->myCyclewayType == WAY_UNKNOWN) {
1883 if (value == "no" || value == "none" || value == "separate") {
1884 myCurrentEdge->myCyclewayType = WAY_NONE;
1885 }
1886 if (value == "yes" || value == "lane" || value == "track") {
1887 myCurrentEdge->myCyclewayType = WAY_BOTH;
1888 }
1889 }
1890 key = "cycleway"; // for type adaption
1891 }
1892 if (key == "cycleway" && value != "lane" && value != "track" && value != "opposite_track" && value != "opposite_lane") {
1893 // typemap covers only the lane and track cases
1894 return;
1895 }
1896 if (StringUtils::startsWith(key, "cycleway:")) {
1897 // no need to extend the type id for other cycleway sub tags
1898 return;
1899 }
1900 // special sidewalk stuff
1901 if (key == "sidewalk") {
1902 if (value == "no" || value == "none" || value == "separate") {
1903 myCurrentEdge->mySidewalkType = WAY_NONE;
1904 } else if (value == "both") {
1905 myCurrentEdge->mySidewalkType = WAY_BOTH;
1906 } else if (value == "right") {
1907 myCurrentEdge->mySidewalkType = WAY_FORWARD;
1908 } else if (value == "left") {
1909 myCurrentEdge->mySidewalkType = WAY_BACKWARD;
1910 }
1911 }
1912 if (key == "sidewalk:left") {
1913 if (myCurrentEdge->mySidewalkType == WAY_UNKNOWN) {
1914 myCurrentEdge->mySidewalkType = WAY_NONE;
1915 }
1916 if (value == "yes") {
1917 myCurrentEdge->mySidewalkType = (WayType)(myCurrentEdge->mySidewalkType | WAY_BACKWARD);
1918 }
1919 }
1920 if (key == "sidewalk:right") {
1921 if (myCurrentEdge->mySidewalkType == WAY_UNKNOWN) {
1922 myCurrentEdge->mySidewalkType = WAY_NONE;
1923 }
1924 if (value == "yes") {
1925 myCurrentEdge->mySidewalkType = (WayType)(myCurrentEdge->mySidewalkType | WAY_FORWARD);
1926 }
1927 }
1928 if (key == "sidewalk:both") {
1929 if (myCurrentEdge->mySidewalkType == WAY_UNKNOWN) {
1930 if (value == "no" || value == "none" || value == "separate") {
1931 myCurrentEdge->mySidewalkType = WAY_NONE;
1932 }
1933 if (value == "yes") {
1934 myCurrentEdge->mySidewalkType = WAY_BOTH;
1935 }
1936 }
1937 }
1938 if (StringUtils::startsWith(key, "sidewalk")) {
1939 // no need to extend the type id
1940 return;
1941 }
1942 // special busway stuff
1943 if (key == "busway") {
1944 if (value == "no") {
1945 return;
1946 }
1947 if (value == "opposite_track") {
1948 myCurrentEdge->myBuswayType = WAY_BACKWARD;
1949 } else if (value == "opposite_lane") {
1950 myCurrentEdge->myBuswayType = WAY_BACKWARD;
1951 }
1952 // no need to extend the type id
1953 return;
1954 }
1955 std::string singleTypeID = key + "." + value;
1956 if (key == "highspeed") {
1957 if (value == "no") {
1958 return;
1959 }
1960 singleTypeID = "railway.highspeed";
1961 }
1962 addType(singleTypeID);
1963
1964 } else if (key == "bus" || key == "psv") {
1965 // 'psv' includes taxi in the UK but not in germany
1966 try {
1967 if (StringUtils::toBool(value)) {
1968 myCurrentEdge->myExtraAllowed |= SVC_BUS;
1969 addType(key);
1970 } else {
1971 myCurrentEdge->myExtraDisallowed |= SVC_BUS;
1972 }
1973 } catch (const BoolFormatException&) {
1974 myCurrentEdge->myExtraAllowed |= SVC_BUS;
1975 addType(key);
1976 }
1977 } else if (key == "emergency") {
1978 try {
1979 if (StringUtils::toBool(value)) {
1980 myCurrentEdge->myExtraAllowed |= SVC_AUTHORITY | SVC_EMERGENCY;
1981 }
1982 } catch (const BoolFormatException&) {
1983 myCurrentEdge->myExtraAllowed |= SVC_AUTHORITY | SVC_EMERGENCY;
1984 }
1985 } else if (key == "access") {
1986 if (value == "no") {
1987 myCurrentEdge->myExtraDisallowed |= ~(SVC_PUBLIC_CLASSES | SVC_EMERGENCY | SVC_AUTHORITY);
1988 }
1989 } else if (StringUtils::startsWith(key, "width:lanes")) {
1990 try {
1991 const std::vector<std::string> values = StringTokenizer(value, "|").getVector();
1992 std::vector<double> widthLanes;
1993 for (std::string width : values) {
1994 const double parsedWidth = width == "" ? -1 : StringUtils::parseDist(width);
1995 widthLanes.push_back(parsedWidth);
1996 }
1997
1998 if (key == "width:lanes" || key == "width:lanes:forward") {
1999 myCurrentEdge->myWidthLanesForward = widthLanes;
2000 } else if (key == "width:lanes:backward") {
2001 myCurrentEdge->myWidthLanesBackward = widthLanes;
2002 } else {
2003 WRITE_WARNINGF(TL("Using default lane width for edge '%' as key '%' could not be parsed."), toString(myCurrentEdge->id), key);
2004 }
2005 } catch (const NumberFormatException&) {
2006 WRITE_WARNINGF(TL("Using default lane width for edge '%' as value '%' could not be parsed."), toString(myCurrentEdge->id), value);
2007 }
2008 } else if (key == "width") {
2009 try {
2010 myCurrentEdge->myWidth = StringUtils::parseDist(value);
2011 } catch (const NumberFormatException&) {
2012 WRITE_WARNINGF(TL("Using default width for edge '%' as value '%' could not be parsed."), toString(myCurrentEdge->id), value);
2013 }
2014 } else if (key == "foot") {
2015 if (value == "use_sidepath" || value == "no") {
2016 myCurrentEdge->myExtraDisallowed |= SVC_PEDESTRIAN;
2017 } else if (value == "yes" || value == "designated" || value == "permissive") {
2018 myCurrentEdge->myExtraAllowed |= SVC_PEDESTRIAN;
2019 }
2020 } else if (key == "bicycle") {
2021 if (value == "use_sidepath" || value == "no") {
2022 myCurrentEdge->myExtraDisallowed |= SVC_BICYCLE;
2023 } else if (value == "yes" || value == "designated" || value == "permissive") {
2024 myCurrentEdge->myExtraAllowed |= SVC_BICYCLE;
2025 }
2026 } else if (key == "oneway:bicycle") {
2027 myCurrentEdge->myExtraTags["oneway:bicycle"] = value;
2028 } else if (key == "oneway:bus" || key == "oneway:psv") {
2029 if (value == "no") {
2030 // need to add a bus way in reversed direction of way
2031 myCurrentEdge->myBuswayType = WAY_BACKWARD;
2032 }
2033 } else if (key == "lanes") {
2034 try {
2035 myCurrentEdge->myNoLanes = StringUtils::toInt(value);
2036 } catch (NumberFormatException&) {
2037 // might be a list of values
2038 StringTokenizer st(value, ";", true);
2039 std::vector<std::string> list = st.getVector();
2040 if (list.size() >= 2) {
2041 int minLanes = std::numeric_limits<int>::max();
2042 try {
2043 for (auto& i : list) {
2044 const int numLanes = StringUtils::toInt(StringUtils::prune(i));
2045 minLanes = MIN2(minLanes, numLanes);
2046 }
2047 myCurrentEdge->myNoLanes = minLanes;
2048 WRITE_WARNINGF(TL("Using minimum lane number from list (%) for edge '%'."), value, toString(myCurrentEdge->id));
2049 } catch (NumberFormatException&) {
2050 WRITE_WARNINGF(TL("Value of key '%' is not numeric ('%') in edge '%'."), key, value, myCurrentEdge->id);
2051 }
2052 }
2053 } catch (EmptyData&) {
2054 WRITE_WARNINGF(TL("Value of key '%' is not numeric ('%') in edge '%'."), key, value, myCurrentEdge->id);
2055 }
2056 } else if (key == "lanes:forward") {
2057 try {
2058 const int numLanes = StringUtils::toInt(value);
2059 if (myCurrentEdge->myNoLanesForward < 0 && myCurrentEdge->myNoLanes < 0) {
2060 // fix lane count in case only lanes:forward and lanes:backward are set
2061 myCurrentEdge->myNoLanes = numLanes - myCurrentEdge->myNoLanesForward;
2062 }
2063 myCurrentEdge->myNoLanesForward = numLanes;
2064 } catch (...) {
2065 WRITE_WARNINGF(TL("Value of key '%' is not numeric ('%') in edge '%'."), key, value, myCurrentEdge->id);
2066 }
2067 } else if (key == "lanes:backward") {
2068 try {
2069 const int numLanes = StringUtils::toInt(value);
2070 if (myCurrentEdge->myNoLanesForward > 0 && myCurrentEdge->myNoLanes < 0) {
2071 // fix lane count in case only lanes:forward and lanes:backward are set
2072 myCurrentEdge->myNoLanes = numLanes + myCurrentEdge->myNoLanesForward;
2073 }
2074 // denote backwards count with a negative sign
2075 myCurrentEdge->myNoLanesForward = -numLanes;
2076 } catch (...) {
2077 WRITE_WARNINGF(TL("Value of key '%' is not numeric ('%') in edge '%'."), key, value, myCurrentEdge->id);
2078 }
2079 } else if (myCurrentEdge->myMaxSpeed == MAXSPEED_UNGIVEN &&
2080 (key == "maxspeed" || key == "maxspeed:type" || key == "maxspeed:forward" || key == "zone:maxspeed")) {
2081 // both 'maxspeed' and 'maxspeed:type' may be given so we must take care not to overwrite an already seen value
2082 myCurrentEdge->myMaxSpeed = interpretSpeed(key, value);
2083 } else if (key == "maxspeed:backward" && myCurrentEdge->myMaxSpeedBackward == MAXSPEED_UNGIVEN) {
2084 myCurrentEdge->myMaxSpeedBackward = interpretSpeed(key, value);
2085 } else if (key == "junction") {
2086 if ((value == "roundabout" || value == "circular") && myCurrentEdge->myIsOneWay.empty()) {
2087 myCurrentEdge->myIsOneWay = "yes";
2088 }
2089 if (value == "roundabout") {
2090 myCurrentEdge->myAmInRoundabout = true;
2091 }
2092 } else if (key == "oneway") {
2093 myCurrentEdge->myIsOneWay = value;
2094 } else if (key == "name") {
2095 myCurrentEdge->streetName = value;
2096 } else if (key == "ref") {
2097 myCurrentEdge->ref = value;
2098 myCurrentEdge->setParameter("ref", value);
2099 } else if (key == "layer") {
2100 try {
2101 myCurrentEdge->myLayer = StringUtils::toInt(value);
2102 } catch (...) {
2103 WRITE_WARNINGF(TL("Value of key '%' is not numeric ('%') in edge '%'."), key, value, myCurrentEdge->id);
2104 }
2105 } else if (key == "tracks") {
2106 try {
2107 if (StringUtils::toInt(value) == 1) {
2108 myCurrentEdge->myIsOneWay = "true";
2109 } else {
2110 WRITE_WARNINGF(TL("Ignoring track count % for edge '%'."), value, myCurrentEdge->id);
2111 }
2112 } catch (...) {
2113 WRITE_WARNINGF(TL("Value of key '%' is not numeric ('%') in edge '%'."), key, value, myCurrentEdge->id);
2114 }
2115 } else if (key == "railway:preferred_direction") {
2116 if (value == "both") {
2117 myCurrentEdge->myRailDirection = WAY_BOTH;
2118 } else if (myCurrentEdge->myRailDirection == WAY_UNKNOWN) {
2119 if (value == "backward") {
2120 myCurrentEdge->myRailDirection = WAY_BACKWARD;
2121 } else if (value == "forward") {
2122 myCurrentEdge->myRailDirection = WAY_FORWARD;
2123 }
2124 }
2125 } else if (key == "railway:bidirectional") {
2126 if (value == "regular") {
2127 myCurrentEdge->myRailDirection = WAY_BOTH;
2128 }
2129 } else if (key == "electrified" || key == "segregated") {
2130 if (value != "no") {
2131 myCurrentEdge->myExtraTags[key] = value;
2132 }
2133 } else if (key == "railway:track_ref") {
2134 myCurrentEdge->setParameter(key, value);
2135 } else if (key == "public_transport" && value == "platform") {
2136 myCurrentEdge->myExtraTags["platform"] = "yes";
2137 } else if ((key == "parking:both" || key == "parking:lane:both") && !StringUtils::startsWith(value, "no")) {
2138 myCurrentEdge->myParkingType |= PARKING_BOTH;
2139 } else if ((key == "parking:left" || key == "parking:lane:left") && !StringUtils::startsWith(value, "no")) {
2140 myCurrentEdge->myParkingType |= PARKING_LEFT;
2141 } else if ((key == "parking:right" || key == "parking:lane:right") && !StringUtils::startsWith(value, "no")) {
2142 myCurrentEdge->myParkingType |= PARKING_RIGHT;
2143 } else if (key == "change" || key == "change:lanes") {
2144 myCurrentEdge->myChangeForward = myCurrentEdge->myChangeBackward = interpretChangeType(value);
2145 } else if (key == "change:forward" || key == "change:lanes:forward") {
2146 myCurrentEdge->myChangeForward = interpretChangeType(value);
2147 } else if (key == "change:backward" || key == "change:lanes:backward") {
2148 myCurrentEdge->myChangeBackward = interpretChangeType(value);
2149 } else if (key == "vehicle:lanes" || key == "vehicle:lanes:forward") {
2150 interpretLaneUse(value, SVC_PASSENGER, true);
2151 interpretLaneUse(value, SVC_PRIVATE, true);
2152 } else if (key == "vehicle:lanes:backward") {
2153 interpretLaneUse(value, SVC_PASSENGER, false);
2154 interpretLaneUse(value, SVC_PRIVATE, false);
2155 } else if (key == "bus:lanes" || key == "bus:lanes:forward") {
2156 interpretLaneUse(value, SVC_BUS, true);
2157 } else if (key == "bus:lanes:backward") {
2158 interpretLaneUse(value, SVC_BUS, false);
2159 } else if (key == "psv:lanes" || key == "psv:lanes:forward") {
2160 interpretLaneUse(value, SVC_BUS, true);
2161 interpretLaneUse(value, SVC_TAXI, true);
2162 } else if (key == "psv:lanes:backward") {
2163 interpretLaneUse(value, SVC_BUS, false);
2164 interpretLaneUse(value, SVC_TAXI, false);
2165 } else if (key == "bicycle:lanes" || key == "bicycle:lanes:forward") {
2166 interpretLaneUse(value, SVC_BICYCLE, true);
2167 } else if (key == "bicycle:lanes:backward") {
2168 interpretLaneUse(value, SVC_BICYCLE, false);
2169 } else if (StringUtils::startsWith(key, "turn:") && key.find(":lanes") != std::string::npos) {
2170 int shift = 0;
2171 // use the first 8 bit to encode permitted directions for all classes
2172 // and the successive 8 bit blocks for selected classes
2173 if (StringUtils::startsWith(key, "turn:bus") || StringUtils::startsWith(key, "turn:psv:")) {
2175 } else if (StringUtils::startsWith(key, "turn:taxi")) {
2177 } else if (StringUtils::startsWith(key, "turn:bicycle")) {
2179 }
2180 const std::vector<std::string> values = StringTokenizer(value, "|").getVector();
2181 std::vector<int> turnCodes;
2182 for (std::string codeList : values) {
2183 const std::vector<std::string> codes = StringTokenizer(codeList, ";").getVector();
2184 int turnCode = 0;
2185 if (codes.size() == 0) {
2186 turnCode = (int)LinkDirection::STRAIGHT;
2187 }
2188 for (std::string code : codes) {
2189 if (code == "" || code == "none" || code == "through") {
2190 turnCode |= (int)LinkDirection::STRAIGHT << shift ;
2191 } else if (code == "left" || code == "sharp_left") {
2192 turnCode |= (int)LinkDirection::LEFT << shift;
2193 } else if (code == "right" || code == "sharp_right") {
2194 turnCode |= (int)LinkDirection::RIGHT << shift;
2195 } else if (code == "slight_left") {
2196 turnCode |= (int)LinkDirection::PARTLEFT << shift;
2197 } else if (code == "slight_right") {
2198 turnCode |= (int)LinkDirection::PARTRIGHT << shift;
2199 } else if (code == "reverse") {
2200 turnCode |= (int)LinkDirection::TURN << shift;
2201 } else if (code == "merge_to_left" || code == "merge_to_right") {
2202 turnCode |= (int)LinkDirection::NODIR << shift;
2203 }
2204 }
2205 turnCodes.push_back(turnCode);
2206 }
2207 if (StringUtils::endsWith(key, "lanes") || StringUtils::endsWith(key, "lanes:forward")) {
2208 mergeTurnSigns(myCurrentEdge->myTurnSignsForward, turnCodes);
2209 } else if (StringUtils::endsWith(key, "lanes:backward")) {
2210 mergeTurnSigns(myCurrentEdge->myTurnSignsBackward, turnCodes);
2211 } else if (StringUtils::endsWith(key, "lanes:both_ways")) {
2212 mergeTurnSigns(myCurrentEdge->myTurnSignsForward, turnCodes);
2213 mergeTurnSigns(myCurrentEdge->myTurnSignsBackward, turnCodes);
2214 }
2215 }
2216 }
2217}
2218
2219
2220void
2221NIImporter_OpenStreetMap::EdgesHandler::addType(const std::string& singleTypeID) {
2222 // special case: never build compound type for highspeed rail
2223 if (!myCurrentEdge->myHighWayType.empty() && singleTypeID != "railway.highspeed") {
2224 if (myCurrentEdge->myHighWayType == "railway.highspeed") {
2225 return;
2226 }
2227 // osm-ways may be used by more than one mode (eg railway.tram + highway.residential. this is relevant for multimodal traffic)
2228 // we create a new type for this kind of situation which must then be resolved in insertEdge()
2229 std::vector<std::string> types = StringTokenizer(myCurrentEdge->myHighWayType,
2231 types.push_back(singleTypeID);
2232 myCurrentEdge->myHighWayType = joinToStringSorting(types, compoundTypeSeparator);
2233 } else {
2234 myCurrentEdge->myHighWayType = singleTypeID;
2235 }
2236}
2237
2238
2239double
2240NIImporter_OpenStreetMap::EdgesHandler::interpretSpeed(const std::string& key, std::string value) {
2241 if (mySpeedMap.find(value) != mySpeedMap.end()) {
2242 return mySpeedMap[value];
2243 } else {
2244 // handle symbolic names of the form DE:30 / DE:zone30
2245 if (value.size() > 3 && value[2] == ':') {
2246 if (value.substr(3, 4) == "zone") {
2247 value = value.substr(7);
2248 } else {
2249 value = value.substr(3);
2250 }
2251 }
2252 try {
2253 return StringUtils::parseSpeed(value);
2254 } catch (...) {
2255 WRITE_WARNING("Value of key '" + key + "' is not numeric ('" + value + "') in edge '" +
2256 toString(myCurrentEdge->id) + "'.");
2257 return MAXSPEED_UNGIVEN;
2258 }
2259 }
2260}
2261
2262
2263int
2265 int result = 0;
2266 const std::vector<std::string> values = StringTokenizer(value, "|").getVector();
2267 for (const std::string& val : values) {
2268 if (val == "no") {
2269 result += CHANGE_NO;
2270 } else if (val == "not_left") {
2271 result += CHANGE_NO_LEFT;
2272 } else if (val == "not_right") {
2273 result += CHANGE_NO_RIGHT;
2274 }
2275 result = result << 2;
2276 }
2277 // last shift was superfluous
2278 result = result >> 2;
2279
2280 if (values.size() > 1) {
2281 result += 2 << 29; // mark multi-value input
2282 }
2283 //std::cout << " way=" << myCurrentEdge->id << " value=" << value << " result=" << std::bitset<32>(result) << "\n";
2284 return result;
2285}
2286
2287
2288void
2289NIImporter_OpenStreetMap::EdgesHandler::interpretLaneUse(const std::string& value, SUMOVehicleClass svc, const bool forward) const {
2290 const std::vector<std::string> values = StringTokenizer(value, "|").getVector();
2291 std::vector<bool>& designated = forward ? myCurrentEdge->myDesignatedLaneForward : myCurrentEdge->myDesignatedLaneBackward;
2292 std::vector<SVCPermissions>& allowed = forward ? myCurrentEdge->myAllowedLaneForward : myCurrentEdge->myAllowedLaneBackward;
2293 std::vector<SVCPermissions>& disallowed = forward ? myCurrentEdge->myDisallowedLaneForward : myCurrentEdge->myDisallowedLaneBackward;
2294 designated.resize(MAX2(designated.size(), values.size()), false);
2295 allowed.resize(MAX2(allowed.size(), values.size()), SVC_IGNORING);
2296 disallowed.resize(MAX2(disallowed.size(), values.size()), SVC_IGNORING);
2297 int i = 0;
2298 for (const std::string& val : values) {
2299 if (val == "yes" || val == "permissive") {
2300 allowed[i] |= svc;
2301 } else if (val == "lane" || val == "designated") {
2302 allowed[i] |= svc;
2303 designated[i] = true;
2304 } else if (val == "no") {
2305 disallowed[i] |= svc;
2306 } else {
2307 WRITE_WARNINGF(TL("Unknown lane use specifier '%' ignored for way '%'"), val, myCurrentEdge->id);
2308 }
2309 i++;
2310 }
2311}
2312
2313
2314void
2316 if (element == SUMO_TAG_WAY && myCurrentEdge != nullptr) {
2317 if (myCurrentEdge->myCurrentIsRoad) {
2318 const auto insertionIt = myEdgeMap.lower_bound(myCurrentEdge->id);
2319 if (insertionIt == myEdgeMap.end() || insertionIt->first != myCurrentEdge->id) {
2320 // assume we are loading multiple files, so we won't report duplicate edges
2321 myEdgeMap.emplace_hint(insertionIt, myCurrentEdge->id, myCurrentEdge);
2322 } else {
2323 delete myCurrentEdge;
2324 }
2325 } else if (myCurrentEdge->myExtraTags.count("platform") != 0) {
2326 const auto insertionIt = myPlatformShapesMap.lower_bound(myCurrentEdge->id);
2327 if (insertionIt == myPlatformShapesMap.end() || insertionIt->first != myCurrentEdge->id) {
2328 // assume we are loading multiple files, so we won't report duplicate platforms
2329 myPlatformShapesMap.emplace_hint(insertionIt, myCurrentEdge->id, myCurrentEdge);
2330 } else {
2331 delete myCurrentEdge;
2332 }
2333 } else {
2334 delete myCurrentEdge;
2335 }
2336 myCurrentEdge = nullptr;
2337 }
2338}
2339
2340
2341// ---------------------------------------------------------------------------
2342// definitions of NIImporter_OpenStreetMap::RelationHandler-methods
2343// ---------------------------------------------------------------------------
2345 const std::map<long long int, NIOSMNode*>& osmNodes,
2346 const std::map<long long int, Edge*>& osmEdges, NBPTStopCont* nbptStopCont,
2347 const std::map<long long int, Edge*>& platformShapes,
2348 NBPTLineCont* nbptLineCont,
2349 const OptionsCont& oc) :
2350 SUMOSAXHandler("osm - file"),
2351 myOSMNodes(osmNodes),
2352 myOSMEdges(osmEdges),
2353 myPlatformShapes(platformShapes),
2354 myNBPTStopCont(nbptStopCont),
2355 myNBPTLineCont(nbptLineCont),
2356 myOptionsCont(oc) {
2357 resetValues();
2358}
2359
2360
2362
2363
2364void
2366 myCurrentRelation = INVALID_ID;
2367 myIsRestriction = false;
2368 myRestrictionException = SVC_IGNORING;
2369 myFromWay = INVALID_ID;
2370 myToWay = INVALID_ID;
2371 myViaNode = INVALID_ID;
2372 myViaWay = INVALID_ID;
2373 myStation = INVALID_ID;
2374 myRestrictionType = RestrictionType::UNKNOWN;
2375 myPlatforms.clear();
2376 myStops.clear();
2377 myPlatformStops.clear();
2378 myWays.clear();
2379 myIsStopArea = false;
2380 myIsRoute = false;
2381 myPTRouteType = "";
2382 myRouteColor.setValid(false);
2383}
2384
2385
2386void
2388 if (element == SUMO_TAG_RELATION) {
2389 bool ok = true;
2390 myCurrentRelation = attrs.get<long long int>(SUMO_ATTR_ID, nullptr, ok);
2391 const std::string& action = attrs.getOpt<std::string>(SUMO_ATTR_ACTION, nullptr, ok);
2392 if (action == "delete" || !ok) {
2393 myCurrentRelation = INVALID_ID;
2394 }
2395 myName = "";
2396 myRef = "";
2397 myInterval = -1;
2398 myNightService = "";
2399 return;
2400 }
2401 if (myCurrentRelation == INVALID_ID) {
2402 return;
2403 }
2404 if (element == SUMO_TAG_MEMBER) {
2405 bool ok = true;
2406 std::string role = attrs.hasAttribute("role") ? attrs.getStringSecure("role", "") : "";
2407 const long long int ref = attrs.get<long long int>(SUMO_ATTR_REF, nullptr, ok);
2408 if (role == "via") {
2409 // u-turns for divided ways may be given with 2 via-nodes or 1 via-way
2410 std::string memberType = attrs.get<std::string>(SUMO_ATTR_TYPE, nullptr, ok);
2411 if (memberType == "way" && checkEdgeRef(ref)) {
2412 myViaWay = ref;
2413 } else if (memberType == "node") {
2414 if (myOSMNodes.find(ref) != myOSMNodes.end()) {
2415 myViaNode = ref;
2416 } else {
2417 WRITE_WARNINGF(TL("No node found for reference '%' in relation '%'."), toString(ref), toString(myCurrentRelation));
2418 }
2419 }
2420 } else if (role == "from" && checkEdgeRef(ref)) {
2421 myFromWay = ref;
2422 } else if (role == "to" && checkEdgeRef(ref)) {
2423 myToWay = ref;
2424 } else if (StringUtils::startsWith(role, "stop")) {
2425 // permit _entry_only and _exit_only variants
2426 myStops.push_back(ref);
2427 } else if (StringUtils::startsWith(role, "platform")) {
2428 // permit _entry_only and _exit_only variants
2429 std::string memberType = attrs.get<std::string>(SUMO_ATTR_TYPE, nullptr, ok);
2430 if (memberType == "way") {
2431 const std::map<long long int, NIImporter_OpenStreetMap::Edge*>::const_iterator& wayIt = myPlatformShapes.find(ref);
2432 if (wayIt != myPlatformShapes.end()) {
2433 NIIPTPlatform platform;
2434 platform.isWay = true;
2435 platform.ref = ref;
2436 myPlatforms.push_back(platform);
2437 }
2438 } else if (memberType == "node") {
2439 // myIsStopArea may not be set yet
2440 myStops.push_back(ref);
2441 myPlatformStops.insert(ref);
2442 NIIPTPlatform platform;
2443 platform.isWay = false;
2444 platform.ref = ref;
2445 myPlatforms.push_back(platform);
2446 }
2447
2448 } else if (role == "station") {
2449 myStation = ref;
2450 } else if (role.empty()) {
2451 std::string memberType = attrs.get<std::string>(SUMO_ATTR_TYPE, nullptr, ok);
2452 if (memberType == "way") {
2453 myWays.push_back(ref);
2454 } else if (memberType == "node") {
2455 auto it = myOSMNodes.find(ref);
2456 if (it != myOSMNodes.end() && it->second->hasParameter("railway:ref")) {
2457 myStation = ref;
2458 } else {
2459 myStops.push_back(ref);
2460 }
2461 }
2462 }
2463 return;
2464 }
2465 // parse values
2466 if (element == SUMO_TAG_TAG) {
2467 bool ok = true;
2468 std::string key = attrs.get<std::string>(SUMO_ATTR_K, toString(myCurrentRelation).c_str(), ok, false);
2469 // we check whether the key is relevant (and we really need to transcode the value) to avoid hitting #1636
2470 if (key == "type" || key == "restriction") {
2471 std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
2472 if (key == "type" && value == "restriction") {
2473 myIsRestriction = true;
2474 return;
2475 }
2476 if (key == "type" && value == "route") {
2477 myIsRoute = true;
2478 return;
2479 }
2480 if (key == "restriction") {
2481 // @note: the 'right/left/straight' part is ignored since the information is
2482 // redundantly encoded in the 'from', 'to' and 'via' members
2483 if (value.substr(0, 5) == "only_") {
2484 myRestrictionType = RestrictionType::ONLY;
2485 } else if (value.substr(0, 3) == "no_") {
2486 myRestrictionType = RestrictionType::NO;
2487 } else {
2488 WRITE_WARNINGF(TL("Found unknown restriction type '%' in relation '%'"), value, toString(myCurrentRelation));
2489 }
2490 return;
2491 }
2492 } else if (key == "except") {
2493 std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
2494 for (const std::string& v : StringTokenizer(value, ";").getVector()) {
2495 if (v == "psv") {
2496 myRestrictionException |= SVC_BUS;
2497 } else if (v == "bicycle") {
2498 myRestrictionException |= SVC_BICYCLE;
2499 } else if (v == "hgv") {
2500 myRestrictionException |= SVC_TRUCK | SVC_TRAILER;
2501 } else if (v == "motorcar") {
2502 myRestrictionException |= SVC_PASSENGER | SVC_TAXI;
2503 } else if (v == "emergency") {
2504 myRestrictionException |= SVC_EMERGENCY;
2505 }
2506 }
2507 } else if (key == "public_transport") {
2508 std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
2509 if (value == "stop_area") {
2510 myIsStopArea = true;
2511 }
2512 } else if (key == "route") {
2513 std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
2514 if (value == "train" || value == "subway" || value == "light_rail" || value == "monorail" || value == "tram" || value == "bus"
2515 || value == "trolleybus" || value == "aerialway" || value == "ferry" || value == "share_taxi" || value == "minibus") {
2516 myPTRouteType = value;
2517 }
2518
2519 } else if (key == "name") {
2520 myName = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
2521 } else if (key == "colour") {
2522 std::string value = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
2523 try {
2524 myRouteColor = RGBColor::parseColor(value);
2525 } catch (...) {
2526 WRITE_WARNINGF(TL("Invalid color value '%' in relation %"), value, myCurrentRelation);
2527 }
2528 } else if (key == "ref") {
2529 myRef = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
2530 } else if (key == "interval" || key == "headway") {
2531 myInterval = attrs.get<int>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
2532 } else if (key == "by_night") {
2533 myNightService = attrs.get<std::string>(SUMO_ATTR_V, toString(myCurrentRelation).c_str(), ok, false);
2534 }
2535 }
2536}
2537
2538
2539bool
2541 if (myOSMEdges.find(ref) != myOSMEdges.end()) {
2542 return true;
2543 }
2544 WRITE_WARNINGF(TL("No way found for reference '%' in relation '%'"), toString(ref), toString(myCurrentRelation));
2545 return false;
2546}
2547
2548
2549void
2551 if (element == SUMO_TAG_RELATION) {
2552 if (myIsRestriction) {
2553 assert(myCurrentRelation != INVALID_ID);
2554 bool ok = true;
2555 if (myRestrictionType == RestrictionType::UNKNOWN) {
2556 WRITE_WARNINGF(TL("Ignoring restriction relation '%' with unknown type."), toString(myCurrentRelation));
2557 ok = false;
2558 }
2559 if (myFromWay == INVALID_ID) {
2560 WRITE_WARNINGF(TL("Ignoring restriction relation '%' with unknown from-way."), toString(myCurrentRelation));
2561 ok = false;
2562 }
2563 if (myToWay == INVALID_ID) {
2564 WRITE_WARNINGF(TL("Ignoring restriction relation '%' with unknown to-way."), toString(myCurrentRelation));
2565 ok = false;
2566 }
2567 if (myViaNode == INVALID_ID && myViaWay == INVALID_ID) {
2568 WRITE_WARNINGF(TL("Ignoring restriction relation '%' with unknown via."), toString(myCurrentRelation));
2569 ok = false;
2570 }
2571 if (ok && !applyRestriction()) {
2572 WRITE_WARNINGF(TL("Ignoring restriction relation '%'."), toString(myCurrentRelation));
2573 }
2574 } else if (myIsStopArea) {
2575 for (long long ref : myStops) {
2576 myStopAreas[ref] = myCurrentRelation;
2577 if (myOSMNodes.find(ref) == myOSMNodes.end()) {
2578 //WRITE_WARNING(
2579 // "Referenced node: '" + toString(ref) + "' in relation: '" + toString(myCurrentRelation)
2580 // + "' does not exist. Probably OSM file is incomplete.");
2581 continue;
2582 }
2583
2584 NIOSMNode* n = myOSMNodes.find(ref)->second;
2585 std::shared_ptr<NBPTStop> ptStop = myNBPTStopCont->get(toString(n->id));
2586 if (ptStop == nullptr) {
2587 //WRITE_WARNING(
2588 // "Relation '" + toString(myCurrentRelation) + "' refers to a non existing pt stop at node: '"
2589 // + toString(n->id) + "'. Probably OSM file is incomplete.");
2590 continue;
2591 }
2592 for (NIIPTPlatform& myPlatform : myPlatforms) {
2593 if (myPlatform.isWay) {
2594 assert(myPlatformShapes.find(myPlatform.ref) != myPlatformShapes.end()); //already tested earlier
2595 Edge* edge = (*myPlatformShapes.find(myPlatform.ref)).second;
2596 if (edge->myCurrentNodes.size() > 1 && edge->myCurrentNodes[0] == *(edge->myCurrentNodes.end() - 1)) {
2597 WRITE_WARNINGF(TL("Platform '%' in relation: '%' is given as polygon, which currently is not supported."), myPlatform.ref, myCurrentRelation);
2598 continue;
2599
2600 }
2602 for (auto nodeRef : edge->myCurrentNodes) {
2603 if (myOSMNodes.find(nodeRef) == myOSMNodes.end()) {
2604 //WRITE_WARNING(
2605 // "Referenced node: '" + toString(ref) + "' in relation: '" + toString(myCurrentRelation)
2606 // + "' does not exist. Probably OSM file is incomplete.");
2607 continue;
2608 }
2609 NIOSMNode* pNode = myOSMNodes.find(nodeRef)->second;
2610 Position pNodePos(pNode->lon, pNode->lat, pNode->ele);
2611 if (!NBNetBuilder::transformCoordinate(pNodePos)) {
2612 WRITE_ERRORF("Unable to project coordinates for node '%'.", pNode->id);
2613 continue;
2614 }
2615 p.push_back(pNodePos);
2616 }
2617 if (p.size() == 0) {
2618 WRITE_WARNINGF(TL("Referenced platform: '%' in relation: '%' is corrupt. Probably OSM file is incomplete."),
2619 toString(myPlatform.ref), toString(myCurrentRelation));
2620 continue;
2621 }
2622 NBPTPlatform platform(p[(int)p.size() / 2], p.length());
2623 ptStop->addPlatformCand(platform);
2624 } else {
2625 if (myOSMNodes.find(myPlatform.ref) == myOSMNodes.end()) {
2626 //WRITE_WARNING(
2627 // "Referenced node: '" + toString(ref) + "' in relation: '" + toString(myCurrentRelation)
2628 // + "' does not exist. Probably OSM file is incomplete.");
2629 continue;
2630 }
2631 NIOSMNode* pNode = myOSMNodes.find(myPlatform.ref)->second;
2632 Position platformPos(pNode->lon, pNode->lat, pNode->ele);
2633 if (!NBNetBuilder::transformCoordinate(platformPos)) {
2634 WRITE_ERRORF("Unable to project coordinates for node '%'.", pNode->id);
2635 }
2636 NBPTPlatform platform(platformPos, myOptionsCont.getFloat("osm.stop-output.length"));
2637 ptStop->addPlatformCand(platform);
2638
2639 }
2640 }
2641 ptStop->setIsMultipleStopPositions(myStops.size() > 1, myCurrentRelation);
2642 if (myStation != INVALID_ID) {
2643 const auto& nodeIt = myOSMNodes.find(myStation);
2644 if (nodeIt != myOSMNodes.end()) {
2645 NIOSMNode* station = nodeIt->second;
2646 if (station != nullptr) {
2647 if (station->hasParameter("railway:ref")) {
2648 ptStop->setParameter("stationRef", station->getParameter("railway:ref"));
2649 }
2650 }
2651 }
2652 }
2653 }
2654 } else if (myPTRouteType != "" && myIsRoute) {
2655 NBPTLine* ptLine = new NBPTLine(toString(myCurrentRelation), myName, myPTRouteType, myRef, myInterval, myNightService,
2656 interpretTransportType(myPTRouteType), myRouteColor);
2657 int consecutiveGap = false;
2658 int missingBefore = 0;
2659 int missingAfter = 0;
2660 for (long long ref : myStops) {
2661 const auto& nodeIt = myOSMNodes.find(ref);
2662 if (nodeIt == myOSMNodes.end()) {
2663 if (ptLine->getStops().empty()) {
2664 missingBefore++;
2665 } else {
2666 missingAfter++;
2667 consecutiveGap++;
2668 }
2669 continue;
2670 }
2671 // give some slack for single missing stops
2672 if (consecutiveGap > 1) {
2673 WRITE_WARNINGF(TL("PT line '%' in relation % has a gap of % stops, only keeping first part."), myName, myCurrentRelation, consecutiveGap);
2674 missingAfter = (int)myStops.size() - missingBefore - (int)ptLine->getStops().size();
2675 break;
2676 }
2677 // reset gap
2678 consecutiveGap = 0;
2679
2680 const NIOSMNode* const n = nodeIt->second;
2681 std::shared_ptr<NBPTStop> ptStop = myNBPTStopCont->get(toString(n->id));
2682 if (ptStop == nullptr) {
2683 // loose stop, which must later be mapped onto a line way
2684 Position ptPos(n->lon, n->lat, n->ele);
2686 WRITE_ERRORF("Unable to project coordinates for node '%'.", n->id);
2687 }
2689 ptStop = std::make_shared<NBPTStop>(element, toString(n->id), ptPos, "", "", n->ptStopLength, n->name, n->permissions);
2690 myNBPTStopCont->insert(ptStop);
2691 if (myStopAreas.count(n->id)) {
2692 ptStop->setIsMultipleStopPositions(false, myStopAreas[n->id]);
2693 }
2694 if (myPlatformStops.count(n->id) > 0) {
2695 ptStop->setIsPlatform();
2696 }
2697 }
2698 ptLine->addPTStop(ptStop);
2699 }
2700 for (long long& myWay : myWays) {
2701 auto entr = myOSMEdges.find(myWay);
2702 if (entr != myOSMEdges.end()) {
2703 Edge* edge = entr->second;
2704 for (long long& myCurrentNode : edge->myCurrentNodes) {
2705 ptLine->addWayNode(myWay, myCurrentNode);
2706 }
2707 }
2708 }
2709 ptLine->setNumOfStops((int)myStops.size(), missingBefore, missingAfter);
2710 if (ptLine->getStops().empty()) {
2711 WRITE_WARNINGF(TL("PT line in relation % with no stops ignored. Probably OSM file is incomplete."), myCurrentRelation);
2712 delete ptLine;
2713 resetValues();
2714 return;
2715 }
2716 if (!myNBPTLineCont->insert(ptLine)) {
2717 WRITE_WARNINGF(TL("Ignoring duplicate PT line '%'."), myCurrentRelation);
2718 delete ptLine;
2719 }
2720 }
2721 // other relations might use similar subelements so reset in any case
2722 resetValues();
2723 }
2724}
2725
2726bool
2728 // since OSM ways are bidirectional we need the via to figure out which direction was meant
2729 if (myViaNode != INVALID_ID) {
2730 NBNode* viaNode = myOSMNodes.find(myViaNode)->second->node;
2731 if (viaNode == nullptr) {
2732 WRITE_WARNINGF(TL("Via-node '%' was not instantiated"), toString(myViaNode));
2733 return false;
2734 }
2735 NBEdge* from = findEdgeRef(myFromWay, viaNode->getIncomingEdges());
2736 NBEdge* to = findEdgeRef(myToWay, viaNode->getOutgoingEdges());
2737 if (from == nullptr) {
2738 WRITE_WARNINGF(TL("from-edge '%' of restriction relation could not be determined"), toString(myFromWay));
2739 return false;
2740 }
2741 if (to == nullptr) {
2742 WRITE_WARNINGF(TL("to-edge '%' of restriction relation could not be determined"), toString(myToWay));
2743 return false;
2744 }
2745 if (myRestrictionType == RestrictionType::ONLY) {
2746 from->addEdge2EdgeConnection(to, true);
2747 // make sure that these connections remain disabled even if network
2748 // modifications (ramps.guess) reset existing connections
2749 for (NBEdge* cand : from->getToNode()->getOutgoingEdges()) {
2750 if (!from->isConnectedTo(cand)) {
2751 if (myRestrictionException == SVC_IGNORING) {
2752 from->removeFromConnections(cand, -1, -1, true);
2753 } else {
2754 from->addEdge2EdgeConnection(cand, true, myRestrictionException);
2755 }
2756 }
2757 }
2758 } else {
2759 if (myRestrictionException == SVC_IGNORING) {
2760 from->removeFromConnections(to, -1, -1, true);
2761 } else {
2762 from->addEdge2EdgeConnection(to, true, myRestrictionException);
2763 for (NBEdge* cand : from->getToNode()->getOutgoingEdges()) {
2764 if (!from->isConnectedTo(cand)) {
2765 from->addEdge2EdgeConnection(cand, true);
2766 }
2767 }
2768 }
2769 }
2770 } else {
2771 // XXX interpreting via-ways or via-node lists not yet implemented
2772 WRITE_WARNINGF(TL("direction of restriction relation could not be determined%"), "");
2773 return false;
2774 }
2775 return true;
2776}
2777
2778NBEdge*
2780 const std::vector<NBEdge*>& candidates) const {
2781 const std::string prefix = toString(wayRef);
2782 const std::string backPrefix = "-" + prefix;
2783 NBEdge* result = nullptr;
2784 int found = 0;
2785 for (auto candidate : candidates) {
2786 if ((candidate->getID().substr(0, prefix.size()) == prefix) ||
2787 (candidate->getID().substr(0, backPrefix.size()) == backPrefix)) {
2788 result = candidate;
2789 found++;
2790 }
2791 }
2792 if (found > 1) {
2793 WRITE_WARNINGF(TL("Ambiguous way reference '%' in restriction relation"), prefix);
2794 result = nullptr;
2795 }
2796 return result;
2797}
2798
2799
2800/****************************************************************************/
#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
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:1994
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:4082
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:3021
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.