Source code for simvx.graphics.picking.raycast_utils

"""Multi-ray casting helpers for batch intersection tests."""


from __future__ import annotations

import logging

import numpy as np

from .raycast import ray_aabb_intersect

log = logging.getLogger(__name__)

__all__ = ["compute_aabb", "cast_rays_single_hit", "cast_rays_multi_hit"]


[docs] def compute_aabb( center: np.ndarray, half_extents: np.ndarray, ) -> tuple[np.ndarray, np.ndarray]: """Compute world-space AABB from center position and half-extents.""" return center - half_extents, center + half_extents
[docs] def cast_rays_single_hit( ray_origins: np.ndarray, ray_direction: np.ndarray, cubes: list[dict], ) -> np.ndarray: """Cast rays against cubes, return first hit cube index per ray. Returns (N,) array of hit cube indices, -1 for miss. """ num_rays = len(ray_origins) hits = np.full(num_rays, -1, dtype=np.int32) for i in range(num_rays): origin = ray_origins[i] closest_t = float("inf") for cube in cubes: is_hit, t = ray_aabb_intersect( origin, ray_direction, cube["aabb_min"], cube["aabb_max"], ) if is_hit and 0 <= t < closest_t: closest_t = t hits[i] = cube["index"] return hits
[docs] def cast_rays_multi_hit( ray_origins: np.ndarray, ray_direction: np.ndarray, cubes: list[dict], ) -> list[list[int]]: """Cast rays against cubes, return ALL hit cube indices per ray.""" num_rays = len(ray_origins) hits: list[list[int]] = [[] for _ in range(num_rays)] for i in range(num_rays): origin = ray_origins[i] for cube in cubes: is_hit, t = ray_aabb_intersect( origin, ray_direction, cube["aabb_min"], cube["aabb_max"], ) if is_hit and t >= 0: hits[i].append(cube["index"]) return hits