Carma-platform v4.2.0
CARMA Platform is built on robot operating system (ROS) and utilizes open source software (OSS) that enables Cooperative Driving Automation (CDA) features to allow Automated Driving Systems to interact and cooperate with infrastructure and other vehicles through communication.
carma_wm::query Namespace Reference

Functions

std::vector< lanelet::ConstLanelet > getLaneletsFromPoint (const lanelet::LaneletMapConstPtr &semantic_map, const lanelet::BasicPoint2d &point, const unsigned int n=10)
 carma_wm::query namespace contains implementations for query functions (input and output read or write-able) for stand-alone lanelet map without rest of the CARMAWorldModel features. Currently mainly WMBroadcaster (carma_wm_ctrl) is using this to manipulate its own map without creating instance of carma_wm More...
 
std::vector< lanelet::Lanelet > getLaneletsFromPoint (const lanelet::LaneletMapPtr &semantic_map, const lanelet::BasicPoint2d &point, const unsigned int n=10)
 (non-const version) Gets the underlying lanelet, given the cartesian point on the map More...
 
std::vector< lanelet::ConstLanelet > nonConnectedAdjacentLeft (const lanelet::LaneletMapConstPtr &semantic_map, const lanelet::BasicPoint2d &input_point, const unsigned int n=10)
 Given the cartesian point on the map, tries to get the opposite direction lanelet on the left This function is intended to find "adjacentLeft lanelets" that doesn't share points between lanelets where adjacentLeft of lanelet library fails. More...
 
std::vector< lanelet::Lanelet > nonConnectedAdjacentLeft (const lanelet::LaneletMapPtr &semantic_map, const lanelet::BasicPoint2d &input_point, const unsigned int n=10)
 (non-const version) Given the cartesian point on the map, tries to get the opposite direction lanelet on the left This function is intended to find "adjacentLeft lanelets" that doesn't share points between lanelets where adjacentLeft of lanelet library fails More...
 
lanelet::ConstLaneletOrAreas getAffectedLaneletOrAreas (const lanelet::Points3d &gf_pts, const lanelet::LaneletMapPtr &lanelet_map, std::shared_ptr< const lanelet::routing::RoutingGraph > routing_graph, double max_lane_width)
 Gets the affected lanelet or areas based on the points in the given map's frame. More...
 
std::unordered_set< lanelet::Lanelet > filterSuccessorLanelets (const std::unordered_set< lanelet::Lanelet > &possible_lanelets, const std::unordered_set< lanelet::Lanelet > &root_lanelets, const lanelet::LaneletMapPtr &lanelet_map, std::shared_ptr< const lanelet::routing::RoutingGraph > routing_graph)
 A function that filters successor lanelets of root_lanelets from possible_lanelets. More...
 

Function Documentation

◆ filterSuccessorLanelets()

std::unordered_set< lanelet::Lanelet > carma_wm::query::filterSuccessorLanelets ( const std::unordered_set< lanelet::Lanelet > &  possible_lanelets,
const std::unordered_set< lanelet::Lanelet > &  root_lanelets,
const lanelet::LaneletMapPtr &  lanelet_map,
std::shared_ptr< const lanelet::routing::RoutingGraph routing_graph 
)

A function that filters successor lanelets of root_lanelets from possible_lanelets.

Parameters
possible_laneletsall possible lanelets to check
root_laneletslanelets to filter from
lanelet_mapLanelet Map Ptr
routing_graphRouting graph of the lanelet map

NOTE:Mainly used as a helper function for getAffectedLaneletOrAreas

Definition at line 270 of file WorldModelUtils.cpp.

272{
273 if (!routing_graph) {
274 throw std::invalid_argument("No routing graph available");
275 }
276
277 std::unordered_set<lanelet::Lanelet> filtered_lanelets;
278 // we utilize routes to filter llts that are overlapping but not connected
279 // as this is the last lanelet
280 // we have to filter the llts that are only geometrically overlapping yet not connected to prev llts
281 for (auto recorded_llt: root_lanelets)
282 {
283 for (auto following_llt: routing_graph->following(recorded_llt, false))
284 {
285 auto mutable_llt = lanelet_map->laneletLayer.get(following_llt.id());
286 auto it = possible_lanelets.find(mutable_llt);
287 if (it != possible_lanelets.end())
288 {
289 filtered_lanelets.insert(mutable_llt);
290 }
291 }
292 }
293 return filtered_lanelets;
294}

