use crate::prelude::*;
use bevy_ecs::prelude::*;
use bevy_math::{prelude::*, Affine3A, DAffine3, DVec3};
use bevy_reflect::prelude::*;
use bevy_transform::prelude::*;
use local_origin::LocalFloatingOrigin;
pub mod cell;
pub mod local_origin;
pub mod propagation;
#[derive(Debug, Clone, Reflect, Component)]
#[reflect(Component)]
pub struct Grid {
local_floating_origin: LocalFloatingOrigin,
cell_edge_length: f32,
maximum_distance_from_origin: f32,
}
impl Default for Grid {
fn default() -> Self {
Self::new(2_000f32, 100f32)
}
}
impl Grid {
pub fn new(cell_edge_length: f32, switching_threshold: f32) -> Self {
Self {
local_floating_origin: LocalFloatingOrigin::default(),
cell_edge_length,
maximum_distance_from_origin: cell_edge_length / 2.0 + switching_threshold,
}
}
#[inline]
pub fn local_floating_origin(&self) -> &LocalFloatingOrigin {
&self.local_floating_origin
}
#[inline]
pub fn cell_edge_length(&self) -> f32 {
self.cell_edge_length
}
#[inline]
pub fn maximum_distance_from_origin(&self) -> f32 {
self.maximum_distance_from_origin
}
#[inline]
pub fn grid_position_double(&self, pos: &CellCoord, transform: &Transform) -> DVec3 {
DVec3 {
x: pos.x as f64 * self.cell_edge_length as f64 + transform.translation.x as f64,
y: pos.y as f64 * self.cell_edge_length as f64 + transform.translation.y as f64,
z: pos.z as f64 * self.cell_edge_length as f64 + transform.translation.z as f64,
}
}
#[inline]
pub fn grid_position(&self, pos: &CellCoord, transform: &Transform) -> Vec3 {
Vec3 {
x: pos.x as f64 as f32 * self.cell_edge_length + transform.translation.x,
y: pos.y as f64 as f32 * self.cell_edge_length + transform.translation.y,
z: pos.z as f64 as f32 * self.cell_edge_length + transform.translation.z,
}
}
pub fn cell_to_float(&self, pos: &CellCoord) -> DVec3 {
DVec3 {
x: pos.x as f64,
y: pos.y as f64,
z: pos.z as f64,
} * self.cell_edge_length as f64
}
#[inline]
pub fn translation_to_grid(&self, input: impl Into<DVec3>) -> (CellCoord, Vec3) {
let l = self.cell_edge_length as f64;
let input = input.into();
let DVec3 { x, y, z } = input;
if input.abs().max_element() < self.maximum_distance_from_origin as f64 {
return (CellCoord::default(), input.as_vec3());
}
let x_r = round(x / l);
let y_r = round(y / l);
let z_r = round(z / l);
let t_x = x - x_r * l;
let t_y = y - y_r * l;
let t_z = z - z_r * l;
(
CellCoord {
x: x_r as GridPrecision,
y: y_r as GridPrecision,
z: z_r as GridPrecision,
},
Vec3::new(t_x as f32, t_y as f32, t_z as f32),
)
}
#[inline]
pub fn imprecise_translation_to_grid(&self, input: Vec3) -> (CellCoord, Vec3) {
self.translation_to_grid(input.as_dvec3())
}
#[inline]
pub fn global_transform(
&self,
local_cell: &CellCoord,
local_transform: &Transform,
) -> GlobalTransform {
let transform_origin = self.local_floating_origin().grid_transform();
let cell_origin_relative = *local_cell - self.local_floating_origin().cell();
let grid_offset = self.cell_to_float(&cell_origin_relative);
let local_transform = DAffine3::from_scale_rotation_translation(
local_transform.scale.as_dvec3(),
local_transform.rotation.as_dquat(),
local_transform.translation.as_dvec3() + grid_offset,
);
let global_64 = transform_origin * local_transform;
Affine3A {
matrix3: global_64.matrix3.as_mat3().into(),
translation: global_64.translation.as_vec3a(),
}
.into()
}
}
fn round(x: f64) -> f64 {
#[cfg(feature = "libm")]
{
libm::round(x)
}
#[cfg(all(not(feature = "libm"), feature = "std"))]
{
x.round()
}
#[cfg(all(not(feature = "libm"), not(feature = "std")))]
{
compile_error!("Must enable the `libm` and/or `std` feature.");
f64::NAN
}
}