66#define DEBUG_COND(road) ((road)->id == DEBUG_ID)
67#define DEBUG_COND2(edgeID) (StringUtils::startsWith((edgeID), DEBUG_ID))
68#define DEBUG_COND3(roadID) (roadID == DEBUG_ID)
208 const bool customLaneShapes = oc.
getBool(
"opendrive.lane-shapes");
212 std::map<std::string, OpenDriveEdge*> edges;
216 for (
const std::string& file : oc.
getStringVector(
"opendrive-files")) {
223 for (
auto& item : edges) {
225 if (signal.type ==
"") {
226 if (handler.
getSignals().count(signal.id) == 0) {
230 signal.type = ref.
type;
231 signal.name = ref.
name;
240 std::map<std::string, OpenDriveEdge*> innerEdges, outerEdges;
241 for (std::map<std::string, OpenDriveEdge*>::iterator i = edges.begin(); i != edges.end(); ++i) {
242 if ((*i).second->isInner) {
243 innerEdges[(*i).first] = (*i).second;
245 outerEdges[(*i).first] = (*i).second;
260 std::map<std::string, Boundary> posMap;
261 std::map<std::string, std::string> edge2junction;
262 std::vector<NodeSet> joinedNodeIDs;
264 for (std::map<std::string, OpenDriveEdge*>::iterator i = innerEdges.begin(); i != innerEdges.end(); ++i) {
268 if (posMap.find(e->
junction) == posMap.end()) {
272 if (e->
geom.size() > 0) {
276 !std::isnan(geomBoundary.
xmin()) && !std::isnan(geomBoundary.
xmax()) &&
277 !std::isnan(geomBoundary.
ymin()) && !std::isnan(geomBoundary.
ymax())) {
280 WRITE_WARNINGF(
TL(
"Ignoring invalid geometry for inner edge '%' (xodr road '%') in junction '%'."),
284 WRITE_WARNINGF(
TL(
"Inner edge '%' (xodr road '%') in junction '%' has no geometry."),
289 for (std::map<std::string, Boundary>::iterator i = posMap.begin(); i != posMap.end(); ++i) {
292 if (!(*i).second.isInitialised()) {
293 WRITE_ERRORF(
TL(
"Junction '%' has no valid inner edges to determine its position."), (*i).first);
294 throw ProcessError(
TLF(
"Could not determine position for junction '%'.", (*i).first));
296 Position center = (*i).second.getCenter();
298 if (center.
isNAN()) {
299 WRITE_ERRORF(
TL(
"Junction '%' resulted in invalid (NaN) position."), (*i).first);
300 throw ProcessError(
TLF(
"Could not compute valid position for junction '%'.", (*i).first));
307 for (std::map<std::string, OpenDriveEdge*>::iterator i = outerEdges.begin(); i != outerEdges.end(); ++i) {
309 for (std::vector<OpenDriveLink>::iterator j = e->
links.begin(); j != e->
links.end(); ++j) {
324 if (edge2junction.find(l.
elementID) != edge2junction.end()) {
336 for (std::map<std::string, OpenDriveEdge*>::iterator i = outerEdges.begin(); i != outerEdges.end(); ++i) {
338 for (std::vector<OpenDriveLink>::iterator j = e->
links.begin(); j != e->
links.end(); ++j) {
345 std::string id1 = e->
id;
350 std::string nid = id1 +
"." + id2;
373 for (std::map<std::string, OpenDriveEdge*>::iterator i = outerEdges.begin(); i != outerEdges.end(); ++i) {
375 if (e->
to !=
nullptr && e->
from !=
nullptr) {
378 for (std::map<std::string, OpenDriveEdge*>::iterator j = innerEdges.begin(); j != innerEdges.end(); ++j) {
380 for (std::vector<OpenDriveLink>::iterator k = ie->
links.begin(); k != ie->
links.end(); ++k) {
386 std::string nid = edge2junction[ie->
id];
398 for (std::map<std::string, OpenDriveEdge*>::iterator i = outerEdges.begin(); i != outerEdges.end(); ++i) {
400 if ((e->
from ==
nullptr || e->
to ==
nullptr) && e->
geom.size() == 0) {
403 if (e->
from ==
nullptr) {
404 const std::string nid = e->
id +
".begin";
407 if (e->
to ==
nullptr) {
408 const std::string nid = e->
id +
".end";
413 std::map<NBNode*, NBNode*> joinedNodes;
414 for (
NodeSet& joined : joinedNodeIDs) {
416 for (
NBNode* j : joined) {
417 joinedPos.
add(j->getPosition());
419 joinedPos.
mul(1. / (
double)joined.size());
421 if (!nc.
insert(joinedID, joinedPos)) {
425 for (
NBNode* j : joined) {
429 for (std::map<std::string, OpenDriveEdge*>::iterator i = outerEdges.begin(); i != outerEdges.end(); ++i) {
431 if (joinedNodes.count(e->
from) != 0) {
435 if (joinedNodes.count(e->
to) != 0) {
437 e->
to = joinedNodes[e->
to];
449 std::map<std::pair<NBEdge*, int>,
int> laneIndexMap;
451 for (std::map<std::string, OpenDriveEdge*>::iterator i = outerEdges.begin(); i != outerEdges.end(); ++i) {
453 if (e->
geom.size() < 2) {
457 bool lanesBuilt =
false;
483 std::cout <<
" geomWithOffset=" << geomWithOffset <<
"\n";
486 const double length2D = geomWithOffset.
length2D();
487 double cF = length2D == 0 ? 1 : e->
length / length2D;
488 NBEdge* prevRight =
nullptr;
489 NBEdge* prevLeft =
nullptr;
497 WRITE_WARNING(
"Edge '" + e->
id +
"' has to be split as it connects same junctions.")
501 const double minDist = oc.
getFloat(
"opendrive.curve-resolution");
506 int sectionIndex = 0;
513 double nextS = (j + 1)->s;
514 const std::string nodeID = e->
id + (positionIDs ?
"." +
toString(nextS) :
"#" +
toString(sectionIndex + 1));
522 std::string
id = e->
id;
524 if (sFrom != e->
from || sTo != e->
to) {
530 id =
id +
"#" +
toString(sectionIndex++);
532#ifdef DEBUG_VARIABLE_WIDTHS
534 std::cout <<
" id=" <<
id <<
" sB=" << sB <<
" sE=" << sE <<
" geom=" << geom <<
"\n";
539 NBEdge* currRight =
nullptr;
540 if ((*j).rightLaneNumber > 0) {
541 std::vector<double> offsets(geom.size(), 0);
542 bool useOffsets =
false;
549 rightGeom.
move2side((*j).discardedInnerWidthRight);
552 std::cout <<
" -" <<
id <<
"_geom=" << geom <<
" -" <<
id <<
"_rightGeom=" << rightGeom <<
"\n";
561 std::sort(lanes.begin(), lanes.end(),
LaneSorter());
563 std::map<int, int>::const_iterator lp = (*j).laneMap.find(odl.id);
564 if (lp != (*j).laneMap.end()) {
565 int sumoLaneIndex = lp->second;
567 laneIndexMap[std::make_pair(currRight, sumoLaneIndex)] = odl.id;
573 }
else if (customLaneShapes) {
576 if (customLaneShapes) {
587 if (prevRight !=
nullptr) {
589 for (std::map<int, int>::const_iterator k = connections.begin(); k != connections.end(); ++k) {
590#ifdef DEBUG_CONNECTIONS
592 std::cout <<
"addCon1 from=" << prevRight->
getID() <<
"_" << (*k).first <<
" to=" << currRight->
getID() <<
"_" << (*k).second <<
"\n";
598 prevRight = currRight;
603 NBEdge* currLeft =
nullptr;
604 if ((*j).leftLaneNumber > 0) {
605 std::vector<double> offsets(geom.size(), 0);
606 bool useOffsets =
false;
608 leftGeom.
move2side(-(*j).discardedInnerWidthLeft);
612 std::cout <<
" " <<
id <<
"_geom=" << geom <<
" " <<
id <<
"_leftGeom=" << leftGeom <<
"\n";
619 std::sort(lanes.begin(), lanes.end(),
LaneSorter());
620 for (std::vector<OpenDriveLane>::const_iterator k = lanes.begin(); k != lanes.end(); ++k) {
621 std::map<int, int>::const_iterator lp = (*j).laneMap.find((*k).id);
622 if (lp != (*j).laneMap.end()) {
623 int sumoLaneIndex = lp->second;
625 laneIndexMap[std::make_pair(currLeft, sumoLaneIndex)] = (*k).id;
631 }
else if (customLaneShapes) {
634 if (customLaneShapes) {
645 if (prevLeft !=
nullptr) {
646 std::map<int, int> connections = (*j).getInnerConnections(
OPENDRIVE_TAG_LEFT, *(j - 1));
647 for (std::map<int, int>::const_iterator k = connections.begin(); k != connections.end(); ++k) {
648#ifdef DEBUG_CONNECTIONS
650 std::cout <<
"addCon2 from=" << currLeft->
getID() <<
"_" << (*k).first <<
" to=" << prevLeft->
getID() <<
"_" << (*k).second <<
"\n";
665 if (oc.
isSet(
"polygon-output")) {
672 if (oc.
isSet(
"polygon-output")) {
673 for (
auto item : innerEdges) {
682 for (std::map<std::string, OpenDriveEdge*>::iterator i = edges.begin(); i != edges.end(); ++i) {
686 std::vector<Connection> connections2;
687 for (std::map<std::string, OpenDriveEdge*>::iterator j = edges.begin(); j != edges.end(); ++j) {
688 const std::set<Connection>& conns = (*j).second->connections;
690 for (std::set<Connection>::const_iterator i = conns.begin(); i != conns.end(); ++i) {
691 if (innerEdges.find((*i).fromEdge) != innerEdges.end()) {
695 if (innerEdges.find((*i).toEdge) != innerEdges.end()) {
696 std::set<Connection> seen;
699 connections2.push_back(*i);
704 for (std::vector<Connection>::const_iterator i = connections2.begin(); i != connections2.end(); ++i) {
705#ifdef DEBUG_CONNECTIONS
706 std::cout <<
"connections2 " << (*i).getDescription() <<
"\n";
708 std::string fromEdge = (*i).fromEdge;
709 if (edges.find(fromEdge) == edges.end()) {
710 WRITE_WARNINGF(
TL(
"While setting connections: from-edge '%' is not known."), fromEdge);
714 int fromLane = (*i).fromLane;
718 std::string toEdge = (*i).toEdge;
719 if (edges.find(toEdge) == edges.end()) {
720 WRITE_WARNINGF(
TL(
"While setting connections: to-edge '%' is not known."), toEdge);
725 int toLane = (*i).toLane;
745 if (from ==
nullptr) {
746 WRITE_WARNINGF(
TL(
"Could not find fromEdge representation of '%' in connection '%'."), fromEdge, (*i).origID);
749 WRITE_WARNINGF(
TL(
"Could not find fromEdge representation of '%' in connection '%'."), toEdge, (*i).origID);
751 if (from ==
nullptr || to ==
nullptr) {
755#ifdef DEBUG_CONNECTIONS
757 std::cout <<
"addCon3 from=" << from->
getID() <<
"_" << fromLane <<
" to=" << to->
getID() <<
"_" << toLane <<
"\n";
769 if ((*i).origID !=
"" && saveOrigIDs) {
772 for (std::vector<NBEdge::Connection>::iterator k = cons.begin(); k != cons.end(); ++k) {
773 if ((*k).fromLane == fromLane && (*k).toEdge == to && (*k).toLane == toLane) {
785 std::map<std::string, std::string> signal2junction;
786 std::map<std::string, OpenDriveController>& controllers = handler.
getControllers();
788 for (
const auto& it : edges) {
791 if (signal.controller.size() == 0) {
794 std::string junctionID;
796 if ((connection.fromLane < 0 && signal.orientation < 0) || (connection.fromLane > 0 && signal.orientation > 0)) {
799 if ((signal.minLane == 0 && signal.maxLane == 0) || (signal.maxLane >= connection.fromLane && signal.minLane <= connection.fromLane)) {
800 const OpenDriveEdge* connectedEdge = edges[connection.toEdge];
801 if (controllers[signal.controller].junction.size() > 0 && controllers[signal.controller].junction != connectedEdge->
junction) {
802 WRITE_WARNINGF(
TL(
"Controlling multiple junctions by the same controller '%' is currently not implemented."), signal.controller);
804 controllers[signal.controller].junction = connectedEdge->
junction;
810 const bool importSignalGroups = oc.
getBool(
"opendrive.signal-groups");
811 for (std::map<std::string, OpenDriveEdge*>::iterator i = edges.begin(); i != edges.end(); ++i) {
818 if (intType < 1000001 || (intType > 1000013 && intType != 1000020) || intType == 1000008) {
826 std::vector<OpenDriveLaneSection>::iterator k = e->
laneSections.begin();
829 if (signal.s > (*k).s && signal.s <= (*(k + 1)).s) {
836 std::string
id = (*k).sumoID;
841 std::string fromID, toID;
842 for (std::vector<OpenDriveLink>::const_iterator l = e->
links.begin(); l != e->
links.end(); ++l) {
850 if (signal.orientation < 0) {
851 fromID =
"-" + fromID;
855 if (signal.orientation > 0) {
856 fromID =
"-" + fromID;
874 if (from ==
nullptr) {
875 WRITE_WARNINGF(
TL(
"Could not find edge '%' for signal '%'."), fromID, signal.id);
880 if (signal.maxLane != 0) {
881 bool fromForward = from->
getID()[0] ==
'-';
882 bool lanesForward = signal.maxLane < 0;
883 if (fromForward != lanesForward) {
887 from = signalFromTo.first;
888 to = signalFromTo.second;
889 if (from ==
nullptr) {
890 WRITE_WARNINGF(
TL(
"Could not find edge '%' for signal '%'."), fromID, signal.id);
896 if (c.toEdge == to) {
897 int odLane = laneIndexMap[std::make_pair(from, c.fromLane)];
899 if (signal.minLane == 0 || (signal.minLane <= odLane && signal.maxLane >= odLane)) {
900 if (c.hasParameter(
"signalID")) {
901 c.setParameter(
"signalID", c.getParameter(
"signalID") +
" " + signal.id);
903 c.setParameter(
"signalID", signal.id);
907 if (importSignalGroups) {
909 if (controller.
id !=
"") {
910 if (c.getParameter(
"controllerID") !=
"") {
911 WRITE_WARNINGF(
TL(
"The signaling of the connection from '%' to '%' (controller '%') is ambiguous because it is overwritten signal '%' and with controller '%'."), from->
getID(), c.toEdge->getID(), c.getParameter(
"controllerID"), signal.id, controller.
id);
915 c.tlLinkIndex = tlIndex;
916 c.setParameter(
"controllerID", controller.
id);
926 WRITE_WARNINGF(
TL(
"Found a traffic light signal on an unknown edge (original edge id='%')."), e->
id);
931 if (signal.orientation == 1) {
936 if (edge ==
nullptr) {
937 WRITE_WARNINGF(
TL(
"Could not find edge '%' for signal '%'."),
id, signal.id);
943 int odLane = laneIndexMap[std::make_pair(edge, c.fromLane)];
944 if (signal.minLane == 0 || (signal.minLane <= odLane && signal.maxLane >= odLane)) {
945 if (c.hasParameter(
"signalID")) {
946 c.setParameter(
"signalID", c.getParameter(
"signalID") +
" " + signal.id);
948 c.setParameter(
"signalID", signal.id);
953 if (importSignalGroups) {
955 if (controller.
id !=
"") {
956 if (c.getParameter(
"controllerID") !=
"") {
957 WRITE_WARNINGF(
TL(
"The signaling of the connection from '%' to '%' (controller '%') is ambiguous because it is overwritten with signal '%' and controller '%'."), edge->
getID(), c.toEdge->getID(), c.getParameter(
"controllerID"), signal.id, controller.
id);
961 c.tlLinkIndex = tlIndex;
962 c.setParameter(
"controllerID", controller.
id);
978 for (std::map<std::string, OpenDriveEdge*>::iterator i = edges.begin(); i != edges.end(); ++i) {
1000 POI.setParameter(
"name", o.name);
1001 POI.writeXML(dev, writeGeo);
1005 centerLine.push_back(
Position(-o.length / 2, 0));
1006 centerLine.push_back(
Position(o.length / 2, 0));
1008 centerLine.
rotate2D(roadHdg + o.hdg);
1011 centerLine.
add(ref);
1033std::pair<NBEdge*, NBEdge*>
1044 if (from ==
nullptr) {
1047 if (to ==
nullptr) {
1053 }
else if (fromReverse !=
nullptr && toReverse !=
nullptr && fromReverse->
getToNode() == toReverse->
getFromNode() && signalMinLane <= 0) {
1068 return std::make_pair(from, to);
1106 if (sumoLane.
width >= 0 && widthResolution > 0) {
1107 sumoLane.
width = floor(sumoLane.
width / widthResolution + 0.5) * widthResolution;
1109 sumoLane.
width -= widthResolution;
1110 if (sumoLane.
width <= 0) {
1113 }
else if (sumoLane.
width == 0) {
1115 sumoLane.
width = widthResolution;
1121 if (forbiddenNarrow) {
1129 const std::map<std::string, OpenDriveEdge*>& innerEdges,
1130 const std::map<std::string, OpenDriveEdge*>& edges,
1132 std::vector<Connection>& into, std::set<Connection>& seen) {
1135#ifdef DEBUG_CONNECTIONS
1137 std::cout <<
" buildConnectionsToOuter " << c.
getDescription() <<
"\n";
1138 std::cout <<
" dest=" << (dest ==
nullptr ?
"NULL" : dest->
id) <<
" seenlist=";
1139 for (std::set<Connection>::const_iterator i = seen.begin(); i != seen.end(); ++i) {
1140 std::cout <<
" " << (*i).fromEdge <<
"," << (*i).toEdge <<
" ";
1145 if (dest ==
nullptr) {
1151 auto innerEdgesIt = innerEdges.find(destCon.toEdge);
1152#ifdef DEBUG_CONNECTIONS
1154 std::cout <<
" toInner=" << (innerEdgesIt != innerEdges.end()) <<
" destCon " << destCon.getDescription() <<
"\n";
1157 if (innerEdgesIt != innerEdges.end()) {
1158 std::vector<Connection> t;
1159 if (seen.count(destCon) == 0) {
1161 for (std::vector<Connection>::const_iterator j = t.begin(); j != t.end(); ++j) {
1169 cn.shape = innerEdgesIt->second->geom + c.
shape;
1178 int out = destCon.fromLane;
1183#ifdef DEBUG_CONNECTIONS
1185 std::cout <<
" laneSectionsConnected dest=" << dest->
id <<
" in=" << in <<
" out=" << out
1202 int referenceLane = 0;
1203 int offsetFactor = 1;
1207 for (
const auto& destLane : dest->
laneSections.front().lanesByDir[lanesDir]) {
1208 if (destLane.successor == c.
fromLane) {
1209 referenceLane = destLane.id;
1215 for (
const auto& destLane : dest->
laneSections.front().lanesByDir[lanesDir]) {
1216 if (destLane.predecessor == c.
fromLane) {
1217 referenceLane = destLane.id;
1226 std::vector<double> offsets(dest->
geom.size(), 0);
1230#ifdef DEBUG_INTERNALSHAPES
1231 std::string destPred;
1235 for (
int laneSectionIndex = 0; laneSectionIndex < (int)dest->
laneSections.size(); laneSectionIndex++) {
1237 const double nextS = laneSectionIndex + 1 < (int)dest->
laneSections.size() ? dest->
laneSections[laneSectionIndex + 1].s : std::numeric_limits<double>::max();
1240 int finalI = iShape;
1243 double sectionS = 0;
1246#ifdef DEBUG_INTERNALSHAPES
1247 destPred +=
" lane=" +
toString(destLane.id)
1248 +
" pred=" +
toString(destLane.predecessor)
1249 +
" succ=" +
toString(destLane.successor)
1250 +
" wStart=" + (destLane.widthData.empty() ?
"?" :
toString(destLane.widthData.front().computeAt(0)))
1251 +
" wEnd=" + (destLane.widthData.empty() ?
"?" :
toString(destLane.widthData.front().computeAt(
cn.shape.length2D())))
1252 +
" width=" +
toString(destLane.width) +
"\n";
1254 if (abs(destLane.id) <= abs(referenceLane) || abs(destLane.id) == abs(c.
toLane)) {
1255 const double multiplier = offsetFactor * (destLane.id == referenceLane ? 0.5 : 1);
1256#ifdef DEBUG_INTERNALSHAPES
1257 destPred +=
" multiplier=" +
toString(multiplier) +
"\n";
1259 int widthDataIndex = 0;
1260 while (s < nextS && i < (
int)
cn.shape.size()) {
1262 const double dist =
cn.shape[i - 1].distanceTo2D(
cn.shape[i]);
1267 while (widthDataIndex + 1 < (
int)destLane.widthData.size()
1268 && sectionS >= destLane.widthData[widthDataIndex + 1].s) {
1272 if (destLane.widthData.size() > 0) {
1273 width = destLane.widthData[widthDataIndex].computeAt(sectionS);
1275#ifdef DEBUG_INTERNALSHAPES
1276 std::cout <<
" missing width data at inner edge " << dest->
id <<
" to=" <<
cn.toEdge <<
"_" <<
cn.toLane <<
" cp=" <<
cn.toCP <<
"\n";
1283 if (outerToLane.id ==
cn.toLane && outerToLane.width > 0) {
1284#ifdef DEBUG_INTERNALSHAPES
1285 std::cout <<
" using toLane width " << width <<
"\n";
1291 offsets[i] += width * multiplier;
1299 }
else if (finalS == s) {
1301 while (s < nextS && i < (
int)
cn.shape.size()) {
1303 const double dist =
cn.shape[i - 1].distanceTo2D(
cn.shape[i]);
1319 cn.shape.move2sideCustom(offsets);
1324#ifdef DEBUG_INTERNALSHAPES
1325 std::cout <<
"internalShape "
1327 <<
" dest=" << dest->
id
1328 <<
" refLane=" << referenceLane
1329 <<
"\n destPred=" << destPred
1330 <<
"\n offsets=" << offsets
1331 <<
"\n shape=" << dest->
geom
1332 <<
"\n shape2=" <<
cn.shape
1339#ifdef DEBUG_CONNECTIONS
1341 std::cout <<
" added connection\n";
1361 if (lane.id == in) {
1362 in = lane.successor;
1369 if (lane.id == in) {
1370 in = lane.successor;
1383 for (std::vector<OpenDriveLink>::iterator i = e.
links.begin(); i != e.
links.end(); ++i) {
1390 std::string connectedEdge = l.
elementID;
1391 std::string edgeID = e.
id;
1394 const std::map<int, int>& laneMap = laneSection.
laneMap;
1395#ifdef DEBUG_CONNECTIONS
1397 std::cout <<
"edge=" << e.
id <<
" eType=" << l.
elementType <<
" lType=" << l.
linkType <<
" connectedEdge=" << connectedEdge <<
" laneSection=" << laneSection.
s <<
" map:\n";
1403 for (std::vector<OpenDriveLane>::const_iterator j = lanes.begin(); j != lanes.end(); ++j) {
1412 c.
toEdge = connectedEdge;
1421 if (edges.find(c.
fromEdge) == edges.end()) {
1426#ifdef DEBUG_CONNECTIONS
1428 std::cout <<
"insertConRight from=" << src->
id <<
"_" << c.
fromLane <<
" to=" << c.
toEdge <<
"_" << c.
toLane <<
"\n";
1436 for (std::vector<OpenDriveLane>::const_iterator j = lanes.begin(); j != lanes.end(); ++j) {
1454 if (edges.find(c.
fromEdge) == edges.end()) {
1459#ifdef DEBUG_CONNECTIONS
1461 std::cout <<
"insertConLeft from=" << src->
id <<
"_" << c.
fromLane <<
" to=" << c.
toEdge <<
"_" << c.
toLane <<
"\n";
1473 return edgeID[0] ==
'-' ? edgeID.substr(1) :
"-" + edgeID;
1482 if (!nc.
insert(
id, pos)) {
1498 NBNode* toJoin =
nullptr;
1500 if (e.
to !=
nullptr && e.
to != n) {
1505 if (e.
from !=
nullptr && e.
from != n) {
1510 if (toJoin !=
nullptr) {
1514 for (
NodeSet& joined : joinedNodeIDs) {
1515 if (joined.count(toJoin) != 0) {
1518 if (joined.count(n) != 0) {
1522 if (set1 ==
nullptr && set2 ==
nullptr) {
1523 joinedNodeIDs.push_back(
NodeSet());
1524 joinedNodeIDs.back().insert(n);
1525 joinedNodeIDs.back().insert(toJoin);
1526 }
else if (set1 ==
nullptr && set2 !=
nullptr) {
1527 set2->insert(toJoin);
1528 }
else if (set1 !=
nullptr && set2 ==
nullptr) {
1531 set1->insert(set2->begin(), set2->end());
1532 joinedNodeIDs.erase(std::find(joinedNodeIDs.begin(), joinedNodeIDs.end(), *set2));
1543 if (el.c != 0 || el.d != 0) {
1553 const double res = oc.
getFloat(
"opendrive.curve-resolution");
1554 for (
const auto& i : edges) {
1588 WRITE_WARNINGF(
TL(
"Mismatched geometry for edge '%' between geometry segments % and %."), e.
id, index - 1, index);
1593 for (PositionVector::iterator k = geom.begin(); k != geom.end(); ++k) {
1600 if (e.
geom.size() == 1 && e.
geom.front() != last) {
1602 e.
geom.push_back(last);
1606 std::cout << e.
id <<
" initialGeom=" << e.
geom <<
"\n";
1609 if (oc.
exists(
"geometry.min-dist") && !oc.
isDefault(
"geometry.min-dist")) {
1612 if (e.
geom.size() > 4) {
1618 std::cout << e.
id <<
" reducedGeom=" << e.
geom <<
"\n";
1629 for (std::vector<OpenDriveElevation>::iterator j = e.
elevations.begin(); j != e.
elevations.end(); ++j) {
1631 const double sNext = (j + 1) == e.
elevations.end() ? std::numeric_limits<double>::max() : (*(j + 1)).s;
1632 while (k < (
int)e.
geom.size() && pos < sNext) {
1637 if (k < (
int)e.
geom.size()) {
1640 pos += e.
geom[k - 1].distanceTo2D(e.
geom[k]);
1658 std::vector<double> laneOffsets;
1674 for (
auto j = offsets.begin(); j != offsets.end(); ++j) {
1676 const double sNext = (j + 1) == offsets.end() ? std::numeric_limits<double>::max() : (*(j + 1)).s;
1677 while (kk < (
int)geom.size() && ppos < sNext) {
1678 const double offset = el.
computeAt(ppos);
1679 laneOffsets.push_back(fabs(offset) > POSITION_EPS ? -offset : 0);
1681 if (kk < (
int)geom.size()) {
1684 ppos += geom[kk - 1].distanceTo2D(geom[kk]);
1704 double interpolatedOffset = 0;
1706 interpolatedOffset = result.front();
1707 }
else if (at == (
int)geom.size() - 1) {
1708 interpolatedOffset = result.back();
1710 interpolatedOffset = (result[at - 1] + result[at]) / 2;
1712 result.insert(result.begin() + at, interpolatedOffset);
1718 const int sign = left ? -1 : 1;
1719 for (
auto j = offsets.begin(); j != offsets.end(); ++j) {
1721 const double sNext = (j + 1) == offsets.end() ? std::numeric_limits<double>::max() : (*(j + 1)).s;
1722 while (kk < (
int)geom.size() && ppos < sNext) {
1723 const double offset = el.
computeAt(ppos);
1724 result[kk] += fabs(offset) > POSITION_EPS ? sign * offset : 0;
1726 if (kk < (
int)geom.size()) {
1729 ppos += geom[kk - 1].distanceTo2D(geom[kk]);
1738 for (
const auto& i : edges) {
1740#ifdef DEBUG_VARIABLE_SPEED
1743 std::cout <<
"revisitLaneSections e=" << e.
id <<
"\n";
1747 std::vector<OpenDriveLaneSection> newSections;
1749 std::vector<OpenDriveLaneSection> splitSections;
1750 const bool splitByAttrChange = section.buildAttributeChanges(tc, splitSections);
1751 if (!splitByAttrChange) {
1752 newSections.push_back(section);
1754 std::copy(splitSections.begin(), splitSections.end(), back_inserter(newSections));
1763 if (section.s <= lastS) {
1779 if ((j + 1)->s - j->s < POSITION_EPS) {
1780 WRITE_WARNINGF(
TL(
"Almost duplicate s-value '%' for lane sections occurred at edge '%'; first entry was removed."),
toString(j->s), e.
id);
1787#ifdef DEBUG_VARIABLE_SPEED
1800 if (resolution > 0 && g.
length > 0) {
1801 const int numPoints = (int)ceil(g.
length / resolution) + 1;
1802 double dx = (end.
x() - start.
x()) / (numPoints - 1);
1803 double dy = (end.
y() - start.
y()) / (numPoints - 1);
1804 for (
int i = 0; i < numPoints; i++) {
1805 ret.push_back(
Position(g.
x + i * dx, g.
y + i * dy));
1808 ret.push_back(start);
1819 double curveStart = g.
params[0];
1820 double curveEnd = g.
params[1];
1822 double cDot = (curveEnd - curveStart) / g.
length;
1823 if (cDot == 0 || g.
length == 0) {
1828 double sStart = curveStart / cDot;
1829 double sEnd = curveEnd / cDot;
1835 odrSpiral(sStart, cDot, &x, &y, &tStart);
1836 for (s = sStart; s <= sEnd; s += resolution) {
1847 assert(ret.size() >= 2);
1848 assert(ret[0] != ret[1]);
1851 ret.
add(ret.front() * -1);
1857 << std::setprecision(4)
1858 <<
"edge=" << e.
id <<
" s=" << g.
s
1859 <<
" cStart=" << curveStart
1860 <<
" cEnd=" << curveEnd
1862 <<
" sStart=" << sStart
1866 <<
"\n beforeShift=" << ret1
1867 <<
"\n beforeRot=" << ret2
1871 ret.
add(g.
x, g.
y, 0);
1872 }
catch (
const std::runtime_error&
error) {
1884 double centerX = g.
x;
1885 double centerY = g.
y;
1887 double curvature = g.
params[0];
1888 double radius = 1. / curvature;
1893 double startX = g.
x;
1894 double startY = g.
y;
1895 double geo_posS = g.
s;
1896 double geo_posE = g.
s;
1899 geo_posE += resolution;
1900 if (geo_posE - g.
s > g.
length) {
1903 if (geo_posE - g.
s > g.
length) {
1906 calcPointOnCurve(&endX, &endY, centerX, centerY, radius, geo_posE - geo_posS);
1907 ret.push_back(
Position(startX, startY));
1911 geo_posS = geo_posE;
1913 if (geo_posE - (g.
s + g.
length) < 0.001 && geo_posE - (g.
s + g.
length) > -0.001) {
1917 ret.push_back(
Position(startX, startY));
1925 const double s = sin(g.
hdg);
1926 const double c = cos(g.
hdg);
1928 for (
double off = 0; off < g.
length + 2.; off += resolution) {
1931 double xnew = x * c - y * s;
1932 double ynew = x * s + y * c;
1933 ret.push_back(
Position(g.
x + xnew, g.
y + ynew));
1942 const double s = sin(g.
hdg);
1943 const double c = cos(g.
hdg);
1945 const double pStep = pMax / ceil(g.
length / resolution);
1947 for (
double p = 0; p <= pMax + pStep; p += pStep) {
1950 double xnew = x * c - y * s;
1951 double ynew = x * s + y * c;
1952 ret.push_back(
Position(g.
x + xnew, g.
y + ynew));
1960 double normx = 1.0f;
1961 double normy = 0.0f;
1962 double x2 = normx * cos(hdg) - normy * sin(hdg);
1963 double y2 = normx * sin(hdg) + normy * cos(hdg);
1964 normx = x2 * length;
1965 normy = y2 * length;
1966 return Position(start.
x() + normx, start.
y() + normy);
1976 if (ad_radius > 0) {
1983 normX = normX * cos(ad_hdg) + normY * sin(ad_hdg);
1984 normY = tmpX * sin(ad_hdg) + normY * cos(ad_hdg);
1987 normX = turn * normY;
1988 normY = -turn * tmpX;
1990 normX = fabs(ad_radius) * normX;
1991 normY = fabs(ad_radius) * normY;
2000 double ad_r,
double ad_length) {
2001 double rotAngle = ad_length / fabs(ad_r);
2002 double vx = *ad_x - ad_centerX;
2003 double vy = *ad_y - ad_centerY;
2013 vx = vx * cos(rotAngle) + turn * vy * sin(rotAngle);
2014 vy = -1 * turn * tmpx * sin(rotAngle) + vy * cos(rotAngle);
2015 *ad_x = vx + ad_centerX;
2016 *ad_y = vy + ad_centerY;
2032 discardedInnerWidthRight = 0;
2034 bool singleType =
true;
2035 std::vector<std::string> types;
2036 const std::vector<OpenDriveLane>& dirLanesR = lanesByDir.find(
OPENDRIVE_TAG_RIGHT)->second;
2037 for (std::vector<OpenDriveLane>::const_reverse_iterator i = dirLanesR.rbegin(); i != dirLanesR.rend(); ++i) {
2039 discardedInnerWidthRight = 0;
2040 laneMap[(*i).id] = sumoLane++;
2041 types.push_back((*i).type);
2042 if (types.front() != types.back()) {
2046 discardedInnerWidthRight += (*i).width;
2049 discardedInnerWidthLeft = 0;
2050 rightLaneNumber = sumoLane;
2051 rightType = sumoLane > 0 ? (singleType ? types.front() :
joinToString(types,
"|")) :
"";
2055 const std::vector<OpenDriveLane>& dirLanesL = lanesByDir.find(
OPENDRIVE_TAG_LEFT)->second;
2056 for (std::vector<OpenDriveLane>::const_iterator i = dirLanesL.begin(); i != dirLanesL.end(); ++i) {
2058 discardedInnerWidthLeft = 0;
2059 laneMap[(*i).id] = sumoLane++;
2060 types.push_back((*i).type);
2061 if (types.front() != types.back()) {
2065 discardedInnerWidthLeft += (*i).width;
2068 leftLaneNumber = sumoLane;
2069 leftType = sumoLane > 0 ? (singleType ? types.front() :
joinToString(types,
"|")) :
"";
2075 std::map<int, int> ret;
2076 const std::vector<OpenDriveLane>& dirLanes = lanesByDir.find(dir)->second;
2077 for (std::vector<OpenDriveLane>::const_reverse_iterator i = dirLanes.rbegin(); i != dirLanes.rend(); ++i) {
2078 std::map<int, int>::const_iterator toP = laneMap.find((*i).id);
2079 if (toP == laneMap.end()) {
2083 int to = (*toP).second;
2086 from = (*i).predecessor;
2089 std::map<int, int>::const_iterator fromP = prev.
laneMap.find(from);
2090 if (fromP != prev.
laneMap.end()) {
2091 from = (*fromP).second;
2097 if (ret.find(from) != ret.end()) {
2122 l.
speed = (*it).second.speed;
2132 l.
speed = (*it).second.speed;
2142 const std::vector<std::string>& denied)
const {
2144 if (allowed.size() > 0 && denied.size() > 0) {
2145 WRITE_WARNING(
TL(
"Will discard access settings as both denied and allowed classes have been specified."));
2146 }
else if (allowed.size() > 0) {
2148 for (
const std::string& allow : allowed) {
2149 if (allow ==
"simulator") {
2152 }
else if (allow ==
"autonomousTraffic" || allow ==
"autonomous traffic" || allow ==
"throughTraffic") {
2155 }
else if (allow ==
"pedestrian") {
2157 }
else if (allow ==
"passengerCar") {
2159 }
else if (allow ==
"bus") {
2161 }
else if (allow ==
"delivery") {
2163 }
else if (allow ==
"emergency") {
2165 }
else if (allow ==
"taxi") {
2167 }
else if (allow ==
"bicycle") {
2169 }
else if (allow ==
"motorcycle") {
2171 }
else if (allow ==
"truck" || allow ==
"trucks") {
2176 }
else if (denied.size() > 0) {
2177 for (
const std::string& deny : denied) {
2178 if (deny ==
"none") {
2181 }
else if (deny ==
"autonomousTraffic" || deny ==
"autonomous traffic" || deny ==
"throughTraffic") {
2184 }
else if (deny ==
"pedestrian") {
2185 perms &= ~SVC_PEDESTRIAN;
2186 }
else if (deny ==
"passengerCar") {
2187 perms &= ~SVC_PASSENGER;
2188 }
else if (deny ==
"bus") {
2190 }
else if (deny ==
"delivery") {
2191 perms &= ~SVC_DELIVERY;
2192 }
else if (deny ==
"emergency") {
2193 perms &= ~SVC_EMERGENCY;
2194 }
else if (deny ==
"taxi") {
2196 }
else if (deny ==
"bicycle") {
2197 perms &= ~SVC_BICYCLE;
2198 }
else if (deny ==
"motorcycle") {
2199 perms &= ~SVC_MOTORCYCLE;
2200 }
else if (deny ==
"truck" || deny ==
"trucks") {
2201 perms &= ~SVC_TRUCK;
2202 perms &= ~SVC_TRAILER;
2212 std::set<double> attributeChangePositions;
2215 for (std::vector<std::pair<double, LaneAttributeChange> >::const_iterator l = (*k).attributeChanges.begin(); l != (*k).attributeChanges.end(); ++l) {
2216 attributeChangePositions.insert((*l).first);
2217 if ((*l).first == 0) {
2218 (*k).speed = (*l).second.speed;
2219 (*k).permission = (*k).computePermission(tc, (*l).second.allowed, (*l).second.denied);
2224 for (std::vector<std::pair<double, LaneAttributeChange> >::const_iterator l = (*k).attributeChanges.begin(); l != (*k).attributeChanges.end(); ++l) {
2225 attributeChangePositions.insert((*l).first);
2226 if ((*l).first == 0) {
2227 (*k).speed = (*l).second.speed;
2228 (*k).permission = (*k).computePermission(tc, (*l).second.allowed, (*l).second.denied);
2234 if (attributeChangePositions.size() == 0) {
2238 if (*attributeChangePositions.begin() > 0) {
2239 attributeChangePositions.insert(0);
2241#ifdef DEBUG_VARIABLE_SPEED
2243 <<
" buildSpeedChanges sectionStart=" << s
2244 <<
" speedChangePositions=" <<
joinToString(speedChangePositions,
", ")
2247 for (std::set<double>::iterator i = attributeChangePositions.begin(); i != attributeChangePositions.end(); ++i) {
2248 if (i == attributeChangePositions.begin()) {
2249 newSections.push_back(*
this);
2251 newSections.push_back(buildLaneSection(tc, *i));
2255 for (
int i = 0; i != (int)newSections.size(); ++i) {
2256 for (
auto& k : newSections[i].lanesByDir) {
2257 for (
int j = 0; j != (int)k.second.size(); ++j) {
2261 l.
speed = newSections[i - 1].lanesByDir[k.first][j].speed;
2268 l.
permission = newSections[i - 1].lanesByDir[k.first][j].permission;
2269 l.
type = newSections[i - 1].lanesByDir[k.first][j].type;
2289 for (std::vector<OpenDriveSignal>::const_iterator i = signals.begin(); i != signals.end(); ++i) {
2291 if ((*i).type ==
"301" || (*i).type ==
"306") {
2294 if ((*i).type ==
"205" ) {
2315 myTypeContainer(tc),
myCurrentEdge(
"",
"",
"", -1),
myCurrentController(
"",
""),
myEdges(edges),
myOffset(0, 0),
2337 if (majorVersion == 1 && minorVersion > 4) {
2418 std::vector<double> vals;
2424 std::vector<double> vals;
2431 std::vector<double> vals;
2437 std::vector<double> vals;
2446 std::vector<double> vals;
2456 if (pRange ==
"normalized") {
2457 vals.push_back(1.0);
2458 }
else if (pRange ==
"arcLength") {
2459 vals.push_back(-1.0);
2462 vals.push_back(1.0);
2511 int orientationCode = orientation ==
"-" ? -1 : orientation ==
"+" ? 1 : 0;
2522 int orientationCode = orientation ==
"-" ? -1 : orientation ==
"+" ? 1 : 0;
2587 WRITE_ERRORF(
TL(
"In laneLink-element: incoming road '%' is not known."), c.fromEdge);
2603 l.width =
MAX2(l.width, a);
2605#ifdef DEBUG_VARIABLE_WIDTHS
2612 <<
" type=" << l.type
2613 <<
" width=" << l.width
2619 <<
" entries=" << l.widthData.size()
2633 std::vector<std::pair<double, LaneAttributeChange> >::iterator i = std::find_if(attributeChanges.begin(), attributeChanges.end(),
same_position_finder(pos));
2634 if (i != attributeChanges.end()) {
2635 if (rule ==
"allow") {
2636 (*i).second.allowed.push_back(vClass);
2637 }
else if (rule ==
"deny") {
2638 (*i).second.denied.push_back(vClass);
2642 if (rule ==
"allow") {
2643 lac.
allowed.push_back(vClass);
2644 }
else if (rule ==
"deny") {
2645 lac.
denied.push_back(vClass);
2647 attributeChanges.push_back(std::make_pair(pos, lac));
2659 if (!unit.empty()) {
2661 if (unit ==
"km/h") {
2664 if (unit ==
"mph") {
2665 speed *= 1.609344 / 3.6;
2670 std::vector<std::pair<double, LaneAttributeChange> >::iterator i = std::find_if(attributeChanges.begin(), attributeChanges.end(),
same_position_finder(pos));
2671 if (i != attributeChanges.end()) {
2672 (*i).second.speed = speed;
2675 attributeChanges.push_back(std::make_pair(pos, lac));
2704 const std::string baseID = o.
id;
2719 for (
double x = 0; x <= length + NUMERICAL_EPS; x += dist) {
2721 const double a = x / length;
2722 o.
width = wStart * (1 - a) + wEnd * a;
2723 o.
t = tStart * (1 - a) + tEnd * a;
2751 size_t i = cdata.find(
"+proj");
2752 if (i != std::string::npos) {
2753 const std::string proj = cdata.substr(i);
2763 WRITE_ERRORF(
TL(
"Could not set projection (%). This can be ignored with --ignore-errors."), std::string(e.what()));
2767 WRITE_WARNINGF(
TL(
"geoReference format '%' currently not supported"), cdata);
2818 if (intType < 1000001 || (intType > 1000013 && intType != 1000020) || intType == 1000008) {
2825 bool foundDrivingType =
false;
2827 if (ls.s <= s && ls.s + ls.length > s) {
2830 if ((minLane < 0 && l.id >= minLane && l.id <= maxLane) && l.type ==
"driving") {
2831 foundDrivingType =
true;
2836 if ((minLane > 0 && l.id >= minLane && l.id <= maxLane) && l.type ==
"driving") {
2837 foundDrivingType =
true;
2843 if (!foundDrivingType) {
2858 const std::string& elementID,
2859 const std::string& contactPoint) {
2862 if (elementType ==
"road") {
2864 }
else if (elementType ==
"junction") {
2868 if (contactPoint ==
"start") {
2870 }
else if (contactPoint ==
"end") {
2910#ifdef DEBUG_VARIABLE_WIDTHS
2913 std::cout <<
"sanitizeWidths e=" << e->
id <<
" sections=" << e->
laneSections.size() <<
"\n";
2919 if (sec.rightLaneNumber > 0) {
2922 if (sec.leftLaneNumber > 0) {
2931 if (l.widthData.size() > 0) {
2932 auto& wd = l.widthData;
2933 const double threshold = POSITION_EPS;
2934 double maxNoShort = -std::numeric_limits<double>::max();
2936 for (
int i = 0; i < (int)wd.size(); i++) {
2937 const double wdLength = i < (int)wd.size() - 1 ? wd[i + 1].s - wd[i].s : length - seen;
2939 if (wdLength > threshold) {
2940 maxNoShort =
MAX2(maxNoShort, wd[i].a);
2943 if (maxNoShort > 0) {
2944 l.width = maxNoShort;
2945#ifdef DEBUG_VARIABLE_WIDTHS
2947 std::cout <<
" lane=" << l.id <<
" width=" << l.width <<
"\n";
2958 std::vector<OpenDriveLaneSection> newSections;
2959#ifdef DEBUG_VARIABLE_WIDTHS
2962 std::cout <<
"splitMinWidths e=" << e->
id <<
" sections=" << e->
laneSections.size() <<
"\n";
2967 std::vector<double> splitPositions;
2968 const double sectionEnd = (j + 1) == e->
laneSections.end() ? e->
length : (*(j + 1)).s;
2969 const int section = (int)(j - e->
laneSections.begin());
2970#ifdef DEBUG_VARIABLE_WIDTHS
2972 std::cout <<
" findWidthSplit section=" << section <<
" sectionStart=" << sec.
s <<
" sectionOrigStart=" << sec.
sOrig <<
" sectionEnd=" << sectionEnd <<
"\n";
2981 newSections.push_back(sec);
2982 std::sort(splitPositions.begin(), splitPositions.end());
2984 double prevSplit = sec.
s;
2985 for (std::vector<double>::iterator it = splitPositions.begin(); it != splitPositions.end();) {
2986 if ((*it) - prevSplit < minDist || sectionEnd - (*it) < minDist) {
2988#ifdef DEBUG_VARIABLE_WIDTHS
2990 std::cout <<
" skip close split=" << (*it) <<
" prevSplit=" << prevSplit <<
"\n";
2993 it = splitPositions.erase(it);
2994 }
else if ((*it) < sec.
s) {
2996#ifdef DEBUG_VARIABLE_WIDTHS
2998 std::cout <<
" skip early split=" << (*it) <<
" s=" << sec.
s <<
"\n";
3001 it = splitPositions.erase(it);
3008 if (splitPositions.size() > 0) {
3009#ifdef DEBUG_VARIABLE_WIDTHS
3011 std::cout <<
" road=" << e->
id <<
" splitMinWidths section=" << section
3012 <<
" start=" << sec.
s
3013 <<
" origStart=" << sec.
sOrig
3014 <<
" end=" << sectionEnd <<
" minDist=" << minDist
3015 <<
" splitPositions=" <<
toString(splitPositions) <<
"\n";
3018#ifdef DEBUG_VARIABLE_WIDTHS
3020 std::cout <<
"first section...\n";
3024 for (std::vector<double>::iterator it = splitPositions.begin(); it != splitPositions.end(); ++it) {
3027#ifdef DEBUG_VARIABLE_WIDTHS
3029 std::cout <<
"splitAt " << secNew.
s <<
"\n";
3032 newSections.push_back(secNew);
3039 double end = (it + 1) == splitPositions.end() ? sectionEnd : *(it + 1);
3051 int section,
double sectionStart,
double sectionEnd,
3052 std::vector<double>& splitPositions) {
3057 double sPrev = l.widthData.front().s;
3058 double wPrev = l.widthData.front().computeAt(sPrev);
3059#ifdef DEBUG_VARIABLE_WIDTHS
3061 <<
"findWidthSplit section=" << section
3062 <<
" sectionStart=" << sectionStart
3063 <<
" sectionEnd=" << sectionEnd
3065 <<
" type=" << l.type
3066 <<
" widthEntries=" << l.widthData.size() <<
"\n"
3071 for (std::vector<OpenDriveWidth>::const_iterator it_w = l.widthData.begin(); it_w != l.widthData.end(); ++it_w) {
3072 double sEnd = (it_w + 1) != l.widthData.end() ? (*(it_w + 1)).s : sectionEnd - sectionStart;
3073 double w = (*it_w).computeAt(sEnd);
3074#ifdef DEBUG_VARIABLE_WIDTHS
3077 <<
" s=" << (*it_w).s
3078 <<
" a=" << (*it_w).a <<
" b=" << (*it_w).b <<
" c=" << (*it_w).c <<
" d=" << (*it_w).d
3082 const double changeDist = fabs(
myMinWidth - wPrev);
3085 double splitPos = sPrev + (sEnd - sPrev) / fabs(w - wPrev) * changeDist;
3086 double wSplit = (*it_w).computeAt(splitPos);
3087#ifdef DEBUG_VARIABLE_WIDTHS
3089 std::cout <<
" candidate splitPos=" << splitPos <<
" w=" << wSplit <<
"\n";
3096 splitPos -= POSITION_EPS;
3097 if (splitPos < sPrev) {
3098#ifdef DEBUG_VARIABLE_WIDTHS
3100 std::cout <<
" aborting search splitPos=" << splitPos <<
" wSplit=" << wSplit <<
" sPrev=" << sPrev <<
" wPrev=" << wPrev <<
"\n";
3108 splitPos += POSITION_EPS;
3109 if (splitPos > sEnd) {
3110#ifdef DEBUG_VARIABLE_WIDTHS
3112 std::cout <<
" aborting search splitPos=" << splitPos <<
" wSplit=" << wSplit <<
" sEnd=" << sEnd <<
" w=" << w <<
"\n";
3119 wSplit = (*it_w).computeAt(splitPos);
3120#ifdef DEBUG_VARIABLE_WIDTHS
3122 std::cout <<
" refined splitPos=" << splitPos <<
" w=" << wSplit <<
"\n";
3126 splitPositions.push_back(sectionStart + splitPos);
3144 for (std::vector<OpenDriveLane>::iterator k = lanes.begin(); k != lanes.end(); ++k) {
3145 (*k).predecessor = (*k).id;
3163 for (std::vector<OpenDriveLane>::iterator k = lanes.begin(); k != lanes.end(); ++k) {
3166#ifdef DEBUG_VARIABLE_WIDTHS
3168 <<
"recomputeWidths lane=" << l.
id
3169 <<
" type=" << l.
type
3170 <<
" start=" << start
3172 <<
" sectionStart=" << sectionStart
3173 <<
" sectionEnd=" << sectionEnd
3174 <<
" widthEntries=" << l.
widthData.size() <<
"\n"
3179 double sPrevAbs = sPrev + sectionStart;
3180 for (std::vector<OpenDriveWidth>::iterator it_w = l.
widthData.begin(); it_w != l.
widthData.end(); ++it_w) {
3181 double sEnd = (it_w + 1) != l.
widthData.end() ? (*(it_w + 1)).s : sectionEnd - sectionStart;
3182 double sEndAbs = sEnd + sectionStart;
3183#ifdef DEBUG_VARIABLE_WIDTHS
3185 <<
" sPrev=" << sPrev <<
" sPrevAbs=" << sPrevAbs
3186 <<
" sEnd=" << sEnd <<
" sEndAbs=" << sEndAbs
3187 <<
" widthData s=" << (*it_w).s
3188 <<
" a=" << (*it_w).a
3189 <<
" b=" << (*it_w).b
3190 <<
" c=" << (*it_w).c
3191 <<
" d=" << (*it_w).d
3194 if (sPrevAbs <= start && sEndAbs >= start) {
3195#ifdef DEBUG_VARIABLE_WIDTHS
3197 std::cout <<
" atStart=" << start <<
" pos=" << start - sectionStart <<
" w=" << (*it_w).computeAt(start - sectionStart) <<
"\n";
3200 l.
width =
MAX2(l.
width, (*it_w).computeAt(start - sectionStart));
3202 if (sPrevAbs <= end && sEndAbs >= end) {
3203#ifdef DEBUG_VARIABLE_WIDTHS
3205 std::cout <<
" atEnd=" << end <<
" pos=" << end - sectionStart <<
" w=" << (*it_w).computeAt(end - sectionStart) <<
"\n";
3210 if (start <= sPrevAbs && end >= sPrevAbs) {
3211#ifdef DEBUG_VARIABLE_WIDTHS
3213 std::cout <<
" atSPrev=" << sPrev <<
" w=" << (*it_w).computeAt(sPrev) <<
"\n";
3218 if (start <= sEndAbs && end >= sEndAbs) {
3219#ifdef DEBUG_VARIABLE_WIDTHS
3221 std::cout <<
" atSEnd=" << sEnd <<
" w=" << (*it_w).computeAt(sEnd) <<
"\n";
3226#ifdef DEBUG_VARIABLE_WIDTHS
3228 std::cout <<
" sPrev=" << sPrev <<
" sEnd=" << sEnd <<
" l.width=" << l.
width <<
"\n";
#define WRITE_WARNINGF(...)
#define WRITE_ERRORF(...)
#define WRITE_WARNING(msg)
#define PROGRESS_DONE_MESSAGE()
#define PROGRESS_BEGIN_MESSAGE(msg)
std::set< NBNode *, ComparatorIdLess > NodeSet
#define DEBUG_COND3(roadID)
bool operator<(const NIImporter_OpenDrive::Connection &c1, const NIImporter_OpenDrive::Connection &c2)
long long int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
@ SVC_TRUCK
vehicle is a large transport vehicle
@ SVC_IGNORING
vehicles ignoring classes
@ SVC_PASSENGER
vehicle is a passenger car (a "normal" car)
@ SVC_BICYCLE
vehicle is a bicycle
@ SVC_TRAILER
vehicle is a large transport vehicle
@ SVC_DELIVERY
vehicle is a small delivery vehicle
@ SVC_MOTORCYCLE
vehicle is a motorcycle
@ SVC_EMERGENCY
public emergency vehicles
@ SVC_AUTHORITY
authorities vehicles
@ SVC_TAXI
vehicle is a taxi
@ SVC_BUS
vehicle is a bus
@ SVC_PEDESTRIAN
pedestrian
const std::string SUMO_PARAM_ORIGID
int gPrecision
the precision for floating point outputs
bool gDebugFlag1
global utility flags for debugging
std::string joinToString(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
A class that stores a 2D geometrical boundary.
void add(double x, double y, double z=0)
Makes the boundary include the given coordinate.
bool isInitialised() const
check if Boundary is Initialised
double ymin() const
Returns minimum y-coordinate.
double xmin() const
Returns minimum x-coordinate.
double ymax() const
Returns maximum y-coordinate.
double xmax() const
Returns maximum x-coordinate.
static bool isAbsolute(const std::string &path)
Returns the information whether the given path is absolute.
static std::string getConfigurationRelative(const std::string &configPath, const std::string &path)
Returns the second path as a relative path to the first file.
A handler which converts occurring elements and attributes into enums.
void needsCharacterData(const bool value=true)
void error(const XERCES_CPP_NAMESPACE::SAXParseException &exception)
Handler for XML-errors.
void setFileName(const std::string &name)
Sets the current file name.
const std::string & getFileName() const
returns the current file name
static methods for processing the coordinates conversion for the current net
void cartesian2geo(Position &cartesian) const
Converts the given cartesian (shifted) position to its geo (lat/long) representation.
void moveConvertedBy(double x, double y)
Shifts the converted boundary by the given amounts.
static int getNumLoaded()
static void setLoaded(const GeoConvHelper &loaded)
sets the coordinate transformation loaded from a location element
bool usingGeoProjection() const
Returns whether a transformation from geo to metric coordinates will be performed.
static GeoConvHelper & getLoaded()
the coordinate transformation that was loaded fron an input file
static double naviDegree(const double angle)
NBEdge * retrieve(const std::string &id, bool retrieveExtracted=false) const
Returns the edge that has the given id.
bool wasIgnored(std::string id) const
Returns whether the edge with the id was ignored during parsing.
bool insert(NBEdge *edge, bool ignorePrunning=false)
Adds an edge to the dictionary.
The representation of a single edge during network building.
const std::vector< Connection > & getConnections() const
Returns the connections.
NBNode * getToNode() const
Returns the destination node of the edge.
static const double UNSPECIFIED_FRICTION
unspecified lane friction
Lane & getLaneStruct(int lane)
bool addLane2LaneConnection(int fromLane, NBEdge *dest, int toLane, Lane2LaneInfoType type, bool mayUseSameDestination=false, bool mayDefinitelyPass=false, KeepClear keepClear=KEEPCLEAR_UNSPECIFIED, double contPos=UNSPECIFIED_CONTPOS, double visibility=UNSPECIFIED_VISIBILITY_DISTANCE, double speed=UNSPECIFIED_SPEED, double friction=UNSPECIFIED_FRICTION, double length=myDefaultConnectionLength, const PositionVector &customShape=PositionVector::EMPTY, const bool uncontrolled=UNSPECIFIED_CONNECTION_UNCONTROLLED, SVCPermissions permissions=SVC_UNSPECIFIED, const bool indirectLeft=false, const std::string &edgeType="", SVCPermissions changeLeft=SVC_UNSPECIFIED, SVCPermissions changeRight=SVC_UNSPECIFIED, bool postProcess=false)
Adds a connection between the specified this edge's lane and an approached one.
const std::string & getID() const
static const double UNSPECIFIED_LOADED_LENGTH
no length override given
static const double UNSPECIFIED_CONTPOS
unspecified internal junction position
static const double UNSPECIFIED_VISIBILITY_DISTANCE
unspecified foe visibility for connections
static const double UNSPECIFIED_SPEED
unspecified lane speed
@ USER
The connection was given by the user.
@ VALIDATED
The connection was computed and validated.
NBNode * getFromNode() const
Returns the origin node of the edge.
static const double UNSPECIFIED_WIDTH
unspecified lane width
static const double UNSPECIFIED_OFFSET
unspecified lane offset
Instance responsible for building networks.
static bool transformCoordinates(PositionVector &from, bool includeInBoundary=true, GeoConvHelper *from_srs=nullptr)
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.
Container for nodes during the netbuilding process.
std::string createClusterId(const NodeSet &cluster, const std::string &prefix="cluster_")
generate id from cluster node ids
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.
bool extract(NBNode *node, bool remember=false)
Removes the given node but does not delete it.
Represents a single node (junction) during network building.
const std::set< NBTrafficLightDefinition * > & getControllingTLS() const
Returns the traffic lights that were assigned to this node (The set of tls that control this node)
void addTrafficLight(NBTrafficLightDefinition *tlDef)
Adds a traffic light to the list of traffic lights that control this node.
bool isTLControlled() const
Returns whether this node is controlled by any tls.
A traffic light logics which must be computed (only nodes/edges are given)
The base class for traffic light logic definitions.
bool insert(NBTrafficLightDefinition *logic, bool forceInsert=false)
Adds a logic definition to the dictionary.
A storage for available edgeTypes of edges.
double getEdgeTypeMaxWidth(const std::string &edgeType) const
Returns the maximum edge/lane widths of the given edgeType.
bool getEdgeTypeShallBeDiscarded(const std::string &edgeType) const
Returns the information whether edges of this edgeType shall be discarded.
double getEdgeTypeSpeed(const std::string &edgeType) const
Returns the maximal velocity for the given edgeType [m/s].
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.
double getEdgeTypeWidthResolution(const std::string &edgeType) const
Returns the resolution for interpreting edge/lane widths of the given edgeType.
bool knows(const std::string &edgeType) const
Returns whether the named edgeType is in the container.
A class for sorting lane sections by their s-value.
Importer for networks stored in openDrive format.
static void loadNetwork(const OptionsCont &oc, NBNetBuilder &nb)
Loads content of the optionally given SUMO file.
static void recomputeWidths(OpenDriveLaneSection &sec, double start, double end, double sectionStart, double sectionEnd)
static std::vector< double > discretizeOffsets(PositionVector &geom, const std::vector< OpenDriveLaneOffset > &offsets, const std::string &id)
transform Poly3 into a list of offsets, adding intermediate points to geom if needed
static void addOffsets(bool left, PositionVector &geom, const std::vector< OpenDriveLaneOffset > &offsets, const std::string &id, std::vector< double > &result)
static void writeRoadObjects(const OpenDriveEdge *e)
static PositionVector geomFromParamPoly(const OpenDriveEdge &e, const OpenDriveGeometry &g, double resolution)
void myEndElement(int element)
Called when a closing tag occurs.
static SequentialStringBijection::Entry openDriveAttrs[]
The names of openDrive-XML attributes (for passing to GenericSAXHandler)
static void calcPointOnCurve(double *ad_x, double *ad_y, double ad_centerX, double ad_centerY, double ad_r, double ad_length)
static bool myImportInternalShapes
OpenDriveXMLTag
Numbers representing openDrive-XML - element names.
@ OPENDRIVE_TAG_SEMANTICS
@ OPENDRIVE_TAG_ELEVATION
@ OPENDRIVE_TAG_CONTROLLER
@ OPENDRIVE_TAG_PARAMPOLY3
@ OPENDRIVE_TAG_LANEOFFSET
@ OPENDRIVE_TAG_SIGNALREFERENCE
@ OPENDRIVE_TAG_GEOREFERENCE
@ OPENDRIVE_TAG_SUCCESSOR
@ OPENDRIVE_TAG_PREDECESSOR
@ OPENDRIVE_TAG_LANESECTION
@ OPENDRIVE_TAG_CONNECTION
void addGeometryShape(GeometryType type, const std::vector< double > &vals)
static bool myImportWidths
static void setStraightConnections(std::vector< OpenDriveLane > &lanes)
std::string myCurrentConnectingRoad
OpenDriveController myCurrentController
static void setLaneAttributes(const OpenDriveEdge *e, NBEdge::Lane &sumoLane, const OpenDriveLane &odLane, bool saveOrigIDs, const NBTypeCont &tc)
std::vector< int > myElementStack
~NIImporter_OpenDrive()
Destructor.
static void buildConnectionsToOuter(const Connection &c, const std::map< std::string, OpenDriveEdge * > &innerEdges, const std::map< std::string, OpenDriveEdge * > &edges, const NBTypeCont &tc, std::vector< Connection > &into, std::set< Connection > &seen)
void myStartElement(int element, const SUMOSAXAttributes &attrs)
Called on the opening of a tag;.
std::map< std::string, OpenDriveSignal > & getSignals()
std::map< std::string, OpenDriveSignal > mySignals
static bool laneSectionsConnected(OpenDriveEdge *edge, int in, int out)
void addLink(LinkType lt, const std::string &elementType, const std::string &elementID, const std::string &contactPoint)
static OpenDriveController myDummyController
@ OPENDRIVE_ATTR_REVMAJOR
@ OPENDRIVE_ATTR_SIGNALID
@ OPENDRIVE_ATTR_CURVSTART
@ OPENDRIVE_ATTR_CONTACTPOINT
@ OPENDRIVE_ATTR_REVMINOR
@ OPENDRIVE_ATTR_ORIENTATION
@ OPENDRIVE_ATTR_INCOMINGROAD
@ OPENDRIVE_ATTR_CURVATURE
@ OPENDRIVE_ATTR_ELEMENTTYPE
@ OPENDRIVE_ATTR_JUNCTION
@ OPENDRIVE_ATTR_CONNECTINGROAD
@ OPENDRIVE_ATTR_WIDTHEND
@ OPENDRIVE_ATTR_FROMLANE
@ OPENDRIVE_ATTR_RESTRICTION
@ OPENDRIVE_ATTR_DISTANCE
@ OPENDRIVE_ATTR_ELEMENTID
@ OPENDRIVE_ATTR_WIDTHSTART
static PositionVector geomFromSpiral(const OpenDriveEdge &e, const OpenDriveGeometry &g, double resolution)
static PositionVector geomFromLine(const OpenDriveEdge &e, const OpenDriveGeometry &g, double resolution)
static NBNode * getOrBuildNode(const std::string &id, const Position &pos, NBNodeCont &nc)
Builds a node or returns the already built.
const NBTypeCont & myTypeContainer
NIImporter_OpenDrive(const NBTypeCont &tc, std::map< std::string, OpenDriveEdge * > &edges)
Constructor.
static Position calculateStraightEndPoint(double hdg, double length, const Position &start)
static bool hasNonLinearElevation(const OpenDriveEdge &e)
OpenDriveXMLTag myCurrentLaneDirection
static PositionVector geomFromPoly(const OpenDriveEdge &e, const OpenDriveGeometry &g, double resolution)
static void revisitLaneSections(const NBTypeCont &tc, std::map< std::string, OpenDriveEdge * > &edges)
Rechecks lane sections of the given edges.
Poly3 OpenDriveLaneOffset
static bool myIgnoreMisplacedSignals
OpenDriveEdge myCurrentEdge
static void sanitizeWidths(OpenDriveEdge *e)
GeometryType
OpenDrive geometry type enumeration.
@ OPENDRIVE_GT_PARAMPOLY3
static void computeShapes(std::map< std::string, OpenDriveEdge * > &edges)
Computes a polygon representation of each edge's geometry.
static void calculateCurveCenter(double *ad_x, double *ad_y, double ad_radius, double ad_hdg)
std::string myCurrentJunctionID
static void setEdgeLinks2(OpenDriveEdge &e, const std::map< std::string, OpenDriveEdge * > &edges)
static std::pair< NBEdge *, NBEdge * > retrieveSignalEdges(NBNetBuilder &nb, const std::string &fromID, const std::string &toID, int signalMinLane)
std::string myCurrentIncomingRoad
static void splitMinWidths(OpenDriveEdge *e, const NBTypeCont &tc, double minDist)
bool myConnectionWasEmpty
static bool myImportAllTypes
std::map< std::string, OpenDriveController > myControllers
void myCharacters(int element, const std::string &chars)
Callback method for characters to implement by derived classes.
static std::string reversedEdgeID(const std::string &id)
static NBTrafficLightDefinition * getTLSSecure(NBEdge *inEdge, NBNetBuilder &nb)
Poly3 OpenDriveElevation
LaneOffset has the same fields as Elevation.
ContactPoint myCurrentContactPoint
static void findWidthSplit(const NBTypeCont &tc, std::vector< OpenDriveLane > &lanes, int section, double sectionStart, double sectionEnd, std::vector< double > &splitPositions)
static SequentialStringBijection::Entry openDriveTags[]
The names of openDrive-XML elements (for passing to GenericSAXHandler)
static PositionVector geomFromArc(const OpenDriveEdge &e, const OpenDriveGeometry &g, double resolution)
std::map< std::string, OpenDriveController > & getControllers()
static void setNodeSecure(NBNodeCont &nc, OpenDriveEdge &e, const std::string &nodeID, NIImporter_OpenDrive::LinkType lt, std::vector< NodeSet > &joinedNodeIDs)
LinkType
OpenDrive link type enumeration.
@ OPENDRIVE_LT_PREDECESSOR
std::map< std::string, OpenDriveEdge * > & myEdges
int getTLIndexForController(std::string controllerID)
const OpenDriveController & getController(std::string signalID)
const std::string & getID() const
Returns the id.
A storage for options typed value containers)
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 isDefault(const std::string &name) const
Returns the information whether the named option has still the default value.
bool exists(const std::string &name) const
Returns the information whether the named option is known.
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.
bool isUsableFileList(const std::string &name) const
Checks whether the named option is usable as a file list (with at least a single file)
Static storage of an output device and its base (abstract) implementation.
static OutputDevice & getDevice(const std::string &name, bool usePrefix=true)
Returns the described OutputDevice.
bool writeXMLHeader(const std::string &rootElement, const std::string &schemaFile, std::map< SumoXMLAttr, std::string > attrs=std::map< SumoXMLAttr, std::string >(), bool includeConfig=true)
Writes an XML header with optional configuration.
C++ TraCI client API implementation.
virtual void setParameter(const std::string &key, const std::string &value)
Sets a parameter.
A point in 2D or 3D with translation and scaling methods.
bool isNAN() const
check if position is NAN
void set(double x, double y)
set positions x and y
double distanceTo2D(const Position &p2) const
returns the euclidean distance in the x-y-plane
double x() const
Returns the x-position.
void add(const Position &pos)
Adds the given position to this one.
void mul(double val)
Multiplies position with the given value.
double y() const
Returns the y-position.
double length2D() const
Returns the length.
void append(const PositionVector &v, double sameThreshold=2.0)
void move2sideCustom(std::vector< double > amount, double maxExtension=100)
move position vector to side using a custom offset for each geometry point
void rotate2D(double angle)
double rotationAtOffset(double pos) const
Returns the rotation at the given length.
Position positionAtOffset(double pos, double lateralOffset=0) const
Returns the position at the given length.
void add(double xoff, double yoff, double zoff)
int indexOfClosest(const Position &p, bool twoD=false) const
void move2side(double amount, double maxExtension=100)
move position vector to side using certain amount
bool almostSame(const PositionVector &v2, double maxDiv=POSITION_EPS) const
check if the two vectors have the same length and pairwise similar positions
PositionVector getSubpart2D(double beginOffset, double endOffset) const
get subpart of a position vector in two dimensions (Z is ignored)
Boundary getBoxBoundary() const
Returns a boundary enclosing this list of lines.
int insertAtClosest(const Position &p, bool interpolateZ)
inserts p between the two closest positions
const PositionVector simplified2(const bool closed, const double eps=NUMERICAL_EPS) const
Position positionAtOffset2D(double pos, double lateralOffset=0, bool extrapolateBeyond=false) const
Returns the position at the given length.
void push_back_noDoublePos(const Position &p)
insert in back a non double position
void removeDoublePoints(double minDist=POSITION_EPS, bool assertLength=false, int beginOffset=0, int endOffset=0, bool resample=false)
Removes positions if too near.
PositionVector reverse() const
reverse position vector
static const RGBColor YELLOW
void writeXML(OutputDevice &out, bool geo=false) const
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.
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.
static StringBijection< TrafficLightType > TrafficLightTypes
traffic light types
static StringBijection< POIIcon > POIIcons
POI icon values.
const std::string & getString(const T key) const
get string
T get(const std::string &str) const
get key
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 runParser(GenericSAXHandler &handler, const std::string &file, const bool isNet=false, const bool isRoute=false, const bool isExternal=false, const bool catchExceptions=true)
Runs the given handler on the given file; returns if everything's ok.
#define UNUSED_PARAMETER(x)
NLOHMANN_BASIC_JSON_TPL_DECLARATION void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL &j1, nlohmann::NLOHMANN_BASIC_JSON_TPL &j2) noexcept(//NOLINT(readability-inconsistent-declaration-parameter-name) is_nothrow_move_constructible< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value &&//NOLINT(misc-redundant-expression) is_nothrow_move_assignable< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value)
exchanges the values of two JSON objects
void odrSpiral(double s, double cDot, double *x, double *y, double *t)
A structure which describes a connection between edges or lanes.
An (internal) definition of a single lane of an edge.
double width
This lane's width.
PositionVector customShape
A custom shape for this lane set by the user.
std::string type
the type of this lane
double speed
The speed allowed on this lane.
SVCPermissions permissions
List of vehicle types that are allowed on this lane.
A connection between two roads.
std::string getDescription() const
Attribute set applied at a certain position along a lane.
std::vector< std::string > allowed
std::vector< std::string > denied
Representation of a signal group.
std::vector< std::string > signalIDs
Representation of an openDrive "link".
double length
The length of the edge.
std::vector< double > laneOffsets
std::string id
The id of the edge.
std::set< Connection > connections
std::string junction
The id of the junction the edge belongs to.
std::string streetName
The road name of the edge.
int getPriority(OpenDriveXMLTag dir) const
Returns the edge's priority, regarding the direction.
std::vector< OpenDriveLink > links
std::vector< OpenDriveSignal > signals
std::vector< OpenDriveLaneSection > laneSections
std::vector< OpenDriveLaneOffset > offsets
std::vector< OpenDriveObject > objects
std::vector< OpenDriveGeometry > geometries
std::vector< OpenDriveElevation > elevations
Representation of an OpenDrive geometry part.
std::vector< double > params
Representation of a lane.
std::vector< OpenDriveWidth > widthData
std::vector< std::pair< double, LaneAttributeChange > > attributeChanges
List of permission and speed changes.
std::string type
The lane's type.
double speed
The lane's speed (set in post-processing)
SVCPermissions computePermission(const NBTypeCont &tc, const std::vector< std::string > &allowed, const std::vector< std::string > &denied) const
compute the actual SUMO lane permissions given the lane type as a start solution
SVCPermissions permission
The access permissions (set in post-processing)
Representation of a lane section.
OpenDriveLaneSection buildLaneSection(const NBTypeCont &tc, double startPos)
bool buildAttributeChanges(const NBTypeCont &tc, std::vector< OpenDriveLaneSection > &newSections)
std::map< OpenDriveXMLTag, std::vector< OpenDriveLane > > lanesByDir
The lanes, sorted by their direction.
std::map< int, int > laneMap
A mapping from OpenDrive to SUMO-index (the first is signed, the second unsigned)
OpenDriveLaneSection(double sArg)
Constructor.
int rightLaneNumber
The number of lanes on the right and on the left side, respectively.
double sOrig
The original starting offset of this lane section (differs from s if the section had to be split)
void buildLaneMapping(const NBTypeCont &tc)
Build the mapping from OpenDrive to SUMO lanes.
std::map< int, int > getInnerConnections(OpenDriveXMLTag dir, const OpenDriveLaneSection &prev)
Returns the links from the previous to this lane section.
double s
The starting offset of this lane section.
Representation of an OpenDrive link.
ContactPoint contactPoint
Representation of a signal.
std::string controller
the controller ID
double computeAt(double pos) const