Referenced by getAffectedLaneletOrAreas().

Here is the caller graph for this function:

◆ getAffectedLaneletOrAreas()

lanelet::ConstLaneletOrAreas carma_wm::query::getAffectedLaneletOrAreas ( const lanelet::Points3d &  gf_pts,
const lanelet::LaneletMapPtr &  lanelet_map,
std::shared_ptr< const lanelet::routing::RoutingGraph routing_graph,
double  max_lane_width 
)

Gets the affected lanelet or areas based on the points in the given map's frame.

Parameters
geofence_msglanelet::Points3d in local frame
lanelet_mapLanelet Map Ptr
routing_graphRouting graph of the lanelet map
max_lane_widthmax lane width of the lanes in the map

NOTE:Currently this function only checks lanelets and will be expanded to areas in the future.

Definition at line 117 of file WorldModelUtils.cpp.

118{
119 // Logic to detect which part is affected
120 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("carma_wm::query"), "Get affected lanelets loop");
121 std::unordered_set<lanelet::Lanelet> affected_lanelets;
122 for (size_t idx = 0; idx < gf_pts.size(); idx ++)
123 {
124 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("carma_wm::query"), "Index: " << idx << " Point: " << gf_pts[idx].x() << ", " << gf_pts[idx].y());
125 std::unordered_set<lanelet::Lanelet> possible_lanelets;
126
127 // This loop identifes the lanelets which this point lies within that could be impacted by the geofence
128 // This loop somewhat inefficiently calls the findNearest method iteratively until all the possible lanelets are identified.
129 // The reason findNearest is used instead of nearestUntil is because that method orders results by bounding box which
130 // can give invalid sequences when dealing with large curved lanelets.
131 bool continue_search = true;
132 size_t nearest_count = 0;
133 while (continue_search) {
134
135 nearest_count += 10; // Increase the index search radius by 10 each loop until all nearby lanelets are found
136
137 for (const auto& ll_pair : lanelet::geometry::findNearest(lanelet_map->laneletLayer, gf_pts[idx].basicPoint2d(), nearest_count)) { // Get the nearest lanelets and iterate over them
138 auto ll = std::get<1>(ll_pair);
139
140 if (possible_lanelets.find(ll) != possible_lanelets.end()) { // Skip if already found
141 continue;
142 }
143
144 double dist = std::get<0>(ll_pair);
145 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("carma_wm::query"), "Distance to lanelet " << ll.id() << ": " << dist << " max_lane_width: " << max_lane_width);
146
147 if (dist > max_lane_width) { // Only save values closer than max_lane_width. Since we are iterating in distance order when we reach this distance the search can stop
148 continue_search = false;
149 break;
150 }
151
152 // Check if the point is inside this lanelet
153 if(dist == 0.0) { // boost geometry uses a distance of 0 to indicate a point is within a polygon
154 possible_lanelets.insert(ll);
155 }
156
157 }
158
159 if (nearest_count >= lanelet_map->laneletLayer.size()) { // if we are out of lanelets to evaluate then end the search
160 continue_search = false;
161 }
162 }
163
164 // among these llts, filter the ones that are on same direction as the geofence using routing
165 if (idx + 1 == gf_pts.size()) // we only check this for the last gf_pt after saving everything
166 {
167 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("carma_wm::query"), "Last point");
168 std::unordered_set<lanelet::Lanelet> filtered = filterSuccessorLanelets(possible_lanelets, affected_lanelets, lanelet_map, routing_graph);
169 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("carma_wm::query"), "Got successor lanelets of size: " << filtered.size());
170 affected_lanelets.insert(filtered.begin(), filtered.end());
171
172
173 if (affected_lanelets.empty() && !possible_lanelets.empty() && idx !=0 )
174 {
175 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("carma_wm::query"), "Checking if it is the edge case where only last point falls on a valid (correct direction) lanelet");
176 for (auto llt: possible_lanelets)
177 {
178 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("carma_wm::query"), "Evaluating lanelet: " << llt.id());
179 lanelet::BasicLineString2d gf_dir_line({gf_pts[idx - 1].basicPoint2d(), gf_pts[idx].basicPoint2d()});
180 lanelet::BasicLineString2d llt_boundary({(llt.leftBound2d().begin())->basicPoint2d(), (llt.rightBound2d().begin())->basicPoint2d()});
181
182 // record the llts that are on the same dir
183 if (boost::geometry::intersects(llt_boundary, gf_dir_line))
184 {
185 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("carma_wm::query"), "Overlaps starting line... Picking llt: " << llt.id());
186 affected_lanelets.insert(llt);
187 }
188 }
189 }
190
191 break;
192 }
193
194 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("carma_wm::query"), "Checking possible lanelets");
195 // check if each lines connecting end points of the llt is crossing with the line connecting current and next gf_pts
196 for (auto llt: possible_lanelets)
197 {
198 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("carma_wm::query"), "Evaluating lanelet: " << llt.id());
199 lanelet::BasicLineString2d gf_dir_line({gf_pts[idx].basicPoint2d(), gf_pts[idx+1].basicPoint2d()});
200 lanelet::BasicLineString2d llt_boundary({(llt.leftBound2d().end() -1)->basicPoint2d(), (llt.rightBound2d().end() - 1)->basicPoint2d()});
201
202 // record the llts that are on the same dir
203 if (boost::geometry::intersects(llt_boundary, gf_dir_line))
204 {
205 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("carma_wm::query"), "Overlaps end line");
206 affected_lanelets.insert(llt);
207 }
208 // check condition if two geofence points are in one lanelet then check matching direction and record it also
209 else if (boost::geometry::within(gf_pts[idx+1].basicPoint2d(), llt.polygon2d()) &&
210 affected_lanelets.find(llt) == affected_lanelets.end())
211 {
212 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("carma_wm::query"), "Within new lanelet");
213 lanelet::BasicPoint2d median({((llt.leftBound2d().end() - 1)->basicPoint2d().x() + (llt.rightBound2d().end() - 1)->basicPoint2d().x())/2 ,
214 ((llt.leftBound2d().end() - 1)->basicPoint2d().y() + (llt.rightBound2d().end() - 1)->basicPoint2d().y())/2});
215 // turn into vectors
216 Eigen::Vector2d vec_to_median(median);
217 Eigen::Vector2d vec_to_gf_start(gf_pts[idx].basicPoint2d());
218 Eigen::Vector2d vec_to_gf_end(gf_pts[idx + 1].basicPoint2d());
219
220 // Get vector from start to external point
221 Eigen::Vector2d start_to_median = vec_to_median - vec_to_gf_start;
222
223 // Get vector from start to end point
224 Eigen::Vector2d start_to_end = vec_to_gf_end - vec_to_gf_start;
225
226 // Get angle between both vectors
227 double interior_angle = carma_wm::geometry::getAngleBetweenVectors(start_to_median, start_to_end);
228
229 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("carma_wm::query"), "vec_to_median: " << vec_to_median.x() << ", " << vec_to_median.y());
230 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("carma_wm::query"), "vec_to_gf_start: " << vec_to_gf_start.x() << ", " << vec_to_gf_start.y());
231 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("carma_wm::query"), "vec_to_gf_end: " << vec_to_gf_end.x() << ", " << vec_to_gf_end.y());
232 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("carma_wm::query"), "start_to_median: " << start_to_median.x() << ", " << start_to_median.y());
233 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("carma_wm::query"), "start_to_end: " << start_to_end.x() << ", " << start_to_end.y());
234 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("carma_wm::query"), "interior_angle: " << interior_angle);
235 // Save the lanelet if the direction of two points inside aligns with that of the lanelet
236
237 if (interior_angle < M_PI_2 && interior_angle >= 0)
238 affected_lanelets.insert(llt);
239 }
240 else
241 {
242 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("carma_wm::query"), "------ Did not record anything...");
243 }
244
245 }
246 }
247
248 RCLCPP_DEBUG_STREAM(rclcpp::get_logger("carma_wm::query"), "affected_lanelets size: " << affected_lanelets.size());
249 // Currently only returning lanelet, but this could be expanded to LanelerOrArea compound object
250 // by implementing non-const version of that LaneletOrArea
251 lanelet::ConstLaneletOrAreas affected_parts;
252 // return results in ascending downtrack order from the first point of geofence
253 std::vector<std::pair<double, lanelet::Lanelet>> sorted_parts;
254
255 for (auto llt : affected_lanelets)
256 {
257 sorted_parts.push_back(std::make_pair(carma_wm::geometry::trackPos(llt, gf_pts.front().basicPoint2d()).downtrack, llt));
258 }
259 std::sort(sorted_parts.begin(), sorted_parts.end(), [](const auto& x, const auto& y){return x.first > y.first;});
260
261 for (auto pair : sorted_parts)
262 {
263 affected_parts.push_back(pair.second);
264 }
265
266 return affected_parts;
267}
double getAngleBetweenVectors(const Eigen::Vector2d &vec1, const Eigen::Vector2d &vec2)
Calculates the angle between two vectors.
Definition: Geometry.cpp:65
TrackPos trackPos(const lanelet::ConstLanelet &lanelet, const lanelet::BasicPoint2d &point)
Returns the TrackPos, computed in 2d, of the provided point relative to the centerline of the provide...
Definition: Geometry.cpp:120
std::unordered_set< lanelet::Lanelet > filterSuccessorLanelets(const std::unordered_set< lanelet::Lanelet > &possible_lanelets, const std::unordered_set< lanelet::Lanelet > &root_lanelets, const lanelet::LaneletMapPtr &lanelet_map, std::shared_ptr< const lanelet::routing::RoutingGraph > routing_graph)
A function that filters successor lanelets of root_lanelets from possible_lanelets.

