CARLA
 
载入中...
搜索中...
未找到
test_opendrive.cpp
浏览该文件的文档.
1// Copyright (c) 2017 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 "test.h"
8#include "OpenDrive.h"
9#include "Random.h"
10
11#include <carla/StopWatch.h>
12#include <carla/ThreadPool.h>
13#include <carla/geom/Location.h>
14#include <carla/geom/Math.h>
21
22#include <pugixml/pugixml.hpp>
23
24#include <fstream>
25#include <string>
26
27using namespace carla::road;
28using namespace carla::road::element;
29using namespace carla::geom;
30using namespace carla::opendrive;
31using namespace util;
32
33const std::string BASE_PATH = LIBCARLA_TEST_CONTENT_FOLDER "/OpenDrive/";
34
35// Road Elevation
36static void test_road_elevation(const pugi::xml_document &xml, boost::optional<Map>& map) {
37 pugi::xml_node open_drive_node = xml.child("OpenDRIVE");
38
39 for (pugi::xml_node road_node : open_drive_node.children("road")) {
40 RoadId road_id = road_node.attribute("id").as_uint();
41 auto elevation_profile_nodes = road_node.children("elevationProfile");
42
43 for (pugi::xml_node elevation_profile_node : elevation_profile_nodes) {
44 auto total_elevations = 0;
45 auto elevation_nodes = elevation_profile_node.children("elevation");
46 auto total_elevation_parser = std::distance(elevation_nodes.begin(), elevation_nodes.end());
47
48 for (pugi::xml_node elevation_node : elevation_nodes) {
49 float s = elevation_node.attribute("s").as_float();
50 const auto elevation = map->GetMap().GetRoad(road_id).GetInfo<RoadInfoElevation>(s);
51 if (elevation != nullptr)
52 ++total_elevations;
53 }
54 ASSERT_EQ(total_elevations, total_elevation_parser);
55 }
56 }
57}
58
59// Geometry
60static void test_geometry(const pugi::xml_document &xml, boost::optional<Map>& map) {
61 pugi::xml_node open_drive_node = xml.child("OpenDRIVE");
62
63 for (pugi::xml_node road_node : open_drive_node.children("road")) {
64 RoadId road_id = road_node.attribute("id").as_uint();
65
66 for (pugi::xml_node plan_view_nodes : road_node.children("planView")) {
67 auto geometries_parser = plan_view_nodes.children("geometry");
68 auto total_geometries_parser = std::distance(geometries_parser.begin(), geometries_parser.end());
69 auto total_geometries = 0;
70 for (pugi::xml_node geometry_node : plan_view_nodes.children("geometry")){
71 float s = geometry_node.attribute("s").as_float();
72 auto geometry = map->GetMap().GetRoad(road_id).GetInfo<RoadInfoGeometry>(s);
73 if (geometry != nullptr)
74 ++total_geometries;
75 }
76 ASSERT_EQ(total_geometries, total_geometries_parser);
77 }
78 }
79}
80
81// Road test
84 LaneSection& lane_section) {
85 constexpr auto error = 1e-5;
86 auto total_road_mark = 0;
87 auto total_road_mark_parser = 0;
88 for (pugi::xml_node lane_node : lane_nodes) {
89 // Check Road Mark
90 auto road_mark_nodes = lane_node.children("roadMark");
91 total_road_mark_parser += std::distance(road_mark_nodes.begin(), road_mark_nodes.end());
92
93 const int lane_id = lane_node.attribute("id").as_int();
94 Lane* lane = nullptr;
95 lane = lane_section.GetLane(lane_id);
96 EXPECT_NE(lane, nullptr);
97
98 // <roadMark sOffset="0.0000000000000000e+0" type="none" material="standard" color="white" laneChange="none"/>
99 for (pugi::xml_node road_mark_node : road_mark_nodes) {
100 const auto s_offset = road_mark_node.attribute("sOffset").as_double();
101 const auto type = road_mark_node.attribute("type").as_string();
102 const auto material = road_mark_node.attribute("material").as_string();
103 const auto color = road_mark_node.attribute("color").as_string();
104 const auto road_mark = lane->GetInfo<RoadInfoMarkRecord>(lane->GetDistance() + s_offset);
105 if (road_mark != nullptr) {
106 EXPECT_NEAR(lane->GetDistance() + s_offset, road_mark->GetDistance(), error);
107 EXPECT_EQ(type, road_mark->GetType());
108 EXPECT_EQ(material, road_mark->GetMaterial());
109 EXPECT_EQ(color, road_mark->GetColor());
110 ++total_road_mark;
111 }
112 }
113 }
114 return std::make_pair(total_road_mark, total_road_mark_parser);
115}
116
117static void test_roads(const pugi::xml_document &xml, boost::optional<Map>& map) {
118 pugi::xml_node open_drive_node = xml.child("OpenDRIVE");
119
120 // Check total Roads
121 auto roads_parser = open_drive_node.children("road");
122 auto total_roads_parser = std::distance(roads_parser.begin(), roads_parser.end());
123 auto total_roads = map->GetMap().GetRoads().size();
124 ASSERT_EQ(total_roads, total_roads_parser);
125
126 for (pugi::xml_node road_node : roads_parser) {
127 RoadId road_id = road_node.attribute("id").as_uint();
128
129 for (pugi::xml_node lanes_node : road_node.children("lanes")) {
130
131 // Check total Lane Sections
132 auto lane_sections_parser = lanes_node.children("laneSection");
133 auto total_lane_sections_parser = std::distance(lane_sections_parser.begin(), lane_sections_parser.end());
134 auto total_lane_sections = map->GetMap().GetRoad(road_id).GetLaneSections().size();
135 ASSERT_EQ(total_lane_sections, total_lane_sections_parser);
136
137 for (pugi::xml_node lane_section_node : lane_sections_parser) {
138
139 // Check total Lanes
140 const double s = lane_section_node.attribute("s").as_double();
141 auto lane_section = map->GetMap().GetRoad(road_id).GetLaneSectionsAt(s);
142 size_t total_lanes = 0u;
143 for (auto it = lane_section.begin(); it != lane_section.end(); ++it) {
144 total_lanes = it->GetLanes().size();
145 }
146 auto left_nodes = lane_section_node.child("left").children("lane");
147 auto center_nodes = lane_section_node.child("center").children("lane");
148 auto right_nodes = lane_section_node.child("right").children("lane");
149 auto total_lanes_parser = std::distance(left_nodes.begin(), left_nodes.end());
150 total_lanes_parser += std::distance(right_nodes.begin(), right_nodes.end());
151 total_lanes_parser += std::distance(center_nodes.begin(), center_nodes.end());
152
153 ASSERT_EQ(total_lanes, total_lanes_parser);
154
155
156 auto total_road_mark = 0;
157 auto total_road_mark_parser = 0;
158 for (auto it = lane_section.begin(); it != lane_section.end(); ++it) {
159 auto total_left = get_total_road_marks(left_nodes, *it);
160 auto total_center = get_total_road_marks(center_nodes, *it);
161 auto total_right = get_total_road_marks(right_nodes, *it);
162 total_road_mark = total_left.first + total_center.first + total_right.first;
163 total_road_mark_parser = total_left.first + total_center.first + total_right.first;
164 }
165 ASSERT_EQ(total_road_mark, total_road_mark_parser);
166 }
167 }
168 }
169}
170
171// Junctions
172static void test_junctions(const pugi::xml_document &xml, boost::optional<Map>& map) {
173 pugi::xml_node open_drive_node = xml.child("OpenDRIVE");
174
175 // Check total number of junctions
176 auto& junctions = map->GetMap().GetJunctions();
177 auto total_junctions_parser = std::distance(open_drive_node.children("junction").begin(), open_drive_node.children("junction").end());
178
179 ASSERT_EQ(junctions.size(), total_junctions_parser);
180
181 for (pugi::xml_node junction_node : open_drive_node.children("junction")) {
182 // Check total number of connections
183 auto total_connections_parser = std::distance(junction_node.children("connection").begin(), junction_node.children("connection").end());
184
185 JuncId junction_id = junction_node.attribute("id").as_int();
186 auto& junction = junctions.find(junction_id)->second;
187
188 auto& connections = junction.GetConnections();
189
190 ASSERT_EQ(connections.size(), total_connections_parser);
191
192 for (pugi::xml_node connection_node : junction_node.children("connection")) {
193 auto total_lane_links_parser = std::distance(connection_node.children("laneLink").begin(), connection_node.children("laneLink").end());
194
195 ConId connection_id = connection_node.attribute("id").as_uint();
196 auto& connection = connections.find(connection_id)->second;
197
198 auto& lane_links = connection.lane_links;
199
200 ASSERT_EQ(lane_links.size(), total_lane_links_parser);
201
202 }
203 }
204}
205
206static void test_road_links(boost::optional<Map>& map) {
207
208 // process all roads, sections and lanes
209 for (auto &road : map->GetMap().GetRoads()) {
210 for (auto &section : road.second.GetLaneSections()) {
211 for (auto &lane : section.GetLanes()) {
212 // check all nexts
213 for (auto link : lane.second.GetNextLanes()) {
214 ASSERT_TRUE(link != nullptr);
215 }
216 // check all prevs
217 for (auto link : lane.second.GetPreviousLanes()) {
218 ASSERT_TRUE(link != nullptr);
219 }
220 }
221 }
222 }
223}
224
225TEST(road, parse_files) {
226 for (const auto &file : util::OpenDrive::GetAvailableFiles()) {
227 // std::cerr << file << std::endl;
229 ASSERT_TRUE(map);
230 // print_roads(map, file);
231 }
232}
233
234TEST(road, parse_road_links) {
235 for (const auto &file : util::OpenDrive::GetAvailableFiles()) {
236 // std::cerr << file << std::endl;
238 ASSERT_TRUE(map);
239 test_road_links(map);
240 }
241}
242
243TEST(road, parse_junctions) {
244 for (const auto& file : util::OpenDrive::GetAvailableFiles()) {
246 ASSERT_TRUE(map.has_value());
247
248 const std::string full_path = BASE_PATH + file;
250
251 pugi::xml_parse_result result = xml.load_file( full_path.c_str());
252 ASSERT_TRUE(result);
253
254 test_junctions(xml, map);
255 }
256
257}
258
259TEST(road, parse_road) {
260 for (const auto& file : util::OpenDrive::GetAvailableFiles()) {
262 ASSERT_TRUE(map.has_value());
263
264 const std::string full_path = BASE_PATH + file;
266 pugi::xml_parse_result result = xml.load_file( full_path.c_str());
267 ASSERT_TRUE(result);
268
269 test_roads(xml, map);
270 }
271
272}
273
274TEST(road, parse_road_elevation) {
275 for (const auto& file : util::OpenDrive::GetAvailableFiles()) {
277 ASSERT_TRUE(map.has_value());
278
279 const std::string full_path = BASE_PATH + file;
281 pugi::xml_parse_result result = xml.load_file( full_path.c_str());
282 ASSERT_TRUE(result);
283
284 test_road_elevation(xml, map);
285 }
286
287}
288
289TEST(road, parse_geometry) {
290 for (const auto& file : util::OpenDrive::GetAvailableFiles()) {
292 ASSERT_TRUE(map.has_value());
293
294 const std::string full_path = BASE_PATH + file;
296 pugi::xml_parse_result result = xml.load_file( full_path.c_str());
297 ASSERT_TRUE(result);
298
299 test_geometry(xml, map);
300 }
301
302}
303
304TEST(road, iterate_waypoints) {
306 pool.AsyncRun();
307 std::vector<std::future<void>> results;
308 for (const auto& file : util::OpenDrive::GetAvailableFiles()) {
309 carla::logging::log("Parsing", file);
310 results.push_back(pool.Post([file]() {
311 carla::StopWatch stop_watch;
312 auto m = OpenDriveParser::Load(util::OpenDrive::Load(file));
313 ASSERT_TRUE(m.has_value());
314 auto &map = *m;
315 const auto topology = map.GenerateTopology();
316 ASSERT_FALSE(topology.empty());
317 auto count = 0u;
318 auto waypoints = map.GenerateWaypoints(0.5);
319 ASSERT_FALSE(waypoints.empty());
320 Random::Shuffle(waypoints);
321 const auto number_of_waypoints_to_explore =
322 std::min<size_t>(2000u, waypoints.size());
323 for (auto i = 0u; i < number_of_waypoints_to_explore; ++i) {
324 auto wp = waypoints[i];
325 map.ComputeTransform(wp);
326 if (i != 0u) {
327 ASSERT_NE(wp, waypoints[0u]);
328 }
329 for (auto &&successor : map.GetSuccessors(wp)) {
330 ASSERT_TRUE(
331 successor.road_id != wp.road_id ||
332 successor.section_id != wp.section_id ||
333 successor.lane_id != wp.lane_id ||
334 successor.s != wp.s);
335 }
336 auto origin = wp;
337 for (auto j = 0u; j < 200u; ++j) {
338 auto next_wps = map.GetNext(origin, Random::Uniform(0.0001, 150.0));
339 if (next_wps.empty()) {
340 break;
341 }
342 const auto number_of_next_wps_to_explore =
343 std::min<size_t>(10u, next_wps.size());
344 Random::Shuffle(next_wps);
345 for (auto k = 0u; k < number_of_next_wps_to_explore; ++k) {
346 auto next = next_wps[k];
347 ++count;
348 ASSERT_TRUE(
349 next.road_id != wp.road_id ||
350 next.section_id != wp.section_id ||
351 next.lane_id != wp.lane_id ||
352 next.s != wp.s);
353 auto right = map.GetRight(next);
354 if (right.has_value()) {
355 ASSERT_EQ(right->road_id, next.road_id);
356 ASSERT_EQ(right->section_id, next.section_id);
357 ASSERT_NE(right->lane_id, next.lane_id);
358 ASSERT_EQ(right->s, next.s);
359 }
360 auto left = map.GetLeft(next);
361 if (left.has_value()) {
362 ASSERT_EQ(left->road_id, next.road_id);
363 ASSERT_EQ(left->section_id, next.section_id);
364 ASSERT_NE(left->lane_id, next.lane_id);
365 ASSERT_EQ(left->s, next.s);
366 }
367 }
368 origin = next_wps[0u];
369 }
370 }
371 ASSERT_GT(count, 0u);
372 float seconds = 1e-3f * stop_watch.GetElapsedTime();
373 carla::logging::log(file, "done in", seconds, "seconds.");
374 }));
375 }
376 for (auto &result : results) {
377 result.get();
378 }
379}
380
381TEST(road, get_waypoint) {
383 pool.AsyncRun();
384 std::vector<std::future<void>> results;
385 for (const auto& file : util::OpenDrive::GetAvailableFiles()) {
386 carla::logging::log("Parsing", file);
387 results.push_back(pool.Post([file]() {
388 carla::StopWatch stop_watch;
389 auto m = OpenDriveParser::Load(util::OpenDrive::Load(file));
390 ASSERT_TRUE(m.has_value());
391 auto &map = *m;
392 for (auto i = 0u; i < 10'000u; ++i) {
393 const auto location = Random::Location(-500.0f, 500.0f);
394 auto owp = map.GetClosestWaypointOnRoad(location);
395 ASSERT_TRUE(owp.has_value());
396 auto &wp = *owp;
397 for (auto &next : map.GetNext(wp, 0.5)) {
398 ASSERT_TRUE(
399 next.road_id != wp.road_id ||
400 next.section_id != wp.section_id ||
401 next.lane_id != wp.lane_id ||
402 next.s != wp.s);
403 }
404 auto left = map.GetLeft(wp);
405 if (left.has_value()) {
406 ASSERT_EQ(left->road_id, wp.road_id);
407 ASSERT_EQ(left->section_id, wp.section_id);
408 ASSERT_NE(left->lane_id, wp.lane_id);
409 ASSERT_EQ(left->s, wp.s);
410 }
411 auto right = map.GetRight(wp);
412 if (right.has_value()) {
413 ASSERT_EQ(right->road_id, wp.road_id);
414 ASSERT_EQ(right->section_id, wp.section_id);
415 ASSERT_NE(right->lane_id, wp.lane_id);
416 ASSERT_EQ(right->s, wp.s);
417 }
418 }
419 float seconds = 1e-3f * stop_watch.GetElapsedTime();
420 carla::logging::log(file, "done in", seconds, "seconds.");
421 }));
422 }
423 for (auto &result : results) {
424 result.get();
425 }
426}
A thread pool based on Boost.Asio's io context.
Definition ThreadPool.h:24
void AsyncRun(size_t worker_threads)
Launch threads to run tasks asynchronously.
Definition ThreadPool.h:51
std::future< ResultT > Post(FunctorT &&functor)
Post a task to the pool.
Definition ThreadPool.h:41
static boost::optional< road::Map > Load(const std::string &opendrive)
Lane * GetLane(const LaneId id)
const T * GetInfo(const double s) const
Definition Lane.h:79
double GetDistance() const
Definition Lane.cpp:46
Each lane within a road cross section can be provided with several road markentries.
unsigned int as_uint(unsigned int def=0) const
Definition pugixml.cpp:5173
xml_parse_result load_file(const char *path, unsigned int options=parse_default, xml_encoding encoding=encoding_auto)
Definition pugixml.cpp:7108
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 std::vector< std::string > GetAvailableFiles()
static std::string Load(const std::string &filename)
static void log(Args &&... args)
Definition Logging.h:59
int32_t JuncId
Definition RoadTypes.h:17
uint32_t RoadId
Definition RoadTypes.h:15
uint32_t ConId
Definition RoadTypes.h:27
const std::string BASE_PATH
static void test_roads(const pugi::xml_document &xml, boost::optional< Map > &map)
static void test_road_links(boost::optional< Map > &map)
static void test_junctions(const pugi::xml_document &xml, boost::optional< Map > &map)
static void test_road_elevation(const pugi::xml_document &xml, boost::optional< Map > &map)
TEST(road, parse_files)
static auto get_total_road_marks(pugi::xml_object_range< pugi::xml_named_node_iterator > &lane_nodes, LaneSection &lane_section)
static void test_geometry(const pugi::xml_document &xml, boost::optional< Map > &map)