GenericTrafficRules.cpp
Go to the documentation of this file.
2 
3 #include <lanelet2_core/geometry/Area.h>
4 #include <lanelet2_core/geometry/Lanelet.h>
5 #include <lanelet2_core/primitives/RegulatoryElement.h>
7 
9 
10 namespace lanelet {
11 namespace traffic_rules {
12 
13 namespace {
14 bool canChangeToLeft(LaneChangeType t) { return t == LaneChangeType::Both || t == LaneChangeType::ToLeft; }
15 bool canChangeToRight(LaneChangeType t) { return t == LaneChangeType::Both || t == LaneChangeType::ToRight; }
16 
17 template <typename Map, typename Key, typename Value>
18 Value getMapOrDefault(const Map& map, Key key, Value defaultVal) {
19  auto elem = map.find(key);
20  if (elem == map.end()) {
21  return defaultVal;
22  }
23  return elem->second;
24 }
25 
26 bool startswith(const std::string& str, const std::string& substr) {
27  return str.compare(0, substr.size(), substr) == 0;
28 }
29 
30 LaneChangeType getChangeType(const std::string& type, const std::string& subtype, const std::string& participant) {
31  using LaneChangeMap = std::map<std::pair<std::string, std::string>, LaneChangeType>;
32  const static LaneChangeMap VehicleChangeType{
39  const static LaneChangeMap PedestrianChangeType{
41 
42  if (startswith(participant, Participants::Vehicle)) {
43  return getMapOrDefault(VehicleChangeType, std::make_pair(type, subtype), LaneChangeType::None);
44  }
45  if (participant == Participants::Pedestrian) {
46  return getMapOrDefault(PedestrianChangeType, std::make_pair(type, subtype), LaneChangeType::None);
47  }
48  if (participant == Participants::Bicycle) {
49  auto asVehicle = getMapOrDefault(VehicleChangeType, std::make_pair(type, subtype), LaneChangeType::None);
50  if (asVehicle != LaneChangeType::None) {
51  return asVehicle;
52  }
53  return getMapOrDefault(PedestrianChangeType, std::make_pair(type, subtype), LaneChangeType::None);
54  }
55  return LaneChangeType::None;
56 }
57 
58 Optional<LaneChangeType> getHardcodedChangeType(const ConstLineString3d& boundary) {
59  if (boundary.hasAttribute(AttributeNamesString::LaneChange)) {
60  if (boundary.attributeOr(AttributeNamesString::LaneChange, false)) {
61  return {true, LaneChangeType::Both};
62  }
63  return {true, LaneChangeType::None};
64  }
65  if (boundary.hasAttribute(AttributeNamesString::LaneChangeLeft)) {
66  if (boundary.attributeOr(AttributeNamesString::LaneChangeLeft, false)) {
67  if (boundary.attributeOr(AttributeNamesString::LaneChangeRight, false)) {
68  return {true, LaneChangeType::Both};
69  }
70  return {true, LaneChangeType::ToLeft};
71  }
72  }
73  if (boundary.hasAttribute(AttributeNamesString::LaneChangeRight)) {
74  if (boundary.attributeOr(AttributeNamesString::LaneChangeRight, false)) {
75  return {true, LaneChangeType::ToRight};
76  }
77  return {true, LaneChangeType::None};
78  }
79  return {false, LaneChangeType::None};
80 }
81 
82 bool hasOverride(const AttributeMap& attrs, const std::string& overridePrefix) {
83  return utils::anyOf(attrs, [&overridePrefix](auto& attr) { return startswith(attr.first, overridePrefix); });
84 }
85 
86 template <typename T>
87 T getOverride(const AttributeMap& attrs, const std::string& overridePrefix, const std::string& override, T defaultVal) {
88  auto overrideAttr = utils::findIf(attrs, [&override, &overridePrefix](auto& attr) {
89  // it is forbidden to define overrides at different hierachical levels, so we just have to search for one single
90  // hit.
91  if (attr.first.size() < overridePrefix.size()) {
92  return false;
93  }
94  return startswith(override, attr.first);
95  });
96  if (!overrideAttr) {
97  return defaultVal;
98  }
99  return overrideAttr->second.template as<T>().get_value_or(defaultVal);
100 }
101 
102 bool isDrivingDir(const lanelet::ConstLanelet& ll, const std::string& participant) {
103  if (!ll.inverted()) {
104  return true;
105  }
106  auto hasOneWay = ll.attributeOr(AttributeName::OneWay, Optional<bool>());
107  if (!!hasOneWay) {
108  return !*hasOneWay;
109  }
110  if (hasOverride(ll.attributes(), AttributeNamesString::OneWay)) {
111  return !getOverride(ll.attributes(), AttributeNamesString::OneWay,
112  AttributeNamesString::OneWay + (":" + participant), true);
113  }
114  return participant == Participants::Pedestrian;
115 }
116 
117 template <typename T>
118 T sort(const T& toSort) {
119  auto sorted = toSort;
120  std::sort(sorted.begin(), sorted.end());
121  return sorted;
122 }
123 
124 } // namespace
125 TrafficRules::~TrafficRules() = default;
126 
128  auto regelems = lanelet.regulatoryElements();
129  auto isDynamic = [](const auto& elem) { return elem->attributeOr(AttributeName::Dynamic, false); };
130  return std::any_of(regelems.begin(), regelems.end(), isDynamic);
131 }
132 
134  if (!isDrivingDir(lanelet, participant())) {
135  return false;
136  }
137  auto canPassByRule = canPass(lanelet.regulatoryElements());
138  if (!!canPassByRule) {
139  return *canPassByRule;
140  }
141  if (hasOverride(lanelet.attributes(), AttributeNamesString::Participant)) {
142  return getOverride(lanelet.attributes(), AttributeNamesString::Participant, Participants::tag(participant()),
143  false);
144  }
145  return canPass(lanelet.attributeOr(AttributeName::Subtype, ""), lanelet.attributeOr(AttributeName::Location, ""))
146  .get_value_or(false);
147 }
148 
149 bool GenericTrafficRules::canPass(const ConstArea& area) const {
150  auto canPassByRule = canPass(area.regulatoryElements());
151  if (!!canPassByRule) {
152  return *canPassByRule;
153  }
154  if (hasOverride(area.attributes(), AttributeNamesString::Participant)) {
155  return getOverride(area.attributes(), AttributeNamesString::Participant, Participants::tag(participant()), false);
156  }
158  .get_value_or(false);
159 }
160 
162  bool virtualIsPassable = false) const {
163  using namespace std::string_literals;
164  LaneChangeType changeType;
165  auto result = getHardcodedChangeType(boundary);
166  if (!!result) {
167  changeType = *result;
168  } else {
169  auto type = boundary.attributeOr(AttributeName::Type, ""s);
170  if (virtualIsPassable && type == AttributeValueString::Virtual) {
171  return LaneChangeType::Both;
172  }
173  changeType = getChangeType(type, boundary.attributeOr(AttributeName::Subtype, ""s), participant());
174  }
175  // handle inverted ls
176  if (boundary.inverted()) {
177  if (changeType == LaneChangeType::ToLeft) {
179  }
180  if (changeType == LaneChangeType::ToRight) {
181  return LaneChangeType::ToLeft;
182  }
183  }
184  return changeType;
185 }
186 
187 bool GenericTrafficRules::canPass(const ConstLanelet& from, const ConstLanelet& to) const {
188  return geometry::follows(from, to) && canPass(from) && canPass(to);
189 }
190 
192  return utils::findIf(ar.outerBound(), [p1 = ll.leftBound().back(), p2 = ll.rightBound().back()](auto& boundLs) {
193  return (boundLs.back() == p1 && boundLs.front() == p2);
194  });
195 }
197  return utils::findIf(ar1.outerBound(), [&ar2](auto& ar1Bound) {
198  return !!utils::findIf(ar2.outerBound(),
199  [ar1Bound = ar1Bound.invert()](auto& ar2Bound) { return ar2Bound == ar1Bound; });
200  });
201 }
202 
203 bool GenericTrafficRules::canPass(const ConstLanelet& from, const ConstArea& to) const {
204  if (!canPass(from) || !canPass(to)) {
205  return false;
206  }
207  if (geometry::leftOf(from, to)) {
208  return canChangeToLeft(laneChangeType(from.leftBound(), true));
209  }
210  if (geometry::rightOf(from, to)) {
211  return canChangeToRight(laneChangeType(from.rightBound(), true));
212  }
213  auto line = determineCommonLine(from, to);
214  if (!!line) {
215  return canChangeToRight(laneChangeType(*line, true));
216  }
217  return false;
218 }
219 
220 bool GenericTrafficRules::canPass(const ConstArea& from, const ConstLanelet& to) const {
221  if (!canPass(from) || !canPass(to)) {
222  return false;
223  }
224  if (geometry::leftOf(to, from)) {
225  return canChangeToRight(laneChangeType(to.leftBound(), true));
226  }
227  if (geometry::rightOf(to, from)) {
228  return canChangeToLeft(laneChangeType(to.rightBound(), true));
229  }
230  auto line = determineCommonLine(to.invert(), from);
231  if (!!line) {
232  return canChangeToLeft(laneChangeType(*line, true));
233  }
234  return false;
235 }
236 
237 bool GenericTrafficRules::canPass(const ConstArea& from, const ConstArea& to) const {
238  if (!canPass(from) && canPass(to)) {
239  return false;
240  }
241  auto line = determineCommonLine(from, to);
242  if (!line) {
243  return false;
244  }
245  return canChangeToLeft(laneChangeType(*line, true));
246 }
247 
249  if (!canPass(from) || !canPass(to)) {
250  return false;
251  }
252  bool isLeft = false;
253  if (geometry::leftOf(from, to)) {
254  isLeft = true;
255  } else if (!geometry::rightOf(from, to)) {
256  return false;
257  }
258  auto type = laneChangeType(isLeft ? from.rightBound() : from.leftBound());
259  return isLeft ? canChangeToRight(type) : canChangeToLeft(type);
260 }
261 
263  const std::string& participant) {
264  using Value = AttributeValueString;
265  using SpeedLimitMap = std::map<std::pair<std::string, std::string>, SpeedLimitInformation(CountrySpeedLimits::*)>;
266  const static SpeedLimitMap SpeedLimitLookup{
274  };
275  if (participant == Participants::Pedestrian) {
276  return countryLimits.pedestrian;
277  }
278  if (participant == Participants::Bicycle) {
279  return countryLimits.bicycle;
280  }
281  const std::string vehicle = Participants::Vehicle;
282  if (startswith(participant, vehicle)) {
283  auto location =
284  getMapOrDefault(attributes, AttributeName::Location, Attribute(AttributeValueString::Urban)).value();
285  auto type = getMapOrDefault(attributes, AttributeName::Subtype, Attribute(AttributeValueString::Road)).value();
286  auto limit = SpeedLimitLookup.find(std::make_pair(location, type));
287  if (limit != SpeedLimitLookup.end()) {
288  return countryLimits.*(limit->second);
289  }
290  }
291  return {};
292 }
293 
295  const AttributeMap& attributes) const {
296  using namespace std::string_literals;
297  using namespace units::literals;
298  using Attr = AttributeNamesString;
299  auto regelemSpeedLimit = speedLimit(regelems);
300  if (!!regelemSpeedLimit) {
301  return *regelemSpeedLimit;
302  }
303  if (hasOverride(attributes, Attr::SpeedLimit) || hasOverride(attributes, Attr::SpeedLimitMandatory)) {
304  auto defaultLimit =
305  getMapOrDefault(attributes, AttributeName::SpeedLimit, Attribute(0_kmh)).asVelocity().get_value_or(0_kmh);
306  auto limit =
307  getOverride(attributes, Attr::SpeedLimit + ":"s, Attr::SpeedLimit + ":"s + participant(), defaultLimit);
308  auto mandatory =
309  getOverride(attributes, Attr::SpeedLimitMandatory, Attr::SpeedLimitMandatory + ":"s + participant(), true);
310  return {limit, mandatory};
311  }
312  return getSpeedLimitFromType(attributes, countrySpeedLimits(), participant());
313 }
314 
316  return speedLimit(lanelet.regulatoryElements(), lanelet.attributes());
317 }
318 
320  return speedLimit(area.regulatoryElements(), area.attributes());
321 }
322 
323 const std::string& TrafficRules::participant() const { return config_.at("participant").value(); }
324 
325 const std::string& TrafficRules::location() const { return config_.at("location").value(); }
326 
327 Optional<bool> GenericTrafficRules::canPass(const std::string& type, const std::string& /*location*/) const {
328  using ParticantsMap = std::map<std::string, std::vector<std::string>>;
329  using Value = AttributeValueString;
330  const static ParticantsMap ParticipantMap{
331  {"", {Participants::Vehicle}},
342  auto participants = ParticipantMap.find(type);
343  if (participants == ParticipantMap.end()) {
344  return {};
345  }
346  return utils::anyOf(participants->second,
347  [this](auto& participant) { return startswith(this->participant(), participant); });
348 }
349 
351  return isDrivingDir(lanelet, participant()) != isDrivingDir(lanelet.invert(), participant());
352 }
353 
354 std::ostream& operator<<(std::ostream& stream, const SpeedLimitInformation& obj) {
355  return stream << "speedLimit: " << units::KmHQuantity(obj.speedLimit).value()
356  << "km/h, mandatory: " << (obj.isMandatory ? "yes" : "no");
357 }
358 
359 std::ostream& operator<<(std::ostream& stream, const TrafficRules& obj) {
360  return stream << "location: " << obj.location() << ", participant: " << obj.participant();
361 }
362 
363 } // namespace traffic_rules
364 } // namespace lanelet
lanelet::traffic_rules::CountrySpeedLimits::bicycle
SpeedLimitInformation bicycle
Definition: GenericTrafficRules.h:18
lanelet::Attribute
lanelet::traffic_rules::SpeedLimitInformation::speedLimit
Velocity speedLimit
The current speed limit (must not be Inf)
Definition: TrafficRules.h:9
lanelet::AttributeValueString::BicycleLane
static constexpr const char BicycleLane[]
lanelet::traffic_rules::CountrySpeedLimits::vehicleUrbanRoad
SpeedLimitInformation vehicleUrbanRoad
Definition: GenericTrafficRules.h:12
lanelet
lanelet::ConstLanelet::invert
ConstLanelet invert() const
lanelet::AttributeNamesString::LaneChange
static constexpr const char LaneChange[]
ConstPrimitive< LaneletData >::attributeOr
T attributeOr(AttributeName name, T defaultVal) const
lanelet::traffic_rules::TrafficRules
Class for inferring traffic rules for lanelets and areas.
Definition: TrafficRules.h:18
ConstPrimitive< LaneletData >::attributes
const AttributeMap & attributes() const
lanelet::Participants::VehicleEmergency
static constexpr const char VehicleEmergency[]
lanelet::traffic_rules::CountrySpeedLimits::playStreet
SpeedLimitInformation playStreet
Definition: GenericTrafficRules.h:16
lanelet::ConstArea
lanelet::Participants::Pedestrian
static constexpr const char Pedestrian[]
lanelet::AttributeValueString::Highway
static constexpr const char Highway[]
p2
BasicPoint p2
lanelet::traffic_rules::determineCommonLine
Optional< ConstLineString3d > determineCommonLine(const ConstLanelet &ll, const ConstArea &ar)
Definition: GenericTrafficRules.cpp:191
lanelet::ConstLanelet::inverted
bool inverted() const
lanelet::AttributeName::OneWay
@ OneWay
lanelet::AttributeValueString::Low
static constexpr const char Low[]
lanelet::traffic_rules::CountrySpeedLimits
Definition: GenericTrafficRules.h:11
lanelet::traffic_rules::TrafficRules::config_
Configuration config_
Definition: TrafficRules.h:102
lanelet::geometry::follows
bool follows(const ConstArea &prev, const ConstLanelet &next)
lanelet::AttributeValueString::LineThin
static constexpr const char LineThin[]
lanelet::AttributeName::SpeedLimit
@ SpeedLimit
ConstLineStringImpl< Point3d >::back
const ConstPointType & back() const noexcept
GenericTrafficRules.h
lanelet::traffic_rules::TrafficRules::location
const std::string & location() const
the the location the rules are valid for
Definition: GenericTrafficRules.cpp:325
ConstLineStringImpl< Point3d >::inverted
bool inverted() const noexcept
lanelet::Participants::tag
static std::string tag(const std::string &participant)
lanelet::AttributeValueString::PlayStreet
static constexpr const char PlayStreet[]
lanelet::AttributeValueString::Exit
static constexpr const char Exit[]
Units.h
lanelet::AttributeValueString::Walkway
static constexpr const char Walkway[]
lanelet::AttributeNamesString::LaneChangeRight
static constexpr const char LaneChangeRight[]
lanelet::traffic_rules::CountrySpeedLimits::pedestrian
SpeedLimitInformation pedestrian
Definition: GenericTrafficRules.h:17
lanelet::units::KmHQuantity
boost::units::quantity< KmH > KmHQuantity
lanelet::AttributeValueString::Virtual
static constexpr const char Virtual[]
lanelet::ConstArea::regulatoryElements
RegulatoryElementConstPtrs regulatoryElements() const
Optional
boost::optional< T > Optional
lanelet::AttributeName::Type
@ Type
lanelet::AttributeValueString::Crosswalk
static constexpr const char Crosswalk[]
lanelet::AttributeNamesString::OneWay
static constexpr const char OneWay[]
lanelet::AttributeNamesString
lanelet::AttributeValueString::EmergencyLane
static constexpr const char EmergencyLane[]
lanelet::AttributeNamesString::Participant
static constexpr const char Participant[]
lanelet::traffic_rules::CountrySpeedLimits::vehicleNonurbanRoad
SpeedLimitInformation vehicleNonurbanRoad
Definition: GenericTrafficRules.h:13
lanelet::AttributeValueString::DashedSolid
static constexpr const char DashedSolid[]
p1
BasicPoint p1
lanelet::traffic_rules::GenericTrafficRules::countrySpeedLimits
virtual const CountrySpeedLimits & countrySpeedLimits() const =0
Overloads should return a descripton of their countrie's speed limit definition.
lanelet::utils::findIf
auto findIf(ContainerT &&c, Func f)
lanelet::AttributeNamesString::LaneChangeLeft
static constexpr const char LaneChangeLeft[]
lanelet::AttributeName::Dynamic
@ Dynamic
lanelet::AttributeValueString::SharedWalkway
static constexpr const char SharedWalkway[]
lanelet::traffic_rules::GenericTrafficRules::isOneWay
bool isOneWay(const ConstLanelet &lanelet) const override
returns whether a lanelet can be driven in one direction only
Definition: GenericTrafficRules.cpp:350
lanelet::traffic_rules::CountrySpeedLimits::vehicleNonurbanHighway
SpeedLimitInformation vehicleNonurbanHighway
Definition: GenericTrafficRules.h:15
lanelet::AttributeValueString::Curbstone
static constexpr const char Curbstone[]
lanelet::traffic_rules::GenericTrafficRules::speedLimit
SpeedLimitInformation speedLimit(const ConstLanelet &lanelet) const override
returns speed limit on this lanelet.
Definition: GenericTrafficRules.cpp:315
lanelet::AttributeName::Location
@ Location
lanelet::AttributeValueString::SolidDashed
static constexpr const char SolidDashed[]
lanelet::AttributeValueString::LineThick
static constexpr const char LineThick[]
lanelet::AttributeValueString::Stairs
static constexpr const char Stairs[]
lanelet::traffic_rules::operator<<
std::ostream & operator<<(std::ostream &stream, const SpeedLimitInformation &obj)
Definition: GenericTrafficRules.cpp:354
lanelet::traffic_rules::TrafficRules::participant
const std::string & participant() const
the traffic participant the rules are valid for (e.g. vehicle, car, pedestrian, etc)
Definition: GenericTrafficRules.cpp:323
lanelet::traffic_rules::SpeedLimitInformation
Definition: TrafficRules.h:8
lanelet::Participants::Bicycle
static constexpr const char Bicycle[]
lanelet::Participants::Vehicle
static constexpr const char Vehicle[]
lanelet::traffic_rules::LaneChangeType::ToLeft
@ ToLeft
lanelet::AttributeValueString::Road
static constexpr const char Road[]
HybridMap< Attribute, decltype(AttributeNamesString::Map)&, AttributeNamesString::Map >
lanelet::AttributeValueString::Nonurban
static constexpr const char Nonurban[]
lanelet::utils::anyOf
bool anyOf(const Container &c, Predicate &&p)
lanelet::traffic_rules::TrafficRules::~TrafficRules
virtual ~TrafficRules()
lanelet::traffic_rules::CountrySpeedLimits::vehicleUrbanHighway
SpeedLimitInformation vehicleUrbanHighway
Definition: GenericTrafficRules.h:14
lanelet::AttributeValueString
lanelet::geometry::leftOf
bool leftOf(const ConstLanelet &right, const ConstArea &left)
lanelet::AttributeValueString::Urban
static constexpr const char Urban[]
lanelet::RegulatoryElementConstPtrs
std::vector< RegulatoryElementConstPtr > RegulatoryElementConstPtrs
lanelet::ConstLineString3d
lanelet::traffic_rules::GenericTrafficRules::laneChangeType
virtual LaneChangeType laneChangeType(const ConstLineString3d &boundary, bool virtualIsPassable) const
checks which types of lange changes are allowed along this boundary to make a lane switch from one la...
Definition: GenericTrafficRules.cpp:161
lanelet::traffic_rules::GenericTrafficRules::canPass
bool canPass(const ConstLanelet &lanelet) const override
returns whether it is allowed to pass/drive on this lanelet
Definition: GenericTrafficRules.cpp:133
lanelet::ConstArea::outerBound
ConstLineStrings3d outerBound() const
lanelet::AttributeValueString::Dashed
static constexpr const char Dashed[]
lanelet::ConstLanelet
lanelet::traffic_rules::LaneChangeType::Both
@ Both
lanelet::AttributeName
AttributeName
lanelet::traffic_rules::GenericTrafficRules::hasDynamicRules
bool hasDynamicRules(const ConstLanelet &lanelet) const override
returns whether dynamic traffic rules apply to this lanelet.
Definition: GenericTrafficRules.cpp:127
lanelet::ConstLanelet::leftBound
ConstLineString3d leftBound() const
lanelet::traffic_rules::getSpeedLimitFromType
SpeedLimitInformation getSpeedLimitFromType(const AttributeMap &attributes, const CountrySpeedLimits &countryLimits, const std::string &participant)
Definition: GenericTrafficRules.cpp:262
lanelet::traffic_rules::LaneChangeType::None
@ None
lanelet::AttributeName::Subtype
@ Subtype
lanelet::geometry::rightOf
bool rightOf(const ConstLanelet &left, const ConstArea &area)
lanelet::ConstLanelet::rightBound
ConstLineString3d rightBound() const
lanelet::traffic_rules::SpeedLimitInformation::isMandatory
bool isMandatory
False if speed limit is only a recommendation.
Definition: TrafficRules.h:10
Exceptions.h
lanelet::traffic_rules::LaneChangeType::ToRight
@ ToRight
lanelet::traffic_rules::GenericTrafficRules::canChangeLane
bool canChangeLane(const ConstLanelet &from, const ConstLanelet &to) const override
determines if a lane change can be made between two lanelets
Definition: GenericTrafficRules.cpp:248
lanelet::traffic_rules::LaneChangeType
LaneChangeType
Definition: GenericTrafficRules.h:10


lanelet2_traffic_rules
Author(s): Fabian Poggenhans
autogenerated on Thu Mar 6 2025 03:26:07