CARLA
Loading...
Searching...
No Matches
RoadParser.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
8
9#include "carla/Logging.h"
10#include "carla/StringUtil.h"
13
15
16namespace carla {
17namespace opendrive {
18namespace parser {
19
20 using RoadId = road::RoadId;
23
24 struct Polynomial {
25 double s;
26 double a, b, c, d;
27 };
28
36
37 struct LaneOffset {
38 double s;
39 double a, b, c, d;
40 };
41
42 struct LaneSection {
43 double s;
44 std::vector<Lane> lanes;
45 };
46
48 double s;
49 std::string type;
50 double max;
51 std::string unit;
52 };
53
54 struct Road {
56 std::string name;
57 double length;
61 bool is_rht;
62 std::vector<RoadTypeSpeed> speed;
63 std::vector<LaneOffset> section_offsets;
64 std::vector<LaneSection> sections;
65 };
66
67 static road::Lane::LaneType StringToLaneType(std::string &&str) {
69 if (str == "driving") {
71 } else if (str == "stop") {
73 } else if (str == "shoulder") {
75 } else if (str == "biking") {
77 } else if (str == "sidewalk") {
79 } else if (str == "border") {
81 } else if (str == "restricted") {
83 } else if (str == "parking") {
85 } else if (str == "bidirectional") {
87 } else if (str == "median") {
89 } else if (str == "special1") {
91 } else if (str == "special2") {
93 } else if (str == "special3") {
95 } else if (str == "roadworks") {
97 } else if (str == "tram") {
99 } else if (str == "rail") {
101 } else if (str == "entry") {
103 } else if (str == "exit") {
105 } else if (str == "offramp") {
107 } else if (str == "onramp") {
109 } else {
111 }
112 }
113
115 const pugi::xml_document &xml,
116 carla::road::MapBuilder &map_builder) {
117
118 std::vector<Road> roads;
119
120 for (pugi::xml_node node_road : xml.child("OpenDRIVE").children("road")) {
121 Road road { 0, "", 0.0, -1, 0, 0, true, {}, {}, {} };
122
123 // attributes
124 road.id = node_road.attribute("id").as_uint();
125 road.name = node_road.attribute("name").value();
126 road.length = node_road.attribute("length").as_double();
127 road.junction_id = node_road.attribute("junction").as_int();
128 std::string rule = node_road.attribute("rule") ? node_road.attribute("rule").value(): "RHT";
129 if (rule == "RHT") {
130 road.is_rht = true;
131 } else if (rule == "LHT") {
132 road.is_rht = false;
133 } else {
134 std::cout << "Detected rule '" << rule << "' for road '" << road.id << "'. Defaulting to RHT." << std::endl;
135 road.is_rht = true;
136 }
137 // link
138 pugi::xml_node link = node_road.child("link");
139 if (link) {
140 if (link.child("predecessor")) {
141 road.predecessor = link.child("predecessor").attribute("elementId").as_uint();
142 }
143 if (link.child("successor")) {
144 road.successor = link.child("successor").attribute("elementId").as_uint();
145 }
146 }
147
148 // types
149 for (pugi::xml_node node_type : node_road.children("type")) {
150 RoadTypeSpeed type { 0.0, "", 0.0, "" };
151
152 type.s = node_type.attribute("s").as_double();
153 type.type = node_type.attribute("type").value();
154
155 // speed type
156 pugi::xml_node speed = node_type.child("speed");
157 if (speed) {
158 type.max = speed.attribute("max").as_double();
159 type.unit = speed.attribute("unit").value();
160 }
161
162 // add it
163 road.speed.emplace_back(type);
164 }
165
166 // section offsets
167 for (pugi::xml_node node_offset : node_road.child("lanes").children("laneOffset")) {
168 LaneOffset offset { 0.0, 0.0, 0.0, 0.0, 0.0 };
169 offset.s = node_offset.attribute("s").as_double();
170 offset.a = node_offset.attribute("a").as_double();
171 offset.b = node_offset.attribute("b").as_double();
172 offset.c = node_offset.attribute("c").as_double();
173 offset.d = node_offset.attribute("d").as_double();
174 road.section_offsets.emplace_back(offset);
175 }
176 // Add default lane offset if none is found
177 if(road.section_offsets.size() == 0) {
178 LaneOffset offset { 0.0, 0.0, 0.0, 0.0, 0.0 };
179 road.section_offsets.emplace_back(offset);
180 }
181
182 // lane sections
183 for (pugi::xml_node node_section : node_road.child("lanes").children("laneSection")) {
184 LaneSection section { 0.0, {} };
185
186 section.s = node_section.attribute("s").as_double();
187
188 // left lanes
189 for (pugi::xml_node node_lane : node_section.child("left").children("lane")) {
190 Lane lane { 0, road::Lane::LaneType::None, false, 0, 0 };
191
192 lane.id = node_lane.attribute("id").as_int();
193 lane.type = StringToLaneType(node_lane.attribute("type").value());
194 lane.level = node_lane.attribute("level").as_bool();
195
196 // link
197 pugi::xml_node link2 = node_lane.child("link");
198 if (link2) {
199 if (link2.child("predecessor")) {
200 lane.predecessor = link2.child("predecessor").attribute("id").as_int();
201 }
202 if (link2.child("successor")) {
203 lane.successor = link2.child("successor").attribute("id").as_int();
204 }
205 }
206
207 // add it
208 section.lanes.emplace_back(lane);
209 }
210
211 // center lane
212 for (pugi::xml_node node_lane : node_section.child("center").children("lane")) {
213 Lane lane { 0, road::Lane::LaneType::None, false, 0, 0 };
214
215 lane.id = node_lane.attribute("id").as_int();
216 lane.type = StringToLaneType(node_lane.attribute("type").value());
217 lane.level = node_lane.attribute("level").as_bool();
218
219 // link (probably it never exists)
220 pugi::xml_node link2 = node_lane.child("link");
221 if (link2) {
222 if (link2.child("predecessor")) {
223 lane.predecessor = link2.child("predecessor").attribute("id").as_int();
224 }
225 if (link2.child("successor")) {
226 lane.successor = link2.child("successor").attribute("id").as_int();
227 }
228 }
229
230 // add it
231 section.lanes.emplace_back(lane);
232 }
233
234 // right lane
235 for (pugi::xml_node node_lane : node_section.child("right").children("lane")) {
236 Lane lane { 0, road::Lane::LaneType::None, false, 0, 0 };
237
238 lane.id = node_lane.attribute("id").as_int();
239 lane.type = StringToLaneType(node_lane.attribute("type").value());
240 lane.level = node_lane.attribute("level").as_bool();
241
242 // link
243 pugi::xml_node link2 = node_lane.child("link");
244 if (link2) {
245 if (link2.child("predecessor")) {
246 lane.predecessor = link2.child("predecessor").attribute("id").as_int();
247 }
248 if (link2.child("successor")) {
249 lane.successor = link2.child("successor").attribute("id").as_int();
250 }
251 }
252
253 // add it
254 section.lanes.emplace_back(lane);
255 }
256
257 // add section
258 road.sections.emplace_back(section);
259 }
260
261 // add road
262 roads.emplace_back(road);
263 }
264
265 // test print
266 /*
267 printf("Roads: %d\n", roads.size());
268 for (const auto& r : roads) {
269 printf("Road: %d\n", r.id);
270 printf(" Name: %s\n", r.name.c_str());
271 printf(" Length: %e\n", r.length);
272 printf(" JunctionId: %d\n", r.junction_id);
273 printf(" Predecessor: %d\n", r.predecessor);
274 printf(" Successor: %d\n", r.successor);
275 printf(" Speed: %d\n", r.speed.size());
276 for (const auto& s : r.speed) {
277 printf(" S offset: %e\n", s.s);
278 printf(" Type: %s\n", s.type.c_str());
279 printf(" Max: %e\n", s.max);
280 printf(" Unit: %s\n", s.unit.c_str());
281 }
282 printf("LaneSections: %d\n", r.sections.size());
283 for (const auto& s : r.sections) {
284 printf(" S offset: %e\n", s.s);
285 printf(" a,b,c,d: %e,%e,%e,%e\n", s.a, s.b, s.c, s.d);
286 printf(" Lanes: %d\n", s.lanes.size());
287 for (const auto& l : s.lanes) {
288 printf(" Id: %d\n", l.id);
289 printf(" Type: %s\n", l.type.c_str());
290 printf(" Level: %d\n", l.level);
291 printf(" Predecessor: %d\n", l.predecessor);
292 printf(" Successor: %d\n", l.successor);
293 }
294 }
295 }
296 */
297
298 // map_builder calls
299 for (const auto& r : roads) {
300 carla::road::Road *road = map_builder.AddRoad(r.id,
301 r.name,
302 r.length,
303 r.junction_id,
304 r.predecessor,
305 r.successor,
306 r.is_rht);
307
308 // type speed
309 for (const auto& s : r.speed) {
310 map_builder.CreateRoadSpeed(road, s.s, s.type, s.max, s.unit);
311 }
312
313 // section offsets
314 for (const auto& s : r.section_offsets) {
315 map_builder.CreateSectionOffset(road, s.s, s.a, s.b, s.c, s.d);
316 }
317
318 // lane sections
319 road::SectionId i = 0;
320 for (const auto& s : r.sections) {
321 carla::road::LaneSection *section = map_builder.AddRoadSection(road, i++, s.s);
322
323 // lanes
324 for (const auto& l : s.lanes) {
325 /*carla::road::Lane *lane = */ map_builder.AddRoadSectionLane(section, l.id,
326 static_cast<uint32_t>(l.type), l.level, l.predecessor, l.successor);
327 }
328 }
329 }
330 }
331
332} // namespace parser
333} // namespace opendrive
334} // namespace carla
std::map< std::string, unsigned int > road
static void ToLower(WritableRangeT &str)
Definition StringUtil.h:36
static void Parse(const pugi::xml_document &xml, carla::road::MapBuilder &map_builder)
LaneType
Can be used as flags.
Definition road/Lane.h:29
carla::road::Lane * AddRoadSectionLane(carla::road::LaneSection *section, const LaneId lane_id, const uint32_t lane_type, const bool lane_level, const LaneId predecessor, const LaneId successor)
void CreateRoadSpeed(Road *road, const double s, const std::string type, const double max, const std::string unit)
void CreateSectionOffset(Road *road, const double s, const double a, const double b, const double c, const double d)
carla::road::LaneSection * AddRoadSection(carla::road::Road *road, const SectionId id, const double s)
carla::road::Road * AddRoad(const RoadId road_id, const std::string name, const double length, const JuncId junction_id, const RoadId predecessor, const RoadId successor, const bool is_rht)
int as_int(int def=0) const
Definition pugixml.cpp:5168
double as_double(double def=0) const
Definition pugixml.cpp:5178
unsigned int as_uint(unsigned int def=0) const
Definition pugixml.cpp:5173
const char_t * value() const
Definition pugixml.cpp:5215
xml_node child(const char_t *name) const
Definition pugixml.cpp:5490
xml_object_range< xml_node_iterator > children() const
Definition pugixml.cpp:5425
xml_attribute attribute(const char_t *name) const
Definition pugixml.cpp:5500
static road::Lane::LaneType StringToLaneType(std::string &&str)
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.
road::Lane::LaneType type
std::vector< LaneOffset > section_offsets
std::vector< RoadTypeSpeed > speed
std::vector< LaneSection > sections