bevy_a5 0.1.2

A Bevy plugin providing A5 geospatial pentagonal cells for floating origin use and spatial queries
Documentation
//! Floating origin marker component for camera / player entities.

use bevy_ecs::component::Component;
use bevy_ecs::prelude::ReflectComponent;
use bevy_reflect::Reflect;
use bevy_transform::components::Transform;

use crate::cell::GeoCell;

/// Marker component designating an entity as the floating origin.
///
/// The entity with this component is the **rendering reference point**: it
/// always renders at world `(0, 0, 0)` (with its own `Transform.rotation`
/// and `Transform.scale` preserved). Every other entity with a [`GeoCell`]
/// is placed by [`propagate_geo_transforms`](crate::systems::propagate_geo_transforms)
/// in the origin's local cell frame, at its true sphere-space position
/// relative to the origin. This is the same "big-space" convention used by
/// the `big_space` crate — keeps float precision tight even when the
/// underlying cell coordinate is on the far side of a planet.
///
/// The origin's `Transform.translation` is the *local offset within its
/// current cell*, **not** a world-space coordinate. Move the origin by
/// mutating that translation; when its length exceeds
/// [`recenter_threshold`](Self::recenter_threshold) the recenter system
/// swaps the origin to a neighbouring cell and rebases both the translation
/// and the rotation so the world-space pose is unchanged. Recentres are
/// therefore visually invisible.
///
/// # Required components
///
/// `FloatingOrigin` requires a [`GeoCell`] (which cell the origin is in) and a
/// [`Transform`] (the local offset within that cell). Bevy's `#[require]`
/// attribute auto-inserts defaults if you don't provide them, so the smallest
/// valid spawn is `commands.spawn(FloatingOrigin::default())`.
///
/// # Per-origin recenter threshold
///
/// Each `FloatingOrigin` carries its own [`recenter_threshold`](Self::recenter_threshold)
/// in world units (metres). Multiple floating origins (split-screen,
/// networked players) can have different thresholds.
///
/// # Example
///
/// ```rust,ignore
/// commands.spawn((
///     FloatingOrigin::with_threshold(50.0),
///     GeoCell::from_lon_lat(2.3522, 48.8566, 9).unwrap(),
///     Transform::default(),
/// ));
/// ```
#[derive(Component, Debug, Clone, Copy, Reflect)]
#[reflect(Component)]
#[require(GeoCell, Transform)]
pub struct FloatingOrigin {
    /// Distance in world units from the cell centre at which the recenter
    /// system swaps to a new cell. Larger values mean fewer cell hops at the
    /// cost of larger float values within the cell.
    pub recenter_threshold: f32,
}

impl FloatingOrigin {
    /// Construct a [`FloatingOrigin`] with a custom recenter threshold (metres).
    pub const fn with_threshold(recenter_threshold: f32) -> Self {
        Self {
            recenter_threshold,
        }
    }
}

impl Default for FloatingOrigin {
    fn default() -> Self {
        Self {
            recenter_threshold: 500.0,
        }
    }
}