@@ -34,6 +34,7 @@ using motion_utils::calcArcLength;
34
34
using tier4_autoware_utils::LinearRing2d;
35
35
using tier4_autoware_utils::LineString2d;
36
36
using tier4_autoware_utils::MultiPoint2d;
37
+ using tier4_autoware_utils::MultiPolygon2d;
37
38
using tier4_autoware_utils::Point2d;
38
39
39
40
namespace
@@ -92,6 +93,7 @@ lanelet::ConstLanelets getCandidateLanelets(
92
93
93
94
return candidate_lanelets;
94
95
}
96
+
95
97
} // namespace
96
98
97
99
namespace lane_departure_checker
@@ -298,6 +300,92 @@ bool LaneDepartureChecker::willLeaveLane(
298
300
return false ;
299
301
}
300
302
303
+ std::vector<std::pair<double , lanelet::Lanelet>> LaneDepartureChecker::getLaneletsFromPath (
304
+ const lanelet::LaneletMapPtr lanelet_map_ptr, const PathWithLaneId & path) const
305
+ {
306
+ // Get Footprint Hull basic polygon
307
+ std::vector<LinearRing2d> vehicle_footprints = createVehicleFootprints (path);
308
+ LinearRing2d footprint_hull = createHullFromFootprints (vehicle_footprints);
309
+ auto to_basic_polygon = [](const LinearRing2d & footprint_hull) -> lanelet::BasicPolygon2d {
310
+ lanelet::BasicPolygon2d basic_polygon;
311
+ for (const auto & point : footprint_hull) {
312
+ Eigen::Vector2d p (point.x (), point.y ());
313
+ basic_polygon.push_back (p);
314
+ }
315
+ return basic_polygon;
316
+ };
317
+ lanelet::BasicPolygon2d footprint_hull_basic_polygon = to_basic_polygon (footprint_hull);
318
+
319
+ // Find all lanelets that intersect the footprint hull
320
+ return lanelet::geometry::findWithin2d (
321
+ lanelet_map_ptr->laneletLayer , footprint_hull_basic_polygon, 0.0 );
322
+ }
323
+
324
+ std::optional<lanelet::BasicPolygon2d> LaneDepartureChecker::getFusedLaneletPolygonForPath (
325
+ const lanelet::LaneletMapPtr lanelet_map_ptr, const PathWithLaneId & path) const
326
+ {
327
+ const auto lanelets_distance_pair = getLaneletsFromPath (lanelet_map_ptr, path);
328
+ // Fuse lanelets into a single BasicPolygon2d
329
+ auto fused_lanelets = [&lanelets_distance_pair]() -> std::optional<lanelet::BasicPolygon2d> {
330
+ if (lanelets_distance_pair.empty ()) return std::nullopt;
331
+ if (lanelets_distance_pair.size () == 1 )
332
+ return lanelets_distance_pair.at (0 ).second .polygon2d ().basicPolygon ();
333
+
334
+ lanelet::BasicPolygon2d merged_polygon =
335
+ lanelets_distance_pair.at (0 ).second .polygon2d ().basicPolygon ();
336
+ for (size_t i = 1 ; i < lanelets_distance_pair.size (); ++i) {
337
+ const auto & route_lanelet = lanelets_distance_pair.at (i).second ;
338
+ const auto & poly = route_lanelet.polygon2d ().basicPolygon ();
339
+
340
+ std::vector<lanelet::BasicPolygon2d> lanelet_union_temp;
341
+ boost::geometry::union_ (poly, merged_polygon, lanelet_union_temp);
342
+
343
+ // Update merged_polygon by accumulating all merged results
344
+ merged_polygon.clear ();
345
+ for (const auto & temp_poly : lanelet_union_temp) {
346
+ merged_polygon.insert (merged_polygon.end (), temp_poly.begin (), temp_poly.end ());
347
+ }
348
+ }
349
+ if (merged_polygon.empty ()) return std::nullopt;
350
+ return merged_polygon;
351
+ }();
352
+
353
+ return fused_lanelets;
354
+ }
355
+
356
+ bool LaneDepartureChecker::checkPathWillLeaveLane (
357
+ const lanelet::LaneletMapPtr lanelet_map_ptr, const PathWithLaneId & path) const
358
+ {
359
+ // check if the footprint is not fully contained within the fused lanelets polygon
360
+ const std::vector<LinearRing2d> vehicle_footprints = createVehicleFootprints (path);
361
+ const auto fused_lanelets_polygon = getFusedLaneletPolygonForPath (lanelet_map_ptr, path);
362
+ if (!fused_lanelets_polygon) return true ;
363
+ return !std::all_of (
364
+ vehicle_footprints.begin (), vehicle_footprints.end (),
365
+ [&fused_lanelets_polygon](const auto & footprint) {
366
+ return boost::geometry::within (footprint, fused_lanelets_polygon.value ());
367
+ });
368
+ }
369
+
370
+ PathWithLaneId LaneDepartureChecker::cropPointsOutsideOfLanes (
371
+ const lanelet::LaneletMapPtr lanelet_map_ptr, const PathWithLaneId & path, const size_t end_index)
372
+ {
373
+ PathWithLaneId temp_path;
374
+ const auto fused_lanelets_polygon = getFusedLaneletPolygonForPath (lanelet_map_ptr, path);
375
+ if (path.points .empty () || !fused_lanelets_polygon) return temp_path;
376
+ const auto vehicle_footprints = createVehicleFootprints (path);
377
+ size_t idx = 0 ;
378
+ std::for_each (vehicle_footprints.begin (), vehicle_footprints.end (), [&](const auto & footprint) {
379
+ if (idx > end_index || boost::geometry::within (footprint, fused_lanelets_polygon.value ())) {
380
+ temp_path.points .push_back (path.points .at (idx));
381
+ }
382
+ ++idx;
383
+ });
384
+ PathWithLaneId cropped_path = path;
385
+ cropped_path.points = temp_path.points ;
386
+ return cropped_path;
387
+ }
388
+
301
389
bool LaneDepartureChecker::isOutOfLane (
302
390
const lanelet::ConstLanelets & candidate_lanelets, const LinearRing2d & vehicle_footprint)
303
391
{
@@ -364,4 +452,5 @@ bool LaneDepartureChecker::willCrossBoundary(
364
452
}
365
453
return false ;
366
454
}
455
+
367
456
} // namespace lane_departure_checker
0 commit comments