References carma_wm::TrackPos::downtrack, filterSuccessorLanelets(), carma_wm::geometry::getAngleBetweenVectors(), carma_wm::geometry::trackPos(), process_traj_logs::x, and process_traj_logs::y.

Referenced by carma_wm::SignalizedIntersectionManager::convertLaneToLaneletId(), and carma_wm_ctrl::WMBroadcaster::getAffectedLaneletOrAreas().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ getLaneletsFromPoint() [1/2]

std::vector< lanelet::ConstLanelet > carma_wm::query::getLaneletsFromPoint ( const lanelet::LaneletMapConstPtr &  semantic_map,
const lanelet::BasicPoint2d &  point,
const unsigned int  n = 10 
)

carma_wm::query namespace contains implementations for query functions (input and output read or write-able) for stand-alone lanelet map without rest of the CARMAWorldModel features. Currently mainly WMBroadcaster (carma_wm_ctrl) is using this to manipulate its own map without creating instance of carma_wm

Gets the underlying lanelet, given the cartesian point on the map

Parameters
semantic_mapLanelet Map Ptr
pointCartesian point to check the corressponding lanelet
nNumber of lanelets to return. Default is 10. As there could be many lanelets overlapping.
Exceptions
std::invalid_argumentif the map is not set, contains no lanelets
Returns
vector of underlying lanelet, empty vector if it is not part of any lanelet

