From acbaaec2e907d71e8882058fb7c04a301893e49c Mon Sep 17 00:00:00 2001 From: Matteo Princisgh Date: Mon, 29 Dec 2025 19:16:16 +0100 Subject: [PATCH 1/2] add Lidar2D class and changed yaw calculation --- src/raycast2D/__init__.py | 4 +- src/raycast2D/raycast2D.py | 153 ++++++++++++++++++++++++++++++------- 2 files changed, 128 insertions(+), 29 deletions(-) diff --git a/src/raycast2D/__init__.py b/src/raycast2D/__init__.py index 2e16ec8..70c2afd 100644 --- a/src/raycast2D/__init__.py +++ b/src/raycast2D/__init__.py @@ -1,3 +1,3 @@ -from .raycast2D import cast +from .raycast2D import cast, Lidar2D -__all__ = ["cast"] \ No newline at end of file +__all__ = ["cast", "Lidar2D"] \ No newline at end of file diff --git a/src/raycast2D/raycast2D.py b/src/raycast2D/raycast2D.py index 2dd0024..7ddbc46 100644 --- a/src/raycast2D/raycast2D.py +++ b/src/raycast2D/raycast2D.py @@ -1,3 +1,4 @@ +from typing import Optional from . import raycaster import numpy as np from numpy.typing import NDArray @@ -6,6 +7,94 @@ import warnings +class Lidar2D: + + def __init__( + self, + num_rays: int = 1000, + FOV: int = 360, + ray_length: int = 500, + occupancy_grid: NDArray | None = None, + obstacle_threshold: int = 0, + ) -> None: + """ + Initialize the Lidar2D raycaster. + Args: + num_rays: Number of rays to cast (samples uniformly over the FOV). + FOV: Field of view in degrees. + ray_length: Max ray length in pixels. + occupancy_grid: Optional occupancy grid to set at initialization. + obstacle_threshold: Cells with values less than or equal to this are treated as occupied. + """ + self.angles = np.linspace( + -math.radians(FOV) / 2.0, + math.radians(FOV) / 2.0, + num_rays, + ) + self.ray_length = ray_length + self.obstacle_threshold = obstacle_threshold + self._map = None + if occupancy_grid is not None: + self.set_map(occupancy_grid) + + def scan( + self, + pose: tuple[int, int] | tuple[int, int, float], + image: Optional[NDArray] = None, + only_true_collisions: bool = True + ) -> NDArray[np.uint32]: + """ + Perform a LiDAR scan from the given pose on the occupancy image. + + Args: + pose: ``(x, y)`` or ``(x, y, yaw)`` where ``yaw`` is in radians. + image: Optional occupancy grid of shape ``(H, W)`` or ``(H, W, 1)`` with an integer dtype. + The raycaster treats values less than or equal to ``obstacle_threshold`` as occupied; + the start cell at ``pose`` must be free. + NOTE: the provided image overrides any occupancy grid set at initialization. + only_true_collisions: If True, return only rays that actually hit an obstacle + (LiDAR-style). If False, return endpoints for all rays. + + Returns: + An array of shape ``(N, 2)`` with dtype ``uint32`` containing ``(x, y)`` collision coordinates. + """ + if self._map is None and image is None: + raise ValueError( + "No occupancy grid provided at initialization or scan time.") + + if image is not None : + _map = (_check_map(image) > self.obstacle_threshold).astype(np.uint8) + else: + _map = self._map + + _check_pose(_map, pose) + + p = _POSE(*pose) # type: ignore + x_rays = np.round(p.x + self.ray_length * + np.cos(self.angles + p.yaw)).astype(np.uint32) + y_rays = np.round(p.y + self.ray_length * + np.sin(self.angles + p.yaw)).astype(np.uint32) + + rays = np.column_stack((x_rays, y_rays, np.zeros_like(y_rays))) + + # raycaster modifies the rays array inplace to include collisions + raycaster.raycast(_map, rays, p.x, p.y) + + if only_true_collisions: # LiDaR-style output + return rays[rays[:, -1] == 1][:, :-1] + return rays[:, :-1] + + def set_map(self, occupancy_grid: NDArray) -> None: + """ + Set or update the occupancy grid used by the raycaster. + + Args: + occupancy_grid: Occupancy grid of shape ``(H, W)`` or ``(H, W, 1)`` with an integer dtype. + """ + self._map = _check_map(occupancy_grid) + self._map = (self._map > self.obstacle_threshold).astype(np.uint8) + + def cast( image: NDArray, pose: tuple[int, int] | tuple[int, int, float], @@ -31,14 +120,10 @@ def cast( An array of shape ``(N, 2)`` with dtype ``uint32`` containing ``(x, y)`` collision coordinates. If ``only_true_collisions=True``, ``N`` is the number of hits; otherwise ``N == num_rays``. """ - _check_args(image, pose) - if len(image.shape) == 3: # take only the first channel - image = image[:, :, 0] - if image.dtype != np.uint8: - warnings.warn(f"Converting image of dtype {image.dtype} to uint8 for raycasting.") - image = image.astype(np.uint8) - - p = _POSE(*pose) # type: ignore + image = _check_map(image) + _check_pose(image, pose) + + p = _POSE(*pose) # type: ignore half_fov = math.radians(FOV) / 2.0 start_angle = p.yaw - half_fov end_angle = p.yaw + half_fov @@ -46,47 +131,61 @@ def cast( theta = np.linspace(start_angle, end_angle, num_rays) x_rays = np.round(p.x + ray_length * np.cos(theta)).astype(np.uint32) y_rays = np.round(p.y + ray_length * np.sin(theta)).astype(np.uint32) - + rays = np.column_stack((x_rays, y_rays, np.zeros_like(y_rays))) - + # raycaster modifies the rays array inplace to include collisions raycaster.raycast(image, rays, p.x, p.y) - + if only_true_collisions: # LiDaR-style output - return rays[rays[:, 2] == 1][:, :2] - return rays[:, :2] + return rays[rays[:, -1] == 1][:, :-1] + return rays[:, :-1] @dataclass class _POSE: x: int y: int - yaw: float = -math.pi / 2 - - -def _check_args(img: NDArray, pose: tuple) -> None: - if not np.issubdtype(img.dtype, np.integer): - raise ValueError( - f"Received an array with dtype {img.dtype}, The only supported dtypes are subtypes of np.integral.") + yaw: float = 0.0 + + def __post_init__(self): + self.yaw -= math.pi / 2.0 # adjust so yaw=0 points upwards - shape = img.shape - if len(shape) < 2 or (len(shape) > 2 and shape[2] > 1): - raise ValueError( - f"Received an array of shape {shape}. The only supported shapes are (H x W), (H x W x 1)." - ) +def _check_pose(img: NDArray[np.uint8], pose: tuple) -> None: if len(pose) < 2 or len(pose) > 3: raise ValueError( f"Received a pose tuple {pose}. The only supported pose formats are (x, y) and (x, y, yaw).") x, y = pose[0], pose[1] - H, W = shape[0], shape[1] + H, W = img.shape[0], img.shape[1] if x < 0 or x >= W: raise IndexError( f"x coordinate ({x}) if out of bounds for array with width {W}.") if y < 0 or y >= H: raise IndexError( f"y coordinate ({y}) if out of bounds for array with height {H}.") - + if img[y, x] == 0: raise ValueError( f"The pose {pose} corresponds to an occupied cell, cannot raycast from an occupied cell.") + + +def _check_map(img: NDArray) -> NDArray[np.uint8]: + if not np.issubdtype(img.dtype, np.integer): + raise ValueError( + f"Received an array with dtype {img.dtype}, The only supported dtypes are subtypes of np.integral.") + + shape = img.shape + if len(shape) < 2 or (len(shape) > 2 and shape[2] > 1): + raise ValueError( + f"Received an array of shape {shape}. The only supported shapes are (H x W), (H x W x 1)." + ) + + if len(img.shape) == 3: # take only the first channel + img = img[:, :, 0] + if img.dtype != np.uint8: + warnings.warn( + f"Converting image of dtype {img.dtype} to uint8 for raycasting.") + img = img.astype(np.uint8) + + return img From 04c75b16644a22a20317706f34fdac205ac0f704 Mon Sep 17 00:00:00 2001 From: Matteo Princisgh Date: Mon, 29 Dec 2025 19:17:08 +0100 Subject: [PATCH 2/2] updated tests and README.md --- README.md | 72 +++++++++++---- media/example.png | Bin 0 -> 82886 bytes test/test_lidar2D.py | 194 +++++++++++++++++++++++++++++++++++++++++ test/test_raycast2D.py | 18 ++-- 4 files changed, 256 insertions(+), 28 deletions(-) create mode 100644 media/example.png create mode 100644 test/test_lidar2D.py diff --git a/README.md b/README.md index 18fb5b5..1010ca1 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,10 @@ [![Build](https://github.com/prina404/raycast2D/actions/workflows/build.yml/badge.svg)](https://github.com/prina404/raycast2D/actions/workflows/build.yml) [![Tests](https://github.com/prina404/raycast2D/actions/workflows/tests.yml/badge.svg)](https://github.com/prina404/raycast2D/actions/workflows/tests.yml) -`raycast2D` is a fast, single-core 2D raycasting implementation written in C with a small Python API. +`raycast2D` is a fast, single-thread 2D raycasting implementation written in C with a small Python API. It operates on NumPy occupancy grids / binary images (free cells are non-zero; occupied cells are `0`) and computes ray intersections using Bresenham line algorithm. -The core package depends only on `numpy`. Optional extras are provided for the interactive demo and development. +The core package depends only on `numpy`. ![](media/raycast_compressed.gif) @@ -18,30 +18,66 @@ The core package depends only on `numpy`. Optional extras are provided for the i ```bash $ pip install raycast2D ``` -### Basic raycast on an image +### Basic `cast` function usage ```python import numpy as np -from raycast2D import cast from PIL import Image -import matplotlib.pyplot as plt +from raycast2D import cast img = Image.open("") -img_array = np.array(img) -img_array = img_array[:, :, 0].astype(np.uint8) # Use single channel -# img_array = img_array[img_array < 100] = 0 # threshold obstacles if needed +img_array = np.array(img)[:, :, 0] # Use single channel +pose = (250, 250, 0.5) # x, y, yaw in radians + +rays = cast(img_array, pose, num_rays=360, ray_length=500) + +print(rays[:5]) +# Expected output (example): +# [[x0 y0] +# [x1 y1] +# [x2 y2] +# [x3 y3] +# [x4 y4]] +``` + +### Using the `Lidar2D` class -rays = cast(img_array, pose=(250, 250), num_rays=360, ray_length=500) -# rays is an array of shape (N, 2) where each row contains the (x, y) coordinates of the ray collisions +```python +from raycast2D import Lidar2D +# [...] +lidar = Lidar2D(num_rays=360, FOV=360, ray_length=500) +lidar.set_map(img_array) -plt.imshow(img_array, cmap='gray') -plt.scatter([250], [250], c='green', s=10) -plt.scatter(rays[:, 0], rays[:, 1], c='blue', s=1) +rays = lidar.scan((250, 250, 0.5)) + +print(rays[:5]) +# same output as before... +``` + +### Plotting example + +```python +import numpy as np +import matplotlib.pyplot as plt +from PIL import Image +from raycast2D import cast + +img = Image.open("media/lab_intel.png") +img_array = np.array(img)[:, :, 0] # Use single channel + +pose = (350, 350, -1.0) +rays = cast(img_array, pose=pose, num_rays=200, FOV=90, ray_length=250) + +plt.imshow(img_array, cmap="gray") +plt.scatter([pose[0]], [pose[1]], c="green", s=10) +plt.scatter(rays[:, 0], rays[:, 1], c="blue", s=1) for ray in rays: - plt.plot([250, ray[0]], [250, ray[1]], c='red', linewidth=0.5, alpha=0.3) + plt.plot([pose[0], ray[0]], [pose[1], ray[1]], c="red", linewidth=0.5, alpha=0.3) plt.show() ``` +![](media/example.png) + ## Performance The benchmark script in `test/benchmark.py` runs a small set of examples and prints throughput in rays/s. @@ -49,9 +85,9 @@ Example results (tested on an i7-9700k): | Map size | Ray length | Rays per call | Mean time (ms) | Throughput (rays/s) | | --------: | ---------: | ------------: | -------------: | ------------------: | -| 512×512 | 2000px | 5000 | 0.2904 | 17,216,880 | -| 4096×4096 | 2000px | 5000 | 1.7626 | 2,836,661 | -| 8192×8192 | 2000px | 5000 | 7.3452 | 680,719 | +| 512×512 | 2000px | 5000 | 0.2490 | 20,083,924 | +| 4096×4096 | 2000px | 5000 | 0.2848 | 17,556,549 | +| 8192×8192 | 2000px | 5000 | 0.2571 | 19,446,324 | To reproduce on your machine: @@ -59,8 +95,6 @@ To reproduce on your machine: $ python3 test/benchmark.py ``` - - ## Interactive demo The repository includes an interactive `pygame` demo that raycasts from the current mouse position. diff --git a/media/example.png b/media/example.png new file mode 100644 index 0000000000000000000000000000000000000000..fc65f0393dda1a2eb1a75adb7b570c89feddf117 GIT binary patch literal 82886 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 Sl;TanfAq8uX%%QXg#AC^lY#XB literal 0 HcmV?d00001 diff --git a/test/test_lidar2D.py b/test/test_lidar2D.py new file mode 100644 index 0000000..8927aba --- /dev/null +++ b/test/test_lidar2D.py @@ -0,0 +1,194 @@ +import math +import warnings + +import numpy as np +import pytest + +from raycast2D.raycast2D import Lidar2D +import raycast2D.raycast2D as rc_mod + + +def _scan( + img: np.ndarray, + pose: tuple[int, int] | tuple[int, int, float], + *, + num_rays: int = 1000, + FOV: int = 360, + ray_length: int = 500, + only_true_collisions: bool = True, +): + lidar = Lidar2D(num_rays=num_rays, FOV=FOV, ray_length=ray_length) + return lidar.scan(pose, image=img, only_true_collisions=only_true_collisions) + + +def test_empty_map_single_ray_hits_border_right() -> None: + img = np.full((10, 10), 255, dtype=np.uint8) + pose = (5, 5, math.pi / 2) # yaw=pi/2 -> right (yaw=0 points up) + + rays = _scan(img, pose, num_rays=1, FOV=1, ray_length=100) + assert rays.shape == (1, 2) + + x, y = map(int, rays[0]) + assert (x, y) == (img.shape[1] - 1, pose[1]) + + +def test_obstacle_above_origin_collision_is_obstacle_cell() -> None: + img = np.full((12, 12), 255, dtype=np.uint8) + pose = (6, 9, 0.0) # up (yaw=0 points up) + img[4, 6] = 0 # obstacle directly above along same column + + rays = _scan(img, pose, num_rays=1, FOV=1, ray_length=200) + x, y = map(int, rays[0]) + assert (x, y) == (6, 4) + + +def test_yaw_controls_direction_right_vs_left() -> None: + img = np.full((11, 11), 255, dtype=np.uint8) + pose = (5, 5) + + rays_right = _scan(img, (pose[0], pose[1], math.pi / 2), + num_rays=1, FOV=1, ray_length=200) + xr, yr = rays_right[0] + assert (xr, yr) == (img.shape[1] - 1, pose[1]) + + rays_left = _scan(img, (pose[0], pose[1], -math.pi / 2), + num_rays=1, FOV=1, ray_length=200) + xl, yl = rays_left[0] + assert (xl, yl) == (0, pose[1]) + + +def test_fov_180_default_yaw_first_left_last_right() -> None: + img = np.full((21, 21), 255, dtype=np.uint8) + pose = (10, 10) # default yaw=0 (points up) + + rays = _scan(img, pose, num_rays=2, FOV=180, ray_length=500) + (x0, y0) = map(int, rays[0]) + (x1, y1) = map(int, rays[-1]) + + assert (x0, y0) == (0, pose[1]) + assert (x1, y1) == (img.shape[1] - 1, pose[1]) + + +def test_fov_180_yaw_pi_over_2_first_top_last_bottom() -> None: + img = np.full((21, 21), 255, dtype=np.uint8) + pose = (10, 10, math.pi / 2) + + rays = _scan(img, pose, num_rays=2, FOV=180, ray_length=500) + (x0, y0) = map(int, rays[0]) + (x1, y1) = map(int, rays[-1]) + + assert (x0, y0) == (pose[0], 0) + assert (x1, y1) == (pose[0], img.shape[0] - 1) + + +def test_pose_on_occupied_cell_raises() -> None: + img = np.full((10, 10), 255, dtype=np.uint8) + img[3, 4] = 0 + with pytest.raises(ValueError): + _scan(img, (4, 3)) + + +def test_rejects_non_integer_dtype() -> None: + img = np.zeros((10, 10), dtype=np.float32) + img[:] = 1.0 + with pytest.raises(ValueError): + _scan(img, (5, 5)) + + +def test_raises_when_image_dtype_is_not_np_integral() -> None: + img = np.full((10, 10), 1.0, dtype=np.float64) + with pytest.raises(ValueError): + _scan(img, (5, 5)) + + +def test_accepts_single_channel_3d_image() -> None: + img = np.full((10, 10, 1), 255, dtype=np.uint8) + rays = _scan(img, (5, 5, 0.0), num_rays=1, FOV=1, ray_length=50) + assert rays.shape == (1, 2) + + +def test_only_true_collisions_true_returns_empty_when_no_collision() -> None: + img = np.full((30, 30), 255, dtype=np.uint8) + pose = (15, 15, 0.0) + + # Small ray_length keeps endpoints inside free space (no border hit, no obstacles) + rays_true = _scan( + img, + pose, + num_rays=5, + FOV=30, + ray_length=3, + only_true_collisions=True, + ) + assert rays_true.shape == (0, 2) + + rays_false = _scan( + img, + pose, + num_rays=5, + FOV=30, + ray_length=3, + only_true_collisions=False, + ) + assert rays_false.shape == (5, 2) + + +def test_only_true_collisions_filters_to_obstacle_hits_subset() -> None: + img = np.full((30, 30), 255, dtype=np.uint8) + pose = (15, 15, math.pi / 2) + + # With num_rays=2 and FOV=180 around yaw=pi/2, angles are exactly -pi/2 (up) and +pi/2 (down) + # Put an obstacle only on the "up" ray. + img[13, 15] = 0 # (x=15, y=13) + + rays_true = _scan( + img, + pose, + num_rays=2, + FOV=180, + ray_length=3, + only_true_collisions=True, + ) + assert rays_true.shape == (1, 2) + assert tuple(map(int, rays_true[0])) == (15, 13) + + rays_false = _scan( + img, + pose, + num_rays=2, + FOV=180, + ray_length=3, + only_true_collisions=False, + ) + assert rays_false.shape == (2, 2) + + pts = {tuple(map(int, p)) for p in rays_false} + # One ray hits the obstacle; the other ends in free space (no collision) + assert (15, 13) in pts + assert (15, 18) in pts + + +def test_uint8_conversion_warning_emitted_only_once() -> None: + img = np.full((20, 20), 255, dtype=np.int32) + pose = (10, 10, 0.0) + + # Make this test deterministic: clear the module warning registry so the first call warns. + registry = getattr(rc_mod, "__warningregistry__", None) + if isinstance(registry, dict): + registry.clear() + + with warnings.catch_warnings(record=True) as recorded: + warnings.simplefilter("default") + + _scan(img, pose, num_rays=1, FOV=1, + ray_length=3, only_true_collisions=False) + _scan(img, pose, num_rays=1, FOV=1, + ray_length=3, only_true_collisions=False) + + conversion_warnings = [ + w + for w in recorded + if issubclass(w.category, UserWarning) + and "Converting image of dtype" in str(w.message) + ] + assert len(conversion_warnings) == 1 diff --git a/test/test_raycast2D.py b/test/test_raycast2D.py index f7a89e3..163ba2b 100644 --- a/test/test_raycast2D.py +++ b/test/test_raycast2D.py @@ -10,7 +10,7 @@ def test_empty_map_single_ray_hits_border_right() -> None: img = np.full((10, 10), 255, dtype=np.uint8) - pose = (5, 5, 0.0) # yaw=0 -> right + pose = (5, 5, math.pi / 2) # yaw=pi/2 -> right (yaw=0 points up) rays = cast(img, pose, num_rays=1, FOV=1, ray_length=100) assert rays.shape == (1, 2) @@ -21,7 +21,7 @@ def test_empty_map_single_ray_hits_border_right() -> None: def test_obstacle_above_origin_collision_is_obstacle_cell() -> None: img = np.full((12, 12), 255, dtype=np.uint8) - pose = (6, 9, -math.pi / 2) # up + pose = (6, 9, 0.0) # up (yaw=0 points up) img[4, 6] = 0 # obstacle directly above along same column rays = cast(img, pose, num_rays=1, FOV=1, ray_length=200) @@ -33,12 +33,12 @@ def test_yaw_controls_direction_right_vs_left() -> None: img = np.full((11, 11), 255, dtype=np.uint8) pose = (5, 5) - rays_right = cast(img, (pose[0], pose[1], 0.0), + rays_right = cast(img, (pose[0], pose[1], math.pi / 2), num_rays=1, FOV=1, ray_length=200) xr, yr = rays_right[0] assert (xr, yr) == (img.shape[1] - 1, pose[1]) - rays_left = cast(img, (pose[0], pose[1], -math.pi), + rays_left = cast(img, (pose[0], pose[1], -math.pi / 2), num_rays=1, FOV=1, ray_length=200) xl, yl = rays_left[0] assert (xl, yl) == (0, pose[1]) @@ -46,7 +46,7 @@ def test_yaw_controls_direction_right_vs_left() -> None: def test_fov_180_default_yaw_first_left_last_right() -> None: img = np.full((21, 21), 255, dtype=np.uint8) - pose = (10, 10) # default yaw=-pi/2 + pose = (10, 10) # default yaw=0 (points up) rays = cast(img, pose, num_rays=2, FOV=180, ray_length=500) (x0, y0) = map(int, rays[0]) @@ -56,9 +56,9 @@ def test_fov_180_default_yaw_first_left_last_right() -> None: assert (x1, y1) == (img.shape[1] - 1, pose[1]) -def test_fov_180_yaw0_first_top_last_bottom() -> None: +def test_fov_180_yaw_pi_over_2_first_top_last_bottom() -> None: img = np.full((21, 21), 255, dtype=np.uint8) - pose = (10, 10, 0.0) + pose = (10, 10, math.pi / 2) rays = cast(img, pose, num_rays=2, FOV=180, ray_length=500) (x0, y0) = map(int, rays[0]) @@ -122,9 +122,9 @@ def test_only_true_collisions_true_returns_empty_when_no_collision() -> None: def test_only_true_collisions_filters_to_obstacle_hits_subset() -> None: img = np.full((30, 30), 255, dtype=np.uint8) - pose = (15, 15, 0.0) + pose = (15, 15, math.pi / 2) - # With num_rays=2 and FOV=180 around yaw=0, angles are exactly -pi/2 (up) and +pi/2 (down) + # With num_rays=2 and FOV=180 around yaw=pi/2, angles are exactly -pi/2 (up) and +pi/2 (down) # Put an obstacle only on the "up" ray. img[13, 15] = 0 # (x=15, y=13)