Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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