Definition at line 24 of file WorldModelUtils.cpp.

26{
27 // Check if the map is loaded yet
28 if (!semantic_map || semantic_map->laneletLayer.size() == 0)
29 {
30 throw std::invalid_argument("Map is not set or does not contain lanelets");
31 }
32 std::vector<lanelet::ConstLanelet> possible_lanelets;
33 auto nearestLanelets = lanelet::geometry::findNearest(semantic_map->laneletLayer, point, n);
34 if (nearestLanelets.size() == 0)
35 return {};
36
37 size_t id = 0; // closest ones are in the back
38 // loop through until the point is no longer geometrically in the lanelet
39
40 while (boost::geometry::within(point, nearestLanelets[id].second.polygon2d()))
41 {
42 possible_lanelets.push_back(nearestLanelets[id].second);
43 id++;
44 if (id >= nearestLanelets.size())
45 break;
46 }
47 return possible_lanelets;
48}

References process_traj_logs::point.

Referenced by carma_wm::CARMAWorldModel::getLaneletsFromPoint(), getLaneletsFromPoint(), carma_wm::CARMAWorldModel::nonConnectedAdjacentLeft(), nonConnectedAdjacentLeft(), and carma_wm_ctrl::WMBroadcaster::preprocessWorkzoneGeometry().

