From 13768481d104cd7dba1bfc6bac65fc6df8c3b6f4 Mon Sep 17 00:00:00 2001 From: strawberry Date: Mon, 8 Jul 2024 23:16:17 -0500 Subject: [PATCH 01/31] added MVector in math.rs generally for points and directions in hyperbolic space, replacing na::Vector4 when appropriate added MIsometry in math.rs representing hyperbolic isometries, replacing na::Matrix4 when appropriate to compensate for these changes, added inline functions passing self to respective functions, as well as reimplementing traits moved some functions in math.rs with MIsometry and MVector arguments to respective impls --- common/src/character_controller/collision.rs | 10 +- common/src/character_controller/mod.rs | 2 +- common/src/chunk_collision.rs | 85 +-- common/src/chunk_ray_casting.rs | 29 +- common/src/collision_math.rs | 201 ++++--- common/src/dodeca.rs | 60 +- common/src/graph.rs | 13 +- common/src/graph_collision.rs | 37 +- common/src/math.rs | 544 +++++++++++++++---- common/src/node.rs | 29 +- common/src/plane.rs | 22 +- common/src/proto.rs | 5 +- common/src/sim_config.rs | 6 +- common/src/traversal.rs | 39 +- common/src/worldgen.rs | 5 +- 15 files changed, 699 insertions(+), 388 deletions(-) diff --git a/common/src/character_controller/collision.rs b/common/src/character_controller/collision.rs index 5d0eec0b..464efa2c 100644 --- a/common/src/character_controller/collision.rs +++ b/common/src/character_controller/collision.rs @@ -2,7 +2,7 @@ use tracing::error; -use crate::{collision_math::Ray, graph::Graph, graph_collision, math, proto::Position}; +use crate::{collision_math::Ray, graph::Graph, graph_collision, math, math::{MVector,MIsometry}, proto::Position}; /// Checks for collisions when a character moves with a character-relative displacement vector of `relative_displacement`. pub fn check_collision( @@ -22,7 +22,7 @@ pub fn check_collision( let displacement_norm = displacement_sqr.sqrt(); let displacement_normalized = relative_displacement / displacement_norm; - let ray = Ray::new(math::origin(), displacement_normalized); + let ray = Ray::new(MVector::origin(), MVector::::from(displacement_normalized)); let tanh_distance = displacement_norm.tanh(); let cast_hit = graph_collision::sphere_cast( @@ -58,7 +58,7 @@ pub fn check_collision( // This normal now represents a contact point at the origin, so we omit the w-coordinate // to ensure that it's orthogonal to the origin. normal: na::UnitVector3::new_normalize( - (math::mtranspose(&displacement_transform) * hit.normal).xyz(), + ((displacement_transform.mtranspose()) * hit.normal).xyz(), ), }), } @@ -77,7 +77,7 @@ pub struct CollisionCheckingResult { /// Multiplying the character's position by this matrix will move the character as far as it can up to its intended /// displacement until it hits the wall. - pub displacement_transform: na::Matrix4, + pub displacement_transform: MIsometry, pub collision: Option, } @@ -88,7 +88,7 @@ impl CollisionCheckingResult { pub fn stationary() -> CollisionCheckingResult { CollisionCheckingResult { displacement_vector: na::Vector3::zeros(), - displacement_transform: na::Matrix4::identity(), + displacement_transform: MIsometry::identity(), collision: None, } } diff --git a/common/src/character_controller/mod.rs b/common/src/character_controller/mod.rs index 9b56098f..12ac56d0 100644 --- a/common/src/character_controller/mod.rs +++ b/common/src/character_controller/mod.rs @@ -47,7 +47,7 @@ pub fn run_character_step( } // Renormalize - position.local = math::renormalize_isometry(&position.local); + position.local = position.local.renormalize_isometry(); let (next_node, transition_xf) = graph.normalize_transform(position.node, &position.local); if next_node != position.node { position.node = next_node; diff --git a/common/src/chunk_collision.rs b/common/src/chunk_collision.rs index 3ef1207a..a6217610 100644 --- a/common/src/chunk_collision.rs +++ b/common/src/chunk_collision.rs @@ -1,6 +1,7 @@ use crate::{ collision_math::Ray, math, + math::MVector, node::{ChunkLayout, Coords, VoxelAABB, VoxelData}, world::Material, }; @@ -11,7 +12,7 @@ pub struct ChunkCastHit { /// Represents the normal vector of the hit surface in the dual coordinate system of the chunk. /// To get the actual normal vector, project it so that it is orthogonal to the endpoint in Lorentz space. - pub normal: na::Vector4, + pub normal: MVector, } /// Performs sphere casting (swept collision query) against the voxels in the chunk with the given `voxel_data` @@ -92,10 +93,10 @@ fn find_face_collision( for t in bounding_box.grid_planes(t_axis) { // Find a normal to the grid plane. Note that (t, 0, 0, x) is a normal of the plane whose closest point // to the origin is (x, 0, 0, t), and we use that fact here. - let normal = math::lorentz_normalize(&math::tuv_to_xyz( + let normal = math::tuv_to_xyz( t_axis, - na::Vector4::new(1.0, 0.0, 0.0, layout.grid_to_dual(t)), - )); + MVector::new(1.0, 0.0, 0.0, layout.grid_to_dual(t)), + ).lorentz_normalize(); let Some(new_tanh_distance) = ray.solve_sphere_plane_intersection(&normal, collider_radius.sinh()) @@ -111,7 +112,7 @@ fn find_face_collision( // Which side we approach the plane from affects which voxel we want to use for hit detection. // If exiting a chunk via a chunk boundary, hit detection is handled by a different chunk. // We also want to adjust the normal vector to always face outward from the hit block - let (normal, voxel_t) = if math::mip(&ray.direction, &normal) < 0.0 { + let (normal, voxel_t) = if ray.direction.mip(&normal) < 0.0 { if t == 0 { continue; } @@ -124,7 +125,7 @@ fn find_face_collision( }; let ray_endpoint = ray.ray_point(new_tanh_distance); - let contact_point = ray_endpoint - normal * math::mip(&ray_endpoint, &normal); + let contact_point = ray_endpoint - normal * ray_endpoint.mip(&normal); // Compute the u and v-coordinates of the voxels at the contact point let Some(voxel_u) = layout.dual_to_voxel(contact_point[u_axis] / contact_point.w) else { @@ -171,18 +172,18 @@ fn find_edge_collision( // Loop through all grid lines overlapping the bounding box for (u, v) in bounding_box.grid_lines(u_axis, v_axis) { // Compute vectors Lorentz-orthogonal to the edge and to each other - let edge_normal0 = math::lorentz_normalize(&math::tuv_to_xyz( + let edge_normal0 = math::tuv_to_xyz( t_axis, - na::Vector4::new(0.0, 1.0, 0.0, layout.grid_to_dual(u)), - )); + MVector::new(0.0, 1.0, 0.0, layout.grid_to_dual(u)), + ).lorentz_normalize(); let edge_normal1 = math::tuv_to_xyz( t_axis, - na::Vector4::new(0.0, 0.0, 1.0, layout.grid_to_dual(v)), - ); - let edge_normal1 = math::lorentz_normalize( - &(edge_normal1 - edge_normal0 * math::mip(&edge_normal0, &edge_normal1)), + MVector::new(0.0, 0.0, 1.0, layout.grid_to_dual(v)), ); + let edge_normal1 = + (edge_normal1 - edge_normal0 * edge_normal0.mip(&edge_normal1)) + .lorentz_normalize(); let Some(new_tanh_distance) = ray.solve_sphere_line_intersection( &edge_normal0, @@ -199,8 +200,8 @@ fn find_edge_collision( let ray_endpoint = ray.ray_point(new_tanh_distance); let contact_point = ray_endpoint - - edge_normal0 * math::mip(&ray_endpoint, &edge_normal0) - - edge_normal1 * math::mip(&ray_endpoint, &edge_normal1); + - edge_normal0 * ray_endpoint.mip(&edge_normal0) + - edge_normal1 * ray_endpoint.mip(&edge_normal1); // Compute the t-coordinate of the voxels at the contact point let Some(voxel_t) = layout.dual_to_voxel(contact_point[t_axis] / contact_point.w) else { @@ -256,19 +257,20 @@ fn find_vertex_collision( // Compute vectors Lorentz-orthogonal to the vertex and to each other let vertex_normal0 = - math::lorentz_normalize(&na::Vector4::new(1.0, 0.0, 0.0, layout.grid_to_dual(x))); + MVector::new(1.0, 0.0, 0.0, layout.grid_to_dual(x)) + .lorentz_normalize(); - let vertex_normal1 = na::Vector4::new(0.0, 1.0, 0.0, layout.grid_to_dual(y)); - let vertex_normal1 = math::lorentz_normalize( - &(vertex_normal1 - vertex_normal0 * math::mip(&vertex_normal0, &vertex_normal1)), - ); + let vertex_normal1 = MVector::new(0.0, 1.0, 0.0, layout.grid_to_dual(y)); + let vertex_normal1 = + (vertex_normal1 - vertex_normal0 * vertex_normal0.mip(&vertex_normal1)) + .lorentz_normalize(); - let vertex_normal2 = na::Vector4::new(0.0, 0.0, 1.0, layout.grid_to_dual(z)); - let vertex_normal2 = math::lorentz_normalize( - &(vertex_normal2 - - vertex_normal0 * math::mip(&vertex_normal0, &vertex_normal2) - - vertex_normal1 * math::mip(&vertex_normal1, &vertex_normal2)), - ); + let vertex_normal2 = MVector::new(0.0, 0.0, 1.0, layout.grid_to_dual(z)); + let vertex_normal2 = + (vertex_normal2 + - vertex_normal0 * vertex_normal0.mip(&vertex_normal2) + - vertex_normal1 * vertex_normal1.mip(&vertex_normal2)) + .lorentz_normalize(); let Some(new_tanh_distance) = ray.solve_sphere_point_intersection( &vertex_normal0, @@ -285,12 +287,12 @@ fn find_vertex_collision( } // Determine the cube-centric coordinates of the vertex - let vertex_position = math::lorentz_normalize(&na::Vector4::new( + let vertex_position = MVector::new( layout.grid_to_dual(x), layout.grid_to_dual(y), layout.grid_to_dual(z), 1.0, - )); + ).lorentz_normalize(); // A collision was found. Update the hit. let ray_endpoint = ray.ray_point(new_tanh_distance); @@ -358,29 +360,28 @@ mod tests { ray_end_grid_coords: [f32; 3], wrapped_fn: impl FnOnce(&Ray, f32), ) { - let ray_start = math::lorentz_normalize(&na::Vector4::new( + let ray_start = MVector::new( ray_start_grid_coords[0] / ctx.layout.dual_to_grid_factor(), ray_start_grid_coords[1] / ctx.layout.dual_to_grid_factor(), ray_start_grid_coords[2] / ctx.layout.dual_to_grid_factor(), 1.0, - )); + ).lorentz_normalize(); - let ray_end = math::lorentz_normalize(&na::Vector4::new( + let ray_end = MVector::new( ray_end_grid_coords[0] / ctx.layout.dual_to_grid_factor(), ray_end_grid_coords[1] / ctx.layout.dual_to_grid_factor(), ray_end_grid_coords[2] / ctx.layout.dual_to_grid_factor(), 1.0, - )); + ).lorentz_normalize(); let ray = Ray::new( ray_start, - math::lorentz_normalize( - &((ray_end - ray_start) - + ray_start * math::mip(&ray_start, &(ray_end - ray_start))), - ), + ((ray_end - ray_start) + + ray_start * ray_start.mip(&(ray_end - ray_start))) + .lorentz_normalize(), ); - let tanh_distance = (-math::mip(&ray_start, &ray_end)).acosh(); + let tanh_distance = (-ray_start.mip(&ray_end)).acosh(); wrapped_fn(&ray, tanh_distance) } @@ -520,16 +521,16 @@ mod tests { // The ray we care about is after its start point has moved to the contact point. let ray = math::translate( &ray.position, - &math::lorentz_normalize(&ray.ray_point(hit.tanh_distance)), + &ray.ray_point(hit.tanh_distance).lorentz_normalize(), ) * ray; // Project normal to be perpendicular to the ray's position - let corrected_normal = math::lorentz_normalize( - &(hit.normal + ray.position * math::mip(&hit.normal, &ray.position)), - ); + let corrected_normal = + (hit.normal + ray.position * hit.normal.mip(&ray.position)) + .lorentz_normalize(); // Check that the normal and ray are pointing opposite directions - assert!(math::mip(&corrected_normal, &ray.direction) < 0.0); + assert!(corrected_normal.mip(&ray.direction) < 0.0); } /// Tests that a suitable collision is found when approaching a single voxel from various angles and that diff --git a/common/src/chunk_ray_casting.rs b/common/src/chunk_ray_casting.rs index 71453e1d..e03a9092 100644 --- a/common/src/chunk_ray_casting.rs +++ b/common/src/chunk_ray_casting.rs @@ -1,6 +1,7 @@ use crate::{ collision_math::Ray, math, + math::MVector, node::{ChunkLayout, CoordAxis, CoordDirection, Coords, VoxelAABB, VoxelData}, world::Material, }; @@ -71,10 +72,10 @@ fn find_face_collision( for t in bounding_box.grid_planes(t_axis) { // Find a normal to the grid plane. Note that (t, 0, 0, x) is a normal of the plane whose closest point // to the origin is (x, 0, 0, t), and we use that fact here. - let normal = math::lorentz_normalize(&math::tuv_to_xyz( + let normal = math::tuv_to_xyz( t_axis, - na::Vector4::new(1.0, 0.0, 0.0, layout.grid_to_dual(t)), - )); + MVector::new(1.0, 0.0, 0.0, layout.grid_to_dual(t)), + ).lorentz_normalize(); let Some(new_tanh_distance) = ray.solve_point_plane_intersection(&normal) else { continue; @@ -88,7 +89,7 @@ fn find_face_collision( // Which side we approach the plane from affects which voxel we want to use for hit detection. // If exiting a chunk via a chunk boundary, hit detection is handled by a different chunk. // We also want to retain this face_direction for reporting the hit result later. - let (face_direction, voxel_t) = if math::mip(&ray.direction, &normal) < 0.0 { + let (face_direction, voxel_t) = if ray.direction.mip(&normal) < 0.0 { if t == 0 { continue; } @@ -101,7 +102,7 @@ fn find_face_collision( }; let ray_endpoint = ray.ray_point(new_tanh_distance); - let contact_point = ray_endpoint - normal * math::mip(&ray_endpoint, &normal); + let contact_point = ray_endpoint - normal * ray_endpoint.mip(&normal); // Compute the u and v-coordinates of the voxels at the contact point let Some(voxel_u) = layout.dual_to_voxel(contact_point[u_axis] / contact_point.w) else { @@ -185,29 +186,29 @@ mod tests { ray_end_grid_coords: [f32; 3], wrapped_fn: impl FnOnce(&Ray, f32), ) { - let ray_start = math::lorentz_normalize(&na::Vector4::new( + let ray_start = MVector::new( ray_start_grid_coords[0] / ctx.layout.dual_to_grid_factor(), ray_start_grid_coords[1] / ctx.layout.dual_to_grid_factor(), ray_start_grid_coords[2] / ctx.layout.dual_to_grid_factor(), 1.0, - )); + ).lorentz_normalize(); - let ray_end = math::lorentz_normalize(&na::Vector4::new( + let ray_end = MVector::new( ray_end_grid_coords[0] / ctx.layout.dual_to_grid_factor(), ray_end_grid_coords[1] / ctx.layout.dual_to_grid_factor(), ray_end_grid_coords[2] / ctx.layout.dual_to_grid_factor(), 1.0, - )); + ).lorentz_normalize(); let ray = Ray::new( ray_start, - math::lorentz_normalize( - &((ray_end - ray_start) - + ray_start * math::mip(&ray_start, &(ray_end - ray_start))), - ), + ( + ((ray_end - ray_start) + + ray_start * ray_start.mip(&(ray_end - ray_start))), + ).lorentz_normalize(), ); - let tanh_distance = (-math::mip(&ray_start, &ray_end)).acosh(); + let tanh_distance = (- (ray_start.mip(&ray_end))).acosh(); wrapped_fn(&ray, tanh_distance) } diff --git a/common/src/collision_math.rs b/common/src/collision_math.rs index b64f2eed..3766e918 100644 --- a/common/src/collision_math.rs +++ b/common/src/collision_math.rs @@ -1,15 +1,16 @@ use crate::math; +use crate::math::{MVector,MIsometry}; /// A ray in hyperbolic space. The fields must be lorentz normalized, with `mip(position, position) == -1`, /// `mip(direction, direction) == 1`, and `mip(position, direction) == 0`. #[derive(Debug)] pub struct Ray { - pub position: na::Vector4, - pub direction: na::Vector4, + pub position: MVector, + pub direction: MVector, } impl Ray { - pub fn new(position: na::Vector4, direction: na::Vector4) -> Ray { + pub fn new(position: MVector, direction: MVector) -> Ray { Ray { position, direction, @@ -18,7 +19,7 @@ impl Ray { /// Returns a point along this ray `atanh(tanh_distance)` units away from the origin. This point /// is _not_ lorentz normalized. - pub fn ray_point(&self, tanh_distance: f32) -> na::Vector4 { + pub fn ray_point(&self, tanh_distance: f32) -> MVector { self.position + self.direction * tanh_distance } @@ -26,11 +27,11 @@ impl Ray { /// intersects the given plane. pub fn solve_sphere_plane_intersection( &self, - plane_normal: &na::Vector4, + plane_normal: &MVector, sinh_radius: f32, ) -> Option { - let mip_pos_a = math::mip(&self.position, plane_normal); - let mip_dir_a = math::mip(&self.direction, plane_normal); + let mip_pos_a = self.position.mip(plane_normal); + let mip_dir_a = self.direction.mip(plane_normal); solve_quadratic( mip_pos_a.powi(2) - sinh_radius.powi(2), @@ -43,14 +44,14 @@ impl Ray { /// intersects the given line. pub fn solve_sphere_line_intersection( &self, - line_normal0: &na::Vector4, - line_normal1: &na::Vector4, + line_normal1: &MVector, + line_normal0: &MVector, sinh_radius: f32, ) -> Option { - let mip_pos_a = math::mip(&self.position, line_normal0); - let mip_dir_a = math::mip(&self.direction, line_normal0); - let mip_pos_b = math::mip(&self.position, line_normal1); - let mip_dir_b = math::mip(&self.direction, line_normal1); + let mip_pos_a = &self.position.mip(line_normal0); + let mip_dir_a = &self.direction.mip(line_normal0); + let mip_pos_b = &self.position.mip(line_normal1); + let mip_dir_b = &self.direction.mip(line_normal1); solve_quadratic( mip_pos_a.powi(2) + mip_pos_b.powi(2) - sinh_radius.powi(2), @@ -63,17 +64,17 @@ impl Ray { /// intersects the given point. pub fn solve_sphere_point_intersection( &self, - point_normal0: &na::Vector4, - point_normal1: &na::Vector4, - point_normal2: &na::Vector4, + point_normal0: &MVector, + point_normal1: &MVector, + point_normal2: &MVector, sinh_radius: f32, ) -> Option { - let mip_pos_a = math::mip(&self.position, point_normal0); - let mip_dir_a = math::mip(&self.direction, point_normal0); - let mip_pos_b = math::mip(&self.position, point_normal1); - let mip_dir_b = math::mip(&self.direction, point_normal1); - let mip_pos_c = math::mip(&self.position, point_normal2); - let mip_dir_c = math::mip(&self.direction, point_normal2); + let mip_pos_a = &self.position.mip(point_normal0); + let mip_dir_a = &self.direction.mip(point_normal0); + let mip_pos_b = &self.position.mip(point_normal1); + let mip_dir_b = &self.direction.mip(point_normal1); + let mip_pos_c = &self.position.mip(point_normal2); + let mip_dir_c = &self.direction.mip(point_normal2); solve_quadratic( mip_pos_a.powi(2) + mip_pos_b.powi(2) + mip_pos_c.powi(2) - sinh_radius.powi(2), @@ -84,9 +85,9 @@ impl Ray { /// Finds the tanh of the distance a point will have to travel along a ray before it /// intersects the given plane. - pub fn solve_point_plane_intersection(&self, plane_normal: &na::Vector4) -> Option { - let mip_pos_a = math::mip(&self.position, plane_normal); - let mip_dir_a = math::mip(&self.direction, plane_normal); + pub fn solve_point_plane_intersection(&self, plane_normal: &MVector) -> Option { + let mip_pos_a = &self.position.mip(plane_normal); + let mip_dir_a = &self.direction.mip(plane_normal); let result = -mip_pos_a / mip_dir_a; if result.is_finite() && result > 0.0 { @@ -97,7 +98,7 @@ impl Ray { } } -impl std::ops::Mul<&Ray> for na::Matrix4 { +impl std::ops::Mul<&Ray> for MIsometry { type Output = Ray; #[inline] @@ -157,16 +158,16 @@ mod tests { fn solve_sphere_plane_intersection_example() { // Hit the z=0 plane with a radius of 0.2 let ray = math::translate_along(&na::Vector3::new(0.0, 0.0, -0.5)) - * &Ray::new(math::origin(), na::Vector4::new(0.8, 0.0, 0.6, 0.0)); - let normal = -na::Vector4::z(); - let hit_point = math::lorentz_normalize( - &ray.ray_point( - ray.solve_sphere_plane_intersection(&normal, 0.2_f32.sinh()) - .unwrap(), - ), - ); + * &Ray::new(MVector::origin(), MVector::new(0.8, 0.0, 0.6, 0.0)); + let normal = -MVector::z(); + let hit_point = + ray.ray_point( + ray.solve_sphere_plane_intersection(&normal, 0.2_f32.sinh()) + .unwrap(), + ).lorentz_normalize(); + assert_abs_diff_eq!( - math::mip(&hit_point, &normal), + hit_point.mip(&normal), 0.2_f32.sinh(), epsilon = 1e-4 ); @@ -176,8 +177,8 @@ mod tests { fn solve_sphere_plane_intersection_direct_hit() { // Directly hit the z=0 plane with a ray 0.5 units away and a radius of 0.2. let ray = math::translate_along(&na::Vector3::new(0.0, 0.0, -0.5)) - * &Ray::new(math::origin(), na::Vector4::z()); - let normal = -na::Vector4::z(); + * &Ray::new(MVector::origin(), MVector::z()); + let normal = -MVector::z(); assert_abs_diff_eq!( ray.solve_sphere_plane_intersection(&normal, 0.2_f32.sinh()) .unwrap(), @@ -190,8 +191,8 @@ mod tests { fn solve_sphere_plane_intersection_miss() { // No collision with the plane anywhere along the ray's line let ray = math::translate_along(&na::Vector3::new(0.0, 0.0, -0.5)) - * &Ray::new(math::origin(), na::Vector4::x()); - let normal = -na::Vector4::z(); + * &Ray::new(MVector::origin(), MVector::x()); + let normal = -MVector::z(); assert!(ray .solve_sphere_plane_intersection(&normal, 0.2_f32.sinh()) .is_none()); @@ -201,8 +202,8 @@ mod tests { fn solve_sphere_plane_intersection_margin() { // Sphere is already contacting the plane, with some error let ray = math::translate_along(&na::Vector3::new(0.0, 0.0, -0.2)) - * &Ray::new(math::origin(), na::Vector4::z()); - let normal = -na::Vector4::z(); + * &Ray::new(MVector::origin(), MVector::z()); + let normal = -MVector::z(); assert_eq!( ray.solve_sphere_plane_intersection(&normal, 0.2001_f32.sinh()) .unwrap(), @@ -215,21 +216,20 @@ mod tests { // Hit the x=z=0 line with a radius of 0.2 let ray = math::translate_along(&na::Vector3::new(0.0, 0.0, -0.5)) * &Ray::new( - math::origin(), - na::Vector4::new(1.0, 2.0, 3.0, 0.0).normalize(), + MVector::origin(), + MVector::new(1.0, 2.0, 3.0, 0.0).normalize(), ); - let line_normal0 = na::Vector4::x(); - let line_normal1 = na::Vector4::z(); - let hit_point = math::lorentz_normalize( - &ray.ray_point( - ray.solve_sphere_line_intersection(&line_normal0, &line_normal1, 0.2_f32.sinh()) - .unwrap(), - ), - ); + let line_normal0 = MVector::x(); + let line_normal1 = MVector::z(); + let hit_point = + ray.ray_point( + ray.solve_sphere_line_intersection(&line_normal0, &line_normal1, 0.2_f32.sinh()) + .unwrap(), + ).lorentz_normalize(); // Measue the distance from hit_point to the line and ensure it's equal to the radius assert_abs_diff_eq!( - (math::mip(&hit_point, &line_normal0).powi(2) - + math::mip(&hit_point, &line_normal1).powi(2)) + (hit_point.mip(&line_normal0).powi(2) + + hit_point.mip(&line_normal1).powi(2)) .sqrt(), 0.2_f32.sinh(), epsilon = 1e-4 @@ -243,9 +243,9 @@ mod tests { // Ensure the ray is slightly off-center so that the distance math is shown to be correct let ray = math::translate_along(&na::Vector3::new(0.0, 0.7, 0.0)) * math::translate_along(&na::Vector3::new(0.0, 0.0, -0.5)) - * &Ray::new(math::origin(), na::Vector4::z()); - let line_normal0 = na::Vector4::x(); - let line_normal1 = na::Vector4::z(); + * &Ray::new(MVector::origin(), MVector::z()); + let line_normal0 = MVector::x(); + let line_normal1 = MVector::z(); assert_abs_diff_eq!( ray.solve_sphere_line_intersection(&line_normal0, &line_normal1, 0.2_f32.sinh()) .unwrap(), @@ -258,9 +258,9 @@ mod tests { fn solve_sphere_line_intersection_miss() { // No collision with the line anywhere along the ray's line let ray = math::translate_along(&na::Vector3::new(0.0, 0.0, -0.5)) - * &Ray::new(math::origin(), na::Vector4::x()); - let line_normal0 = na::Vector4::x(); - let line_normal1 = na::Vector4::z(); + * &Ray::new(MVector::origin(), MVector::x()); + let line_normal0 = MVector::x(); + let line_normal1 = MVector::z(); assert!(ray .solve_sphere_line_intersection(&line_normal0, &line_normal1, 0.2_f32.sinh()) .is_none()); @@ -270,9 +270,9 @@ mod tests { fn solve_sphere_line_intersection_margin() { // Sphere is already contacting the line, with some error let ray = math::translate_along(&na::Vector3::new(0.0, 0.0, -0.2)) - * &Ray::new(math::origin(), na::Vector4::z()); - let line_normal0 = na::Vector4::x(); - let line_normal1 = na::Vector4::z(); + * &Ray::new(MVector::origin(), MVector::z()); + let line_normal0 = MVector::x(); + let line_normal1 = MVector::z(); assert_eq!( ray.solve_sphere_line_intersection(&line_normal0, &line_normal1, 0.2001_f32.sinh()) .unwrap(), @@ -288,11 +288,11 @@ mod tests { // Similar reasoning can also apply to `solve_sphere_point_intersection` even though it is // not tested explicitly in the same way. let ray = Ray::new( - na::Vector4::new(-0.019093871, -0.0014823675, 0.059645057, 1.0019588), - na::Vector4::new(-0.02954007, 0.9965602, 0.07752046, 0.003702946), + MVector::new(-0.019093871, -0.0014823675, 0.059645057, 1.0019588), + MVector::new(-0.02954007, 0.9965602, 0.07752046, 0.003702946), ); - let line_normal0 = na::Vector4::::x(); - let line_normal1 = na::Vector4::::y(); + let line_normal0 = MVector::::x(); + let line_normal1 = MVector::::y(); let radius = 0.019090926_f32; // The following returns wrong results in the other implementation, so we test this case // to make sure there are no regressions. @@ -306,26 +306,25 @@ mod tests { // Hit the origin with a radius of 0.2 let ray = math::translate_along(&na::Vector3::new(0.0, 0.0, -0.5)) * &Ray::new( - math::origin(), - na::Vector4::new(1.0, 2.0, 6.0, 0.0).normalize(), + math::MVector::origin(), + MVector::new(1.0, 2.0, 6.0, 0.0).normalize(), ); - let point_position = math::origin(); - let point_normal0 = na::Vector4::x(); - let point_normal1 = na::Vector4::y(); - let point_normal2 = na::Vector4::z(); - let hit_point = math::lorentz_normalize( - &ray.ray_point( - ray.solve_sphere_point_intersection( - &point_normal0, - &point_normal1, - &point_normal2, - 0.2_f32.sinh(), - ) - .unwrap(), - ), - ); + let point_position = math::MVector::origin(); + let point_normal0 = MVector::x(); + let point_normal1 = MVector::y(); + let point_normal2 = MVector::z(); + let hit_point = + ray.ray_point( + ray.solve_sphere_point_intersection( + &point_normal0, + &point_normal1, + &point_normal2, + 0.2_f32.sinh(), + ) + .unwrap(), + ).lorentz_normalize(); assert_abs_diff_eq!( - -math::mip(&hit_point, &point_position), + - hit_point.mip(&point_position), 0.2_f32.cosh(), epsilon = 1e-4 ); @@ -335,10 +334,10 @@ mod tests { fn solve_sphere_point_intersection_direct_hit() { // Directly hit the origin with a ray 0.5 units away and a radius of 0.2. let ray = math::translate_along(&na::Vector3::new(0.0, 0.0, -0.5)) - * &Ray::new(math::origin(), na::Vector4::z()); - let point_normal0 = na::Vector4::x(); - let point_normal1 = na::Vector4::y(); - let point_normal2 = na::Vector4::z(); + * &Ray::new(MVector::origin(), MVector::z()); + let point_normal0 = MVector::x(); + let point_normal1 = MVector::y(); + let point_normal2 = MVector::z(); assert_abs_diff_eq!( ray.solve_sphere_point_intersection( &point_normal0, @@ -356,10 +355,10 @@ mod tests { fn solve_sphere_point_intersection_miss() { // No collision with the point anywhere along the ray's line let ray = math::translate_along(&na::Vector3::new(0.0, 0.0, -0.5)) - * &Ray::new(math::origin(), na::Vector4::x()); - let point_normal0 = na::Vector4::x(); - let point_normal1 = na::Vector4::y(); - let point_normal2 = na::Vector4::z(); + * &Ray::new(MVector::origin(), MVector::x()); + let point_normal0 = MVector::x(); + let point_normal1 = MVector::y(); + let point_normal2 = MVector::z(); assert!(ray .solve_sphere_point_intersection( &point_normal0, @@ -374,10 +373,10 @@ mod tests { fn solve_sphere_point_intersection_margin() { // Sphere is already contacting the point, with some error let ray = math::translate_along(&na::Vector3::new(0.0, 0.0, -0.2)) - * &Ray::new(math::origin(), na::Vector4::z()); - let point_normal0 = na::Vector4::x(); - let point_normal1 = na::Vector4::y(); - let point_normal2 = na::Vector4::z(); + * &Ray::new(MVector::origin(), MVector::z()); + let point_normal0 = MVector::x(); + let point_normal1 = MVector::y(); + let point_normal2 = MVector::z(); assert_eq!( ray.solve_sphere_point_intersection( &point_normal0, @@ -394,12 +393,10 @@ mod tests { fn foo() { // Hit the z=0 plane let ray = math::translate_along(&na::Vector3::new(0.0, 0.0, -0.5)) - * &Ray::new(math::origin(), na::Vector4::new(0.8, 0.0, 0.6, 0.0)); - let normal = -na::Vector4::z(); - let hit_point = math::lorentz_normalize( - &ray.ray_point(ray.solve_point_plane_intersection(&normal).unwrap()), - ); - assert_abs_diff_eq!(math::mip(&hit_point, &normal), 0.0, epsilon = 1e-4); + * &Ray::new(MVector::origin(), MVector::new(0.8, 0.0, 0.6, 0.0)); + let normal = -MVector::z(); + let hit_point = ray.ray_point(ray.solve_point_plane_intersection(&normal).unwrap()).lorentz_normalize(); + assert_abs_diff_eq!(hit_point.mip(&normal), 0.0, epsilon = 1e-4); } #[test] diff --git a/common/src/dodeca.rs b/common/src/dodeca.rs index fc7276d1..cbc98850 100644 --- a/common/src/dodeca.rs +++ b/common/src/dodeca.rs @@ -4,6 +4,7 @@ use lazy_static::lazy_static; use serde::{Deserialize, Serialize}; use crate::math; +use crate::math::{MVector,MIsometry}; /// Sides of a right dodecahedron #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] @@ -45,21 +46,21 @@ impl Side { /// Outward normal vector of this side #[inline] - pub fn normal(self) -> &'static na::Vector4 { + pub fn normal(self) -> &'static MVector { &SIDE_NORMALS[self as usize] } /// Reflection across this side #[inline] - pub fn reflection(self) -> &'static na::Matrix4 { + pub fn reflection(self) -> &'static MIsometry { &REFLECTIONS[self as usize] } /// Whether `p` is opposite the dodecahedron across the plane containing `self` #[inline] - pub fn is_facing(self, p: &na::Vector4) -> bool { + pub fn is_facing(self, p: &MVector) -> bool { let r = na::convert::<_, na::RowVector4>(self.reflection().row(3).clone_owned()); - (r * p).x < p.w + (r * *p).x < p.w } } @@ -139,21 +140,21 @@ impl Vertex { /// Transform from euclidean chunk coordinates to hyperbolic node space pub fn chunk_to_node(self) -> na::Matrix4 { - self.dual_to_node() * na::Matrix4::new_scaling(1.0 / Self::dual_to_chunk_factor()) + as Into>>::into(*self.dual_to_node()) * na::Matrix4::new_scaling(1.0 / Self::dual_to_chunk_factor()) } /// Transform from hyperbolic node space to euclidean chunk coordinates pub fn node_to_chunk(self) -> na::Matrix4 { - na::Matrix4::new_scaling(Self::dual_to_chunk_factor()) * self.node_to_dual() + na::Matrix4::new_scaling(Self::dual_to_chunk_factor()) * as Into>>::into(*self.node_to_dual()) } /// Transform from cube-centric coordinates to dodeca-centric coordinates - pub fn dual_to_node(self) -> &'static na::Matrix4 { + pub fn dual_to_node(self) -> &'static MIsometry { &DUAL_TO_NODE[self as usize] } /// Transform from dodeca-centric coordinates to cube-centric coordinates - pub fn node_to_dual(self) -> &'static na::Matrix4 { + pub fn node_to_dual(self) -> &'static MIsometry { &NODE_TO_DUAL[self as usize] } @@ -173,7 +174,7 @@ impl Vertex { /// Convenience method for `self.chunk_to_node().determinant() < 0`. pub fn parity(self) -> bool { - CHUNK_TO_NODE_PARITY[self as usize] + DUAL_TO_NODE_PARITY[self as usize] } } @@ -197,11 +198,11 @@ lazy_static! { }; /// Vector corresponding to the outer normal of each side - static ref SIDE_NORMALS: [na::Vector4; SIDE_COUNT] = { + static ref SIDE_NORMALS: [MVector; SIDE_COUNT] = { let phi = libm::sqrt(1.25) + 0.5; // golden ratio - let f = math::lorentz_normalize(&na::Vector4::new(1.0, phi, 0.0, libm::sqrt(phi))); + let f = MVector::new(1.0, phi, 0.0, libm::sqrt(phi)).lorentz_normalize(); - let mut result: [na::Vector4; SIDE_COUNT] = [na::zero(); SIDE_COUNT]; + let mut result: [MVector; SIDE_COUNT] = [MVector::zero(); SIDE_COUNT]; let mut i = 0; for (x, y, z, w) in [ (f.x, f.y, f.z, f.w), @@ -211,7 +212,7 @@ lazy_static! { ] { for (x, y, z, w) in [(x, y, z, w), (y, z, x, w), (z, x, y, w)] { - result[i] = na::Vector4::new(x, y, z, w); + result[i] = MVector::new(x, y, z, w); i += 1; } } @@ -219,8 +220,8 @@ lazy_static! { }; /// Transform that moves from a neighbor to a reference node, for each side - static ref REFLECTIONS: [na::Matrix4; SIDE_COUNT] = { - SIDE_NORMALS.map(|r| math::reflect(&r)) + static ref REFLECTIONS: [MIsometry; SIDE_COUNT] = { + SIDE_NORMALS.map(|r| r.reflect()) }; /// Sides incident to a vertex, in canonical order @@ -267,22 +268,21 @@ lazy_static! { }; /// Transform that converts from cube-centric coordinates to dodeca-centric coordinates - static ref DUAL_TO_NODE: [na::Matrix4; VERTEX_COUNT] = { - let mip_origin_normal = math::mip(&math::origin(), &SIDE_NORMALS[0]); // This value is the same for every side - let mut result = [na::zero(); VERTEX_COUNT]; + static ref DUAL_TO_NODE: [MIsometry; VERTEX_COUNT] = { + let mip_origin_normal = MVector::origin().mip(&SIDE_NORMALS[0]); // This value is the same for every side + let mut result = [MIsometry::identity(); VERTEX_COUNT]; for i in 0..VERTEX_COUNT { let [a, b, c] = VERTEX_SIDES[i]; - let vertex_position = math::lorentz_normalize( - &(math::origin() - (a.normal() + b.normal() + c.normal()) * mip_origin_normal), - ); - result[i] = na::Matrix4::from_columns(&[-a.normal(), -b.normal(), -c.normal(), vertex_position]); + let vertex_position = (MVector::origin() - (*a.normal() + *b.normal() + *c.normal()) * mip_origin_normal).lorentz_normalize(); + result[i] = MIsometry::from_columns_unchecked(&[-*a.normal(), -*b.normal(), -*c.normal(), vertex_position]); } result + }; /// Transform that converts from dodeca-centric coordinates to cube-centric coordinates - static ref NODE_TO_DUAL: [na::Matrix4; VERTEX_COUNT] = { - DUAL_TO_NODE.map(|m| math::mtranspose(&m)) + static ref NODE_TO_DUAL: [MIsometry; VERTEX_COUNT] = { + DUAL_TO_NODE.map(|m| m.mtranspose()) }; static ref DUAL_TO_CHUNK_FACTOR: f64 = (2.0 + 5.0f64.sqrt()).sqrt(); @@ -317,11 +317,11 @@ lazy_static! { }; /// Whether the determinant of the cube-to-node transform is negative - static ref CHUNK_TO_NODE_PARITY: [bool; VERTEX_COUNT] = { + static ref DUAL_TO_NODE_PARITY: [bool; VERTEX_COUNT] = { let mut result = [false; VERTEX_COUNT]; for v in Vertex::iter() { - result[v as usize] = math::parity(&v.chunk_to_node()); + result[v as usize] = v.dual_to_node().parity(); } result @@ -364,17 +364,17 @@ mod tests { #[test] fn side_is_facing() { for side in Side::iter() { - assert!(!side.is_facing::(&math::origin())); - assert!(side.is_facing(&(side.reflection() * math::origin()))); + assert!(!side.is_facing::(&MVector::origin())); + assert!(side.is_facing(&(side.reflection() * MVector::origin()))); } } #[test] fn radius() { - let corner = Vertex::A.chunk_to_node() * math::origin(); + let corner = Vertex::A.chunk_to_node() * MVector::origin(); assert_abs_diff_eq!( BOUNDING_SPHERE_RADIUS, - math::distance(&corner, &math::origin()), + math::distance(&corner, &MVector::origin()), epsilon = 1e-10 ); let phi = (1.0 + 5.0f64.sqrt()) / 2.0; // Golden ratio diff --git a/common/src/graph.rs b/common/src/graph.rs index ab2922ae..041f574a 100644 --- a/common/src/graph.rs +++ b/common/src/graph.rs @@ -9,6 +9,7 @@ use serde::{Deserialize, Serialize}; use crate::{ dodeca::{Side, SIDE_COUNT}, math, + math::{MIsometry,MVector}, node::{ChunkId, ChunkLayout, Node}, }; @@ -123,10 +124,10 @@ impl Graph { pub fn normalize_transform( &self, mut reference: NodeId, - original: &na::Matrix4, - ) -> (NodeId, na::Matrix4) { - let mut transform = na::Matrix4::identity(); - let mut location = original * math::origin(); + original: &MIsometry, + ) -> (NodeId, MIsometry) { + let mut transform = MIsometry::identity(); + let mut location = *original * MVector::origin(); 'outer: loop { for side in Side::iter() { if !side.is_facing(&location) { @@ -402,9 +403,9 @@ mod tests { let a = graph.ensure_neighbor(NodeId::ROOT, Side::A); { let (node, xf) = - graph.normalize_transform::(NodeId::ROOT, &na::Matrix4::identity()); + graph.normalize_transform::(NodeId::ROOT, &MIsometry::identity()); assert_eq!(node, NodeId::ROOT); - assert_abs_diff_eq!(xf, na::Matrix4::identity(), epsilon = 1e-5); + assert_abs_diff_eq!(xf, MIsometry::identity(), epsilon = 1e-5); } { let (node, xf) = graph.normalize_transform(NodeId::ROOT, Side::A.reflection()); diff --git a/common/src/graph_collision.rs b/common/src/graph_collision.rs index 4c388f43..1cc14bd6 100644 --- a/common/src/graph_collision.rs +++ b/common/src/graph_collision.rs @@ -3,6 +3,7 @@ use crate::{ collision_math::Ray, graph::Graph, math, + math::{MVector, MIsometry}, node::{Chunk, ChunkId}, proto::Position, traversal::RayTraverser, @@ -56,7 +57,7 @@ pub fn sphere_cast( Some(GraphCastHit { tanh_distance: hit.tanh_distance, chunk, - normal: math::mtranspose(&transform) * hit.normal, + normal: transform.mtranspose() * hit.normal, }) }); } @@ -79,7 +80,7 @@ pub struct GraphCastHit { /// Represents the normal vector of the hit surface in the original coordinate system /// of the sphere casting. To get the actual normal vector, project it so that it is orthogonal /// to the endpoint in Lorentz space. - pub normal: na::Vector4, + pub normal: MVector, } #[cfg(test)] @@ -169,38 +170,36 @@ mod tests { } // Find the transform of the chosen chunk - let chosen_chunk_transform: na::Matrix4 = + let chosen_chunk_transform: MIsometry = self.chosen_voxel.node_path.iter().fold( - na::Matrix4::identity(), - |transform: na::Matrix4, side| transform * side.reflection().cast::(), - ) * self.chosen_voxel.vertex.dual_to_node().cast(); + MIsometry::identity(), + |transform: MIsometry, side| transform * side.reflection().to_f32(), + ) * self.chosen_voxel.vertex.dual_to_node().to_f32(); let dual_to_grid_factor = graph.layout().dual_to_grid_factor(); let ray_target = chosen_chunk_transform - * math::lorentz_normalize(&na::Vector4::new( + * MVector::new( self.chosen_chunk_relative_grid_ray_end[0] / dual_to_grid_factor, self.chosen_chunk_relative_grid_ray_end[1] / dual_to_grid_factor, self.chosen_chunk_relative_grid_ray_end[2] / dual_to_grid_factor, 1.0, - )); + ).lorentz_normalize(); - let ray_position = Vertex::A.dual_to_node().cast() - * math::lorentz_normalize(&na::Vector4::new( + let ray_position = Vertex::A.dual_to_node().to_f32() + * MVector::new( self.start_chunk_relative_grid_ray_start[0] / dual_to_grid_factor, self.start_chunk_relative_grid_ray_start[1] / dual_to_grid_factor, self.start_chunk_relative_grid_ray_start[2] / dual_to_grid_factor, 1.0, - )); + ).lorentz_normalize(); let ray_direction = ray_target - ray_position; let ray = Ray::new( ray_position, - math::lorentz_normalize( - &(ray_direction + ray_position * math::mip(&ray_position, &ray_direction)), - ), + (ray_direction + ray_position * ray_position.mip(&ray_direction)).lorentz_normalize(), ); - let tanh_distance = ((-math::mip(&ray_position, &ray_target)).acosh() + let tanh_distance = ((-ray_position.mip(&ray_target)).acosh() + self.ray_length_modifier) .tanh(); @@ -221,7 +220,7 @@ mod tests { "collision occurred in wrong chunk" ); assert!( - math::mip(&hit.as_ref().unwrap().normal, &ray.direction) < 0.0, + hit.as_ref().unwrap().normal.mip(&ray.direction) < 0.0, "normal is facing the wrong way" ); } else { @@ -435,13 +434,13 @@ mod tests { } // The node coordinates of the corner of the missing node - let vertex_pos = Vertex::A.dual_to_node().cast::() * math::origin(); + let vertex_pos = Vertex::A.dual_to_node().to_f32() * MVector::origin(); // Use a ray starting from the origin. The direction vector is vertex_pos with the w coordinate // set to 0 and normalized let ray = Ray::new( - math::origin(), - (vertex_pos - na::Vector4::w() * vertex_pos.w).normalize(), + MVector::origin(), + (vertex_pos - MVector::w() * vertex_pos.w).normalize(), ); let sphere_radius = 0.1; diff --git a/common/src/math.rs b/common/src/math.rs index 1c6c3d6b..800d6df9 100644 --- a/common/src/math.rs +++ b/common/src/math.rs @@ -3,62 +3,409 @@ //! Vector4 values are assumed to be homogeneous Klein model coordinates unless otherwise //! stated. Note that Minkowski model coordinates are valid Klein coordinates, but not vis versa. +// all the inline functions are basically just wrappers around corresponding nalgebra functions + use na::{RealField, Scalar}; use serde::{Deserialize, Serialize}; +use std::ops::*; + +#[derive(Debug, Copy, Clone, Serialize, Deserialize,PartialEq)] +#[repr(C)] +pub struct MVector(na::Vector4); -/// A point on the surface of the 3D hyperboloid in Minkowski coordinates with an implicit w -#[derive(Debug, Copy, Clone, Serialize, Deserialize)] +#[derive(Debug, Copy, Clone, Serialize, Deserialize,PartialEq)] #[repr(C)] -pub struct HPoint(na::Vector3); +pub struct MIsometry(na::Matrix4); + +#[cfg(test)] +impl approx::AbsDiffEq> for MIsometry +{ + type Epsilon = N; + #[inline] + fn default_epsilon() -> Self::Epsilon + { + na::Matrix4::::default_epsilon() + } + #[inline] + fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool + { + self.abs_diff_eq(other, epsilon) + } +} + +#[cfg(test)] +impl approx::AbsDiffEq> for MVector +{ + type Epsilon = N; + #[inline] + fn default_epsilon() -> Self::Epsilon + { + na::Vector4::::default_epsilon() + } + #[inline] + fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool + { + self.abs_diff_eq(other, epsilon) + } +} + +impl From>> for MVector +{ + fn from(value: na::Unit>) -> Self + { + Self(value.into_inner().push(na::zero())) + } +} + +impl From> for MVector +{ + fn from(value: na::Vector4) -> Self + { + Self(value) + } +} -impl HPoint { - pub fn new(x: N, y: N, z: N) -> Self { - Self(na::Vector3::new(x, y, z)) +impl Deref for MVector +{ + type Target = na::coordinates::XYZW; + #[inline] + fn deref(&self) -> &Self::Target + { + self.0.deref() } +} - /// Construct from Minkowski coordinates - pub fn from_homogeneous(v: &na::Vector4) -> Self { - Self(v.xyz()) +impl DerefMut for MVector { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target + { + self.0.deref_mut() } } -impl HPoint { - pub fn origin() -> Self { - Self::new(na::zero(), na::zero(), na::zero()) +impl Deref for MIsometry { + type Target = na::coordinates::M4x4; + #[inline] + fn deref(&self) -> &Self::Target + { + self.0.deref() } +} - /// Convert to Minkowski coordinates - pub fn to_homogeneous(self) -> na::Vector4 { +impl Into> for MIsometry +{ + fn into(self) -> na::Matrix4 + { + self.0 + } +} + + +impl MIsometry +{ + pub fn to_f64(self) -> MIsometry + { + MIsometry(self.0.cast::()) + } +} + +impl MIsometry +{ + pub fn to_f32(self) -> MIsometry + { + MIsometry(self.0.cast::()) + } +} + +impl MVector +{ + pub fn to_f64(self) -> MVector + { + MVector(self.0.cast::()) + } +} + +impl MVector +{ + pub fn to_f32(self) -> MVector + { + MVector(self.0.cast::()) + } +} + +impl MIsometry +{ + #[inline] + pub fn row(self, i: usize) -> na::Vector4 + { + self.row(i) + } + #[inline] + pub fn identity() -> Self + { + Self(na::Matrix4::identity()) + } + #[inline] + pub fn map N2>(&self, mut f: F) -> MIsometry + { + MIsometry(self.0.map(f)) + } + #[inline] + pub fn from_columns_unchecked(columns: &[MVector;4]) -> Self + { + Self(na::Matrix4::from_columns(&(*columns).map(|x| x.0))) + } + /// Minkowski transpose. Inverse for hyperbolic isometries + #[rustfmt::skip] + pub fn mtranspose(self) -> Self { + MIsometry( + na::Matrix4::new( + self.0.m11, self.0.m21, self.0.m31, -self.0.m41, + self.0.m12, self.0.m22, self.0.m32, -self.0.m42, + self.0.m13, self.0.m23, self.0.m33, -self.0.m43, + -self.0.m14, -self.0.m24, -self.0.m34, self.0.m44, + ) + ) + } + /// Whether an isometry reverses winding with respect to the norm + pub fn parity(self) -> bool { + self.0.fixed_view::<3, 3>(0, 0).determinant() < na::zero::() + } + pub fn renormalize_isometry(self) -> MIsometry + { + let boost = translate(&MVector::origin(), &MVector(self.0.index((.., 3)).into()).lorentz_normalize()); + let inverse_boost = boost.mtranspose(); + let rotation = renormalize_rotation_reflection( + &((inverse_boost * self).0).fixed_view::<3, 3>(0, 0).clone_owned(), + ); + MIsometry(boost.0 * rotation.to_homogeneous()) + } + /*pub fn cast(self) -> MIsometry where N: simba::scalar::SubsetOf + { + Self(self.0.cast::()) + }*/ +} + +impl MVector { + pub fn lorentz_normalize(self: &MVector) -> Self { + let sf2 = self.mip(self); + if sf2 == na::zero() { + return MVector::origin(); + } + let sf = sf2.abs().sqrt(); + *self / sf + } + /// Point or plane reflection around point or normal `p` + pub fn reflect(self) -> MIsometry { + MIsometry(na::Matrix4::::identity() + - self.minkowski_outer_product(&self) * na::convert::<_, N>(2.0) / self.mip(&self)) + } + /// Minkowski inner product, aka _h + pub fn mip(self, other: &Self) -> N + { + self.0.x * other.0.x + self.0.y * other.0.y + self.0.z * other.0.z - self.0.w * other.0.w + } + pub fn minkowski_outer_product(self, other: &Self) -> na::Matrix4 + { + ((self).0) * na::RowVector4::new(other.0.x, other.0.y, other.0.z, -other.0.w) + } + pub fn from_gans(gans: &na::Vector3) -> Self + { // x^2 + y^2 + z^2 - w^2 = -1 // sqrt(x^2 + y^2 + z^2 + 1) = w - let w = (sqr(self.0.x) + sqr(self.0.y) + sqr(self.0.z) + na::one()).sqrt(); - na::Vector4::new(self.0.x, self.0.y, self.0.z, w) + let w = (sqr(gans.x) + sqr(gans.y) + sqr(gans.z) + na::one()).sqrt(); + MVector(na::Vector4::new(gans.x, gans.y, gans.z, w)) + } + #[inline] + pub fn zero() -> Self + { + Self(na::zero()) + } + pub fn origin() -> Self + { + Self(na::Vector4::new(na::zero(),na::zero(),na::zero(),na::one())) + } + #[inline] + pub fn normalize(self) -> Self + { + Self(self.0.normalize()) + } + #[inline] + pub fn x() -> Self + { + Self(na::Vector4::x()) + } + #[inline] + pub fn y() -> Self + { + Self(na::Vector4::y()) + } + #[inline] + pub fn z() -> Self + { + Self(na::Vector4::z()) + } + #[inline] + pub fn w() -> Self + { + Self(na::Vector4::w()) + } + #[inline] + pub fn new(x: N, y: N, z: N, w: N) -> Self + { + MVector(na::Vector4::new(x,y,z,w)) + } + #[inline] + pub fn xyz(self) -> na::Vector3 + { + self.0.xyz() + } +} + +impl Mul> for MIsometry +{ + type Output = MIsometry; + #[inline] + fn mul(self, rhs: MIsometry) -> Self::Output + { + MIsometry(self.0 * rhs.0) + } +} + +impl Mul for MVector +{ + type Output = MVector; + #[inline] + fn mul(self, rhs: N) -> Self::Output + { + MVector(self.0 * rhs) + } +} + +impl Div for MVector +{ + type Output = MVector; + #[inline] + fn div(self, rhs: N) -> Self::Output + { + MVector(self.0 / rhs) + } +} + +impl Add for MVector +{ + type Output = Self; + #[inline] + fn add(self, other: Self) -> Self + { + Self(self.0 + other.0) } } -/// Point or plane reflection around point or normal `p` -pub fn reflect(p: &na::Vector4) -> na::Matrix4 { - na::Matrix4::::identity() - - minkowski_outer_product(p, p) * na::convert::<_, N>(2.0) / mip(p, p) +impl Sub for MVector +{ + type Output = Self; + #[inline] + fn sub(self, other: Self) -> Self + { + Self(self.0 - other.0) + } +} + +impl Neg for MVector +{ + type Output = Self; + #[inline] + fn neg(self) -> Self + { + Self(-self.0) + } +} + +impl Mul> for MIsometry +{ + type Output = MVector; + #[inline] + fn mul(self, rhs: MVector) -> Self::Output + { + MVector(self.0 * rhs.0) + } +} + +impl MulAssign for MVector +{ + #[inline] + fn mul_assign(&mut self, rhs: N) + { + *self *= rhs; + } +} + +impl std::ops::AddAssign for MVector +{ + #[inline] + fn add_assign(&mut self, other: Self) + { + *self += other; + } +} + + +impl MulAssign for MIsometry +{ + #[inline] + fn mul_assign(&mut self, rhs: N) + { + *self *= rhs; + } +} + +impl Index for MVector +{ + type Output = N; + #[inline] + fn index(&self, i: usize) -> &Self::Output + { + &self.0[i] + } +} + +impl IndexMut for MVector +{ + #[inline] + fn index_mut(&mut self, i: usize) -> &mut N + { + &mut self.0[i] + } +} + +impl Index<(usize,usize)> for MIsometry +{ + type Output = N; + #[inline] + fn index(&self, ij: (usize, usize)) -> &Self::Output + { + &self.0[ij] + } } /// Transform that translates `a` to `b` given that `a` and `b` are Lorentz normalized pointlike vectors -pub fn translate(a: &na::Vector4, b: &na::Vector4) -> na::Matrix4 { - let a_plus_b = a + b; - na::Matrix4::::identity() - minkowski_outer_product(b, a) * na::convert::<_, N>(2.0) - + minkowski_outer_product(&a_plus_b, &a_plus_b) / (N::one() - mip(a, b)) +pub fn translate(a: &MVector, b: &MVector) -> MIsometry { + let a_plus_b = *a + *b; + MIsometry(na::Matrix4::::identity() - (b.minkowski_outer_product(a) * na::convert::<_, N>(2.0)) + + a_plus_b.minkowski_outer_product(&a_plus_b) / (N::one() - a.mip(b))) } /// Transform that translates the origin in the direction of the given vector with distance equal to its magnitude -pub fn translate_along(v: &na::Vector3) -> na::Matrix4 { +pub fn translate_along(v: &na::Vector3) -> MIsometry { let norm = v.norm(); if norm == na::zero() { - return na::Matrix4::identity(); + return MIsometry::identity(); } // g = Lorentz gamma factor let g = norm.cosh(); let bgc = norm.sinhc(); - translate(&origin(), &(v * bgc).insert_row(3, g)) + translate(&MVector::origin(), &MVector(((v * bgc)).insert_row(3, g))) } /// 4D reflection around a normal vector; length is not significant (so long as it's nonzero) @@ -66,34 +413,12 @@ pub fn euclidean_reflect(v: &na::Vector4) -> na::Matrix4 na::Matrix4::identity() - v * v.transpose() * (na::convert::<_, N>(2.0) / v.norm_squared()) } -pub fn midpoint(a: &na::Vector4, b: &na::Vector4) -> na::Vector4 { - a * (mip(b, b) * mip(a, b)).sqrt() + b * (mip(a, a) * mip(a, b)).sqrt() +pub fn midpoint(a: &MVector, b: &MVector) -> MVector { + *a * (b.mip(b) * a.mip(b)).sqrt() + *b * (a.mip(a) * a.mip(b)).sqrt() } -pub fn distance(a: &na::Vector4, b: &na::Vector4) -> N { - (sqr(mip(a, b)) / (mip(a, a) * mip(b, b))).sqrt().acosh() -} - -pub fn origin() -> na::Vector4 { - na::Vector4::new(na::zero(), na::zero(), na::zero(), na::one()) -} - -pub fn lorentz_normalize(v: &na::Vector4) -> na::Vector4 { - let sf2 = mip(v, v); - if sf2 == na::zero() { - return origin(); - } - let sf = sf2.abs().sqrt(); - v / sf -} - -pub fn renormalize_isometry(m: &na::Matrix4) -> na::Matrix4 { - let boost = translate(&origin(), &lorentz_normalize(&m.index((.., 3)).into())); - let inverse_boost = mtranspose(&boost); - let rotation = renormalize_rotation_reflection( - &(inverse_boost * m).fixed_view::<3, 3>(0, 0).clone_owned(), - ); - boost * rotation.to_homogeneous() +pub fn distance(a: &MVector, b: &MVector) -> N { + (sqr(a.mip(b)) / (a.mip(a) * b.mip(b))).sqrt().acosh() } #[rustfmt::skip] @@ -110,31 +435,11 @@ fn renormalize_rotation_reflection(m: &na::Matrix3) -> n ) } -/// Whether an isometry reverses winding with respect to the norm -pub fn parity(m: &na::Matrix4) -> bool { - m.fixed_view::<3, 3>(0, 0).determinant() < na::zero::() -} - -/// Minkowski inner product, aka _h -pub fn mip(a: &na::Vector4, b: &na::Vector4) -> N { - a.x * b.x + a.y * b.y + a.z * b.z - a.w * b.w -} - #[inline] pub fn sqr(x: N) -> N { x * x } -/// Minkowski transpose. Inverse for hyperbolic isometries -#[rustfmt::skip] -pub fn mtranspose(m: &na::Matrix4) -> na::Matrix4 { - na::Matrix4::new( - m.m11, m.m21, m.m31, -m.m41, - m.m12, m.m22, m.m32, -m.m42, - m.m13, m.m23, m.m33, -m.m43, - -m.m14, -m.m24, -m.m34, m.m44, - ) -} /// Updates `subject` by moving it along the line determined by `projection_direction` so that /// its dot product with `normal` is `distance`. This effectively projects vectors onto the plane @@ -180,10 +485,10 @@ pub fn tuv_to_xyz, N: Copy>(t_axis: usi } fn minkowski_outer_product( - a: &na::Vector4, - b: &na::Vector4, + a: &MVector, + b: &MVector, ) -> na::Matrix4 { - *a * na::RowVector4::new(b.x, b.y, b.z, -b.w) + ((*a).0) * na::RowVector4::new(b.0.x, b.0.y, b.0.z, -b.0.w) } #[cfg(test)] @@ -191,16 +496,19 @@ mod tests { use super::*; use approx::*; + #[test] #[rustfmt::skip] fn reflect_example() { assert_abs_diff_eq!( - reflect(&lorentz_normalize(&na::Vector4::new(0.5, 0.0, 0.0, 1.0))), - na::Matrix4::new( - 1.666, 0.0, 0.0, -1.333, - 0.0 , 1.0, 0.0, 0.0, - 0.0 , 0.0, 1.0, 0.0, - 1.333, 0.0, 0.0, -1.666 + MVector::new(0.5, 0.0, 0.0, 1.0).lorentz_normalize().reflect(), + MIsometry( + na::Matrix4::new( + 1.666, 0.0, 0.0, -1.333, + 0.0 , 1.0, 0.0, 0.0, + 0.0 , 0.0, 1.0, 0.0, + 1.333, 0.0, 0.0, -1.666 + ) ), epsilon = 1e-3 ); @@ -211,14 +519,16 @@ mod tests { fn translate_example() { assert_abs_diff_eq!( translate( - &lorentz_normalize(&na::Vector4::new(-0.5, -0.5, 0.0, 1.0)), - &lorentz_normalize(&na::Vector4::new(0.3, -0.7, 0.0, 1.0)) + &MVector::new(-0.5, -0.5, 0.0, 1.0).lorentz_normalize(), + &MVector::new(0.3, -0.7, 0.0, 1.0).lorentz_normalize() ), - na::Matrix4::new( - 1.676, 0.814, 0.0, 1.572, - -1.369, 0.636, 0.0, -1.130, - 0.0, 0.0, 1.0, 0.0, - 1.919, 0.257, 0.0, 2.179, + MIsometry( + na::Matrix4::new( + 1.676, 0.814, 0.0, 1.572, + -1.369, 0.636, 0.0, -1.130, + 0.0, 0.0, 1.0, 0.0, + 1.919, 0.257, 0.0, 2.179, + ) ), epsilon = 1e-3 ); @@ -226,9 +536,9 @@ mod tests { #[test] fn translate_identity() { - let a = lorentz_normalize(&na::Vector4::new(-0.5, -0.5, 0.0, 1.0)); - let b = lorentz_normalize(&na::Vector4::new(0.3, -0.7, 0.0, 1.0)); - let o = na::Vector4::new(0.0, 0.0, 0.0, 1.0); + let a = MVector::new(-0.5, -0.5, 0.0, 1.0).lorentz_normalize(); + let b = MVector::new(0.3, -0.7, 0.0, 1.0).lorentz_normalize(); + let o = MVector::new(0.0, 0.0, 0.0, 1.0); assert_abs_diff_eq!( translate(&a, &b), translate(&o, &a) * translate(&o, &(translate(&a, &o) * b)) * translate(&a, &o), @@ -238,9 +548,9 @@ mod tests { #[test] fn translate_equivalence() { - let a = lorentz_normalize(&na::Vector4::new(-0.5, -0.5, 0.0, 1.0)); - let o = na::Vector4::new(0.0, 0.0, 0.0, 1.0); - let direction = a.xyz().normalize(); + let a = MVector::new(-0.5, -0.5, 0.0, 1.0).lorentz_normalize(); + let o = MVector::new(0.0, 0.0, 0.0, 1.0); + let direction = a.0.xyz().normalize(); let distance = dbg!(distance(&o, &a)); assert_abs_diff_eq!( translate(&o, &a), @@ -253,28 +563,28 @@ mod tests { fn translate_distance() { let dx = 2.3; let xf = translate_along(&(na::Vector3::x() * dx)); - assert_abs_diff_eq!(dx, distance(&origin(), &(xf * origin()))); + assert_abs_diff_eq!(dx, distance(&MVector::origin(), &(xf * MVector::origin()))); } #[test] fn distance_example() { - let a = na::Vector4::new(0.2, 0.0, 0.0, 1.0); - let b = na::Vector4::new(-0.5, -0.5, 0.0, 1.0); + let a = MVector::new(0.2, 0.0, 0.0, 1.0); + let b = MVector::new(-0.5, -0.5, 0.0, 1.0); // Paper doubles distances for reasons unknown assert_abs_diff_eq!(distance(&a, &b), 2.074 / 2.0, epsilon = 1e-3); } #[test] fn distance_commutative() { - let p = HPoint::new(-1.0, -1.0, 0.0).to_homogeneous(); - let q = HPoint::new(1.0, -1.0, 0.0).to_homogeneous(); + let p = MVector::from_gans(&na::Vector3::new(-1.0, -1.0, 0.0)); + let q = MVector::from_gans(&na::Vector3::new(1.0, -1.0, 0.0)); assert_abs_diff_eq!(distance(&p, &q), distance(&q, &p)); } #[test] fn midpoint_distance() { - let p = HPoint::new(-1.0, -1.0, 0.0).to_homogeneous(); - let q = HPoint::new(1.0, -1.0, 0.0).to_homogeneous(); + let p = MVector::from_gans(&na::Vector3::new(-1.0, -1.0, 0.0)); + let q = MVector::from_gans(&na::Vector3::new(1.0, -1.0, 0.0)); let m = midpoint(&p, &q); assert_abs_diff_eq!(distance(&p, &m), distance(&m, &q), epsilon = 1e-5); assert_abs_diff_eq!(distance(&p, &m) * 2.0, distance(&p, &q), epsilon = 1e-5); @@ -283,44 +593,44 @@ mod tests { #[test] fn renormalize_translation() { let mat = translate( - &lorentz_normalize(&na::Vector4::new(-0.5, -0.5, 0.0, 1.0)), - &lorentz_normalize(&na::Vector4::new(0.3, -0.7, 0.0, 1.0)), + &MVector::new(-0.5, -0.5, 0.0, 1.0).lorentz_normalize(), + &MVector::new(0.3, -0.7, 0.0, 1.0).lorentz_normalize(), ); - assert_abs_diff_eq!(renormalize_isometry(&mat), mat, epsilon = 1e-5); + assert_abs_diff_eq!(mat.renormalize_isometry(), mat, epsilon = 1e-5); } #[test] #[rustfmt::skip] fn renormalize_reflection() { - let mat = na::Matrix4::new(-1.0, 0.0, 0.0, 0.0, + let mat = MIsometry(na::Matrix4::new(-1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0); - assert_abs_diff_eq!(renormalize_isometry(&mat), mat, epsilon = 1e-5); + 0.0, 0.0, 0.0, 1.0)); + assert_abs_diff_eq!(mat.renormalize_isometry(), mat, epsilon = 1e-5); } #[test] #[rustfmt::skip] fn renormalize_normalizes_matrix() { // Matrix chosen with random entries between -1 and 1 - let error = na::Matrix4::new( + let error = MIsometry(na::Matrix4::new( -0.77, -0.21, 0.57, -0.59, 0.49, -0.68, 0.36, 0.68, -0.75, -0.54, -0.13, -0.59, - -0.57, -0.80, 0.00, -0.53); + -0.57, -0.80, 0.00, -0.53)); // translation with some error - let mat = translate( - &lorentz_normalize(&na::Vector4::new(-0.5, -0.5, 0.0, 1.0)), - &lorentz_normalize(&na::Vector4::new(0.3, -0.7, 0.0, 1.0)), - ) + error * 0.05; + let mat = MIsometry(translate( + &MVector::new(-0.5, -0.5, 0.0, 1.0), + &MVector::new(0.3, -0.7, 0.0, 1.0), + ).0 + error.0 * 0.05); - let normalized_mat = renormalize_isometry(&mat); + let normalized_mat = mat.renormalize_isometry(); // Check that the matrix is actually normalized assert_abs_diff_eq!( - mtranspose(&normalized_mat) * normalized_mat, - na::Matrix4::identity(), + normalized_mat.mtranspose() * normalized_mat, + MIsometry(na::Matrix4::identity()), epsilon = 1e-5 ); } diff --git a/common/src/node.rs b/common/src/node.rs index a840bc5d..fa3cd0ba 100644 --- a/common/src/node.rs +++ b/common/src/node.rs @@ -39,7 +39,7 @@ impl Graph { pub fn get_relative_up(&self, position: &Position) -> Option> { let node = self.get(position.node).as_ref()?; Some(na::UnitVector3::new_normalize( - (math::mtranspose(&position.local) * node.state.up_direction()).xyz(), + (position.local.mtranspose() * node.state.up_direction()).xyz(), )) } @@ -586,6 +586,7 @@ mod tests { use std::collections::HashSet; use crate::math; + use crate::math::MVector; use super::*; @@ -600,7 +601,7 @@ mod tests { // Pick an arbitrary ray by transforming the positive-x-axis ray. let ray = na::Rotation3::from_axis_angle(&na::Vector3::z_axis(), 0.4).to_homogeneous() * math::translate_along(&na::Vector3::new(0.2, 0.3, 0.1)) - * &Ray::new(na::Vector4::w(), na::Vector4::x()); + * &Ray::new(MVector::w(), MVector::x()); let tanh_distance = 0.2; let radius = 0.1; @@ -611,9 +612,7 @@ mod tests { let num_ray_test_points = 20; let ray_test_points: Vec<_> = (0..num_ray_test_points) .map(|i| { - math::lorentz_normalize( - &ray.ray_point(tanh_distance * (i as f32 / (num_ray_test_points - 1) as f32)), - ) + ray.ray_point(tanh_distance * (i as f32 / (num_ray_test_points - 1) as f32)).lorentz_normalize() }) .collect(); @@ -633,14 +632,14 @@ mod tests { continue; } - let mut plane_normal = na::Vector4::zeros(); + let mut plane_normal = MVector::zero(); plane_normal[t_axis] = 1.0; plane_normal[3] = layout.grid_to_dual(t); - let plane_normal = math::lorentz_normalize(&plane_normal); + let plane_normal = plane_normal.lorentz_normalize(); for test_point in &ray_test_points { assert!( - math::mip(test_point, &plane_normal).abs() > radius.sinh(), + test_point.mip(&plane_normal).abs() > radius.sinh(), "Plane not covered: t_axis={t_axis}, t={t}, test_point={test_point:?}", ); } @@ -666,16 +665,16 @@ mod tests { continue; } - let mut line_position = na::Vector4::zeros(); + let mut line_position = MVector::zero(); line_position[u_axis] = layout.grid_to_dual(u); line_position[v_axis] = layout.grid_to_dual(v); line_position[3] = 1.0; - let line_position = math::lorentz_normalize(&line_position); + let line_position = line_position.lorentz_normalize(); for test_point in &ray_test_points { assert!( - (math::mip(test_point, &line_position).powi(2) - - math::mip(test_point, &line_direction).powi(2)) + (test_point.mip(&line_position).powi(2) + - test_point.mip(&line_direction).powi(2)) .sqrt() > radius.cosh(), "Line not covered: t_axis={t_axis}, u={u}, v={v}, test_point={test_point:?}", @@ -696,16 +695,16 @@ mod tests { continue; } - let point_position = math::lorentz_normalize(&na::Vector4::new( + let point_position = MVector::new( layout.grid_to_dual(x), layout.grid_to_dual(y), layout.grid_to_dual(z), 1.0, - )); + ).lorentz_normalize(); for test_point in &ray_test_points { assert!( - -math::mip(test_point, &point_position) > radius.cosh(), + -test_point.mip(&point_position) > radius.cosh(), "Point not covered: x={x}, y={y}, z={z}, test_point={test_point:?}", ); } diff --git a/common/src/plane.rs b/common/src/plane.rs index d38d1028..28e07831 100644 --- a/common/src/plane.rs +++ b/common/src/plane.rs @@ -2,13 +2,13 @@ use std::ops::{Mul, Neg}; use crate::{ dodeca::{Side, Vertex}, - math::{lorentz_normalize, mip}, + math::{MVector, MIsometry}, }; /// A hyperbolic plane #[derive(Debug, Copy, Clone)] pub struct Plane { - normal: na::Vector4, + normal: MVector, } impl From for Plane { @@ -24,7 +24,7 @@ impl From>> for Plane { /// A plane passing through the origin fn from(x: na::Unit>) -> Self { Self { - normal: x.into_inner().push(na::zero()), + normal: MVector::from(x), } } } @@ -46,24 +46,24 @@ impl Mul> for Side { } } -impl<'a, N: na::RealField + Copy> Mul> for &'a na::Matrix4 { +impl<'a, N: na::RealField + Copy> Mul> for &'a MIsometry { type Output = Plane; fn mul(self, rhs: Plane) -> Plane { Plane { - normal: lorentz_normalize(&(self * rhs.normal)), + normal: (*self * rhs.normal).lorentz_normalize(), } } } impl Plane { /// Hyperbolic normal vector identifying the plane - pub fn normal(&self) -> &na::Vector4 { + pub fn normal(&self) -> &MVector { &self.normal } /// Shortest distance between the plane and a point - pub fn distance_to(&self, point: &na::Vector4) -> N { - let mip_value = mip(&self.normal, point); + pub fn distance_to(&self, point: &MVector) -> N { + let mip_value = &self.normal.mip(point); // Workaround for bug fixed in rust PR #72486 mip_value.abs().asinh() * mip_value.signum() } @@ -72,7 +72,7 @@ impl Plane { impl Plane { /// Like `distance_to`, but using chunk coordinates for a chunk in the same node space pub fn distance_to_chunk(&self, chunk: Vertex, coord: &na::Vector3) -> f64 { - let pos = lorentz_normalize(&(chunk.chunk_to_node() * coord.push(1.0))); + let pos = (MVector::::from(chunk.chunk_to_node() * coord.push(1.0))).lorentz_normalize(); self.distance_to(&pos) } } @@ -80,7 +80,7 @@ impl Plane { #[cfg(test)] mod tests { use super::*; - use crate::math::{origin, translate_along}; + use crate::math::translate_along; use approx::*; #[test] @@ -94,7 +94,7 @@ mod tests { let plane = Plane::from(axis); assert_abs_diff_eq!( plane.distance_to( - &(translate_along(&(axis.into_inner() * distance)) * origin()) + &(translate_along(&(axis.into_inner() * distance)) * MVector::origin()) ), distance ); diff --git a/common/src/proto.rs b/common/src/proto.rs index 2c63758b..e7ce3299 100644 --- a/common/src/proto.rs +++ b/common/src/proto.rs @@ -6,6 +6,7 @@ use crate::{ node::{ChunkId, Coords}, world::Material, EntityId, SimConfig, Step, + math, }; #[derive(Debug, Serialize, Deserialize)] @@ -22,14 +23,14 @@ pub struct ServerHello { #[derive(Debug, Serialize, Deserialize, Copy, Clone)] pub struct Position { pub node: NodeId, - pub local: na::Matrix4, + pub local: math::MIsometry, } impl Position { pub fn origin() -> Self { Self { node: NodeId::ROOT, - local: na::Matrix4::identity(), + local: math::MIsometry::identity(), } } } diff --git a/common/src/sim_config.rs b/common/src/sim_config.rs index 54fb979a..5129d89c 100644 --- a/common/src/sim_config.rs +++ b/common/src/sim_config.rs @@ -2,7 +2,7 @@ use std::time::Duration; use serde::{Deserialize, Serialize}; -use crate::{dodeca, math}; +use crate::{dodeca, math, math::MVector}; /// Manually specified simulation config parameters #[derive(Serialize, Deserialize, Default)] @@ -61,8 +61,8 @@ impl SimConfig { /// Compute the scaling factor from meters to absolute units, given the number of voxels in a chunk /// and the approximate size of a voxel in meters. fn meters_to_absolute(chunk_size: u8, voxel_size: f32) -> f32 { - let a = dodeca::Vertex::A.chunk_to_node() * na::Vector4::new(1.0, 0.5, 0.5, 1.0); - let b = dodeca::Vertex::A.chunk_to_node() * na::Vector4::new(0.0, 0.5, 0.5, 1.0); + let a = MVector::::from(dodeca::Vertex::A.chunk_to_node() * na::Vector4::new(1.0, 0.5, 0.5, 1.0)); + let b = MVector::::from(dodeca::Vertex::A.chunk_to_node() * na::Vector4::new(0.0, 0.5, 0.5, 1.0)); let minimum_chunk_face_separation = math::distance(&a, &b); let absolute_voxel_size = minimum_chunk_face_separation / f64::from(chunk_size); absolute_voxel_size as f32 / voxel_size diff --git a/common/src/traversal.rs b/common/src/traversal.rs index a86608ce..d7c85cc9 100644 --- a/common/src/traversal.rs +++ b/common/src/traversal.rs @@ -7,18 +7,19 @@ use crate::{ dodeca::{self, Side, Vertex}, graph::{Graph, NodeId}, math, + math::{MVector,MIsometry}, node::ChunkId, proto::Position, }; /// Ensure all nodes within `distance` of `start` exist pub fn ensure_nearby(graph: &mut Graph, start: &Position, distance: f64) { - let mut pending = Vec::<(NodeId, na::Matrix4)>::new(); + let mut pending = Vec::<(NodeId, MIsometry)>::new(); let mut visited = FxHashSet::::default(); - pending.push((start.node, na::Matrix4::identity())); + pending.push((start.node, MIsometry::identity())); visited.insert(start.node); - let start_p = start.local.map(|x| x as f64) * math::origin(); + let start_p = start.local.map(|x| x as f64) * MVector::origin(); while let Some((node, current_transform)) = pending.pop() { for side in Side::iter() { @@ -27,8 +28,8 @@ pub fn ensure_nearby(graph: &mut Graph, start: &Position, distance: f64) { continue; } visited.insert(neighbor); - let neighbor_transform = current_transform * side.reflection(); - let neighbor_p = neighbor_transform * math::origin(); + let neighbor_transform = current_transform * *side.reflection(); + let neighbor_p = neighbor_transform * MVector::origin(); if math::distance(&start_p, &neighbor_p) > distance { continue; } @@ -43,29 +44,29 @@ pub fn nearby_nodes( graph: &Graph, start: &Position, distance: f64, -) -> Vec<(NodeId, na::Matrix4)> { +) -> Vec<(NodeId, MIsometry)> { struct PendingNode { id: NodeId, - transform: na::Matrix4, + transform: MIsometry, } let mut result = Vec::new(); let mut pending = Vec::::new(); let mut visited = FxHashSet::::default(); - let start_p = start.local.map(|x| x as f64) * math::origin(); + let start_p = start.local.map(|x| x as f64) * MVector::origin(); pending.push(PendingNode { id: start.node, - transform: na::Matrix4::identity(), + transform: MIsometry::identity(), }); visited.insert(start.node); while let Some(current) = pending.pop() { - let current_p = current.transform * math::origin(); + let current_p = current.transform * MVector::origin(); if math::distance(&start_p, ¤t_p) > distance { continue; } - result.push((current.id, na::convert(current.transform))); + result.push((current.id, current.transform.to_f32())); for side in Side::iter() { let neighbor = match graph.neighbor(current.id, side) { @@ -77,7 +78,7 @@ pub fn nearby_nodes( } pending.push(PendingNode { id: neighbor, - transform: current.transform * side.reflection(), + transform: current.transform * *side.reflection(), }); visited.insert(neighbor); } @@ -93,9 +94,9 @@ pub struct RayTraverser<'a> { /// Chunks that have already been added to `iterator_queue` and shouldn't be added again visited_chunks: FxHashSet, /// Chunks that should be returned by `next` in the future - iterator_queue: VecDeque<(Option, Vertex, na::Matrix4)>, + iterator_queue: VecDeque<(Option, Vertex, MIsometry)>, /// Chunks whose neighbors should be queried in the future - search_queue: VecDeque<(Option, Vertex, na::Matrix4)>, + search_queue: VecDeque<(Option, Vertex, MIsometry)>, klein_lower_boundary: f32, klein_upper_boundary: f32, } @@ -107,7 +108,7 @@ impl<'a> RayTraverser<'a> { let mut closest_vertex_cosh_distance = f32::INFINITY; for vertex in Vertex::iter() { let vertex_cosh_distance = - (vertex.node_to_dual().cast::() * position.local * math::origin()).w; + (vertex.node_to_dual().to_f32() * position.local * MVector::origin()).w; if vertex_cosh_distance < closest_vertex_cosh_distance { closest_vertex = vertex; closest_vertex_cosh_distance = vertex_cosh_distance; @@ -138,7 +139,7 @@ impl<'a> RayTraverser<'a> { } } - pub fn next(&mut self, tanh_distance: f32) -> Option<(Option, na::Matrix4)> { + pub fn next(&mut self, tanh_distance: f32) -> Option<(Option, MIsometry)> { loop { // Return the next entry that's queued up if let Some(entry @ (node, vertex, node_transform)) = self.iterator_queue.pop_front() { @@ -146,7 +147,7 @@ impl<'a> RayTraverser<'a> { // Combine node and vertex, and convert node transform to chunk transform return Some(( node.map(|node| ChunkId::new(node, vertex)), - vertex.node_to_dual().cast::() * node_transform, + vertex.node_to_dual().to_f32() * node_transform, )); } @@ -157,7 +158,7 @@ impl<'a> RayTraverser<'a> { continue; }; - let local_ray = vertex.node_to_dual().cast::() * node_transform * self.ray; + let local_ray = vertex.node_to_dual().to_f32() * node_transform * self.ray; // Compute the Klein-Beltrami coordinates of the ray segment's endpoints. To check whether neighboring chunks // are needed, we need to check whether the endpoints of the line segments lie outside the boundaries of the square @@ -173,7 +174,7 @@ impl<'a> RayTraverser<'a> { || klein_ray_end[axis] <= self.klein_lower_boundary { let side = vertex.canonical_sides()[axis]; - let next_node_transform = side.reflection().cast::() * node_transform; + let next_node_transform = side.reflection().to_f32() * node_transform; // Crude check to ensure that the neighboring chunk's node can be in the path of the ray. For simplicity, this // check treats each node as a sphere and assumes the ray is pointed directly towards its center. The check is // needed because chunk generation uses this approximation, and this check is not guaranteed to pass near corners diff --git a/common/src/worldgen.rs b/common/src/worldgen.rs index 8cd9fc26..631f8f82 100644 --- a/common/src/worldgen.rs +++ b/common/src/worldgen.rs @@ -5,6 +5,7 @@ use crate::{ dodeca::{Side, Vertex}, graph::{Graph, NodeId}, math, + math::MVector, node::{ChunkId, VoxelData}, terraingen::VoronoiInfo, world::Material, @@ -119,8 +120,8 @@ impl NodeState { } } - pub fn up_direction(&self) -> na::Vector4 { - self.surface.normal().cast() + pub fn up_direction(&self) -> MVector { + self.surface.normal().to_f32() } } From 8f3c12d47a5b73679eb056090d3bca92c006a85e Mon Sep 17 00:00:00 2001 From: strawberry Date: Tue, 16 Jul 2024 16:54:10 -0500 Subject: [PATCH 02/31] reconcile merge --- common/src/chunk_collision.rs | 4 - common/src/chunk_ray_casting.rs | 19 +-- common/src/dodeca.rs | 197 ++++++++------------------------ common/src/graph_collision.rs | 15 --- common/src/plane.rs | 4 - common/src/proto.rs | 11 +- common/src/traversal.rs | 71 ++---------- common/src/worldgen.rs | 7 +- 8 files changed, 61 insertions(+), 267 deletions(-) diff --git a/common/src/chunk_collision.rs b/common/src/chunk_collision.rs index abf6446e..dd9e1962 100644 --- a/common/src/chunk_collision.rs +++ b/common/src/chunk_collision.rs @@ -1,13 +1,9 @@ use crate::{ collision_math::Ray, math, -<<<<<<< HEAD math::MVector, - node::{ChunkLayout, Coords, VoxelAABB, VoxelData}, -======= node::{ChunkLayout, VoxelAABB, VoxelData}, voxel_math::Coords, ->>>>>>> d49df99d371ca6354789deefff6900b1eea46533 world::Material, }; diff --git a/common/src/chunk_ray_casting.rs b/common/src/chunk_ray_casting.rs index 218a529b..0cb26b15 100644 --- a/common/src/chunk_ray_casting.rs +++ b/common/src/chunk_ray_casting.rs @@ -1,13 +1,9 @@ use crate::{ collision_math::Ray, math, -<<<<<<< HEAD math::MVector, - node::{ChunkLayout, CoordAxis, CoordDirection, Coords, VoxelAABB, VoxelData}, -======= node::{ChunkLayout, VoxelAABB, VoxelData}, voxel_math::{CoordAxis, CoordSign, Coords}, ->>>>>>> d49df99d371ca6354789deefff6900b1eea46533 world::Material, }; @@ -90,11 +86,7 @@ fn find_face_collision( // Which side we approach the plane from affects which voxel we want to use for hit detection. // If exiting a chunk via a chunk boundary, hit detection is handled by a different chunk. // We also want to retain this face_direction for reporting the hit result later. -<<<<<<< HEAD - let (face_direction, voxel_t) = if ray.direction.mip(&normal) < 0.0 { -======= - let (face_sign, voxel_t) = if math::mip(&ray.direction, &normal) < 0.0 { ->>>>>>> d49df99d371ca6354789deefff6900b1eea46533 + let (face_sign, voxel_t) = if ray.direction.mip(&normal) < 0.0 { if t == 0 { continue; } @@ -133,8 +125,7 @@ fn find_face_collision( face_axis: CoordAxis::try_from(t_axis).unwrap(), face_sign, }); - } - + }; hit } @@ -207,10 +198,8 @@ mod tests { let ray = Ray::new( ray_start, - ( - ((ray_end - ray_start) - + ray_start * ray_start.mip(&(ray_end - ray_start))), - ).lorentz_normalize(), + ((ray_end - ray_start) + + ray_start * ray_start.mip(&(ray_end - ray_start))).lorentz_normalize(), ); let tanh_distance = (- (ray_start.mip(&ray_end))).acosh(); diff --git a/common/src/dodeca.rs b/common/src/dodeca.rs index 13cd365c..3f8e51fe 100644 --- a/common/src/dodeca.rs +++ b/common/src/dodeca.rs @@ -3,12 +3,9 @@ use data::*; use serde::{Deserialize, Serialize}; -<<<<<<< HEAD use crate::math; use crate::math::{MVector,MIsometry}; -======= use crate::voxel_math::ChunkAxisPermutation; ->>>>>>> d49df99d371ca6354789deefff6900b1eea46533 /// Sides of a right dodecahedron #[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)] @@ -50,49 +47,32 @@ impl Side { /// Outward normal vector of this side #[inline] -<<<<<<< HEAD - pub fn normal(self) -> &'static MVector { - &SIDE_NORMALS[self as usize] -======= - pub fn normal(self) -> &'static na::Vector4 { + pub fn normal(self) -> &'static MVector { &side_normals_f32()[self as usize] } /// Outward normal vector of this side #[inline] - pub fn normal_f64(self) -> &'static na::Vector4 { + pub fn normal_f64(self) -> &'static MVector { &side_normals_f64()[self as usize] ->>>>>>> d49df99d371ca6354789deefff6900b1eea46533 } /// Reflection across this side #[inline] -<<<<<<< HEAD - pub fn reflection(self) -> &'static MIsometry { - &REFLECTIONS[self as usize] -======= - pub fn reflection(self) -> &'static na::Matrix4 { + pub fn reflection(self) -> &'static MIsometry { &reflections_f32()[self as usize] } - /// Reflection across this side #[inline] - pub fn reflection_f64(self) -> &'static na::Matrix4 { + pub fn reflection_f64(self) -> &'static MIsometry { &reflections_f64()[self as usize] ->>>>>>> d49df99d371ca6354789deefff6900b1eea46533 } /// Whether `p` is opposite the dodecahedron across the plane containing `self` #[inline] -<<<<<<< HEAD pub fn is_facing(self, p: &MVector) -> bool { let r = na::convert::<_, na::RowVector4>(self.reflection().row(3).clone_owned()); (r * *p).x < p.w -======= - pub fn is_facing(self, p: &na::Vector4) -> bool { - let r = na::convert::<_, na::RowVector4>(self.reflection_f64().row(3).clone_owned()); - (r * p).x < p.w ->>>>>>> d49df99d371ca6354789deefff6900b1eea46533 } } @@ -198,28 +178,18 @@ impl Vertex { } /// Transform from euclidean chunk coordinates to hyperbolic node space -<<<<<<< HEAD - pub fn chunk_to_node(self) -> na::Matrix4 { - as Into>>::into(*self.dual_to_node()) * na::Matrix4::new_scaling(1.0 / Self::dual_to_chunk_factor()) -======= pub fn chunk_to_node(self) -> na::Matrix4 { - self.dual_to_node() * na::Matrix4::new_scaling(1.0 / Self::dual_to_chunk_factor()) ->>>>>>> d49df99d371ca6354789deefff6900b1eea46533 + as Into>>::into(*self.dual_to_node()) * na::Matrix4::new_scaling(1.0 / Self::dual_to_chunk_factor()) } /// Transform from euclidean chunk coordinates to hyperbolic node space pub fn chunk_to_node_f64(self) -> na::Matrix4 { - self.dual_to_node_f64() * na::Matrix4::new_scaling(1.0 / Self::dual_to_chunk_factor_f64()) + as Into>>::into(*self.dual_to_node_f64()) * na::Matrix4::new_scaling(1.0 / Self::dual_to_chunk_factor_f64()) } /// Transform from hyperbolic node space to euclidean chunk coordinates -<<<<<<< HEAD pub fn node_to_chunk(self) -> na::Matrix4 { na::Matrix4::new_scaling(Self::dual_to_chunk_factor()) * as Into>>::into(*self.node_to_dual()) -======= - pub fn node_to_chunk(self) -> na::Matrix4 { - na::Matrix4::new_scaling(Self::dual_to_chunk_factor()) * self.node_to_dual() ->>>>>>> d49df99d371ca6354789deefff6900b1eea46533 } /// Transform from hyperbolic node space to euclidean chunk coordinates @@ -228,33 +198,23 @@ impl Vertex { } /// Transform from cube-centric coordinates to dodeca-centric coordinates -<<<<<<< HEAD - pub fn dual_to_node(self) -> &'static MIsometry { - &DUAL_TO_NODE[self as usize] - } - - /// Transform from dodeca-centric coordinates to cube-centric coordinates - pub fn node_to_dual(self) -> &'static MIsometry { - &NODE_TO_DUAL[self as usize] -======= - pub fn dual_to_node(self) -> &'static na::Matrix4 { + pub fn dual_to_node(self) -> &'static MIsometry { &dual_to_node_f32()[self as usize] } /// Transform from cube-centric coordinates to dodeca-centric coordinates - pub fn dual_to_node_f64(self) -> &'static na::Matrix4 { + pub fn dual_to_node_f64(self) -> &'static MIsometry { &dual_to_node_f64()[self as usize] } /// Transform from dodeca-centric coordinates to cube-centric coordinates - pub fn node_to_dual(self) -> &'static na::Matrix4 { + pub fn node_to_dual(self) -> &'static MIsometry { &node_to_dual_f32()[self as usize] } /// Transform from dodeca-centric coordinates to cube-centric coordinates - pub fn node_to_dual_f64(self) -> &'static na::Matrix4 { + pub fn node_to_dual_f64(self) -> &'static MIsometry { &node_to_dual_f64()[self as usize] ->>>>>>> d49df99d371ca6354789deefff6900b1eea46533 } /// Scale factor used in conversion from cube-centric coordinates to euclidean chunk coordinates. @@ -287,11 +247,7 @@ impl Vertex { /// Convenience method for `self.chunk_to_node().determinant() < 0`. pub fn parity(self) -> bool { -<<<<<<< HEAD - DUAL_TO_NODE_PARITY[self as usize] -======= chunk_to_node_parity()[self as usize] ->>>>>>> d49df99d371ca6354789deefff6900b1eea46533 } } @@ -306,6 +262,7 @@ mod data { use crate::dodeca::{Side, Vertex, SIDE_COUNT, VERTEX_COUNT}; use crate::math; + use crate::math::{MVector,MIsometry}; use crate::voxel_math::ChunkAxisPermutation; /// Whether two sides share an edge @@ -326,31 +283,13 @@ mod data { } /// Vector corresponding to the outer normal of each side -<<<<<<< HEAD - static ref SIDE_NORMALS: [MVector; SIDE_COUNT] = { - let phi = libm::sqrt(1.25) + 0.5; // golden ratio - let f = MVector::new(1.0, phi, 0.0, libm::sqrt(phi)).lorentz_normalize(); - - let mut result: [MVector; SIDE_COUNT] = [MVector::zero(); SIDE_COUNT]; - let mut i = 0; - for (x, y, z, w) in [ - (f.x, f.y, f.z, f.w), - (-f.x, f.y, -f.z, f.w), - (f.x, -f.y, -f.z, f.w), - (-f.x, -f.y, f.z, f.w), - ] - { - for (x, y, z, w) in [(x, y, z, w), (y, z, x, w), (z, x, y, w)] { - result[i] = MVector::new(x, y, z, w); - i += 1; -======= - pub fn side_normals_f64() -> &'static [na::Vector4; SIDE_COUNT] { - static LOCK: OnceLock<[na::Vector4; SIDE_COUNT]> = OnceLock::new(); + pub fn side_normals_f64() -> &'static [MVector; SIDE_COUNT] { + static LOCK: OnceLock<[MVector; SIDE_COUNT]> = OnceLock::new(); LOCK.get_or_init(|| { let phi = libm::sqrt(1.25) + 0.5; // golden ratio - let f = math::lorentz_normalize(&na::Vector4::new(1.0, phi, 0.0, libm::sqrt(phi))); + let f = MVector::new(1.0, phi, 0.0, libm::sqrt(phi)).lorentz_normalize(); - let mut result: [na::Vector4; SIDE_COUNT] = [na::zero(); SIDE_COUNT]; + let mut result: [MVector; SIDE_COUNT] = [MVector::zero(); SIDE_COUNT]; let mut i = 0; for (x, y, z, w) in [ (f.x, f.y, f.z, f.w), @@ -359,26 +298,19 @@ mod data { (-f.x, -f.y, f.z, f.w), ] { for (x, y, z, w) in [(x, y, z, w), (y, z, x, w), (z, x, y, w)] { - result[i] = na::Vector4::new(x, y, z, w); + result[i] = MVector::new(x, y, z, w); i += 1; } ->>>>>>> d49df99d371ca6354789deefff6900b1eea46533 } result }) } /// Transform that moves from a neighbor to a reference node, for each side -<<<<<<< HEAD - static ref REFLECTIONS: [MIsometry; SIDE_COUNT] = { - SIDE_NORMALS.map(|r| r.reflect()) - }; -======= - pub fn reflections_f64() -> &'static [na::Matrix4; SIDE_COUNT] { - static LOCK: OnceLock<[na::Matrix4; SIDE_COUNT]> = OnceLock::new(); - LOCK.get_or_init(|| side_normals_f64().map(|r| math::reflect(&r))) + pub fn reflections_f64() -> &'static [MIsometry; SIDE_COUNT] { + static LOCK: OnceLock<[MIsometry; SIDE_COUNT]> = OnceLock::new(); + LOCK.get_or_init(|| side_normals_f64().map(|r| r.reflect())) } ->>>>>>> d49df99d371ca6354789deefff6900b1eea46533 /// Sides incident to a vertex, in canonical order pub fn vertex_sides() -> &'static [[Side; 3]; VERTEX_COUNT] { @@ -469,39 +401,20 @@ mod data { } /// Transform that converts from cube-centric coordinates to dodeca-centric coordinates -<<<<<<< HEAD - static ref DUAL_TO_NODE: [MIsometry; VERTEX_COUNT] = { - let mip_origin_normal = MVector::origin().mip(&SIDE_NORMALS[0]); // This value is the same for every side - let mut result = [MIsometry::identity(); VERTEX_COUNT]; - for i in 0..VERTEX_COUNT { - let [a, b, c] = VERTEX_SIDES[i]; - let vertex_position = (MVector::origin() - (*a.normal() + *b.normal() + *c.normal()) * mip_origin_normal).lorentz_normalize(); - result[i] = MIsometry::from_columns_unchecked(&[-*a.normal(), -*b.normal(), -*c.normal(), vertex_position]); - } - result - - }; - - /// Transform that converts from dodeca-centric coordinates to cube-centric coordinates - static ref NODE_TO_DUAL: [MIsometry; VERTEX_COUNT] = { - DUAL_TO_NODE.map(|m| m.mtranspose()) - }; -======= - pub fn dual_to_node_f64() -> &'static [na::Matrix4; VERTEX_COUNT] { - static LOCK: OnceLock<[na::Matrix4; VERTEX_COUNT]> = OnceLock::new(); + pub fn dual_to_node_f64() -> &'static [MIsometry; VERTEX_COUNT] { + static LOCK: OnceLock<[MIsometry; VERTEX_COUNT]> = OnceLock::new(); LOCK.get_or_init(|| { - let mip_origin_normal = math::mip(&math::origin(), &side_normals_f64()[0]); // This value is the same for every side - let mut result = [na::zero(); VERTEX_COUNT]; + let mip_origin_normal = MVector::origin().mip(&side_normals_f64()[0]); // This value is the same for every side + let mut result = [MIsometry::identity(); VERTEX_COUNT]; for (i, map) in result.iter_mut().enumerate() { let [a, b, c] = vertex_sides()[i]; - let vertex_position = math::lorentz_normalize( - &(math::origin() - - (a.normal_f64() + b.normal_f64() + c.normal_f64()) * mip_origin_normal), - ); - *map = na::Matrix4::from_columns(&[ - -a.normal_f64(), - -b.normal_f64(), - -c.normal_f64(), + let vertex_position = + (MVector::origin() + - (*a.normal_f64() + *b.normal_f64() + *c.normal_f64()) * mip_origin_normal).lorentz_normalize(); + *map = MIsometry::from_columns_unchecked(&[ + -*a.normal_f64(), + -*b.normal_f64(), + -*c.normal_f64(), vertex_position, ]); } @@ -510,11 +423,10 @@ mod data { } /// Transform that converts from dodeca-centric coordinates to cube-centric coordinates - pub fn node_to_dual_f64() -> &'static [na::Matrix4; VERTEX_COUNT] { - static LOCK: OnceLock<[na::Matrix4; VERTEX_COUNT]> = OnceLock::new(); - LOCK.get_or_init(|| dual_to_node_f64().map(|m| math::mtranspose(&m))) + pub fn node_to_dual_f64() -> &'static [MIsometry; VERTEX_COUNT] { + static LOCK: OnceLock<[MIsometry; VERTEX_COUNT]> = OnceLock::new(); + LOCK.get_or_init(|| dual_to_node_f64().map(|m| m.mtranspose())) } ->>>>>>> d49df99d371ca6354789deefff6900b1eea46533 pub fn dual_to_chunk_factor_f64() -> f64 { static LOCK: OnceLock = OnceLock::new(); @@ -559,46 +471,36 @@ mod data { } /// Whether the determinant of the cube-to-node transform is negative -<<<<<<< HEAD - static ref DUAL_TO_NODE_PARITY: [bool; VERTEX_COUNT] = { - let mut result = [false; VERTEX_COUNT]; - - for v in Vertex::iter() { - result[v as usize] = v.dual_to_node().parity(); - } -======= pub fn chunk_to_node_parity() -> &'static [bool; VERTEX_COUNT] { static LOCK: OnceLock<[bool; VERTEX_COUNT]> = OnceLock::new(); LOCK.get_or_init(|| { let mut result = [false; VERTEX_COUNT]; for v in Vertex::iter() { - result[v as usize] = math::parity(&v.chunk_to_node_f64()); + result[v as usize] = v.dual_to_node().parity(); } ->>>>>>> d49df99d371ca6354789deefff6900b1eea46533 - result }) } - pub fn side_normals_f32() -> &'static [na::Vector4; SIDE_COUNT] { - static LOCK: OnceLock<[na::Vector4; SIDE_COUNT]> = OnceLock::new(); - LOCK.get_or_init(|| side_normals_f64().map(|n| n.cast())) + pub fn side_normals_f32() -> &'static [MVector; SIDE_COUNT] { + static LOCK: OnceLock<[MVector; SIDE_COUNT]> = OnceLock::new(); + LOCK.get_or_init(|| side_normals_f64().map(|n| n.to_f32())) } - pub fn reflections_f32() -> &'static [na::Matrix4; SIDE_COUNT] { - static LOCK: OnceLock<[na::Matrix4; SIDE_COUNT]> = OnceLock::new(); - LOCK.get_or_init(|| reflections_f64().map(|n| n.cast())) + pub fn reflections_f32() -> &'static [MIsometry; SIDE_COUNT] { + static LOCK: OnceLock<[MIsometry; SIDE_COUNT]> = OnceLock::new(); + LOCK.get_or_init(|| reflections_f64().map(|n| n.to_f32())) } - pub fn dual_to_node_f32() -> &'static [na::Matrix4; VERTEX_COUNT] { - static LOCK: OnceLock<[na::Matrix4; VERTEX_COUNT]> = OnceLock::new(); - LOCK.get_or_init(|| dual_to_node_f64().map(|n| n.cast())) + pub fn dual_to_node_f32() -> &'static [MIsometry; VERTEX_COUNT] { + static LOCK: OnceLock<[MIsometry; VERTEX_COUNT]> = OnceLock::new(); + LOCK.get_or_init(|| dual_to_node_f64().map(|n| n.to_f32())) } - pub fn node_to_dual_f32() -> &'static [na::Matrix4; VERTEX_COUNT] { - static LOCK: OnceLock<[na::Matrix4; VERTEX_COUNT]> = OnceLock::new(); - LOCK.get_or_init(|| node_to_dual_f64().map(|n| n.cast())) + pub fn node_to_dual_f32() -> &'static [MIsometry; VERTEX_COUNT] { + static LOCK: OnceLock<[MIsometry; VERTEX_COUNT]> = OnceLock::new(); + LOCK.get_or_init(|| node_to_dual_f64().map(|n| n.to_f32())) } pub fn dual_to_chunk_factor_f32() -> f32 { @@ -707,17 +609,10 @@ mod tests { #[test] fn radius() { -<<<<<<< HEAD let corner = Vertex::A.chunk_to_node() * MVector::origin(); assert_abs_diff_eq!( BOUNDING_SPHERE_RADIUS, math::distance(&corner, &MVector::origin()), -======= - let corner = Vertex::A.chunk_to_node_f64() * math::origin(); - assert_abs_diff_eq!( - BOUNDING_SPHERE_RADIUS_F64, - math::distance(&corner, &math::origin()), ->>>>>>> d49df99d371ca6354789deefff6900b1eea46533 epsilon = 1e-10 ); let phi = (1.0 + 5.0f64.sqrt()) / 2.0; // Golden ratio diff --git a/common/src/graph_collision.rs b/common/src/graph_collision.rs index 93e30941..70e9395c 100644 --- a/common/src/graph_collision.rs +++ b/common/src/graph_collision.rs @@ -172,15 +172,9 @@ mod tests { // Find the transform of the chosen chunk let chosen_chunk_transform: MIsometry = self.chosen_voxel.node_path.iter().fold( -<<<<<<< HEAD MIsometry::identity(), |transform: MIsometry, side| transform * side.reflection().to_f32(), ) * self.chosen_voxel.vertex.dual_to_node().to_f32(); -======= - na::Matrix4::identity(), - |transform: na::Matrix4, side| transform * side.reflection(), - ) * self.chosen_voxel.vertex.dual_to_node(); ->>>>>>> d49df99d371ca6354789deefff6900b1eea46533 let dual_to_grid_factor = graph.layout().dual_to_grid_factor(); let ray_target = chosen_chunk_transform @@ -191,13 +185,8 @@ mod tests { 1.0, ).lorentz_normalize(); -<<<<<<< HEAD let ray_position = Vertex::A.dual_to_node().to_f32() * MVector::new( -======= - let ray_position = Vertex::A.dual_to_node() - * math::lorentz_normalize(&na::Vector4::new( ->>>>>>> d49df99d371ca6354789deefff6900b1eea46533 self.start_chunk_relative_grid_ray_start[0] / dual_to_grid_factor, self.start_chunk_relative_grid_ray_start[1] / dual_to_grid_factor, self.start_chunk_relative_grid_ray_start[2] / dual_to_grid_factor, @@ -444,11 +433,7 @@ mod tests { } // The node coordinates of the corner of the missing node -<<<<<<< HEAD let vertex_pos = Vertex::A.dual_to_node().to_f32() * MVector::origin(); -======= - let vertex_pos = Vertex::A.dual_to_node() * math::origin(); ->>>>>>> d49df99d371ca6354789deefff6900b1eea46533 // Use a ray starting from the origin. The direction vector is vertex_pos with the w coordinate // set to 0 and normalized diff --git a/common/src/plane.rs b/common/src/plane.rs index c59837b7..fd283ec6 100644 --- a/common/src/plane.rs +++ b/common/src/plane.rs @@ -72,11 +72,7 @@ impl Plane { impl Plane { /// Like `distance_to`, but using chunk coordinates for a chunk in the same node space pub fn distance_to_chunk(&self, chunk: Vertex, coord: &na::Vector3) -> f64 { -<<<<<<< HEAD let pos = (MVector::::from(chunk.chunk_to_node() * coord.push(1.0))).lorentz_normalize(); -======= - let pos = lorentz_normalize(&(chunk.chunk_to_node_f64() * coord.push(1.0))); ->>>>>>> d49df99d371ca6354789deefff6900b1eea46533 self.distance_to(&pos) } } diff --git a/common/src/proto.rs b/common/src/proto.rs index 21342d12..3f482692 100644 --- a/common/src/proto.rs +++ b/common/src/proto.rs @@ -1,17 +1,8 @@ use serde::{Deserialize, Serialize}; use crate::{ -<<<<<<< HEAD - dodeca, - graph::NodeId, - node::{ChunkId, Coords}, - world::Material, - EntityId, SimConfig, Step, - math, -======= dodeca, graph::NodeId, node::ChunkId, voxel_math::Coords, world::Material, EntityId, SimConfig, - Step, ->>>>>>> d49df99d371ca6354789deefff6900b1eea46533 + Step, math }; #[derive(Debug, Serialize, Deserialize)] diff --git a/common/src/traversal.rs b/common/src/traversal.rs index 882e0bd2..624367c2 100644 --- a/common/src/traversal.rs +++ b/common/src/traversal.rs @@ -13,26 +13,16 @@ use crate::{ }; /// Ensure all nodes within `distance` of `start` exist -<<<<<<< HEAD -pub fn ensure_nearby(graph: &mut Graph, start: &Position, distance: f64) { - let mut pending = Vec::<(NodeId, MIsometry)>::new(); - let mut visited = FxHashSet::::default(); - - pending.push((start.node, MIsometry::identity())); - visited.insert(start.node); - let start_p = start.local.map(|x| x as f64) * MVector::origin(); -======= pub fn ensure_nearby(graph: &mut Graph, start: &Position, distance: f32) { // We do a breadth-first instead of a depth-first traversal here to ensure that we take the // minimal path to each node. This greatly helps prevent error from accumulating due to // hundreds of transformations being composed. - let mut pending = VecDeque::<(NodeId, na::Matrix4)>::new(); + let mut pending = VecDeque::<(NodeId, MIsometry)>::new(); let mut visited = FxHashSet::::default(); - pending.push_back((start.node, na::Matrix4::identity())); + pending.push_back((start.node, MIsometry::identity())); visited.insert(start.node); - let start_p = start.local * math::origin(); ->>>>>>> d49df99d371ca6354789deefff6900b1eea46533 + let start_p = start.local * MVector::origin(); while let Some((node, current_transform)) = pending.pop_front() { for side in Side::iter() { @@ -41,15 +31,9 @@ pub fn ensure_nearby(graph: &mut Graph, start: &Position, distance: f32) { continue; } visited.insert(neighbor); -<<<<<<< HEAD let neighbor_transform = current_transform * *side.reflection(); let neighbor_p = neighbor_transform * MVector::origin(); - if math::distance(&start_p, &neighbor_p) > distance { -======= - let neighbor_transform = current_transform * side.reflection(); - let neighbor_p = neighbor_transform * math::origin(); - if -math::mip(&start_p, &neighbor_p) > distance.cosh() { ->>>>>>> d49df99d371ca6354789deefff6900b1eea46533 + if -(start_p.mip(&neighbor_p)) > distance.cosh() { continue; } pending.push_back((neighbor, neighbor_transform)); @@ -62,35 +46,21 @@ pub fn ensure_nearby(graph: &mut Graph, start: &Position, distance: f32) { pub fn nearby_nodes( graph: &Graph, start: &Position, -<<<<<<< HEAD - distance: f64, -) -> Vec<(NodeId, MIsometry)> { - struct PendingNode { - id: NodeId, - transform: MIsometry, - } - - let mut result = Vec::new(); - let mut pending = Vec::::new(); - let mut visited = FxHashSet::::default(); - let start_p = start.local.map(|x| x as f64) * MVector::origin(); -======= distance: f32, -) -> Vec<(NodeId, na::Matrix4)> { +) -> Vec<(NodeId, MIsometry)> { struct PendingNode { id: NodeId, - transform: na::Matrix4, + transform: MIsometry, } let mut result = Vec::new(); ->>>>>>> d49df99d371ca6354789deefff6900b1eea46533 // We do a breadth-first instead of a depth-first traversal here to ensure that we take the // minimal path to each node. This greatly helps prevent error from accumulating due to // hundreds of transformations being composed. let mut pending = VecDeque::::new(); let mut visited = FxHashSet::::default(); - let start_p = start.local * math::origin(); + let start_p = start.local * MVector::origin(); pending.push_back(PendingNode { id: start.node, @@ -98,15 +68,9 @@ pub fn nearby_nodes( }); visited.insert(start.node); -<<<<<<< HEAD while let Some(current) = pending.pop() { let current_p = current.transform * MVector::origin(); - if math::distance(&start_p, ¤t_p) > distance { -======= - while let Some(current) = pending.pop_front() { - let current_p = current.transform * math::origin(); - if -math::mip(&start_p, ¤t_p) > distance.cosh() { ->>>>>>> d49df99d371ca6354789deefff6900b1eea46533 + if -(start_p.mip(¤t_p)) > distance.cosh() { continue; } result.push((current.id, current.transform.to_f32())); @@ -150,12 +114,7 @@ impl<'a> RayTraverser<'a> { let mut closest_vertex = Vertex::A; let mut closest_vertex_cosh_distance = f32::INFINITY; for vertex in Vertex::iter() { -<<<<<<< HEAD - let vertex_cosh_distance = - (vertex.node_to_dual().to_f32() * position.local * MVector::origin()).w; -======= - let vertex_cosh_distance = (vertex.node_to_dual() * position.local * math::origin()).w; ->>>>>>> d49df99d371ca6354789deefff6900b1eea46533 + let vertex_cosh_distance = (vertex.node_to_dual() * position.local * MVector::origin()).w; if vertex_cosh_distance < closest_vertex_cosh_distance { closest_vertex = vertex; closest_vertex_cosh_distance = vertex_cosh_distance; @@ -193,11 +152,7 @@ impl<'a> RayTraverser<'a> { // Combine node and vertex, and convert node transform to chunk transform return Some(( node.map(|node| ChunkId::new(node, vertex)), -<<<<<<< HEAD - vertex.node_to_dual().to_f32() * node_transform, -======= vertex.node_to_dual() * node_transform, ->>>>>>> d49df99d371ca6354789deefff6900b1eea46533 )); } @@ -208,11 +163,7 @@ impl<'a> RayTraverser<'a> { continue; }; -<<<<<<< HEAD - let local_ray = vertex.node_to_dual().to_f32() * node_transform * self.ray; -======= let local_ray = vertex.node_to_dual() * node_transform * self.ray; ->>>>>>> d49df99d371ca6354789deefff6900b1eea46533 // Compute the Klein-Beltrami coordinates of the ray segment's endpoints. To check whether neighboring chunks // are needed, we need to check whether the endpoints of the line segments lie outside the boundaries of the square @@ -228,11 +179,7 @@ impl<'a> RayTraverser<'a> { || klein_ray_end[axis] <= self.klein_lower_boundary { let side = vertex.canonical_sides()[axis]; -<<<<<<< HEAD - let next_node_transform = side.reflection().to_f32() * node_transform; -======= let next_node_transform = side.reflection() * node_transform; ->>>>>>> d49df99d371ca6354789deefff6900b1eea46533 // Crude check to ensure that the neighboring chunk's node can be in the path of the ray. For simplicity, this // check treats each node as a sphere and assumes the ray is pointed directly towards its center. The check is // needed because chunk generation uses this approximation, and this check is not guaranteed to pass near corners diff --git a/common/src/worldgen.rs b/common/src/worldgen.rs index 75a2f205..88e43145 100644 --- a/common/src/worldgen.rs +++ b/common/src/worldgen.rs @@ -4,12 +4,7 @@ use rand_distr::Normal; use crate::{ dodeca::{Side, Vertex}, graph::{Graph, NodeId}, -<<<<<<< HEAD - math, - math::MVector, -======= - margins, math, ->>>>>>> d49df99d371ca6354789deefff6900b1eea46533 + margins, math, math::MVector, node::{ChunkId, VoxelData}, terraingen::VoronoiInfo, world::Material, From 5e4c4dd3e6f45f9fefbedb27b209671637db2a56 Mon Sep 17 00:00:00 2001 From: strawberry Date: Sun, 21 Jul 2024 00:18:36 -0500 Subject: [PATCH 03/31] cleanup --- client/src/graphics/draw.rs | 6 +-- client/src/graphics/frustum.rs | 19 +++---- client/src/graphics/voxels/mod.rs | 10 ++-- client/src/local_character_controller.rs | 2 +- client/src/prediction.rs | 3 +- client/src/sim.rs | 5 +- common/src/dodeca.rs | 20 ++++---- common/src/graph.rs | 10 ++-- common/src/graph_collision.rs | 8 +-- common/src/math.rs | 65 +++++++++++++++++++----- common/src/node.rs | 11 ++-- common/src/plane.rs | 2 +- common/src/sim_config.rs | 4 +- common/src/traversal.rs | 16 +++--- server/src/sim.rs | 2 +- 15 files changed, 113 insertions(+), 70 deletions(-) diff --git a/client/src/graphics/draw.rs b/client/src/graphics/draw.rs index 3dd45155..e8bfdc00 100644 --- a/client/src/graphics/draw.rs +++ b/client/src/graphics/draw.rs @@ -289,7 +289,7 @@ impl Draw { let draw_started = Instant::now(); let view = sim.as_ref().map_or_else(Position::origin, |sim| sim.view()); let projection = frustum.projection(1.0e-4); - let view_projection = projection.matrix() * math::mtranspose(&view.local); + let view_projection = projection.matrix() * as Into>>::into(view.local.mtranspose()); self.loader.drive(); let device = &*self.gfx.device; @@ -482,8 +482,8 @@ impl Draw { .expect("positionless entity in graph"); if let Some(character_model) = self.loader.get(self.character_model) { if let Ok(ch) = sim.world.get::<&Character>(entity) { - let transform = transform - * pos.local + let transform = as Into>>::into(transform) + * as Into>>::into(pos.local) * na::Matrix4::new_scaling(sim.cfg().meters_to_absolute) * ch.state.orientation.to_homogeneous(); for mesh in &character_model.0 { diff --git a/client/src/graphics/frustum.rs b/client/src/graphics/frustum.rs index f5f8a175..6ee68593 100644 --- a/client/src/graphics/frustum.rs +++ b/client/src/graphics/frustum.rs @@ -1,4 +1,5 @@ use common::Plane; +use common::math; #[derive(Debug, Copy, Clone)] pub struct Frustum { @@ -79,7 +80,7 @@ pub struct FrustumPlanes { } impl FrustumPlanes { - pub fn contain(&self, point: &na::Vector4, radius: f32) -> bool { + pub fn contain(&self, point: &math::MVector, radius: f32) -> bool { for &plane in &[&self.left, &self.right, &self.down, &self.up] { if plane.distance_to(point) < -radius { return false; @@ -92,20 +93,20 @@ impl FrustumPlanes { #[cfg(test)] mod tests { use super::*; - use common::math::{origin, translate_along}; + use common::math::{translate_along, MVector}; use std::f32; #[test] fn planes_sanity() { // 90 degree square let planes = Frustum::from_vfov(f32::consts::FRAC_PI_4, 1.0).planes(); - assert!(planes.contain(&origin(), 0.1)); - assert!(planes.contain(&(translate_along(&-na::Vector3::z()) * origin()), 0.0)); - assert!(!planes.contain(&(translate_along(&na::Vector3::z()) * origin()), 0.0)); + assert!(planes.contain(&MVector::origin(), 0.1)); + assert!(planes.contain(&(translate_along(&-na::Vector3::z()) * MVector::origin()), 0.0)); + assert!(!planes.contain(&(translate_along(&na::Vector3::z()) * MVector::origin()), 0.0)); - assert!(!planes.contain(&(translate_along(&na::Vector3::x()) * origin()), 0.0)); - assert!(!planes.contain(&(translate_along(&na::Vector3::y()) * origin()), 0.0)); - assert!(!planes.contain(&(translate_along(&-na::Vector3::x()) * origin()), 0.0)); - assert!(!planes.contain(&(translate_along(&-na::Vector3::y()) * origin()), 0.0)); + assert!(!planes.contain(&(translate_along(&na::Vector3::x()) * MVector::origin()), 0.0)); + assert!(!planes.contain(&(translate_along(&na::Vector3::y()) * MVector::origin()), 0.0)); + assert!(!planes.contain(&(translate_along(&-na::Vector3::x()) * MVector::origin()), 0.0)); + assert!(!planes.contain(&(translate_along(&-na::Vector3::y()) * MVector::origin()), 0.0)); } } diff --git a/client/src/graphics/voxels/mod.rs b/client/src/graphics/voxels/mod.rs index 747e8e60..eb061d76 100644 --- a/client/src/graphics/voxels/mod.rs +++ b/client/src/graphics/voxels/mod.rs @@ -88,7 +88,7 @@ impl Voxels { device: &Device, frame: &mut Frame, sim: &mut Sim, - nearby_nodes: &[(NodeId, na::Matrix4)], + nearby_nodes: &[(NodeId, math::MIsometry)], cmd: vk::CommandBuffer, frustum: &Frustum, ) { @@ -122,12 +122,12 @@ impl Voxels { } let node_scan_started = Instant::now(); let frustum_planes = frustum.planes(); - let local_to_view = math::mtranspose(&view.local); + let local_to_view = view.local.mtranspose(); let mut extractions = Vec::new(); let mut workqueue_is_full = false; for &(node, ref node_transform) in nearby_nodes { - let node_to_view = local_to_view * node_transform; - let origin = node_to_view * math::origin(); + let node_to_view = local_to_view * *node_transform; + let origin = node_to_view * math::MVector::origin(); if !frustum_planes.contain(&origin, dodeca::BOUNDING_SPHERE_RADIUS) { // Don't bother generating or drawing chunks from nodes that are wholly outside the // frustum. @@ -174,7 +174,7 @@ impl Voxels { frame.drawn.push(slot); // Transfer transform frame.surface.transforms_mut()[slot.0 as usize] = - node_transform * vertex.chunk_to_node(); + as Into>>::into(*node_transform) * vertex.chunk_to_node(); } if let (None, &VoxelData::Dense(ref data)) = (&surface, voxels) { // Extract a surface so it can be drawn in future frames diff --git a/client/src/local_character_controller.rs b/client/src/local_character_controller.rs index a4197d7a..7e505219 100644 --- a/client/src/local_character_controller.rs +++ b/client/src/local_character_controller.rs @@ -25,7 +25,7 @@ impl LocalCharacterController { pub fn oriented_position(&self) -> Position { Position { node: self.position.node, - local: self.position.local * self.orientation.to_homogeneous(), + local: self.position.local * math::MIsometry::unit_quaternion_to_homogeneous(self.orientation), } } diff --git a/client/src/prediction.rs b/client/src/prediction.rs index 5d9c5ab7..29383442 100644 --- a/client/src/prediction.rs +++ b/client/src/prediction.rs @@ -101,12 +101,13 @@ impl PredictedMotion { #[cfg(test)] mod tests { use super::*; + use common::math::MIsometry; /// An arbitrary position fn pos() -> Position { Position { node: common::graph::NodeId::ROOT, - local: na::one(), + local: MIsometry::identity(), } } diff --git a/client/src/sim.rs b/client/src/sim.rs index 983e818e..8f41e85f 100644 --- a/client/src/sim.rs +++ b/client/src/sim.rs @@ -18,6 +18,7 @@ use common::{ self, BlockUpdate, Character, CharacterInput, CharacterState, Command, Component, Inventory, Position, }, + math, sanitize_motion_input, world::Material, EntityId, GraphEntities, SimConfig, Step, @@ -109,7 +110,7 @@ impl Sim { selected_material: Material::WoodPlanks, prediction: PredictedMotion::new(proto::Position { node: NodeId::ROOT, - local: na::one(), + local: math::MIsometry::identity(), }), local_character_controller: LocalCharacterController::new(), } @@ -550,7 +551,7 @@ impl Sim { let ray_casing_result = graph_ray_casting::ray_cast( &self.graph, &view_position, - &Ray::new(na::Vector4::w(), -na::Vector4::z()), + &Ray::new(math::MVector::w(), -math::MVector::z()), self.cfg.character.block_reach, ); diff --git a/common/src/dodeca.rs b/common/src/dodeca.rs index 3f8e51fe..6d357d7a 100644 --- a/common/src/dodeca.rs +++ b/common/src/dodeca.rs @@ -3,7 +3,6 @@ use data::*; use serde::{Deserialize, Serialize}; -use crate::math; use crate::math::{MVector,MIsometry}; use crate::voxel_math::ChunkAxisPermutation; @@ -70,9 +69,9 @@ impl Side { /// Whether `p` is opposite the dodecahedron across the plane containing `self` #[inline] - pub fn is_facing(self, p: &MVector) -> bool { - let r = na::convert::<_, na::RowVector4>(self.reflection().row(3).clone_owned()); - (r * *p).x < p.w + pub fn is_facing(self, p: &MVector) -> bool { + let r = na::convert::<_, na::RowVector4>(self.reflection().row(3).clone_owned()); + (r * as Into>>::into(*p)).x < p.w } } @@ -188,13 +187,13 @@ impl Vertex { } /// Transform from hyperbolic node space to euclidean chunk coordinates - pub fn node_to_chunk(self) -> na::Matrix4 { - na::Matrix4::new_scaling(Self::dual_to_chunk_factor()) * as Into>>::into(*self.node_to_dual()) + pub fn node_to_chunk(self) -> na::Matrix4 { + na::Matrix4::new_scaling(Self::dual_to_chunk_factor()) * as Into>>::into(*self.node_to_dual()) } /// Transform from hyperbolic node space to euclidean chunk coordinates pub fn node_to_chunk_f64(self) -> na::Matrix4 { - na::Matrix4::new_scaling(Self::dual_to_chunk_factor_f64()) * self.node_to_dual_f64() + na::Matrix4::new_scaling(Self::dual_to_chunk_factor_f64()) * as Into>>::into(*self.node_to_dual_f64()) } /// Transform from cube-centric coordinates to dodeca-centric coordinates @@ -261,7 +260,6 @@ mod data { use std::sync::OnceLock; use crate::dodeca::{Side, Vertex, SIDE_COUNT, VERTEX_COUNT}; - use crate::math; use crate::math::{MVector,MIsometry}; use crate::voxel_math::ChunkAxisPermutation; @@ -602,14 +600,14 @@ mod tests { #[test] fn side_is_facing() { for side in Side::iter() { - assert!(!side.is_facing::(&MVector::origin())); - assert!(side.is_facing(&(side.reflection() * MVector::origin()))); + assert!(!side.is_facing(&MVector::origin())); + assert!(side.is_facing(&(*side.reflection() * MVector::origin()))); } } #[test] fn radius() { - let corner = Vertex::A.chunk_to_node() * MVector::origin(); + let corner = *Vertex::A.dual_to_node() * MVector::origin(); assert_abs_diff_eq!( BOUNDING_SPHERE_RADIUS, math::distance(&corner, &MVector::origin()), diff --git a/common/src/graph.rs b/common/src/graph.rs index c29418a1..43760526 100644 --- a/common/src/graph.rs +++ b/common/src/graph.rs @@ -121,11 +121,11 @@ impl Graph { /// Given a `transform` relative to a `reference` node, computes the node /// that it's closest to and the transform that moves it there - pub fn normalize_transform( + pub fn normalize_transform( &self, mut reference: NodeId, - original: &MIsometry, - ) -> (NodeId, MIsometry) { + original: &MIsometry, + ) -> (NodeId, MIsometry) { let mut transform = MIsometry::identity(); let mut location = *original * MVector::origin(); 'outer: loop { @@ -137,7 +137,7 @@ impl Graph { None => continue, Some(x) => x, }; - let mat = na::convert::<_, na::Matrix4>(*side.reflection_f64()); + let mat = *side.reflection(); location = mat * location; transform = mat * transform; continue 'outer; @@ -403,7 +403,7 @@ mod tests { let a = graph.ensure_neighbor(NodeId::ROOT, Side::A); { let (node, xf) = - graph.normalize_transform::(NodeId::ROOT, &MIsometry::identity()); + graph.normalize_transform(NodeId::ROOT, &MIsometry::identity()); assert_eq!(node, NodeId::ROOT); assert_abs_diff_eq!(xf, MIsometry::identity(), epsilon = 1e-5); } diff --git a/common/src/graph_collision.rs b/common/src/graph_collision.rs index 70e9395c..0c147cfa 100644 --- a/common/src/graph_collision.rs +++ b/common/src/graph_collision.rs @@ -173,8 +173,8 @@ mod tests { let chosen_chunk_transform: MIsometry = self.chosen_voxel.node_path.iter().fold( MIsometry::identity(), - |transform: MIsometry, side| transform * side.reflection().to_f32(), - ) * self.chosen_voxel.vertex.dual_to_node().to_f32(); + |transform: MIsometry, side| transform * *side.reflection(), + ) * *self.chosen_voxel.vertex.dual_to_node(); let dual_to_grid_factor = graph.layout().dual_to_grid_factor(); let ray_target = chosen_chunk_transform @@ -185,7 +185,7 @@ mod tests { 1.0, ).lorentz_normalize(); - let ray_position = Vertex::A.dual_to_node().to_f32() + let ray_position = *Vertex::A.dual_to_node() * MVector::new( self.start_chunk_relative_grid_ray_start[0] / dual_to_grid_factor, self.start_chunk_relative_grid_ray_start[1] / dual_to_grid_factor, @@ -433,7 +433,7 @@ mod tests { } // The node coordinates of the corner of the missing node - let vertex_pos = Vertex::A.dual_to_node().to_f32() * MVector::origin(); + let vertex_pos = *Vertex::A.dual_to_node() * MVector::origin(); // Use a ray starting from the origin. The direction vector is vertex_pos with the w coordinate // set to 0 and normalized diff --git a/common/src/math.rs b/common/src/math.rs index 800d6df9..a406fc62 100644 --- a/common/src/math.rs +++ b/common/src/math.rs @@ -29,7 +29,7 @@ impl approx::AbsDiffEq> for MIsometry #[inline] fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool { - self.abs_diff_eq(other, epsilon) + self.0.abs_diff_eq(&other.0, epsilon) } } @@ -45,7 +45,7 @@ impl approx::AbsDiffEq> for MVector #[inline] fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool { - self.abs_diff_eq(other, epsilon) + self.0.abs_diff_eq(&other.0, epsilon) } } @@ -100,6 +100,13 @@ impl Into> for MIsometry } } +impl Into> for MVector +{ + fn into(self) -> na::Vector4 + { + self.0 + } +} impl MIsometry { @@ -136,9 +143,24 @@ impl MVector impl MIsometry { #[inline] - pub fn row(self, i: usize) -> na::Vector4 + pub fn as_ref(self) -> [[N;4];4] + { + *self.0.as_ref() + } + #[inline] + pub fn unit_quaternion_to_homogeneous(rotation: na::UnitQuaternion) -> Self { - self.row(i) + MIsometry(rotation.to_homogeneous()) + } + #[inline] + pub fn rotation_to_homogeneous(rotation: na::Rotation3) -> Self + { + MIsometry(rotation.to_homogeneous()) + } + #[inline] + pub fn row(self, i: usize) -> na::RowVector4 + { + self.0.row(i).into() } #[inline] pub fn identity() -> Self @@ -146,7 +168,7 @@ impl MIsometry Self(na::Matrix4::identity()) } #[inline] - pub fn map N2>(&self, mut f: F) -> MIsometry + pub fn map N2>(&self, f: F) -> MIsometry { MIsometry(self.0.map(f)) } @@ -332,34 +354,53 @@ impl Mul> for MIsometry } } -impl MulAssign for MVector +impl Mul for MIsometry { + type Output = MIsometry; #[inline] - fn mul_assign(&mut self, rhs: N) + fn mul(self, rhs: N) -> Self::Output { - *self *= rhs; + MIsometry(self.0 * rhs) } } -impl std::ops::AddAssign for MVector +impl std::ops::AddAssign for MVector { #[inline] fn add_assign(&mut self, other: Self) { - *self += other; + *self = *self + other; } } +impl MulAssign for MVector +{ + #[inline] + fn mul_assign(&mut self, rhs: N) + { + *self = *self * rhs; + } +} -impl MulAssign for MIsometry +impl MulAssign for MIsometry { #[inline] fn mul_assign(&mut self, rhs: N) { - *self *= rhs; + *self = *self * rhs; } } +impl MulAssign> for MIsometry +{ + #[inline] + fn mul_assign(&mut self, rhs: MIsometry) + { + *self = *self * rhs; + } +} + + impl Index for MVector { type Output = N; diff --git a/common/src/node.rs b/common/src/node.rs index 26c35d61..abe46d42 100644 --- a/common/src/node.rs +++ b/common/src/node.rs @@ -8,6 +8,7 @@ use crate::collision_math::Ray; use crate::dodeca::Vertex; use crate::graph::{Graph, NodeId}; use crate::lru_slab::SlotId; +use crate::math::MVector; use crate::proto::{BlockUpdate, Position, SerializedVoxelData}; use crate::voxel_math::{ChunkDirection, CoordAxis, CoordSign, Coords}; use crate::world::Material; @@ -374,8 +375,8 @@ impl VoxelAABB { ) -> Option { // Convert the ray to grid coordinates let grid_start = - na::Point3::from_homogeneous(ray.position).unwrap() * layout.dual_to_grid_factor(); - let grid_end = na::Point3::from_homogeneous(ray.ray_point(tanh_distance)).unwrap() + na::Point3::from_homogeneous(ray.position.into()).unwrap() * layout.dual_to_grid_factor(); + let grid_end = na::Point3::from_homogeneous(ray.ray_point(tanh_distance).into()).unwrap() * layout.dual_to_grid_factor(); // Convert the radius to grid coordinates using a crude conservative estimate let max_grid_radius = radius * layout.dual_to_grid_factor(); @@ -433,7 +434,7 @@ mod tests { use std::collections::HashSet; use crate::math; - use crate::math::MVector; + use crate::math::{MVector,MIsometry}; use super::*; @@ -446,7 +447,7 @@ mod tests { let layout = ChunkLayout::new(dimension); // Pick an arbitrary ray by transforming the positive-x-axis ray. - let ray = na::Rotation3::from_axis_angle(&na::Vector3::z_axis(), 0.4).to_homogeneous() + let ray = MIsometry::rotation_to_homogeneous(na::Rotation3::from_axis_angle(&na::Vector3::z_axis(), 0.4)) * math::translate_along(&na::Vector3::new(0.2, 0.3, 0.1)) * &Ray::new(MVector::w(), MVector::x()); @@ -501,7 +502,7 @@ mod tests { // For a given axis, all lines have the same direction, so set up the appropriate vector // in advance. - let mut line_direction = na::Vector4::zeros(); + let mut line_direction = MVector::zero(); line_direction[t_axis] = 1.0; let line_direction = line_direction; diff --git a/common/src/plane.rs b/common/src/plane.rs index fd283ec6..cfda37af 100644 --- a/common/src/plane.rs +++ b/common/src/plane.rs @@ -72,7 +72,7 @@ impl Plane { impl Plane { /// Like `distance_to`, but using chunk coordinates for a chunk in the same node space pub fn distance_to_chunk(&self, chunk: Vertex, coord: &na::Vector3) -> f64 { - let pos = (MVector::::from(chunk.chunk_to_node() * coord.push(1.0))).lorentz_normalize(); + let pos = (MVector::::from(chunk.chunk_to_node_f64() * coord.push(1.0))).lorentz_normalize(); self.distance_to(&pos) } } diff --git a/common/src/sim_config.rs b/common/src/sim_config.rs index a0ae2bdd..124cb1d0 100644 --- a/common/src/sim_config.rs +++ b/common/src/sim_config.rs @@ -69,8 +69,8 @@ impl SimConfig { /// Compute the scaling factor from meters to absolute units, given the number of voxels in a chunk /// and the approximate size of a voxel in meters. fn meters_to_absolute(chunk_size: u8, voxel_size: f32) -> f32 { - let a = MVector::::from(dodeca::Vertex::A.chunk_to_node() * na::Vector4::new(1.0, 0.5, 0.5, 1.0)); - let b = MVector::::from(dodeca::Vertex::A.chunk_to_node() * na::Vector4::new(0.0, 0.5, 0.5, 1.0)); + let a = MVector::from(dodeca::Vertex::A.chunk_to_node() * na::Vector4::new(1.0, 0.5, 0.5, 1.0)); + let b = MVector::from(dodeca::Vertex::A.chunk_to_node() * na::Vector4::new(0.0, 0.5, 0.5, 1.0)); let minimum_chunk_face_separation = math::distance(&a, &b); let absolute_voxel_size = minimum_chunk_face_separation / f32::from(chunk_size); absolute_voxel_size / voxel_size diff --git a/common/src/traversal.rs b/common/src/traversal.rs index 624367c2..7c88fec2 100644 --- a/common/src/traversal.rs +++ b/common/src/traversal.rs @@ -68,12 +68,12 @@ pub fn nearby_nodes( }); visited.insert(start.node); - while let Some(current) = pending.pop() { + while let Some(current) = pending.pop_front() { let current_p = current.transform * MVector::origin(); if -(start_p.mip(¤t_p)) > distance.cosh() { continue; } - result.push((current.id, current.transform.to_f32())); + result.push((current.id, current.transform)); for side in Side::iter() { let neighbor = match graph.neighbor(current.id, side) { @@ -114,7 +114,7 @@ impl<'a> RayTraverser<'a> { let mut closest_vertex = Vertex::A; let mut closest_vertex_cosh_distance = f32::INFINITY; for vertex in Vertex::iter() { - let vertex_cosh_distance = (vertex.node_to_dual() * position.local * MVector::origin()).w; + let vertex_cosh_distance = (*vertex.node_to_dual() * position.local * MVector::origin()).w; if vertex_cosh_distance < closest_vertex_cosh_distance { closest_vertex = vertex; closest_vertex_cosh_distance = vertex_cosh_distance; @@ -152,7 +152,7 @@ impl<'a> RayTraverser<'a> { // Combine node and vertex, and convert node transform to chunk transform return Some(( node.map(|node| ChunkId::new(node, vertex)), - vertex.node_to_dual() * node_transform, + *vertex.node_to_dual() * node_transform, )); } @@ -163,14 +163,14 @@ impl<'a> RayTraverser<'a> { continue; }; - let local_ray = vertex.node_to_dual() * node_transform * self.ray; + let local_ray = *vertex.node_to_dual() * node_transform * self.ray; // Compute the Klein-Beltrami coordinates of the ray segment's endpoints. To check whether neighboring chunks // are needed, we need to check whether the endpoints of the line segments lie outside the boundaries of the square // bounded by `klein_lower_boundary` and `klein_upper_boundary`. - let klein_ray_start = na::Point3::from_homogeneous(local_ray.position).unwrap(); + let klein_ray_start = na::Point3::from_homogeneous(local_ray.position.into()).unwrap(); let klein_ray_end = - na::Point3::from_homogeneous(local_ray.ray_point(tanh_distance)).unwrap(); + na::Point3::from_homogeneous(local_ray.ray_point(tanh_distance).into()).unwrap(); // Add neighboring chunks as necessary based on a conservative AABB check, using one coordinate at a time. for axis in 0..3 { @@ -179,7 +179,7 @@ impl<'a> RayTraverser<'a> { || klein_ray_end[axis] <= self.klein_lower_boundary { let side = vertex.canonical_sides()[axis]; - let next_node_transform = side.reflection() * node_transform; + let next_node_transform = *side.reflection() * node_transform; // Crude check to ensure that the neighboring chunk's node can be in the path of the ray. For simplicity, this // check treats each node as a sphere and assumes the ray is pointed directly towards its center. The check is // needed because chunk generation uses this approximation, and this check is not guaranteed to pass near corners diff --git a/server/src/sim.rs b/server/src/sim.rs index dac719b4..e5b761ad 100644 --- a/server/src/sim.rs +++ b/server/src/sim.rs @@ -146,7 +146,7 @@ impl Sim { if let Some(pos) = entity.get::<&Position>() { components.push(( ComponentType::Position as u64, - postcard::to_stdvec(pos.local.as_ref()).unwrap(), + postcard::to_stdvec(&pos.local.as_ref()).unwrap(), )); } if let Some(ch) = entity.get::<&Character>() { From f4a88bccdbe58b610efa632cd4130fbbbdf0b17f Mon Sep 17 00:00:00 2001 From: strawberry Date: Sun, 21 Jul 2024 14:28:54 -0500 Subject: [PATCH 04/31] added back lorentz_normalize() fixing the test --- common/src/math.rs | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/common/src/math.rs b/common/src/math.rs index a406fc62..249c123d 100644 --- a/common/src/math.rs +++ b/common/src/math.rs @@ -433,8 +433,8 @@ impl Index<(usize,usize)> for MIsometry /// Transform that translates `a` to `b` given that `a` and `b` are Lorentz normalized pointlike vectors pub fn translate(a: &MVector, b: &MVector) -> MIsometry { let a_plus_b = *a + *b; - MIsometry(na::Matrix4::::identity() - (b.minkowski_outer_product(a) * na::convert::<_, N>(2.0)) - + a_plus_b.minkowski_outer_product(&a_plus_b) / (N::one() - a.mip(b))) + MIsometry((na::Matrix4::::identity()) - (b.minkowski_outer_product(a) * na::convert::<_, N>(2.0)) + + ((a_plus_b.minkowski_outer_product(&a_plus_b)) / (N::one() - a.mip(b)))) } /// Transform that translates the origin in the direction of the given vector with distance equal to its magnitude @@ -525,13 +525,6 @@ pub fn tuv_to_xyz, N: Copy>(t_axis: usi result } -fn minkowski_outer_product( - a: &MVector, - b: &MVector, -) -> na::Matrix4 { - ((*a).0) * na::RowVector4::new(b.0.x, b.0.y, b.0.z, -b.0.w) -} - #[cfg(test)] mod tests { use super::*; @@ -662,8 +655,8 @@ mod tests { // translation with some error let mat = MIsometry(translate( - &MVector::new(-0.5, -0.5, 0.0, 1.0), - &MVector::new(0.3, -0.7, 0.0, 1.0), + &MVector::new(-0.5, -0.5, 0.0, 1.0).lorentz_normalize(), + &MVector::new(0.3, -0.7, 0.0, 1.0).lorentz_normalize(), ).0 + error.0 * 0.05); let normalized_mat = mat.renormalize_isometry(); @@ -671,7 +664,7 @@ mod tests { // Check that the matrix is actually normalized assert_abs_diff_eq!( normalized_mat.mtranspose() * normalized_mat, - MIsometry(na::Matrix4::identity()), + MIsometry::identity(), epsilon = 1e-5 ); } From 4d4b0901c50abc3192fa8312ca71f5f6f0e52cc9 Mon Sep 17 00:00:00 2001 From: strawberry Date: Tue, 23 Jul 2024 18:09:54 -0500 Subject: [PATCH 05/31] decreased verbosity of some into() calls by using less verbose variations using from() --- client/src/graphics/draw.rs | 6 +++--- client/src/graphics/voxels/mod.rs | 2 +- common/src/dodeca.rs | 10 +++++----- common/src/math.rs | 12 ++++++------ 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/client/src/graphics/draw.rs b/client/src/graphics/draw.rs index e8bfdc00..c1a6bfc6 100644 --- a/client/src/graphics/draw.rs +++ b/client/src/graphics/draw.rs @@ -289,7 +289,7 @@ impl Draw { let draw_started = Instant::now(); let view = sim.as_ref().map_or_else(Position::origin, |sim| sim.view()); let projection = frustum.projection(1.0e-4); - let view_projection = projection.matrix() * as Into>>::into(view.local.mtranspose()); + let view_projection = projection.matrix() * na::Matrix4::<_>::from(view.local.mtranspose()); self.loader.drive(); let device = &*self.gfx.device; @@ -482,8 +482,8 @@ impl Draw { .expect("positionless entity in graph"); if let Some(character_model) = self.loader.get(self.character_model) { if let Ok(ch) = sim.world.get::<&Character>(entity) { - let transform = as Into>>::into(transform) - * as Into>>::into(pos.local) + let transform = na::Matrix4::<_>::from(transform) + * na::Matrix4::<_>::from(pos.local) * na::Matrix4::new_scaling(sim.cfg().meters_to_absolute) * ch.state.orientation.to_homogeneous(); for mesh in &character_model.0 { diff --git a/client/src/graphics/voxels/mod.rs b/client/src/graphics/voxels/mod.rs index eb061d76..826b5a67 100644 --- a/client/src/graphics/voxels/mod.rs +++ b/client/src/graphics/voxels/mod.rs @@ -174,7 +174,7 @@ impl Voxels { frame.drawn.push(slot); // Transfer transform frame.surface.transforms_mut()[slot.0 as usize] = - as Into>>::into(*node_transform) * vertex.chunk_to_node(); + na::Matrix4::<_>::from(*node_transform) * vertex.chunk_to_node(); } if let (None, &VoxelData::Dense(ref data)) = (&surface, voxels) { // Extract a surface so it can be drawn in future frames diff --git a/common/src/dodeca.rs b/common/src/dodeca.rs index 6d357d7a..006f4d83 100644 --- a/common/src/dodeca.rs +++ b/common/src/dodeca.rs @@ -71,7 +71,7 @@ impl Side { #[inline] pub fn is_facing(self, p: &MVector) -> bool { let r = na::convert::<_, na::RowVector4>(self.reflection().row(3).clone_owned()); - (r * as Into>>::into(*p)).x < p.w + (r * na::Vector4::<_>::from(*p)).x < p.w } } @@ -178,22 +178,22 @@ impl Vertex { /// Transform from euclidean chunk coordinates to hyperbolic node space pub fn chunk_to_node(self) -> na::Matrix4 { - as Into>>::into(*self.dual_to_node()) * na::Matrix4::new_scaling(1.0 / Self::dual_to_chunk_factor()) + na::Matrix4::<_>::from(*self.dual_to_node()) * na::Matrix4::new_scaling(1.0 / Self::dual_to_chunk_factor()) } /// Transform from euclidean chunk coordinates to hyperbolic node space pub fn chunk_to_node_f64(self) -> na::Matrix4 { - as Into>>::into(*self.dual_to_node_f64()) * na::Matrix4::new_scaling(1.0 / Self::dual_to_chunk_factor_f64()) + na::Matrix4::<_>::from(*self.dual_to_node_f64()) * na::Matrix4::new_scaling(1.0 / Self::dual_to_chunk_factor_f64()) } /// Transform from hyperbolic node space to euclidean chunk coordinates pub fn node_to_chunk(self) -> na::Matrix4 { - na::Matrix4::new_scaling(Self::dual_to_chunk_factor()) * as Into>>::into(*self.node_to_dual()) + na::Matrix4::new_scaling(Self::dual_to_chunk_factor()) * na::Matrix4::<_>::from(*self.node_to_dual()) } /// Transform from hyperbolic node space to euclidean chunk coordinates pub fn node_to_chunk_f64(self) -> na::Matrix4 { - na::Matrix4::new_scaling(Self::dual_to_chunk_factor_f64()) * as Into>>::into(*self.node_to_dual_f64()) + na::Matrix4::new_scaling(Self::dual_to_chunk_factor_f64()) * na::Matrix4::<_>::from(*self.node_to_dual_f64()) } /// Transform from cube-centric coordinates to dodeca-centric coordinates diff --git a/common/src/math.rs b/common/src/math.rs index 249c123d..c033a199 100644 --- a/common/src/math.rs +++ b/common/src/math.rs @@ -92,19 +92,19 @@ impl Deref for MIsometry { } } -impl Into> for MIsometry +impl From> for na::Matrix4 { - fn into(self) -> na::Matrix4 + fn from(value: MIsometry) -> na::Matrix4 { - self.0 + value.0 } } -impl Into> for MVector +impl From> for na::Vector4 { - fn into(self) -> na::Vector4 + fn from(value: MVector) -> na::Vector4 { - self.0 + value.0 } } From 9c0680e7116823a1432e4a57931b5e1f136c046b Mon Sep 17 00:00:00 2001 From: strawberry Date: Tue, 23 Jul 2024 19:22:22 -0500 Subject: [PATCH 06/31] removed obsolete commented out code --- common/src/math.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/common/src/math.rs b/common/src/math.rs index c033a199..1c8ab901 100644 --- a/common/src/math.rs +++ b/common/src/math.rs @@ -202,10 +202,6 @@ impl MIsometry ); MIsometry(boost.0 * rotation.to_homogeneous()) } - /*pub fn cast(self) -> MIsometry where N: simba::scalar::SubsetOf - { - Self(self.0.cast::()) - }*/ } impl MVector { From f22b047fe538d7ba30b51446077049ceed618336 Mon Sep 17 00:00:00 2001 From: strawberry Date: Tue, 23 Jul 2024 19:26:20 -0500 Subject: [PATCH 07/31] readd accidentally removed comment --- common/src/dodeca.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/common/src/dodeca.rs b/common/src/dodeca.rs index 006f4d83..13e9d8b9 100644 --- a/common/src/dodeca.rs +++ b/common/src/dodeca.rs @@ -62,6 +62,7 @@ impl Side { &reflections_f32()[self as usize] } + /// Reflection across this side #[inline] pub fn reflection_f64(self) -> &'static MIsometry { &reflections_f64()[self as usize] From f3225380a194068f7f8cf26ba0de820080500ab8 Mon Sep 17 00:00:00 2001 From: strawberry Date: Tue, 23 Jul 2024 19:31:41 -0500 Subject: [PATCH 08/31] changed the definition of MVector::origin() for brevity --- common/src/math.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/math.rs b/common/src/math.rs index 1c8ab901..c7b6b861 100644 --- a/common/src/math.rs +++ b/common/src/math.rs @@ -241,7 +241,7 @@ impl MVector { } pub fn origin() -> Self { - Self(na::Vector4::new(na::zero(),na::zero(),na::zero(),na::one())) + Self::w() } #[inline] pub fn normalize(self) -> Self From 679f3be9c1d71be0142f815d80a8e46cfaaf54a1 Mon Sep 17 00:00:00 2001 From: strawberry Date: Tue, 23 Jul 2024 19:40:08 -0500 Subject: [PATCH 09/31] used dual_to_node_f64() and BOUNDING_SPHERE_RADIUS_F64 for better precision --- common/src/dodeca.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/src/dodeca.rs b/common/src/dodeca.rs index 13e9d8b9..b765ccd1 100644 --- a/common/src/dodeca.rs +++ b/common/src/dodeca.rs @@ -608,9 +608,9 @@ mod tests { #[test] fn radius() { - let corner = *Vertex::A.dual_to_node() * MVector::origin(); + let corner = *Vertex::A.dual_to_node_f64() * MVector::origin(); assert_abs_diff_eq!( - BOUNDING_SPHERE_RADIUS, + BOUNDING_SPHERE_RADIUS_F64, math::distance(&corner, &MVector::origin()), epsilon = 1e-10 ); From 7d048e6bd7ff78adfaa391dc582faaa96124d5a1 Mon Sep 17 00:00:00 2001 From: strawberry Date: Tue, 23 Jul 2024 19:53:39 -0500 Subject: [PATCH 10/31] formatting --- client/src/graphics/frustum.rs | 32 ++- client/src/local_character_controller.rs | 3 +- client/src/sim.rs | 3 +- common/src/character_controller/collision.rs | 13 +- common/src/chunk_collision.rs | 51 ++-- common/src/chunk_ray_casting.rs | 20 +- common/src/collision_math.rs | 59 ++--- common/src/dodeca.rs | 22 +- common/src/graph.rs | 5 +- common/src/graph_collision.rs | 29 +- common/src/math.rs | 263 +++++++------------ common/src/node.rs | 18 +- common/src/plane.rs | 5 +- common/src/proto.rs | 4 +- common/src/traversal.rs | 5 +- common/src/worldgen.rs | 3 +- 16 files changed, 249 insertions(+), 286 deletions(-) diff --git a/client/src/graphics/frustum.rs b/client/src/graphics/frustum.rs index 6ee68593..07d3480b 100644 --- a/client/src/graphics/frustum.rs +++ b/client/src/graphics/frustum.rs @@ -1,5 +1,5 @@ -use common::Plane; use common::math; +use common::Plane; #[derive(Debug, Copy, Clone)] pub struct Frustum { @@ -101,12 +101,30 @@ mod tests { // 90 degree square let planes = Frustum::from_vfov(f32::consts::FRAC_PI_4, 1.0).planes(); assert!(planes.contain(&MVector::origin(), 0.1)); - assert!(planes.contain(&(translate_along(&-na::Vector3::z()) * MVector::origin()), 0.0)); - assert!(!planes.contain(&(translate_along(&na::Vector3::z()) * MVector::origin()), 0.0)); + assert!(planes.contain( + &(translate_along(&-na::Vector3::z()) * MVector::origin()), + 0.0 + )); + assert!(!planes.contain( + &(translate_along(&na::Vector3::z()) * MVector::origin()), + 0.0 + )); - assert!(!planes.contain(&(translate_along(&na::Vector3::x()) * MVector::origin()), 0.0)); - assert!(!planes.contain(&(translate_along(&na::Vector3::y()) * MVector::origin()), 0.0)); - assert!(!planes.contain(&(translate_along(&-na::Vector3::x()) * MVector::origin()), 0.0)); - assert!(!planes.contain(&(translate_along(&-na::Vector3::y()) * MVector::origin()), 0.0)); + assert!(!planes.contain( + &(translate_along(&na::Vector3::x()) * MVector::origin()), + 0.0 + )); + assert!(!planes.contain( + &(translate_along(&na::Vector3::y()) * MVector::origin()), + 0.0 + )); + assert!(!planes.contain( + &(translate_along(&-na::Vector3::x()) * MVector::origin()), + 0.0 + )); + assert!(!planes.contain( + &(translate_along(&-na::Vector3::y()) * MVector::origin()), + 0.0 + )); } } diff --git a/client/src/local_character_controller.rs b/client/src/local_character_controller.rs index 7e505219..1c5ac13b 100644 --- a/client/src/local_character_controller.rs +++ b/client/src/local_character_controller.rs @@ -25,7 +25,8 @@ impl LocalCharacterController { pub fn oriented_position(&self) -> Position { Position { node: self.position.node, - local: self.position.local * math::MIsometry::unit_quaternion_to_homogeneous(self.orientation), + local: self.position.local + * math::MIsometry::unit_quaternion_to_homogeneous(self.orientation), } } diff --git a/client/src/sim.rs b/client/src/sim.rs index 8f41e85f..0d3995e0 100644 --- a/client/src/sim.rs +++ b/client/src/sim.rs @@ -12,13 +12,12 @@ use common::{ character_controller, collision_math::Ray, graph::{Graph, NodeId}, - graph_ray_casting, + graph_ray_casting, math, node::{populate_fresh_nodes, ChunkId, VoxelData}, proto::{ self, BlockUpdate, Character, CharacterInput, CharacterState, Command, Component, Inventory, Position, }, - math, sanitize_motion_input, world::Material, EntityId, GraphEntities, SimConfig, Step, diff --git a/common/src/character_controller/collision.rs b/common/src/character_controller/collision.rs index 464efa2c..06b8905a 100644 --- a/common/src/character_controller/collision.rs +++ b/common/src/character_controller/collision.rs @@ -2,7 +2,13 @@ use tracing::error; -use crate::{collision_math::Ray, graph::Graph, graph_collision, math, math::{MVector,MIsometry}, proto::Position}; +use crate::{ + collision_math::Ray, + graph::Graph, + graph_collision, math, + math::{MIsometry, MVector}, + proto::Position, +}; /// Checks for collisions when a character moves with a character-relative displacement vector of `relative_displacement`. pub fn check_collision( @@ -22,7 +28,10 @@ pub fn check_collision( let displacement_norm = displacement_sqr.sqrt(); let displacement_normalized = relative_displacement / displacement_norm; - let ray = Ray::new(MVector::origin(), MVector::::from(displacement_normalized)); + let ray = Ray::new( + MVector::origin(), + MVector::::from(displacement_normalized), + ); let tanh_distance = displacement_norm.tanh(); let cast_hit = graph_collision::sphere_cast( diff --git a/common/src/chunk_collision.rs b/common/src/chunk_collision.rs index dd9e1962..548f263c 100644 --- a/common/src/chunk_collision.rs +++ b/common/src/chunk_collision.rs @@ -91,10 +91,8 @@ fn find_face_collision( for t in bounding_box.grid_planes(t_axis) { // Find a normal to the grid plane. Note that (t, 0, 0, x) is a normal of the plane whose closest point // to the origin is (x, 0, 0, t), and we use that fact here. - let normal = math::tuv_to_xyz( - t_axis, - MVector::new(1.0, 0.0, 0.0, layout.grid_to_dual(t)), - ).lorentz_normalize(); + let normal = math::tuv_to_xyz(t_axis, MVector::new(1.0, 0.0, 0.0, layout.grid_to_dual(t))) + .lorentz_normalize(); let Some(new_tanh_distance) = ray.solve_sphere_plane_intersection(&normal, collider_radius.sinh()) @@ -170,18 +168,14 @@ fn find_edge_collision( // Loop through all grid lines overlapping the bounding box for (u, v) in bounding_box.grid_lines(u_axis, v_axis) { // Compute vectors Lorentz-orthogonal to the edge and to each other - let edge_normal0 = math::tuv_to_xyz( - t_axis, - MVector::new(0.0, 1.0, 0.0, layout.grid_to_dual(u)), - ).lorentz_normalize(); + let edge_normal0 = + math::tuv_to_xyz(t_axis, MVector::new(0.0, 1.0, 0.0, layout.grid_to_dual(u))) + .lorentz_normalize(); - let edge_normal1 = math::tuv_to_xyz( - t_axis, - MVector::new(0.0, 0.0, 1.0, layout.grid_to_dual(v)), - ); let edge_normal1 = - (edge_normal1 - edge_normal0 * edge_normal0.mip(&edge_normal1)) - .lorentz_normalize(); + math::tuv_to_xyz(t_axis, MVector::new(0.0, 0.0, 1.0, layout.grid_to_dual(v))); + let edge_normal1 = + (edge_normal1 - edge_normal0 * edge_normal0.mip(&edge_normal1)).lorentz_normalize(); let Some(new_tanh_distance) = ray.solve_sphere_line_intersection( &edge_normal0, @@ -255,19 +249,17 @@ fn find_vertex_collision( // Compute vectors Lorentz-orthogonal to the vertex and to each other let vertex_normal0 = - MVector::new(1.0, 0.0, 0.0, layout.grid_to_dual(x)) - .lorentz_normalize(); + MVector::new(1.0, 0.0, 0.0, layout.grid_to_dual(x)).lorentz_normalize(); let vertex_normal1 = MVector::new(0.0, 1.0, 0.0, layout.grid_to_dual(y)); - let vertex_normal1 = - (vertex_normal1 - vertex_normal0 * vertex_normal0.mip(&vertex_normal1)) + let vertex_normal1 = (vertex_normal1 + - vertex_normal0 * vertex_normal0.mip(&vertex_normal1)) .lorentz_normalize(); let vertex_normal2 = MVector::new(0.0, 0.0, 1.0, layout.grid_to_dual(z)); - let vertex_normal2 = - (vertex_normal2 - - vertex_normal0 * vertex_normal0.mip(&vertex_normal2) - - vertex_normal1 * vertex_normal1.mip(&vertex_normal2)) + let vertex_normal2 = (vertex_normal2 + - vertex_normal0 * vertex_normal0.mip(&vertex_normal2) + - vertex_normal1 * vertex_normal1.mip(&vertex_normal2)) .lorentz_normalize(); let Some(new_tanh_distance) = ray.solve_sphere_point_intersection( @@ -290,7 +282,8 @@ fn find_vertex_collision( layout.grid_to_dual(y), layout.grid_to_dual(z), 1.0, - ).lorentz_normalize(); + ) + .lorentz_normalize(); // A collision was found. Update the hit. let ray_endpoint = ray.ray_point(new_tanh_distance); @@ -363,19 +356,20 @@ mod tests { ray_start_grid_coords[1] / ctx.layout.dual_to_grid_factor(), ray_start_grid_coords[2] / ctx.layout.dual_to_grid_factor(), 1.0, - ).lorentz_normalize(); + ) + .lorentz_normalize(); let ray_end = MVector::new( ray_end_grid_coords[0] / ctx.layout.dual_to_grid_factor(), ray_end_grid_coords[1] / ctx.layout.dual_to_grid_factor(), ray_end_grid_coords[2] / ctx.layout.dual_to_grid_factor(), 1.0, - ).lorentz_normalize(); + ) + .lorentz_normalize(); let ray = Ray::new( ray_start, - ((ray_end - ray_start) - + ray_start * ray_start.mip(&(ray_end - ray_start))) + ((ray_end - ray_start) + ray_start * ray_start.mip(&(ray_end - ray_start))) .lorentz_normalize(), ); @@ -524,8 +518,7 @@ mod tests { // Project normal to be perpendicular to the ray's position let corrected_normal = - (hit.normal + ray.position * hit.normal.mip(&ray.position)) - .lorentz_normalize(); + (hit.normal + ray.position * hit.normal.mip(&ray.position)).lorentz_normalize(); // Check that the normal and ray are pointing opposite directions assert!(corrected_normal.mip(&ray.direction) < 0.0); diff --git a/common/src/chunk_ray_casting.rs b/common/src/chunk_ray_casting.rs index 0cb26b15..b539339f 100644 --- a/common/src/chunk_ray_casting.rs +++ b/common/src/chunk_ray_casting.rs @@ -69,10 +69,8 @@ fn find_face_collision( for t in bounding_box.grid_planes(t_axis) { // Find a normal to the grid plane. Note that (t, 0, 0, x) is a normal of the plane whose closest point // to the origin is (x, 0, 0, t), and we use that fact here. - let normal = math::tuv_to_xyz( - t_axis, - MVector::new(1.0, 0.0, 0.0, layout.grid_to_dual(t)), - ).lorentz_normalize(); + let normal = math::tuv_to_xyz(t_axis, MVector::new(1.0, 0.0, 0.0, layout.grid_to_dual(t))) + .lorentz_normalize(); let Some(new_tanh_distance) = ray.solve_point_plane_intersection(&normal) else { continue; @@ -125,7 +123,7 @@ fn find_face_collision( face_axis: CoordAxis::try_from(t_axis).unwrap(), face_sign, }); - }; + } hit } @@ -187,22 +185,24 @@ mod tests { ray_start_grid_coords[1] / ctx.layout.dual_to_grid_factor(), ray_start_grid_coords[2] / ctx.layout.dual_to_grid_factor(), 1.0, - ).lorentz_normalize(); + ) + .lorentz_normalize(); let ray_end = MVector::new( ray_end_grid_coords[0] / ctx.layout.dual_to_grid_factor(), ray_end_grid_coords[1] / ctx.layout.dual_to_grid_factor(), ray_end_grid_coords[2] / ctx.layout.dual_to_grid_factor(), 1.0, - ).lorentz_normalize(); + ) + .lorentz_normalize(); let ray = Ray::new( ray_start, - ((ray_end - ray_start) - + ray_start * ray_start.mip(&(ray_end - ray_start))).lorentz_normalize(), + ((ray_end - ray_start) + ray_start * ray_start.mip(&(ray_end - ray_start))) + .lorentz_normalize(), ); - let tanh_distance = (- (ray_start.mip(&ray_end))).acosh(); + let tanh_distance = (-(ray_start.mip(&ray_end))).acosh(); wrapped_fn(&ray, tanh_distance) } diff --git a/common/src/collision_math.rs b/common/src/collision_math.rs index 3766e918..aa4b08c4 100644 --- a/common/src/collision_math.rs +++ b/common/src/collision_math.rs @@ -1,5 +1,5 @@ use crate::math; -use crate::math::{MVector,MIsometry}; +use crate::math::{MIsometry, MVector}; /// A ray in hyperbolic space. The fields must be lorentz normalized, with `mip(position, position) == -1`, /// `mip(direction, direction) == 1`, and `mip(position, direction) == 0`. @@ -160,17 +160,14 @@ mod tests { let ray = math::translate_along(&na::Vector3::new(0.0, 0.0, -0.5)) * &Ray::new(MVector::origin(), MVector::new(0.8, 0.0, 0.6, 0.0)); let normal = -MVector::z(); - let hit_point = - ray.ray_point( - ray.solve_sphere_plane_intersection(&normal, 0.2_f32.sinh()) - .unwrap(), - ).lorentz_normalize(); + let hit_point = ray + .ray_point( + ray.solve_sphere_plane_intersection(&normal, 0.2_f32.sinh()) + .unwrap(), + ) + .lorentz_normalize(); - assert_abs_diff_eq!( - hit_point.mip(&normal), - 0.2_f32.sinh(), - epsilon = 1e-4 - ); + assert_abs_diff_eq!(hit_point.mip(&normal), 0.2_f32.sinh(), epsilon = 1e-4); } #[test] @@ -221,16 +218,15 @@ mod tests { ); let line_normal0 = MVector::x(); let line_normal1 = MVector::z(); - let hit_point = - ray.ray_point( - ray.solve_sphere_line_intersection(&line_normal0, &line_normal1, 0.2_f32.sinh()) - .unwrap(), - ).lorentz_normalize(); + let hit_point = ray + .ray_point( + ray.solve_sphere_line_intersection(&line_normal0, &line_normal1, 0.2_f32.sinh()) + .unwrap(), + ) + .lorentz_normalize(); // Measue the distance from hit_point to the line and ensure it's equal to the radius assert_abs_diff_eq!( - (hit_point.mip(&line_normal0).powi(2) - + hit_point.mip(&line_normal1).powi(2)) - .sqrt(), + (hit_point.mip(&line_normal0).powi(2) + hit_point.mip(&line_normal1).powi(2)).sqrt(), 0.2_f32.sinh(), epsilon = 1e-4 ); @@ -313,18 +309,19 @@ mod tests { let point_normal0 = MVector::x(); let point_normal1 = MVector::y(); let point_normal2 = MVector::z(); - let hit_point = - ray.ray_point( - ray.solve_sphere_point_intersection( - &point_normal0, - &point_normal1, - &point_normal2, - 0.2_f32.sinh(), + let hit_point = ray + .ray_point( + ray.solve_sphere_point_intersection( + &point_normal0, + &point_normal1, + &point_normal2, + 0.2_f32.sinh(), + ) + .unwrap(), ) - .unwrap(), - ).lorentz_normalize(); + .lorentz_normalize(); assert_abs_diff_eq!( - - hit_point.mip(&point_position), + -hit_point.mip(&point_position), 0.2_f32.cosh(), epsilon = 1e-4 ); @@ -395,7 +392,9 @@ mod tests { let ray = math::translate_along(&na::Vector3::new(0.0, 0.0, -0.5)) * &Ray::new(MVector::origin(), MVector::new(0.8, 0.0, 0.6, 0.0)); let normal = -MVector::z(); - let hit_point = ray.ray_point(ray.solve_point_plane_intersection(&normal).unwrap()).lorentz_normalize(); + let hit_point = ray + .ray_point(ray.solve_point_plane_intersection(&normal).unwrap()) + .lorentz_normalize(); assert_abs_diff_eq!(hit_point.mip(&normal), 0.0, epsilon = 1e-4); } diff --git a/common/src/dodeca.rs b/common/src/dodeca.rs index b765ccd1..1754065f 100644 --- a/common/src/dodeca.rs +++ b/common/src/dodeca.rs @@ -3,7 +3,7 @@ use data::*; use serde::{Deserialize, Serialize}; -use crate::math::{MVector,MIsometry}; +use crate::math::{MIsometry, MVector}; use crate::voxel_math::ChunkAxisPermutation; /// Sides of a right dodecahedron @@ -179,22 +179,26 @@ impl Vertex { /// Transform from euclidean chunk coordinates to hyperbolic node space pub fn chunk_to_node(self) -> na::Matrix4 { - na::Matrix4::<_>::from(*self.dual_to_node()) * na::Matrix4::new_scaling(1.0 / Self::dual_to_chunk_factor()) + na::Matrix4::<_>::from(*self.dual_to_node()) + * na::Matrix4::new_scaling(1.0 / Self::dual_to_chunk_factor()) } /// Transform from euclidean chunk coordinates to hyperbolic node space pub fn chunk_to_node_f64(self) -> na::Matrix4 { - na::Matrix4::<_>::from(*self.dual_to_node_f64()) * na::Matrix4::new_scaling(1.0 / Self::dual_to_chunk_factor_f64()) + na::Matrix4::<_>::from(*self.dual_to_node_f64()) + * na::Matrix4::new_scaling(1.0 / Self::dual_to_chunk_factor_f64()) } /// Transform from hyperbolic node space to euclidean chunk coordinates pub fn node_to_chunk(self) -> na::Matrix4 { - na::Matrix4::new_scaling(Self::dual_to_chunk_factor()) * na::Matrix4::<_>::from(*self.node_to_dual()) + na::Matrix4::new_scaling(Self::dual_to_chunk_factor()) + * na::Matrix4::<_>::from(*self.node_to_dual()) } /// Transform from hyperbolic node space to euclidean chunk coordinates pub fn node_to_chunk_f64(self) -> na::Matrix4 { - na::Matrix4::new_scaling(Self::dual_to_chunk_factor_f64()) * na::Matrix4::<_>::from(*self.node_to_dual_f64()) + na::Matrix4::new_scaling(Self::dual_to_chunk_factor_f64()) + * na::Matrix4::<_>::from(*self.node_to_dual_f64()) } /// Transform from cube-centric coordinates to dodeca-centric coordinates @@ -261,7 +265,7 @@ mod data { use std::sync::OnceLock; use crate::dodeca::{Side, Vertex, SIDE_COUNT, VERTEX_COUNT}; - use crate::math::{MVector,MIsometry}; + use crate::math::{MIsometry, MVector}; use crate::voxel_math::ChunkAxisPermutation; /// Whether two sides share an edge @@ -407,9 +411,9 @@ mod data { let mut result = [MIsometry::identity(); VERTEX_COUNT]; for (i, map) in result.iter_mut().enumerate() { let [a, b, c] = vertex_sides()[i]; - let vertex_position = - (MVector::origin() - - (*a.normal_f64() + *b.normal_f64() + *c.normal_f64()) * mip_origin_normal).lorentz_normalize(); + let vertex_position = (MVector::origin() + - (*a.normal_f64() + *b.normal_f64() + *c.normal_f64()) * mip_origin_normal) + .lorentz_normalize(); *map = MIsometry::from_columns_unchecked(&[ -*a.normal_f64(), -*b.normal_f64(), diff --git a/common/src/graph.rs b/common/src/graph.rs index 43760526..90f0092a 100644 --- a/common/src/graph.rs +++ b/common/src/graph.rs @@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize}; use crate::{ dodeca::{Side, SIDE_COUNT}, math, - math::{MIsometry,MVector}, + math::{MIsometry, MVector}, node::{ChunkId, ChunkLayout, Node}, }; @@ -402,8 +402,7 @@ mod tests { let mut graph = Graph::new(1); let a = graph.ensure_neighbor(NodeId::ROOT, Side::A); { - let (node, xf) = - graph.normalize_transform(NodeId::ROOT, &MIsometry::identity()); + let (node, xf) = graph.normalize_transform(NodeId::ROOT, &MIsometry::identity()); assert_eq!(node, NodeId::ROOT); assert_abs_diff_eq!(xf, MIsometry::identity(), epsilon = 1e-5); } diff --git a/common/src/graph_collision.rs b/common/src/graph_collision.rs index 0c147cfa..1b2f6653 100644 --- a/common/src/graph_collision.rs +++ b/common/src/graph_collision.rs @@ -3,7 +3,7 @@ use crate::{ collision_math::Ray, graph::Graph, math, - math::{MVector, MIsometry}, + math::{MIsometry, MVector}, node::{Chunk, ChunkId}, proto::Position, traversal::RayTraverser, @@ -170,11 +170,14 @@ mod tests { } // Find the transform of the chosen chunk - let chosen_chunk_transform: MIsometry = - self.chosen_voxel.node_path.iter().fold( - MIsometry::identity(), - |transform: MIsometry, side| transform * *side.reflection(), - ) * *self.chosen_voxel.vertex.dual_to_node(); + let chosen_chunk_transform: MIsometry = self + .chosen_voxel + .node_path + .iter() + .fold(MIsometry::identity(), |transform: MIsometry, side| { + transform * *side.reflection() + }) + * *self.chosen_voxel.vertex.dual_to_node(); let dual_to_grid_factor = graph.layout().dual_to_grid_factor(); let ray_target = chosen_chunk_transform @@ -183,7 +186,8 @@ mod tests { self.chosen_chunk_relative_grid_ray_end[1] / dual_to_grid_factor, self.chosen_chunk_relative_grid_ray_end[2] / dual_to_grid_factor, 1.0, - ).lorentz_normalize(); + ) + .lorentz_normalize(); let ray_position = *Vertex::A.dual_to_node() * MVector::new( @@ -191,17 +195,18 @@ mod tests { self.start_chunk_relative_grid_ray_start[1] / dual_to_grid_factor, self.start_chunk_relative_grid_ray_start[2] / dual_to_grid_factor, 1.0, - ).lorentz_normalize(); + ) + .lorentz_normalize(); let ray_direction = ray_target - ray_position; let ray = Ray::new( ray_position, - (ray_direction + ray_position * ray_position.mip(&ray_direction)).lorentz_normalize(), + (ray_direction + ray_position * ray_position.mip(&ray_direction)) + .lorentz_normalize(), ); - let tanh_distance = ((-ray_position.mip(&ray_target)).acosh() - + self.ray_length_modifier) - .tanh(); + let tanh_distance = + ((-ray_position.mip(&ray_target)).acosh() + self.ray_length_modifier).tanh(); let hit = sphere_cast( self.collider_radius, diff --git a/common/src/math.rs b/common/src/math.rs index c7b6b861..5034ba41 100644 --- a/common/src/math.rs +++ b/common/src/math.rs @@ -9,76 +9,63 @@ use na::{RealField, Scalar}; use serde::{Deserialize, Serialize}; use std::ops::*; -#[derive(Debug, Copy, Clone, Serialize, Deserialize,PartialEq)] +#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq)] #[repr(C)] pub struct MVector(na::Vector4); -#[derive(Debug, Copy, Clone, Serialize, Deserialize,PartialEq)] +#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq)] #[repr(C)] pub struct MIsometry(na::Matrix4); #[cfg(test)] -impl approx::AbsDiffEq> for MIsometry -{ +impl approx::AbsDiffEq> for MIsometry { type Epsilon = N; #[inline] - fn default_epsilon() -> Self::Epsilon - { + fn default_epsilon() -> Self::Epsilon { na::Matrix4::::default_epsilon() } #[inline] - fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool - { + fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool { self.0.abs_diff_eq(&other.0, epsilon) } } #[cfg(test)] -impl approx::AbsDiffEq> for MVector -{ +impl approx::AbsDiffEq> for MVector { type Epsilon = N; #[inline] - fn default_epsilon() -> Self::Epsilon - { + fn default_epsilon() -> Self::Epsilon { na::Vector4::::default_epsilon() } #[inline] - fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool - { + fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool { self.0.abs_diff_eq(&other.0, epsilon) } } -impl From>> for MVector -{ - fn from(value: na::Unit>) -> Self - { +impl From>> for MVector { + fn from(value: na::Unit>) -> Self { Self(value.into_inner().push(na::zero())) } } -impl From> for MVector -{ - fn from(value: na::Vector4) -> Self - { +impl From> for MVector { + fn from(value: na::Vector4) -> Self { Self(value) } } -impl Deref for MVector -{ +impl Deref for MVector { type Target = na::coordinates::XYZW; #[inline] - fn deref(&self) -> &Self::Target - { + fn deref(&self) -> &Self::Target { self.0.deref() } } impl DerefMut for MVector { #[inline] - fn deref_mut(&mut self) -> &mut Self::Target - { + fn deref_mut(&mut self) -> &mut Self::Target { self.0.deref_mut() } } @@ -86,95 +73,74 @@ impl DerefMut for MVector { impl Deref for MIsometry { type Target = na::coordinates::M4x4; #[inline] - fn deref(&self) -> &Self::Target - { + fn deref(&self) -> &Self::Target { self.0.deref() } } -impl From> for na::Matrix4 -{ - fn from(value: MIsometry) -> na::Matrix4 - { +impl From> for na::Matrix4 { + fn from(value: MIsometry) -> na::Matrix4 { value.0 } } -impl From> for na::Vector4 -{ - fn from(value: MVector) -> na::Vector4 - { +impl From> for na::Vector4 { + fn from(value: MVector) -> na::Vector4 { value.0 } } -impl MIsometry -{ - pub fn to_f64(self) -> MIsometry - { +impl MIsometry { + pub fn to_f64(self) -> MIsometry { MIsometry(self.0.cast::()) } } -impl MIsometry -{ - pub fn to_f32(self) -> MIsometry - { +impl MIsometry { + pub fn to_f32(self) -> MIsometry { MIsometry(self.0.cast::()) } } -impl MVector -{ - pub fn to_f64(self) -> MVector - { +impl MVector { + pub fn to_f64(self) -> MVector { MVector(self.0.cast::()) } } -impl MVector -{ - pub fn to_f32(self) -> MVector - { +impl MVector { + pub fn to_f32(self) -> MVector { MVector(self.0.cast::()) } } -impl MIsometry -{ +impl MIsometry { #[inline] - pub fn as_ref(self) -> [[N;4];4] - { + pub fn as_ref(self) -> [[N; 4]; 4] { *self.0.as_ref() } #[inline] - pub fn unit_quaternion_to_homogeneous(rotation: na::UnitQuaternion) -> Self - { + pub fn unit_quaternion_to_homogeneous(rotation: na::UnitQuaternion) -> Self { MIsometry(rotation.to_homogeneous()) } #[inline] - pub fn rotation_to_homogeneous(rotation: na::Rotation3) -> Self - { + pub fn rotation_to_homogeneous(rotation: na::Rotation3) -> Self { MIsometry(rotation.to_homogeneous()) } #[inline] - pub fn row(self, i: usize) -> na::RowVector4 - { + pub fn row(self, i: usize) -> na::RowVector4 { self.0.row(i).into() } #[inline] - pub fn identity() -> Self - { + pub fn identity() -> Self { Self(na::Matrix4::identity()) } #[inline] - pub fn map N2>(&self, f: F) -> MIsometry - { + pub fn map N2>(&self, f: F) -> MIsometry { MIsometry(self.0.map(f)) } #[inline] - pub fn from_columns_unchecked(columns: &[MVector;4]) -> Self - { + pub fn from_columns_unchecked(columns: &[MVector; 4]) -> Self { Self(na::Matrix4::from_columns(&(*columns).map(|x| x.0))) } /// Minkowski transpose. Inverse for hyperbolic isometries @@ -193,12 +159,16 @@ impl MIsometry pub fn parity(self) -> bool { self.0.fixed_view::<3, 3>(0, 0).determinant() < na::zero::() } - pub fn renormalize_isometry(self) -> MIsometry - { - let boost = translate(&MVector::origin(), &MVector(self.0.index((.., 3)).into()).lorentz_normalize()); + pub fn renormalize_isometry(self) -> MIsometry { + let boost = translate( + &MVector::origin(), + &MVector(self.0.index((.., 3)).into()).lorentz_normalize(), + ); let inverse_boost = boost.mtranspose(); let rotation = renormalize_rotation_reflection( - &((inverse_boost * self).0).fixed_view::<3, 3>(0, 0).clone_owned(), + &((inverse_boost * self).0) + .fixed_view::<3, 3>(0, 0) + .clone_owned(), ); MIsometry(boost.0 * rotation.to_homogeneous()) } @@ -215,213 +185,172 @@ impl MVector { } /// Point or plane reflection around point or normal `p` pub fn reflect(self) -> MIsometry { - MIsometry(na::Matrix4::::identity() - - self.minkowski_outer_product(&self) * na::convert::<_, N>(2.0) / self.mip(&self)) + MIsometry( + na::Matrix4::::identity() + - self.minkowski_outer_product(&self) * na::convert::<_, N>(2.0) / self.mip(&self), + ) } /// Minkowski inner product, aka _h - pub fn mip(self, other: &Self) -> N - { + pub fn mip(self, other: &Self) -> N { self.0.x * other.0.x + self.0.y * other.0.y + self.0.z * other.0.z - self.0.w * other.0.w } - pub fn minkowski_outer_product(self, other: &Self) -> na::Matrix4 - { + pub fn minkowski_outer_product(self, other: &Self) -> na::Matrix4 { ((self).0) * na::RowVector4::new(other.0.x, other.0.y, other.0.z, -other.0.w) } - pub fn from_gans(gans: &na::Vector3) -> Self - { + pub fn from_gans(gans: &na::Vector3) -> Self { // x^2 + y^2 + z^2 - w^2 = -1 // sqrt(x^2 + y^2 + z^2 + 1) = w let w = (sqr(gans.x) + sqr(gans.y) + sqr(gans.z) + na::one()).sqrt(); MVector(na::Vector4::new(gans.x, gans.y, gans.z, w)) } #[inline] - pub fn zero() -> Self - { + pub fn zero() -> Self { Self(na::zero()) } - pub fn origin() -> Self - { + pub fn origin() -> Self { Self::w() } #[inline] - pub fn normalize(self) -> Self - { + pub fn normalize(self) -> Self { Self(self.0.normalize()) } #[inline] - pub fn x() -> Self - { + pub fn x() -> Self { Self(na::Vector4::x()) } #[inline] - pub fn y() -> Self - { + pub fn y() -> Self { Self(na::Vector4::y()) } #[inline] - pub fn z() -> Self - { + pub fn z() -> Self { Self(na::Vector4::z()) } #[inline] - pub fn w() -> Self - { + pub fn w() -> Self { Self(na::Vector4::w()) } #[inline] - pub fn new(x: N, y: N, z: N, w: N) -> Self - { - MVector(na::Vector4::new(x,y,z,w)) + pub fn new(x: N, y: N, z: N, w: N) -> Self { + MVector(na::Vector4::new(x, y, z, w)) } #[inline] - pub fn xyz(self) -> na::Vector3 - { + pub fn xyz(self) -> na::Vector3 { self.0.xyz() } } -impl Mul> for MIsometry -{ +impl Mul> for MIsometry { type Output = MIsometry; #[inline] - fn mul(self, rhs: MIsometry) -> Self::Output - { + fn mul(self, rhs: MIsometry) -> Self::Output { MIsometry(self.0 * rhs.0) } } -impl Mul for MVector -{ +impl Mul for MVector { type Output = MVector; #[inline] - fn mul(self, rhs: N) -> Self::Output - { + fn mul(self, rhs: N) -> Self::Output { MVector(self.0 * rhs) } } -impl Div for MVector -{ +impl Div for MVector { type Output = MVector; #[inline] - fn div(self, rhs: N) -> Self::Output - { + fn div(self, rhs: N) -> Self::Output { MVector(self.0 / rhs) } } -impl Add for MVector -{ +impl Add for MVector { type Output = Self; #[inline] - fn add(self, other: Self) -> Self - { + fn add(self, other: Self) -> Self { Self(self.0 + other.0) } } -impl Sub for MVector -{ +impl Sub for MVector { type Output = Self; #[inline] - fn sub(self, other: Self) -> Self - { + fn sub(self, other: Self) -> Self { Self(self.0 - other.0) } } -impl Neg for MVector -{ +impl Neg for MVector { type Output = Self; #[inline] - fn neg(self) -> Self - { + fn neg(self) -> Self { Self(-self.0) } } -impl Mul> for MIsometry -{ +impl Mul> for MIsometry { type Output = MVector; #[inline] - fn mul(self, rhs: MVector) -> Self::Output - { + fn mul(self, rhs: MVector) -> Self::Output { MVector(self.0 * rhs.0) } } -impl Mul for MIsometry -{ +impl Mul for MIsometry { type Output = MIsometry; #[inline] - fn mul(self, rhs: N) -> Self::Output - { + fn mul(self, rhs: N) -> Self::Output { MIsometry(self.0 * rhs) } } -impl std::ops::AddAssign for MVector -{ +impl std::ops::AddAssign for MVector { #[inline] - fn add_assign(&mut self, other: Self) - { + fn add_assign(&mut self, other: Self) { *self = *self + other; } } -impl MulAssign for MVector -{ +impl MulAssign for MVector { #[inline] - fn mul_assign(&mut self, rhs: N) - { + fn mul_assign(&mut self, rhs: N) { *self = *self * rhs; } } -impl MulAssign for MIsometry -{ +impl MulAssign for MIsometry { #[inline] - fn mul_assign(&mut self, rhs: N) - { + fn mul_assign(&mut self, rhs: N) { *self = *self * rhs; } } -impl MulAssign> for MIsometry -{ +impl MulAssign> for MIsometry { #[inline] - fn mul_assign(&mut self, rhs: MIsometry) - { + fn mul_assign(&mut self, rhs: MIsometry) { *self = *self * rhs; } } - -impl Index for MVector -{ +impl Index for MVector { type Output = N; #[inline] - fn index(&self, i: usize) -> &Self::Output - { + fn index(&self, i: usize) -> &Self::Output { &self.0[i] } } -impl IndexMut for MVector -{ +impl IndexMut for MVector { #[inline] - fn index_mut(&mut self, i: usize) -> &mut N - { + fn index_mut(&mut self, i: usize) -> &mut N { &mut self.0[i] } } -impl Index<(usize,usize)> for MIsometry -{ +impl Index<(usize, usize)> for MIsometry { type Output = N; #[inline] - fn index(&self, ij: (usize, usize)) -> &Self::Output - { + fn index(&self, ij: (usize, usize)) -> &Self::Output { &self.0[ij] } } @@ -429,8 +358,10 @@ impl Index<(usize,usize)> for MIsometry /// Transform that translates `a` to `b` given that `a` and `b` are Lorentz normalized pointlike vectors pub fn translate(a: &MVector, b: &MVector) -> MIsometry { let a_plus_b = *a + *b; - MIsometry((na::Matrix4::::identity()) - (b.minkowski_outer_product(a) * na::convert::<_, N>(2.0)) - + ((a_plus_b.minkowski_outer_product(&a_plus_b)) / (N::one() - a.mip(b)))) + MIsometry( + (na::Matrix4::::identity()) - (b.minkowski_outer_product(a) * na::convert::<_, N>(2.0)) + + ((a_plus_b.minkowski_outer_product(&a_plus_b)) / (N::one() - a.mip(b))), + ) } /// Transform that translates the origin in the direction of the given vector with distance equal to its magnitude @@ -442,7 +373,7 @@ pub fn translate_along(v: &na::Vector3) -> MIsometry // g = Lorentz gamma factor let g = norm.cosh(); let bgc = norm.sinhc(); - translate(&MVector::origin(), &MVector(((v * bgc)).insert_row(3, g))) + translate(&MVector::origin(), &MVector((v * bgc).insert_row(3, g))) } /// 4D reflection around a normal vector; length is not significant (so long as it's nonzero) @@ -477,7 +408,6 @@ pub fn sqr(x: N) -> N { x * x } - /// Updates `subject` by moving it along the line determined by `projection_direction` so that /// its dot product with `normal` is `distance`. This effectively projects vectors onto the plane /// `distance` units away from the origin with normal `normal`. The projection is non-orthogonal in @@ -526,7 +456,6 @@ mod tests { use super::*; use approx::*; - #[test] #[rustfmt::skip] fn reflect_example() { diff --git a/common/src/node.rs b/common/src/node.rs index abe46d42..5f12e6a4 100644 --- a/common/src/node.rs +++ b/common/src/node.rs @@ -374,8 +374,8 @@ impl VoxelAABB { radius: f32, ) -> Option { // Convert the ray to grid coordinates - let grid_start = - na::Point3::from_homogeneous(ray.position.into()).unwrap() * layout.dual_to_grid_factor(); + let grid_start = na::Point3::from_homogeneous(ray.position.into()).unwrap() + * layout.dual_to_grid_factor(); let grid_end = na::Point3::from_homogeneous(ray.ray_point(tanh_distance).into()).unwrap() * layout.dual_to_grid_factor(); // Convert the radius to grid coordinates using a crude conservative estimate @@ -434,7 +434,7 @@ mod tests { use std::collections::HashSet; use crate::math; - use crate::math::{MVector,MIsometry}; + use crate::math::{MIsometry, MVector}; use super::*; @@ -447,8 +447,10 @@ mod tests { let layout = ChunkLayout::new(dimension); // Pick an arbitrary ray by transforming the positive-x-axis ray. - let ray = MIsometry::rotation_to_homogeneous(na::Rotation3::from_axis_angle(&na::Vector3::z_axis(), 0.4)) - * math::translate_along(&na::Vector3::new(0.2, 0.3, 0.1)) + let ray = MIsometry::rotation_to_homogeneous(na::Rotation3::from_axis_angle( + &na::Vector3::z_axis(), + 0.4, + )) * math::translate_along(&na::Vector3::new(0.2, 0.3, 0.1)) * &Ray::new(MVector::w(), MVector::x()); let tanh_distance = 0.2; @@ -460,7 +462,8 @@ mod tests { let num_ray_test_points = 20; let ray_test_points: Vec<_> = (0..num_ray_test_points) .map(|i| { - ray.ray_point(tanh_distance * (i as f32 / (num_ray_test_points - 1) as f32)).lorentz_normalize() + ray.ray_point(tanh_distance * (i as f32 / (num_ray_test_points - 1) as f32)) + .lorentz_normalize() }) .collect(); @@ -548,7 +551,8 @@ mod tests { layout.grid_to_dual(y), layout.grid_to_dual(z), 1.0, - ).lorentz_normalize(); + ) + .lorentz_normalize(); for test_point in &ray_test_points { assert!( diff --git a/common/src/plane.rs b/common/src/plane.rs index cfda37af..c2de8279 100644 --- a/common/src/plane.rs +++ b/common/src/plane.rs @@ -2,7 +2,7 @@ use std::ops::{Mul, Neg}; use crate::{ dodeca::{Side, Vertex}, - math::{MVector, MIsometry}, + math::{MIsometry, MVector}, }; /// A hyperbolic plane @@ -72,7 +72,8 @@ impl Plane { impl Plane { /// Like `distance_to`, but using chunk coordinates for a chunk in the same node space pub fn distance_to_chunk(&self, chunk: Vertex, coord: &na::Vector3) -> f64 { - let pos = (MVector::::from(chunk.chunk_to_node_f64() * coord.push(1.0))).lorentz_normalize(); + let pos = + (MVector::::from(chunk.chunk_to_node_f64() * coord.push(1.0))).lorentz_normalize(); self.distance_to(&pos) } } diff --git a/common/src/proto.rs b/common/src/proto.rs index 3f482692..132e7543 100644 --- a/common/src/proto.rs +++ b/common/src/proto.rs @@ -1,8 +1,8 @@ use serde::{Deserialize, Serialize}; use crate::{ - dodeca, graph::NodeId, node::ChunkId, voxel_math::Coords, world::Material, EntityId, SimConfig, - Step, math + dodeca, graph::NodeId, math, node::ChunkId, voxel_math::Coords, world::Material, EntityId, + SimConfig, Step, }; #[derive(Debug, Serialize, Deserialize)] diff --git a/common/src/traversal.rs b/common/src/traversal.rs index 7c88fec2..82450a43 100644 --- a/common/src/traversal.rs +++ b/common/src/traversal.rs @@ -7,7 +7,7 @@ use crate::{ dodeca::{self, Side, Vertex}, graph::{Graph, NodeId}, math, - math::{MVector,MIsometry}, + math::{MIsometry, MVector}, node::ChunkId, proto::Position, }; @@ -114,7 +114,8 @@ impl<'a> RayTraverser<'a> { let mut closest_vertex = Vertex::A; let mut closest_vertex_cosh_distance = f32::INFINITY; for vertex in Vertex::iter() { - let vertex_cosh_distance = (*vertex.node_to_dual() * position.local * MVector::origin()).w; + let vertex_cosh_distance = + (*vertex.node_to_dual() * position.local * MVector::origin()).w; if vertex_cosh_distance < closest_vertex_cosh_distance { closest_vertex = vertex; closest_vertex_cosh_distance = vertex_cosh_distance; diff --git a/common/src/worldgen.rs b/common/src/worldgen.rs index 88e43145..d0b88d0b 100644 --- a/common/src/worldgen.rs +++ b/common/src/worldgen.rs @@ -4,7 +4,8 @@ use rand_distr::Normal; use crate::{ dodeca::{Side, Vertex}, graph::{Graph, NodeId}, - margins, math, math::MVector, + margins, math, + math::MVector, node::{ChunkId, VoxelData}, terraingen::VoronoiInfo, world::Material, From 2d8b016604ad319e4ee5f3ef9f6a6938330da002 Mon Sep 17 00:00:00 2001 From: strawberry Date: Tue, 23 Jul 2024 21:05:32 -0500 Subject: [PATCH 11/31] remove redundant <_> --- client/src/graphics/draw.rs | 6 +++--- client/src/graphics/voxels/mod.rs | 2 +- common/src/dodeca.rs | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/client/src/graphics/draw.rs b/client/src/graphics/draw.rs index c1a6bfc6..06b516e5 100644 --- a/client/src/graphics/draw.rs +++ b/client/src/graphics/draw.rs @@ -289,7 +289,7 @@ impl Draw { let draw_started = Instant::now(); let view = sim.as_ref().map_or_else(Position::origin, |sim| sim.view()); let projection = frustum.projection(1.0e-4); - let view_projection = projection.matrix() * na::Matrix4::<_>::from(view.local.mtranspose()); + let view_projection = projection.matrix() * na::Matrix4::from(view.local.mtranspose()); self.loader.drive(); let device = &*self.gfx.device; @@ -482,8 +482,8 @@ impl Draw { .expect("positionless entity in graph"); if let Some(character_model) = self.loader.get(self.character_model) { if let Ok(ch) = sim.world.get::<&Character>(entity) { - let transform = na::Matrix4::<_>::from(transform) - * na::Matrix4::<_>::from(pos.local) + let transform = na::Matrix4::from(transform) + * na::Matrix4::from(pos.local) * na::Matrix4::new_scaling(sim.cfg().meters_to_absolute) * ch.state.orientation.to_homogeneous(); for mesh in &character_model.0 { diff --git a/client/src/graphics/voxels/mod.rs b/client/src/graphics/voxels/mod.rs index 826b5a67..45310b52 100644 --- a/client/src/graphics/voxels/mod.rs +++ b/client/src/graphics/voxels/mod.rs @@ -174,7 +174,7 @@ impl Voxels { frame.drawn.push(slot); // Transfer transform frame.surface.transforms_mut()[slot.0 as usize] = - na::Matrix4::<_>::from(*node_transform) * vertex.chunk_to_node(); + na::Matrix4::from(*node_transform) * vertex.chunk_to_node(); } if let (None, &VoxelData::Dense(ref data)) = (&surface, voxels) { // Extract a surface so it can be drawn in future frames diff --git a/common/src/dodeca.rs b/common/src/dodeca.rs index 1754065f..23a89937 100644 --- a/common/src/dodeca.rs +++ b/common/src/dodeca.rs @@ -72,7 +72,7 @@ impl Side { #[inline] pub fn is_facing(self, p: &MVector) -> bool { let r = na::convert::<_, na::RowVector4>(self.reflection().row(3).clone_owned()); - (r * na::Vector4::<_>::from(*p)).x < p.w + (r * na::Vector4::from(*p)).x < p.w } } @@ -179,26 +179,26 @@ impl Vertex { /// Transform from euclidean chunk coordinates to hyperbolic node space pub fn chunk_to_node(self) -> na::Matrix4 { - na::Matrix4::<_>::from(*self.dual_to_node()) + na::Matrix4::from(*self.dual_to_node()) * na::Matrix4::new_scaling(1.0 / Self::dual_to_chunk_factor()) } /// Transform from euclidean chunk coordinates to hyperbolic node space pub fn chunk_to_node_f64(self) -> na::Matrix4 { - na::Matrix4::<_>::from(*self.dual_to_node_f64()) + na::Matrix4::from(*self.dual_to_node_f64()) * na::Matrix4::new_scaling(1.0 / Self::dual_to_chunk_factor_f64()) } /// Transform from hyperbolic node space to euclidean chunk coordinates pub fn node_to_chunk(self) -> na::Matrix4 { na::Matrix4::new_scaling(Self::dual_to_chunk_factor()) - * na::Matrix4::<_>::from(*self.node_to_dual()) + * na::Matrix4::from(*self.node_to_dual()) } /// Transform from hyperbolic node space to euclidean chunk coordinates pub fn node_to_chunk_f64(self) -> na::Matrix4 { na::Matrix4::new_scaling(Self::dual_to_chunk_factor_f64()) - * na::Matrix4::<_>::from(*self.node_to_dual_f64()) + * na::Matrix4::from(*self.node_to_dual_f64()) } /// Transform from cube-centric coordinates to dodeca-centric coordinates From 1834ae14fe8178f96a21058deea3c35781d3e4f5 Mon Sep 17 00:00:00 2001 From: strawberry Date: Tue, 23 Jul 2024 21:18:59 -0500 Subject: [PATCH 12/31] made wrapped definitions of used MulAssign and AddAssign more concise --- common/src/math.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/common/src/math.rs b/common/src/math.rs index 5034ba41..74d6fdb0 100644 --- a/common/src/math.rs +++ b/common/src/math.rs @@ -307,28 +307,28 @@ impl Mul for MIsometry { impl std::ops::AddAssign for MVector { #[inline] fn add_assign(&mut self, other: Self) { - *self = *self + other; + (*self).0 += other.0; } } impl MulAssign for MVector { #[inline] fn mul_assign(&mut self, rhs: N) { - *self = *self * rhs; + (*self).0 *= rhs; } } impl MulAssign for MIsometry { #[inline] fn mul_assign(&mut self, rhs: N) { - *self = *self * rhs; + (*self).0 *= rhs; } } impl MulAssign> for MIsometry { #[inline] fn mul_assign(&mut self, rhs: MIsometry) { - *self = *self * rhs; + (*self).0 *= rhs.0; } } From dc29b03ea09f481b951daeaea444e7dd665201ac Mon Sep 17 00:00:00 2001 From: strawberry Date: Tue, 23 Jul 2024 21:40:54 -0500 Subject: [PATCH 13/31] removed unused imports --- client/src/graphics/draw.rs | 2 +- common/src/collision_math.rs | 2 +- common/src/graph.rs | 1 - common/src/graph_collision.rs | 4 ++-- common/src/node.rs | 3 +-- common/src/traversal.rs | 1 - 6 files changed, 5 insertions(+), 8 deletions(-) diff --git a/client/src/graphics/draw.rs b/client/src/graphics/draw.rs index 06b516e5..ea27beec 100644 --- a/client/src/graphics/draw.rs +++ b/client/src/graphics/draw.rs @@ -9,7 +9,7 @@ use metrics::histogram; use super::{fog, voxels, Base, Fog, Frustum, GltfScene, Meshes, Voxels}; use crate::{Asset, Config, Loader, Sim}; use common::proto::{Character, Position}; -use common::{math, SimConfig}; +use common::SimConfig; /// Manages rendering, independent of what is being rendered to pub struct Draw { diff --git a/common/src/collision_math.rs b/common/src/collision_math.rs index aa4b08c4..b985f8c3 100644 --- a/common/src/collision_math.rs +++ b/common/src/collision_math.rs @@ -1,4 +1,3 @@ -use crate::math; use crate::math::{MIsometry, MVector}; /// A ray in hyperbolic space. The fields must be lorentz normalized, with `mip(position, position) == -1`, @@ -153,6 +152,7 @@ mod tests { use approx::assert_abs_diff_eq; use super::*; + use crate::math; #[test] fn solve_sphere_plane_intersection_example() { diff --git a/common/src/graph.rs b/common/src/graph.rs index 90f0092a..7aab13f9 100644 --- a/common/src/graph.rs +++ b/common/src/graph.rs @@ -8,7 +8,6 @@ use serde::{Deserialize, Serialize}; use crate::{ dodeca::{Side, SIDE_COUNT}, - math, math::{MIsometry, MVector}, node::{ChunkId, ChunkLayout, Node}, }; diff --git a/common/src/graph_collision.rs b/common/src/graph_collision.rs index 1b2f6653..a278d46a 100644 --- a/common/src/graph_collision.rs +++ b/common/src/graph_collision.rs @@ -2,8 +2,7 @@ use crate::{ chunk_collision::chunk_sphere_cast, collision_math::Ray, graph::Graph, - math, - math::{MIsometry, MVector}, + math::MVector, node::{Chunk, ChunkId}, proto::Position, traversal::RayTraverser, @@ -94,6 +93,7 @@ mod tests { traversal::{ensure_nearby, nearby_nodes}, voxel_math::Coords, world::Material, + math::MIsometry, }; use super::*; diff --git a/common/src/node.rs b/common/src/node.rs index 5f12e6a4..ac7e02cb 100644 --- a/common/src/node.rs +++ b/common/src/node.rs @@ -8,12 +8,11 @@ use crate::collision_math::Ray; use crate::dodeca::Vertex; use crate::graph::{Graph, NodeId}; use crate::lru_slab::SlotId; -use crate::math::MVector; use crate::proto::{BlockUpdate, Position, SerializedVoxelData}; use crate::voxel_math::{ChunkDirection, CoordAxis, CoordSign, Coords}; use crate::world::Material; use crate::worldgen::NodeState; -use crate::{margins, math, Chunks}; +use crate::{margins, Chunks}; #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct ChunkId { diff --git a/common/src/traversal.rs b/common/src/traversal.rs index 82450a43..daf68556 100644 --- a/common/src/traversal.rs +++ b/common/src/traversal.rs @@ -6,7 +6,6 @@ use crate::{ collision_math::Ray, dodeca::{self, Side, Vertex}, graph::{Graph, NodeId}, - math, math::{MIsometry, MVector}, node::ChunkId, proto::Position, From b9ad6041f9b1e9188ff4f0f00e08cdf9f2036bd7 Mon Sep 17 00:00:00 2001 From: strawberry Date: Tue, 23 Jul 2024 22:02:55 -0500 Subject: [PATCH 14/31] concision concision concision --- common/src/math.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/common/src/math.rs b/common/src/math.rs index 74d6fdb0..8b6c7412 100644 --- a/common/src/math.rs +++ b/common/src/math.rs @@ -307,28 +307,28 @@ impl Mul for MIsometry { impl std::ops::AddAssign for MVector { #[inline] fn add_assign(&mut self, other: Self) { - (*self).0 += other.0; + self.0 += other.0; } } impl MulAssign for MVector { #[inline] fn mul_assign(&mut self, rhs: N) { - (*self).0 *= rhs; + self.0 *= rhs; } } impl MulAssign for MIsometry { #[inline] fn mul_assign(&mut self, rhs: N) { - (*self).0 *= rhs; + self.0 *= rhs; } } impl MulAssign> for MIsometry { #[inline] fn mul_assign(&mut self, rhs: MIsometry) { - (*self).0 *= rhs.0; + self.0 *= rhs.0; } } From 43f76031b6a1f262bdf7339d676a78e9dc9917f1 Mon Sep 17 00:00:00 2001 From: strawberry Date: Tue, 23 Jul 2024 22:04:19 -0500 Subject: [PATCH 15/31] check pass stuff(?) --- common/src/graph_collision.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/graph_collision.rs b/common/src/graph_collision.rs index a278d46a..4ff72863 100644 --- a/common/src/graph_collision.rs +++ b/common/src/graph_collision.rs @@ -88,12 +88,12 @@ mod tests { collision_math::Ray, dodeca::{self, Side, Vertex}, graph::{Graph, NodeId}, + math::MIsometry, node::{populate_fresh_nodes, VoxelData}, proto::Position, traversal::{ensure_nearby, nearby_nodes}, voxel_math::Coords, world::Material, - math::MIsometry, }; use super::*; From 4c0d61cc610b97f2989e61cde1ef60f3ae59741b Mon Sep 17 00:00:00 2001 From: strawberry Date: Fri, 26 Jul 2024 23:34:07 -0500 Subject: [PATCH 16/31] simplification by deref --- common/src/math.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/src/math.rs b/common/src/math.rs index 8b6c7412..6079f2d6 100644 --- a/common/src/math.rs +++ b/common/src/math.rs @@ -192,10 +192,10 @@ impl MVector { } /// Minkowski inner product, aka _h pub fn mip(self, other: &Self) -> N { - self.0.x * other.0.x + self.0.y * other.0.y + self.0.z * other.0.z - self.0.w * other.0.w + self.x * other.x + self.y * other.y + self.z * other.z - self.w * other.w } pub fn minkowski_outer_product(self, other: &Self) -> na::Matrix4 { - ((self).0) * na::RowVector4::new(other.0.x, other.0.y, other.0.z, -other.0.w) + ((self).0) * na::RowVector4::new(other.x, other.y, other.z, -other.w) } pub fn from_gans(gans: &na::Vector3) -> Self { // x^2 + y^2 + z^2 - w^2 = -1 From d99b08efdfd5aeae6501174908bb98dbf8b561b1 Mon Sep 17 00:00:00 2001 From: strawberry Date: Fri, 26 Jul 2024 23:55:13 -0500 Subject: [PATCH 17/31] simplify multiplication step --- client/src/graphics/draw.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/client/src/graphics/draw.rs b/client/src/graphics/draw.rs index ea27beec..2039794b 100644 --- a/client/src/graphics/draw.rs +++ b/client/src/graphics/draw.rs @@ -482,8 +482,7 @@ impl Draw { .expect("positionless entity in graph"); if let Some(character_model) = self.loader.get(self.character_model) { if let Ok(ch) = sim.world.get::<&Character>(entity) { - let transform = na::Matrix4::from(transform) - * na::Matrix4::from(pos.local) + let transform = na::Matrix4::from(transform * pos.local) * na::Matrix4::new_scaling(sim.cfg().meters_to_absolute) * ch.state.orientation.to_homogeneous(); for mesh in &character_model.0 { From 9bb5b4395e81f603026fc76f9ee17c0f61107b7b Mon Sep 17 00:00:00 2001 From: strawberry Date: Sat, 27 Jul 2024 00:08:40 -0500 Subject: [PATCH 18/31] add inline to function --- common/src/math.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/common/src/math.rs b/common/src/math.rs index 6079f2d6..2c4eaf8e 100644 --- a/common/src/math.rs +++ b/common/src/math.rs @@ -207,6 +207,7 @@ impl MVector { pub fn zero() -> Self { Self(na::zero()) } + #[inline] pub fn origin() -> Self { Self::w() } From 19174620d21fcc548a9aaf2c09fd918654e24447 Mon Sep 17 00:00:00 2001 From: strawberry Date: Sat, 27 Jul 2024 00:12:46 -0500 Subject: [PATCH 19/31] group test related code together --- common/src/math.rs | 52 +++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/common/src/math.rs b/common/src/math.rs index 2c4eaf8e..69cc3bd3 100644 --- a/common/src/math.rs +++ b/common/src/math.rs @@ -17,32 +17,6 @@ pub struct MVector(na::Vector4); #[repr(C)] pub struct MIsometry(na::Matrix4); -#[cfg(test)] -impl approx::AbsDiffEq> for MIsometry { - type Epsilon = N; - #[inline] - fn default_epsilon() -> Self::Epsilon { - na::Matrix4::::default_epsilon() - } - #[inline] - fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool { - self.0.abs_diff_eq(&other.0, epsilon) - } -} - -#[cfg(test)] -impl approx::AbsDiffEq> for MVector { - type Epsilon = N; - #[inline] - fn default_epsilon() -> Self::Epsilon { - na::Vector4::::default_epsilon() - } - #[inline] - fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool { - self.0.abs_diff_eq(&other.0, epsilon) - } -} - impl From>> for MVector { fn from(value: na::Unit>) -> Self { Self(value.into_inner().push(na::zero())) @@ -452,6 +426,32 @@ pub fn tuv_to_xyz, N: Copy>(t_axis: usi result } +#[cfg(test)] +impl approx::AbsDiffEq> for MIsometry { + type Epsilon = N; + #[inline] + fn default_epsilon() -> Self::Epsilon { + na::Matrix4::::default_epsilon() + } + #[inline] + fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool { + self.0.abs_diff_eq(&other.0, epsilon) + } +} + +#[cfg(test)] +impl approx::AbsDiffEq> for MVector { + type Epsilon = N; + #[inline] + fn default_epsilon() -> Self::Epsilon { + na::Vector4::::default_epsilon() + } + #[inline] + fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool { + self.0.abs_diff_eq(&other.0, epsilon) + } +} + #[cfg(test)] mod tests { use super::*; From 1d3b6d2341a95df39dcd6ec626eb64292198a41e Mon Sep 17 00:00:00 2001 From: strawberry Date: Sat, 27 Jul 2024 00:42:05 -0500 Subject: [PATCH 20/31] removed verbose paths having math:: --- client/src/graphics/frustum.rs | 6 +++--- client/src/graphics/voxels/mod.rs | 6 +++--- client/src/local_character_controller.rs | 4 ++-- client/src/sim.rs | 10 ++++++---- common/src/collision_math.rs | 4 ++-- common/src/proto.rs | 6 +++--- 6 files changed, 19 insertions(+), 17 deletions(-) diff --git a/client/src/graphics/frustum.rs b/client/src/graphics/frustum.rs index 07d3480b..0ae3a11c 100644 --- a/client/src/graphics/frustum.rs +++ b/client/src/graphics/frustum.rs @@ -1,4 +1,4 @@ -use common::math; +use common::math::MVector; use common::Plane; #[derive(Debug, Copy, Clone)] @@ -80,7 +80,7 @@ pub struct FrustumPlanes { } impl FrustumPlanes { - pub fn contain(&self, point: &math::MVector, radius: f32) -> bool { + pub fn contain(&self, point: &MVector, radius: f32) -> bool { for &plane in &[&self.left, &self.right, &self.down, &self.up] { if plane.distance_to(point) < -radius { return false; @@ -93,7 +93,7 @@ impl FrustumPlanes { #[cfg(test)] mod tests { use super::*; - use common::math::{translate_along, MVector}; + use common::math::translate_along; use std::f32; #[test] diff --git a/client/src/graphics/voxels/mod.rs b/client/src/graphics/voxels/mod.rs index 45310b52..ea72d174 100644 --- a/client/src/graphics/voxels/mod.rs +++ b/client/src/graphics/voxels/mod.rs @@ -20,7 +20,7 @@ use common::{ dodeca::Vertex, graph::NodeId, lru_slab::SlotId, - math, + math::{MIsometry,MVector}, node::{Chunk, ChunkId, VoxelData}, LruSlab, }; @@ -88,7 +88,7 @@ impl Voxels { device: &Device, frame: &mut Frame, sim: &mut Sim, - nearby_nodes: &[(NodeId, math::MIsometry)], + nearby_nodes: &[(NodeId, MIsometry)], cmd: vk::CommandBuffer, frustum: &Frustum, ) { @@ -127,7 +127,7 @@ impl Voxels { let mut workqueue_is_full = false; for &(node, ref node_transform) in nearby_nodes { let node_to_view = local_to_view * *node_transform; - let origin = node_to_view * math::MVector::origin(); + let origin = node_to_view * MVector::origin(); if !frustum_planes.contain(&origin, dodeca::BOUNDING_SPHERE_RADIUS) { // Don't bother generating or drawing chunks from nodes that are wholly outside the // frustum. diff --git a/client/src/local_character_controller.rs b/client/src/local_character_controller.rs index 1c5ac13b..7929e9dd 100644 --- a/client/src/local_character_controller.rs +++ b/client/src/local_character_controller.rs @@ -1,4 +1,4 @@ -use common::{math, proto::Position}; +use common::{math, math::MIsometry, proto::Position}; pub struct LocalCharacterController { /// The last extrapolated inter-frame view position, used for rendering and gravity-specific @@ -26,7 +26,7 @@ impl LocalCharacterController { Position { node: self.position.node, local: self.position.local - * math::MIsometry::unit_quaternion_to_homogeneous(self.orientation), + * MIsometry::unit_quaternion_to_homogeneous(self.orientation), } } diff --git a/client/src/sim.rs b/client/src/sim.rs index 0d3995e0..7bcb8522 100644 --- a/client/src/sim.rs +++ b/client/src/sim.rs @@ -12,7 +12,9 @@ use common::{ character_controller, collision_math::Ray, graph::{Graph, NodeId}, - graph_ray_casting, math, + graph_ray_casting, + math, + math::{MVector,MIsometry}, node::{populate_fresh_nodes, ChunkId, VoxelData}, proto::{ self, BlockUpdate, Character, CharacterInput, CharacterState, Command, Component, @@ -109,7 +111,7 @@ impl Sim { selected_material: Material::WoodPlanks, prediction: PredictedMotion::new(proto::Position { node: NodeId::ROOT, - local: math::MIsometry::identity(), + local: MIsometry::identity(), }), local_character_controller: LocalCharacterController::new(), } @@ -510,7 +512,7 @@ impl Sim { pub fn view(&self) -> Position { let mut pos = self.local_character_controller.oriented_position(); let up = self.graph.get_relative_up(&pos).unwrap(); - pos.local *= common::math::translate_along( + pos.local *= math::translate_along( &(up.as_ref() * (self.cfg.character.character_radius - 1e-3)), ); pos @@ -550,7 +552,7 @@ impl Sim { let ray_casing_result = graph_ray_casting::ray_cast( &self.graph, &view_position, - &Ray::new(math::MVector::w(), -math::MVector::z()), + &Ray::new(MVector::w(), -MVector::z()), self.cfg.character.block_reach, ); diff --git a/common/src/collision_math.rs b/common/src/collision_math.rs index b985f8c3..6ecab7af 100644 --- a/common/src/collision_math.rs +++ b/common/src/collision_math.rs @@ -302,10 +302,10 @@ mod tests { // Hit the origin with a radius of 0.2 let ray = math::translate_along(&na::Vector3::new(0.0, 0.0, -0.5)) * &Ray::new( - math::MVector::origin(), + MVector::origin(), MVector::new(1.0, 2.0, 6.0, 0.0).normalize(), ); - let point_position = math::MVector::origin(); + let point_position = MVector::origin(); let point_normal0 = MVector::x(); let point_normal1 = MVector::y(); let point_normal2 = MVector::z(); diff --git a/common/src/proto.rs b/common/src/proto.rs index 132e7543..0ada3a19 100644 --- a/common/src/proto.rs +++ b/common/src/proto.rs @@ -1,7 +1,7 @@ use serde::{Deserialize, Serialize}; use crate::{ - dodeca, graph::NodeId, math, node::ChunkId, voxel_math::Coords, world::Material, EntityId, + dodeca, graph::NodeId, math::MIsometry, node::ChunkId, voxel_math::Coords, world::Material, EntityId, SimConfig, Step, }; @@ -19,14 +19,14 @@ pub struct ServerHello { #[derive(Debug, Serialize, Deserialize, Copy, Clone)] pub struct Position { pub node: NodeId, - pub local: math::MIsometry, + pub local: MIsometry, } impl Position { pub fn origin() -> Self { Self { node: NodeId::ROOT, - local: math::MIsometry::identity(), + local: MIsometry::identity(), } } } From 3de15b68e7f801829aed72a55358099ca6443f0a Mon Sep 17 00:00:00 2001 From: strawberrycinnabar Date: Sat, 27 Jul 2024 00:52:26 -0500 Subject: [PATCH 21/31] Update common/src/character_controller/collision.rs Co-authored-by: Patrick --- common/src/character_controller/collision.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/character_controller/collision.rs b/common/src/character_controller/collision.rs index 06b8905a..56ed53c1 100644 --- a/common/src/character_controller/collision.rs +++ b/common/src/character_controller/collision.rs @@ -67,7 +67,7 @@ pub fn check_collision( // This normal now represents a contact point at the origin, so we omit the w-coordinate // to ensure that it's orthogonal to the origin. normal: na::UnitVector3::new_normalize( - ((displacement_transform.mtranspose()) * hit.normal).xyz(), + (displacement_transform.mtranspose() * hit.normal).xyz(), ), }), } From 886b335ba66dbb18d8008eb799af6cb697da2e1b Mon Sep 17 00:00:00 2001 From: strawberrycinnabar Date: Sat, 27 Jul 2024 00:56:02 -0500 Subject: [PATCH 22/31] Update common/src/collision_math.rs Co-authored-by: Patrick --- common/src/collision_math.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/common/src/collision_math.rs b/common/src/collision_math.rs index 6ecab7af..5a6c6707 100644 --- a/common/src/collision_math.rs +++ b/common/src/collision_math.rs @@ -47,10 +47,10 @@ impl Ray { line_normal0: &MVector, sinh_radius: f32, ) -> Option { - let mip_pos_a = &self.position.mip(line_normal0); - let mip_dir_a = &self.direction.mip(line_normal0); - let mip_pos_b = &self.position.mip(line_normal1); - let mip_dir_b = &self.direction.mip(line_normal1); + let mip_pos_a = self.position.mip(line_normal0); + let mip_dir_a = self.direction.mip(line_normal0); + let mip_pos_b = self.position.mip(line_normal1); + let mip_dir_b = self.direction.mip(line_normal1); solve_quadratic( mip_pos_a.powi(2) + mip_pos_b.powi(2) - sinh_radius.powi(2), From 2667a8befe0afc0ac7bccc239a55a5a710075433 Mon Sep 17 00:00:00 2001 From: strawberrycinnabar Date: Sat, 27 Jul 2024 00:56:24 -0500 Subject: [PATCH 23/31] Update common/src/collision_math.rs Co-authored-by: Patrick --- common/src/collision_math.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/common/src/collision_math.rs b/common/src/collision_math.rs index 5a6c6707..1a4b51e1 100644 --- a/common/src/collision_math.rs +++ b/common/src/collision_math.rs @@ -68,12 +68,12 @@ impl Ray { point_normal2: &MVector, sinh_radius: f32, ) -> Option { - let mip_pos_a = &self.position.mip(point_normal0); - let mip_dir_a = &self.direction.mip(point_normal0); - let mip_pos_b = &self.position.mip(point_normal1); - let mip_dir_b = &self.direction.mip(point_normal1); - let mip_pos_c = &self.position.mip(point_normal2); - let mip_dir_c = &self.direction.mip(point_normal2); + let mip_pos_a = self.position.mip(point_normal0); + let mip_dir_a = self.direction.mip(point_normal0); + let mip_pos_b = self.position.mip(point_normal1); + let mip_dir_b = self.direction.mip(point_normal1); + let mip_pos_c = self.position.mip(point_normal2); + let mip_dir_c = self.direction.mip(point_normal2); solve_quadratic( mip_pos_a.powi(2) + mip_pos_b.powi(2) + mip_pos_c.powi(2) - sinh_radius.powi(2), From becd60467df62d3ee06ec770442830871e454c52 Mon Sep 17 00:00:00 2001 From: strawberrycinnabar Date: Sat, 27 Jul 2024 00:56:43 -0500 Subject: [PATCH 24/31] Update common/src/collision_math.rs Co-authored-by: Patrick --- common/src/collision_math.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/src/collision_math.rs b/common/src/collision_math.rs index 1a4b51e1..bbee7986 100644 --- a/common/src/collision_math.rs +++ b/common/src/collision_math.rs @@ -85,8 +85,8 @@ impl Ray { /// Finds the tanh of the distance a point will have to travel along a ray before it /// intersects the given plane. pub fn solve_point_plane_intersection(&self, plane_normal: &MVector) -> Option { - let mip_pos_a = &self.position.mip(plane_normal); - let mip_dir_a = &self.direction.mip(plane_normal); + let mip_pos_a = self.position.mip(plane_normal); + let mip_dir_a = self.direction.mip(plane_normal); let result = -mip_pos_a / mip_dir_a; if result.is_finite() && result > 0.0 { From 061428cdaf00c3a045b5b2b30efc9666ab8c7ad3 Mon Sep 17 00:00:00 2001 From: strawberrycinnabar Date: Sat, 27 Jul 2024 01:00:52 -0500 Subject: [PATCH 25/31] Update common/src/plane.rs Co-authored-by: Patrick --- common/src/plane.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/plane.rs b/common/src/plane.rs index c2de8279..b45de13a 100644 --- a/common/src/plane.rs +++ b/common/src/plane.rs @@ -63,7 +63,7 @@ impl Plane { /// Shortest distance between the plane and a point pub fn distance_to(&self, point: &MVector) -> N { - let mip_value = &self.normal.mip(point); + let mip_value = self.normal.mip(point); // Workaround for bug fixed in rust PR #72486 mip_value.abs().asinh() * mip_value.signum() } From 926db6e0f61a2120a8dd15450ece74b453e58d28 Mon Sep 17 00:00:00 2001 From: strawberrycinnabar Date: Sat, 27 Jul 2024 01:06:14 -0500 Subject: [PATCH 26/31] Update common/src/plane.rs Co-authored-by: Patrick --- common/src/plane.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/common/src/plane.rs b/common/src/plane.rs index b45de13a..72888021 100644 --- a/common/src/plane.rs +++ b/common/src/plane.rs @@ -72,8 +72,7 @@ impl Plane { impl Plane { /// Like `distance_to`, but using chunk coordinates for a chunk in the same node space pub fn distance_to_chunk(&self, chunk: Vertex, coord: &na::Vector3) -> f64 { - let pos = - (MVector::::from(chunk.chunk_to_node_f64() * coord.push(1.0))).lorentz_normalize(); + let pos = (MVector::from(chunk.chunk_to_node_f64() * coord.push(1.0))).lorentz_normalize(); self.distance_to(&pos) } } From cea43669055b3a801173678bb6ca4da732c7c544 Mon Sep 17 00:00:00 2001 From: strawberrycinnabar Date: Sat, 27 Jul 2024 01:08:49 -0500 Subject: [PATCH 27/31] Update common/src/traversal.rs Co-authored-by: Patrick --- common/src/traversal.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/traversal.rs b/common/src/traversal.rs index daf68556..c2502530 100644 --- a/common/src/traversal.rs +++ b/common/src/traversal.rs @@ -32,7 +32,7 @@ pub fn ensure_nearby(graph: &mut Graph, start: &Position, distance: f32) { visited.insert(neighbor); let neighbor_transform = current_transform * *side.reflection(); let neighbor_p = neighbor_transform * MVector::origin(); - if -(start_p.mip(&neighbor_p)) > distance.cosh() { + if -start_p.mip(&neighbor_p) > distance.cosh() { continue; } pending.push_back((neighbor, neighbor_transform)); From 7dbf512b2bafdd3e30db3ce91477e54696387ee2 Mon Sep 17 00:00:00 2001 From: strawberrycinnabar Date: Sat, 27 Jul 2024 01:09:00 -0500 Subject: [PATCH 28/31] Update common/src/traversal.rs Co-authored-by: Patrick --- common/src/traversal.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/traversal.rs b/common/src/traversal.rs index c2502530..82695158 100644 --- a/common/src/traversal.rs +++ b/common/src/traversal.rs @@ -69,7 +69,7 @@ pub fn nearby_nodes( while let Some(current) = pending.pop_front() { let current_p = current.transform * MVector::origin(); - if -(start_p.mip(¤t_p)) > distance.cosh() { + if -start_p.mip(¤t_p) > distance.cosh() { continue; } result.push((current.id, current.transform)); From 4d080da48da628a61df059a6fccf6d8e204abeea Mon Sep 17 00:00:00 2001 From: strawberry Date: Sat, 27 Jul 2024 16:24:52 -0500 Subject: [PATCH 29/31] guh --- client/src/graphics/voxels/mod.rs | 2 +- client/src/sim.rs | 10 ++++------ common/src/proto.rs | 4 ++-- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/client/src/graphics/voxels/mod.rs b/client/src/graphics/voxels/mod.rs index ea72d174..dfff5274 100644 --- a/client/src/graphics/voxels/mod.rs +++ b/client/src/graphics/voxels/mod.rs @@ -20,7 +20,7 @@ use common::{ dodeca::Vertex, graph::NodeId, lru_slab::SlotId, - math::{MIsometry,MVector}, + math::{MIsometry, MVector}, node::{Chunk, ChunkId, VoxelData}, LruSlab, }; diff --git a/client/src/sim.rs b/client/src/sim.rs index 7bcb8522..79e0dbc3 100644 --- a/client/src/sim.rs +++ b/client/src/sim.rs @@ -12,9 +12,8 @@ use common::{ character_controller, collision_math::Ray, graph::{Graph, NodeId}, - graph_ray_casting, - math, - math::{MVector,MIsometry}, + graph_ray_casting, math, + math::{MVector, MIsometry}, node::{populate_fresh_nodes, ChunkId, VoxelData}, proto::{ self, BlockUpdate, Character, CharacterInput, CharacterState, Command, Component, @@ -512,9 +511,8 @@ impl Sim { pub fn view(&self) -> Position { let mut pos = self.local_character_controller.oriented_position(); let up = self.graph.get_relative_up(&pos).unwrap(); - pos.local *= math::translate_along( - &(up.as_ref() * (self.cfg.character.character_radius - 1e-3)), - ); + pos.local *= + math::translate_along(&(up.as_ref() * (self.cfg.character.character_radius - 1e-3))); pos } diff --git a/common/src/proto.rs b/common/src/proto.rs index 0ada3a19..898318b7 100644 --- a/common/src/proto.rs +++ b/common/src/proto.rs @@ -1,8 +1,8 @@ use serde::{Deserialize, Serialize}; use crate::{ - dodeca, graph::NodeId, math::MIsometry, node::ChunkId, voxel_math::Coords, world::Material, EntityId, - SimConfig, Step, + dodeca, graph::NodeId, math::MIsometry, node::ChunkId, voxel_math::Coords, world::Material, + EntityId, SimConfig, Step, }; #[derive(Debug, Serialize, Deserialize)] From fe19fecb387528bf0f43923989333551e810bae6 Mon Sep 17 00:00:00 2001 From: strawberry Date: Sat, 27 Jul 2024 16:34:07 -0500 Subject: [PATCH 30/31] guh --- common/src/proto.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/src/proto.rs b/common/src/proto.rs index 898318b7..5895f55c 100644 --- a/common/src/proto.rs +++ b/common/src/proto.rs @@ -1,8 +1,8 @@ use serde::{Deserialize, Serialize}; use crate::{ - dodeca, graph::NodeId, math::MIsometry, node::ChunkId, voxel_math::Coords, world::Material, - EntityId, SimConfig, Step, + dodeca, graph::NodeId, math::MIsometry, node::ChunkId, voxel_math::Coords, world::Material, + EntityId, SimConfig, Step, }; #[derive(Debug, Serialize, Deserialize)] From 701267307f5663ebb43ba64e92d222a423006e69 Mon Sep 17 00:00:00 2001 From: strawberry Date: Sat, 27 Jul 2024 21:08:51 -0500 Subject: [PATCH 31/31] ok --- client/src/sim.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/sim.rs b/client/src/sim.rs index 79e0dbc3..3a0bcd26 100644 --- a/client/src/sim.rs +++ b/client/src/sim.rs @@ -13,7 +13,7 @@ use common::{ collision_math::Ray, graph::{Graph, NodeId}, graph_ray_casting, math, - math::{MVector, MIsometry}, + math::{MIsometry, MVector}, node::{populate_fresh_nodes, ChunkId, VoxelData}, proto::{ self, BlockUpdate, Character, CharacterInput, CharacterState, Command, Component,