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