Here is the caller graph for this function:

◆ getLaneletsFromPoint() [2/2]

std::vector< lanelet::Lanelet > carma_wm::query::getLaneletsFromPoint ( const lanelet::LaneletMapPtr &  semantic_map,
const lanelet::BasicPoint2d &  point,
const unsigned int  n = 10 
)

(non-const version) Gets the underlying lanelet, given the cartesian point on the map

Parameters
semantic_mapLanelet Map Ptr
pointCartesian point to check the corressponding lanelet
nNumber of lanelets to return. Default is 10. As there could be many lanelets overlapping.
Exceptions
std::invalid_argumentif the map is not set, contains no lanelets
Returns
vector of underlying lanelet, empty vector if it is not part of any lanelet

Definition at line 50 of file WorldModelUtils.cpp.

52{
53 lanelet::LaneletMapConstPtr const_ptr = semantic_map;
54 auto possible_lanelets = getLaneletsFromPoint(const_ptr, point, n);
55 std::vector<lanelet::Lanelet> return_lanelets;
56 for (auto llt : possible_lanelets)
57 {
58 return_lanelets.push_back(semantic_map->laneletLayer.get(llt.id()));
59 }
60 return return_lanelets;
61}
std::vector< lanelet::ConstLanelet > getLaneletsFromPoint(const lanelet::LaneletMapConstPtr &semantic_map, const lanelet::BasicPoint2d &point, const unsigned int n=10)
carma_wm::query namespace contains implementations for query functions (input and output read or writ...

References getLaneletsFromPoint(), and process_traj_logs::point.

Here is the call graph for this function:

◆ nonConnectedAdjacentLeft() [1/2]

std::vector< lanelet::ConstLanelet > carma_wm::query::nonConnectedAdjacentLeft ( const lanelet::LaneletMapConstPtr &  semantic_map,
const lanelet::BasicPoint2d &  input_point,
const unsigned int  n = 10 
)

Given the cartesian point on the map, tries to get the opposite direction lanelet on the left This function is intended to find "adjacentLeft lanelets" that doesn't share points between lanelets where adjacentLeft of lanelet library fails.

Parameters
semantic_mapLanelet Map Ptr
pointCartesian point to check the corressponding lanelet
nNumber of lanelets to return. Default is 10. As there could be many lanelets overlapping.
Exceptions
std::invalid_argumentif the map is not set, contains no lanelets, or if adjacent lanelet is not opposite direction NOTE: Only to be used on 2 lane, opposite direction road. Number of points in all linestrings are assumed to be roughly the same. The point is assumed to be on roughly similar shape of overlapping lanelets if any Enhancement issue for protection against checking if the laneis opposite direction here: https://github.com/usdot-fhwa-stol/carma-platform/issues/1381
Returns
vector of underlying lanelet, empty vector if it is not part of any lanelet

Definition at line 79 of file WorldModelUtils.cpp.

81{
82
83 // Check if the map is loaded yet
84 if (!semantic_map || semantic_map->laneletLayer.size() == 0)
85 {
86 throw std::invalid_argument("Map is not set or does not contain lanelets");
87 }
88
89 auto input_lanelets = getLaneletsFromPoint(semantic_map, input_point);
90
91 if (input_lanelets.empty())
92 {
93 throw std::invalid_argument("Input point x: " + std::to_string(input_point.x()) + ", y: " + std::to_string(input_point.y()) + " is not in the map");
94 }
95
96 auto input_lanelet = input_lanelets[0];
97
98 auto point_downtrack = carma_wm::geometry::trackPos(input_lanelet, input_point).downtrack;
99
100 auto point_downtrack_ratio = point_downtrack / carma_wm::geometry::trackPos(input_lanelet, input_lanelet.centerline().back().basicPoint2d()).downtrack;
101
102 auto point_on_ls = input_lanelet.leftBound2d()[std::round((input_lanelet.leftBound2d().size()- 1) * point_downtrack_ratio) ];
103
104 // point_on_opposite_lane coord is acquired by extrapolating the line from input_point to point_on_ls with same distance.
105 // threfore point_on_opposite_lane.x() = input_point.x() + 2dx, where dx = point_on_ls.x() - input_point.x(). Here, one of input_point.x() cancels out, results in:
106 auto point_on_opposite_lane = lanelet::BasicPoint2d{2 * point_on_ls.x() - input_point.x(), 2 * point_on_ls.y() - input_point.y()};
107
108 auto opposite_lanelets = getLaneletsFromPoint(semantic_map, point_on_opposite_lane, n);
109
110 // TODO: create opposite direction protection throw
111 // currently the function doesn't recognize if adjacent lane is opposite direction, but assumes it
112
113 return opposite_lanelets;
114}
auto to_string(const UtmZone &zone) -> std::string
Definition: utm_zone.cpp:21

References carma_wm::TrackPos::downtrack, getLaneletsFromPoint(), carma_cooperative_perception::to_string(), and carma_wm::geometry::trackPos().

Referenced by nonConnectedAdjacentLeft(), and carma_wm_ctrl::WMBroadcaster::splitOppositeLaneletWithPoint().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ nonConnectedAdjacentLeft() [2/2]

std::vector< lanelet::Lanelet > carma_wm::query::nonConnectedAdjacentLeft ( const lanelet::LaneletMapPtr &  semantic_map,
const lanelet::BasicPoint2d &  input_point,
const unsigned int  n = 10 
)

(non-const version) Given the cartesian point on the map, tries to get the opposite direction lanelet on the left This function is intended to find "adjacentLeft lanelets" that doesn't share points between lanelets where adjacentLeft of lanelet library fails

Parameters
semantic_mapLanelet Map Ptr
pointCartesian point to check the corressponding lanelet
nNumber of lanelets to return. Default is 10. As there could be many lanelets overlapping.
Exceptions
std::invalid_argumentif the map is not set, contains no lanelets, or if adjacent lanelet is not opposite direction NOTE: Only to be used on 2 lane, opposite direction road. Number of points in all linestrings are assumed to be roughly the same. The point is assumed to be on roughly similar shape of overlapping lanelets if any Enhancement issue for protection against checking if the laneis opposite direction here: https://github.com/usdot-fhwa-stol/carma-platform/issues/1381
Returns
vector of underlying lanelet, empty vector if it is not part of any lanelet

Definition at line 63 of file WorldModelUtils.cpp.

65{
66
67 lanelet::LaneletMapConstPtr const_ptr = semantic_map;
68 auto possible_lanelets = nonConnectedAdjacentLeft(const_ptr, point, n);
69
70
71 std::vector<lanelet::Lanelet> return_lanelets;
72 for (auto llt : possible_lanelets)
73 {
74 return_lanelets.push_back(semantic_map->laneletLayer.get(llt.id()));
75 }
76 return return_lanelets;
77}
std::vector< lanelet::ConstLanelet > nonConnectedAdjacentLeft(const lanelet::LaneletMapConstPtr &semantic_map, const lanelet::BasicPoint2d &input_point, const unsigned int n=10)
Given the cartesian point on the map, tries to get the opposite direction lanelet on the left This fu...

References nonConnectedAdjacentLeft(), and process_traj_logs::point.

Here is the call graph for this function: