CARLA
Loading...
Searching...
No Matches
road/Road.cpp
Go to the documentation of this file.
1// Copyright (c) 2026 Computer Vision Center (CVC) at the Universitat Autonoma
2// de Barcelona (UAB).
3//
4// This work is licensed under the terms of the MIT license.
5// For a copy, see <https://opensource.org/licenses/MIT>.
6
7#include "carla/Exception.h"
10#include "carla/geom/Math.h"
11#include "carla/ListView.h"
12#include "carla/Logging.h"
18#include "carla/road/Lane.h"
19#include "carla/road/MapData.h"
20#include "carla/road/Road.h"
21
22#include <algorithm>
23#include <stdexcept>
24
25namespace carla {
26namespace road {
27
28 const MapData *Road::GetMap() const {
29 return _map_data;
30 }
31
33 return _id;
34 }
35
36 std::string Road::GetName() const {
37 return _name;
38 }
39
40 double Road::GetLength() const {
41 return _length;
42 }
43
44 bool Road::IsJunction() const {
45 return _is_junction;
46 }
47
49 return _junction_id;
50 }
51
52 bool Road::IsRHT() const {
53 return _is_rht;
54 }
55
57 return _successor;
58 }
59
61 return _predecessor;
62 }
63
64 std::vector<Road *> Road::GetNexts() const {
65 return _nexts;
66 }
67
68 std::vector<Road *> Road::GetPrevs() const {
69 return _prevs;
70 }
71
72 const geom::CubicPolynomial &Road::GetElevationOn(const double s) const {
73 auto info = GetInfo<element::RoadInfoElevation>(s);
74 if (info == nullptr) {
75 throw_exception(std::runtime_error("failed to find road elevation."));
76 }
77 return info->GetPolynomial();
78 }
79
80 Lane &Road::GetLaneByDistance(double s, LaneId lane_id) {
81 for (auto &section : GetLaneSectionsAt(s)) {
82 auto *lane = section.GetLane(lane_id);
83 if (lane != nullptr) {
84 return *lane;
85 }
86 }
87 throw_exception(std::runtime_error("lane not found"));
88 }
89
90 const Lane &Road::GetLaneByDistance(double s, LaneId lane_id) const {
91 return const_cast<Road *>(this)->GetLaneByDistance(s, lane_id);
92 }
93
94 std::vector<Lane*> Road::GetLanesByDistance(double s) {
95 std::vector<Lane*> result;
96 auto lane_sections = GetLaneSectionsAt(s);
97 for (auto &lane_section : lane_sections) {
98 for (auto & lane_pair : lane_section.GetLanes()) {
99 result.emplace_back(&lane_pair.second);
100 }
101 }
102 return result;
103 }
104
105 std::vector<const Lane*> Road::GetLanesByDistance(double s) const {
106 std::vector<const Lane*> result;
107 const auto lane_sections = GetLaneSectionsAt(s);
108 for (const auto &lane_section : lane_sections) {
109 for (const auto & lane_pair : lane_section.GetLanes()) {
110 result.emplace_back(&lane_pair.second);
111 }
112 }
113 return result;
114 }
115
116 Lane &Road::GetLaneById(SectionId section_id, LaneId lane_id) {
117 return GetLaneSectionById(section_id).GetLanes().at(lane_id);
118 }
119
120 const Lane &Road::GetLaneById(SectionId section_id, LaneId lane_id) const {
121 return const_cast<Road *>(this)->GetLaneById(section_id, lane_id);
122 }
123
124 // get the lane on a section next to 's'
125 Lane *Road::GetNextLane(const double s, const LaneId lane_id) {
126
127 auto upper = _lane_sections.upper_bound(s);
128
129 while (upper != _lane_sections.end()) {
130 // check id
131 Lane *ptr = upper->second.GetLane(lane_id);
132 if (ptr != nullptr) {
133 return ptr;
134 }
135 ++upper;
136 }
137
138 return nullptr;
139 }
140
141 // get the lane on a section previous to 's'
142 Lane *Road::GetPrevLane(const double s, const LaneId lane_id) {
143
144 auto lower = _lane_sections.lower_bound(s);
145 auto rlower = std::make_reverse_iterator(lower);
146
147 while (rlower != _lane_sections.rend()) {
148 // check id
149 Lane *ptr = rlower->second.GetLane(lane_id);
150 if (ptr != nullptr) {
151 return ptr;
152 }
153 ++rlower;
154 }
155
156 return nullptr;
157 }
158
159 // get the start and end section with a lan id
161 auto it = _lane_sections.begin();
162 while (it != _lane_sections.end()) {
163 // check id
164 Lane *ptr = it->second.GetLane(id);
165 if (ptr != nullptr) {
166 return &(it->second);
167 }
168 ++it;
169 }
170 return nullptr;
171 }
172
174 auto it = _lane_sections.rbegin();
175 while (it != _lane_sections.rend()) {
176 // check id
177 Lane *ptr = it->second.GetLane(id);
178 if (ptr != nullptr) {
179 return &(it->second);
180 }
181 ++it;
182 }
183 return nullptr;
184 }
185
186
187 double Road::GetLateralShapeZ(const double s, const double t) const {
188 const auto shapes = _info.GetInfos<element::RoadInfoLateralShape>();
189 if (shapes.empty()) {
190 return 0.0;
191 }
192 const double clamped_s = geom::Math::Clamp(s, 0.0, _length);
193
194 // Evaluate one station (all records sharing the same s): pick the record
195 // with the greatest t <= query t, clamping below the first record.
196 auto EvalStation = [t](const std::vector<const element::RoadInfoLateralShape *> &station) {
197 const element::RoadInfoLateralShape *chosen = station.front();
198 for (const auto *record : station) {
199 if (record->GetT() <= t) {
200 chosen = record;
201 } else {
202 break;
203 }
204 }
205 return chosen->Evaluate(t);
206 };
207
208 // Records come ordered by s; group them into stations and keep the two
209 // stations bracketing clamped_s.
210 std::vector<const element::RoadInfoLateralShape *> before, after;
211 double s_before = -1.0, s_after = -1.0;
212 std::vector<const element::RoadInfoLateralShape *> current;
213 double s_current = -1.0;
214 auto CloseStation = [&]() {
215 if (current.empty()) {
216 return;
217 }
218 std::sort(current.begin(), current.end(),
219 [](const auto *a, const auto *b) { return a->GetT() < b->GetT(); });
220 if (s_current <= clamped_s) {
221 before = current; s_before = s_current;
222 } else if (after.empty()) {
223 after = current; s_after = s_current;
224 }
225 current.clear();
226 };
227 for (const auto *record : shapes) {
228 if (record->GetDistance() != s_current) {
229 CloseStation();
230 s_current = record->GetDistance();
231 }
232 current.push_back(record);
233 }
234 CloseStation();
235
236 if (before.empty()) {
237 return after.empty() ? 0.0 : EvalStation(after);
238 }
239 if (after.empty() || s_after <= s_before) {
240 return EvalStation(before);
241 }
242 const double u = (clamped_s - s_before) / (s_after - s_before);
243 return (1.0 - u) * EvalStation(before) + u * EvalStation(after);
244 }
245
247 const auto clamped_s = geom::Math::Clamp(s, 0.0, _length);
248 const auto geometry = _info.GetInfo<element::RoadInfoGeometry>(clamped_s);
249
250 const auto lane_offset = _info.GetInfo<element::RoadInfoLaneOffset>(clamped_s);
251 float offset = 0;
252 if(lane_offset){
253 offset = static_cast<float>(lane_offset->GetPolynomial().Evaluate(clamped_s));
254 }
255 // Apply road's lane offset record
256 element::DirectedPoint p = geometry->GetGeometry().PosFromDist(clamped_s - geometry->GetDistance());
257 // Unreal's Y axis hack (the minus on the offset)
258 p.ApplyLateralOffset(-offset);
259
260 // Apply road's elevation record
261 const auto elevation_info = GetElevationOn(s);
262 p.location.z = static_cast<float>(elevation_info.Evaluate(s));
263 p.pitch = elevation_info.Tangent(s);
264
265 return p;
266 }
267
269 const auto clamped_s = geom::Math::Clamp(s, 0.0, _length);
270 const auto geometry = _info.GetInfo<element::RoadInfoGeometry>(clamped_s);
271
272 element::DirectedPoint p = geometry->GetGeometry().PosFromDist(clamped_s - geometry->GetDistance());
273
274 // Apply road's elevation record
275 const auto elevation_info = GetElevationOn(s);
276 p.location.z = static_cast<float>(elevation_info.Evaluate(s));
277 p.pitch = elevation_info.Tangent(s);
278
279 return p;
280 }
281
282 const std::pair<double, double> Road::GetNearestPoint(const geom::Location &loc) const {
283 std::pair<double, double> last = { 0.0, std::numeric_limits<double>::max() };
284
285 auto geom_info_list = _info.GetInfos<element::RoadInfoGeometry>();
286 decltype(geom_info_list)::iterator nearest_geom = geom_info_list.end();
287
288 for (auto g = geom_info_list.begin(); g != geom_info_list.end(); ++g) {
289 DEBUG_ASSERT(*g != nullptr);
290 auto dist = (*g)->GetGeometry().DistanceTo(loc);
291 if (dist.second < last.second) {
292 last = dist;
293 nearest_geom = g;
294 }
295 }
296
297 for (auto g = geom_info_list.begin();
298 g != geom_info_list.end() && g != nearest_geom;
299 ++g) {
300 DEBUG_ASSERT(*g != nullptr);
301 last.first += (*g)->GetGeometry().GetLength();
302 }
303
304 return last;
305 }
306
307 const std::pair<const Lane *, double> Road::GetNearestLane(
308 const double s,
309 const geom::Location &loc,
310 uint32_t lane_type) const {
311 using namespace carla::road::element;
312 std::map<LaneId, const Lane *> lanes(GetLanesAt(s));
313 // negative right lanes
314 auto right_lanes = MakeListView(
315 std::make_reverse_iterator(lanes.lower_bound(0)), lanes.rend());
316 // positive left lanes
317 auto left_lanes = MakeListView(
318 lanes.lower_bound(1), lanes.end());
319
320 const DirectedPoint dp_lane_zero = GetDirectedPointIn(s);
321 std::pair<const Lane *, double> result =
322 std::make_pair(nullptr, std::numeric_limits<double>::max());
323
324 DirectedPoint current_dp = dp_lane_zero;
325 for (const auto &lane : right_lanes) {
326 const auto lane_width_info = lane.second->GetInfo<RoadInfoLaneWidth>(s);
327 const auto half_width = static_cast<float>(lane_width_info->GetPolynomial().Evaluate(s)) * 0.5f;
328
329 current_dp.ApplyLateralOffset(half_width);
330 const auto current_dist = geom::Math::Distance(current_dp.location, loc);
331
332 // if the current_dp is near to loc, we are in the right way
333 if (current_dist <= result.second) {
334 // only consider the lanes that match the type flag for result
335 // candidates
336 if ((static_cast<uint32_t>(lane.second->GetType()) & lane_type) > 0) {
337 result.first = &(*lane.second);
338 result.second = current_dist;
339 }
340 } else {
341 // elsewhere, we are be moving away
342 break;
343 }
344 current_dp.ApplyLateralOffset(half_width);
345 }
346
347 current_dp = dp_lane_zero;
348 for (const auto &lane : left_lanes) {
349 const auto lane_width_info = lane.second->GetInfo<RoadInfoLaneWidth>(s);
350 const auto half_width = -static_cast<float>(lane_width_info->GetPolynomial().Evaluate(s)) * 0.5f;
351
352 current_dp.ApplyLateralOffset(half_width);
353 const auto current_dist = geom::Math::Distance(current_dp.location, loc);
354
355 // if the current_dp is near to loc, we are in the right way
356 if (current_dist <= result.second) {
357 // only consider the lanes that match the type flag for result
358 // candidates
359 if ((static_cast<uint32_t>(lane.second->GetType()) & lane_type) > 0) {
360 result.first = &(*lane.second);
361 result.second = current_dist;
362 }
363 } else {
364 // elsewhere, we are be moving away
365 break;
366 }
367 current_dp.ApplyLateralOffset(half_width);
368 }
369
370 return result;
371 }
372
373 std::map<LaneId, const Lane *> Road::GetLanesAt(const double s) const {
374 std::map<LaneId, const Lane *> map;
375 for (auto &&lane_section : GetLaneSectionsAt(s)) {
376 for (auto &&lane : lane_section.GetLanes()) {
377 map[lane.first] = &(lane.second);
378 }
379 }
380 return map;
381 }
382
383} // road
384} // carla
#define DEBUG_ASSERT(predicate)
Definition Debug.h:66
long long last
Definition LaneGraph.cpp:35
std::map< std::string, unsigned int > road
Describes a Cubic Polynomial so: f(x) = a + bx + cx^2 + dx^3.
static auto Distance(const Vector3D &a, const Vector3D &b)
Definition Math.h:78
static constexpr T Clamp(T a, T min=T(0), T max=T(1))
Definition Math.h:49
const T * GetInfo(const double s) const
Returns single info given a type and a distance (s) from the start of the road.
std::vector< const T * > GetInfos() const
Return all infos given a type from the start of the road.
std::map< LaneId, Lane > & GetLanes()
MapData * _map_data
Definition road/Road.h:194
RoadId GetPredecessor() const
Definition road/Road.cpp:60
double GetLength() const
Definition road/Road.cpp:40
const std::pair< double, double > GetNearestPoint(const geom::Location &loc) const
Returns a pair containing:
std::vector< Road * > GetPrevs() const
Definition road/Road.cpp:68
Lane * GetPrevLane(const double s, const LaneId lane_id)
std::vector< Road * > _nexts
Definition road/Road.h:216
Lane & GetLaneById(SectionId section_id, LaneId lane_id)
InformationSet _info
Definition road/Road.h:214
LaneSectionMap _lane_sections
Definition road/Road.h:208
RoadId GetSuccessor() const
Definition road/Road.cpp:56
double GetLateralShapeZ(const double s, const double t) const
Surface height offset from the <lateralProfile><shape> records at (s, t).
RoadId GetId() const
Definition road/Road.cpp:32
std::map< LaneId, const Lane * > GetLanesAt(const double s) const
Get all lanes at a given s.
std::vector< Road * > GetNexts() const
Definition road/Road.cpp:64
LaneSection * GetStartSection(LaneId id)
Get the start section (from road coordinates s) given a lane id.
Lane * GetNextLane(const double s, const LaneId lane_id)
const geom::CubicPolynomial & GetElevationOn(const double s) const
Definition road/Road.cpp:72
Lane & GetLaneByDistance(double s, LaneId lane_id)
Definition road/Road.cpp:80
std::vector< Road * > _prevs
Definition road/Road.h:218
auto GetLaneSectionsAt(const double s)
Definition road/Road.h:158
const std::pair< const Lane *, double > GetNearestLane(const double s, const geom::Location &loc, uint32_t type=static_cast< uint32_t >(Lane::LaneType::Any)) const
Returns a pointer to the nearest lane, given s relative to Road and a location.
bool IsRHT() const
Definition road/Road.cpp:52
element::DirectedPoint GetDirectedPointIn(const double s) const
Returns a directed point on the center of the road (lane 0), with the corresponding laneOffset and el...
std::vector< Lane * > GetLanesByDistance(double s)
Get all lanes from all lane sections in a specific s.
Definition road/Road.cpp:94
element::DirectedPoint GetDirectedPointInNoLaneOffset(const double s) const
Returns a directed point on the center of the road (lane 0), with the corresponding laneOffset and el...
JuncId GetJunctionId() const
Definition road/Road.cpp:48
LaneSection * GetEndSection(LaneId id)
Get the end section (from road coordinates s) given a lane id.
std::string GetName() const
Definition road/Road.cpp:36
std::string _name
Definition road/Road.h:198
const MapData * GetMap() const
Definition road/Road.cpp:28
bool IsJunction() const
Definition road/Road.cpp:44
LaneSection & GetLaneSectionById(SectionId id)
Definition road/Road.h:172
The lane offset record defines a lateral shift of the lane reference line(which is usually identical ...
Lane Width RecordEach lane within a road’scross section can be provided with severalwidth entries.
One <lateralProfile><shape> record: at station s, the road surface height relative to the elevation p...
double Evaluate(const double t) const
Evaluate the surface height offset at lateral position t (the polynomial is defined over t - t_record...
int32_t JuncId
Definition RoadTypes.h:17
uint32_t RoadId
Definition RoadTypes.h:15
int32_t LaneId
Definition RoadTypes.h:19
uint32_t SectionId
Definition RoadTypes.h:21
This file contains definitions of common data structures used in traffic manager.
void throw_exception(const ExceptionT &e)
Templated on the static type so the thrown object keeps its dynamic type: taking a const std::excepti...
Definition Exception.h:44