Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion xrspatial/pathfinding.py
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,11 @@ def _hpa_star_search(surface_data, friction_data, start_py, start_px,
local_gy = g_py - min_row
local_gx = g_px - min_col
if sub_path is None or not np.isfinite(sub_path[local_gy, local_gx]):
return path_img # partial result
# Refinement could not connect this segment even at the
# largest radius. Return all-NaN ("no path found") rather
# than a partial cost trail that dead-ends mid-grid, matching
# the no-path contract of the other search paths.
return np.full((h, w), np.nan, dtype=np.float64)

seg_goal_cost = sub_path[local_gy, local_gx]
sh, sw = sub_path.shape
Expand Down
23 changes: 23 additions & 0 deletions xrspatial/tests/test_pathfinding.py
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,29 @@ def test_hpa_star_correctness():
assert (r, c) != (np.nan, np.nan)


def test_hpa_star_unreachable_goal_all_nan():
"""HPA* returns all-NaN when no path exists, not a partial trail.

The coarse grid sees blocks containing a thin NaN wall as passable
(each block still has valid cells), so the coarse route crosses the
wall and refinement fails. The output must follow the no-path
contract (all NaN) instead of keeping the already-refined segments.
"""
H = W = 200
data = np.ones((H, W))
data[:, 100] = np.nan # complete wall: goal unreachable

dy, dx, dd = _neighborhood_structure(1.0, 1.0, 8)
barriers = np.array([], dtype=np.float64)

path_img = _hpa_star_search(
data, None, 0, 0, 199, 199,
barriers, dy, dx, dd,
1.0, False, 1.0, 1.0, H, W)

assert not np.isfinite(path_img).any()


def test_auto_radius_selection():
"""When mocked low memory, auto-radius kicks in and finds path."""
data = np.ones((20, 20))
Expand Down
Loading