1717#ifndef NAV2_SMAC_PLANNER__GOAL_MANAGER_HPP_
1818#define NAV2_SMAC_PLANNER__GOAL_MANAGER_HPP_
1919
20+ #include < algorithm>
2021#include < unordered_set>
2122#include < vector>
2223#include < functional>
@@ -112,6 +113,74 @@ class GoalManager
112113 }
113114 }
114115
116+ /* *
117+ * @brief Checks if zone within the radius of a node is feasible. Returns true if
118+ * there's at least one non-lethal cell within the node radius.
119+ * @param node Input node.
120+ * @param radius Search radius.
121+ * @param collision_checker Collision checker to validate nearby nodes.
122+ * @param traverse_unknown Flag whether traversal through unknown space is allowed.
123+ * @return true
124+ * @return false
125+ */
126+ bool isZoneValid (
127+ const NodePtr node, const float & radius, GridCollisionChecker * collision_checker,
128+ const bool & traverse_unknown) const
129+ {
130+ if (radius < 1 ) {
131+ return false ;
132+ }
133+
134+ const auto size_x = collision_checker->getCostmap ()->getSizeInCellsX ();
135+ const auto size_y = collision_checker->getCostmap ()->getSizeInCellsY ();
136+
137+ auto getIndexFromPoint = [&size_x] (const Coordinates & point) {
138+ unsigned int index = 0 ;
139+
140+ const auto mx = static_cast <unsigned int >(point.x );
141+ const auto my = static_cast <unsigned int >(point.y );
142+
143+ if constexpr (!std::is_same_v<NodeT, Node2D>) {
144+ const auto angle = static_cast <unsigned int >(point.theta );
145+ index = NodeT::getIndex (mx, my, angle);
146+ } else {
147+ index = NodeT::getIndex (mx, my, size_x);
148+ }
149+
150+ return index;
151+ };
152+
153+ const Coordinates & center_point = node->pose ;
154+ const float min_x = std::max (0 .0f , std::floor (center_point.x - radius));
155+ const float min_y = std::max (0 .0f , std::floor (center_point.y - radius));
156+ const float max_x =
157+ std::min (static_cast <float >(size_x - 1 ), std::ceil (center_point.x + radius));
158+ const float max_y =
159+ std::min (static_cast <float >(size_y - 1 ), std::ceil (center_point.y + radius));
160+ const float radius_sq = radius * radius;
161+
162+ Coordinates m;
163+ for (m.x = min_x; m.x <= max_x; m.x += 1 .0f ) {
164+ for (m.y = min_y; m.y <= max_y; m.y += 1 .0f ) {
165+ const float dx = m.x - center_point.x ;
166+ const float dy = m.y - center_point.y ;
167+
168+ if (dx * dx + dy * dy > radius_sq) {
169+ continue ;
170+ }
171+
172+ NodeT current_node (getIndexFromPoint (m));
173+ current_node.setPose (m);
174+
175+ if (current_node.isNodeValid (traverse_unknown, collision_checker)) {
176+ return true ;
177+ }
178+ }
179+ }
180+
181+ return false ;
182+ }
183+
115184 /* *
116185 * @brief Filters and marks invalid goals based on collision checking and tolerance thresholds.
117186 *
@@ -133,7 +202,7 @@ class GoalManager
133202 }
134203 for (unsigned int i = 0 ; i < _goals_state.size (); i++) {
135204 if (_goals_state[i].goal ->isNodeValid (traverse_unknown, collision_checker) ||
136- tolerance > 0.001 )
205+ isZoneValid (_goals_state[i]. goal , tolerance, collision_checker, traverse_unknown) )
137206 {
138207 _goals_state[i].is_valid = true ;
139208 _goals_set.insert (_goals_state[i].goal );
0 commit comments