From 340fd970c0451ec8fb0403672cb152ac40f99a32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Lescaudey=20de=20Maneville?= Date: Wed, 24 Jan 2024 10:04:16 +0100 Subject: [PATCH 1/3] Fractional hex on HexLayout Cleanup matrix code --- src/hex/mod.rs | 18 +++++++++++++++++- src/layout.rs | 40 +++++++++++++++++++++++++++------------- src/orientation.rs | 26 ++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 14 deletions(-) diff --git a/src/hex/mod.rs b/src/hex/mod.rs index 568a3e0..52fdd29 100644 --- a/src/hex/mod.rs +++ b/src/hex/mod.rs @@ -267,7 +267,15 @@ impl Hex { #[inline] #[must_use] - /// Converts `self` to cubic coordinates an array as `[x, y, z]` + #[allow(clippy::cast_precision_loss)] + /// Converts `self` to an [`f32`] array as `[x, y]` + pub const fn to_array_f32(self) -> [f32; 2] { + [self.x as f32, self.y as f32] + } + + #[inline] + #[must_use] + /// Converts `self` to cubic coordinates array as `[x, y, z]` /// /// # Example /// @@ -283,6 +291,14 @@ impl Hex { [self.x, self.y, self.z()] } + #[inline] + #[must_use] + #[allow(clippy::cast_precision_loss)] + /// Converts `self` to cubic [`f32`] coordinates array as `[x, y, z]` + pub const fn to_cubic_array_f32(self) -> [f32; 3] { + [self.x as f32, self.y as f32, self.z() as f32] + } + /// Creates a [`Hex`] from the first 2 values in `slice`. /// /// # Panics diff --git a/src/layout.rs b/src/layout.rs index 9121c03..debd4b7 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -53,32 +53,46 @@ pub struct HexLayout { impl HexLayout { #[must_use] + #[inline] /// Computes hexagonal coordinates `hex` into world/pixel coordinates pub fn hex_to_world_pos(&self, hex: Hex) -> Vec2 { self.hex_to_center_aligned_world_pos(hex) + self.origin } - #[allow(clippy::cast_precision_loss)] #[must_use] + #[inline] + /// Computes hexagonal coordinates `hex` into world/pixel coordinates but + /// ignoring [`HexLayout::origin`] pub(crate) fn hex_to_center_aligned_world_pos(&self, hex: Hex) -> Vec2 { - let matrix = self.orientation.forward_matrix; - Vec2::new( - matrix[0].mul_add(hex.x() as f32, matrix[1] * hex.y() as f32), - matrix[2].mul_add(hex.x() as f32, matrix[3] * hex.y() as f32), - ) * self.hex_size - * self.axis_scale() + let [x, y] = self.orientation.forward(hex.to_array_f32()); + Vec2::new(x, y) * self.hex_size * self.axis_scale() + } + + #[must_use] + #[inline] + /// Computes fractional hexagonal coordinates `hex` into world/pixel + /// coordinates + pub fn fract_hex_to_world_pos(&self, hex: Vec2) -> Vec2 { + let [x, y] = self.orientation.forward(hex.to_array()); + Vec2::new(x, y) * self.hex_size * self.axis_scale() + self.origin } - #[allow(clippy::cast_precision_loss, clippy::cast_possible_truncation)] #[must_use] + #[inline] /// Computes world/pixel coordinates `pos` into hexagonal coordinates pub fn world_pos_to_hex(&self, pos: Vec2) -> Hex { - let matrix = self.orientation.inverse_matrix; + let p = self.world_pos_to_fract_hex(pos).to_array(); + Hex::round(p) + } + + #[allow(clippy::cast_precision_loss, clippy::cast_possible_truncation)] + #[must_use] + /// Computes world/pixel coordinates `pos` into fractional hexagonal + /// coordinates + pub fn world_pos_to_fract_hex(&self, pos: Vec2) -> Vec2 { let point = (pos - self.origin) * self.axis_scale() / self.hex_size; - Hex::round([ - matrix[0].mul_add(point.x, matrix[1] * point.y), - matrix[2].mul_add(point.x, matrix[3] * point.y), - ]) + let [x, y] = self.orientation.inverse(point.to_array()); + Vec2::new(x, y) } #[must_use] diff --git a/src/orientation.rs b/src/orientation.rs index 2ab0ebe..aac8408 100644 --- a/src/orientation.rs +++ b/src/orientation.rs @@ -85,3 +85,29 @@ impl Deref for HexOrientation { self.orientation_data() } } + +impl HexOrientationData { + #[must_use] + #[inline] + /// Applies `matrix` to a point defined by `x` and `y` + fn matrix_op(matrix: [f32; 4], [x, y]: [f32; 2]) -> [f32; 2] { + [ + matrix[0].mul_add(x, matrix[1] * y), + matrix[2].mul_add(x, matrix[3] * y), + ] + } + + #[must_use] + #[inline] + /// Applies [`Self::forward_matrix`] to a point `p` + pub fn forward(&self, p: [f32; 2]) -> [f32; 2] { + Self::matrix_op(self.forward_matrix, p) + } + + #[must_use] + #[inline] + /// Applies [`Self::inverse_matrix`] to a point `p` + pub fn inverse(&self, p: [f32; 2]) -> [f32; 2] { + Self::matrix_op(self.inverse_matrix, p) + } +} From f461eb29b553cdb5eec553ecc36874b6e1809e62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Lescaudey=20de=20Maneville?= Date: Wed, 24 Jan 2024 10:07:43 +0100 Subject: [PATCH 2/3] CHANGELOG --- CHANGELOG.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 95ffb78..1d4bb9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,13 +2,33 @@ ## [Unreleased] +### algorithms + * (**BREAKING**) `a_star` `cost` function parameter now takes two adjacent `Hex` nodes instead of one, allowing for more use cases (#130, #128) + +### Dependencies + * Bumped `bevy_inspector_egui` dependency (#129) + +### Examples + * Added a `sprite_sheet` bevy example (#135) + +### Additions + * Added `HexLayout::rect_size` method (#135) * Added `ColumnMeshBuilder::center_aligned` option (#139) * Added `PlaneMeshBuilder::center_aligned` option (#139) +* Added `Hex::to_array_f32` utility method (#141) +* Added `Hex::to_cubic_array_f32` utility method (#141) +* Added `HexLayout::fract_hex_to_world_pos` method (#141, #138, #140) +* Added `HexLayout::world_pos_to_fract_hex` method (#141, #138, #140) +* Added `HexOrientationData::forward` method (#141) +* Added `HexOrientationData::inverse` method (#141) + +### Deprecation + * Deprecated `MeshInfo::hexagonal_plane` in favor of `PlaneMeshBuilder` (#139) ## 0.12.0 From 8e6b69db3fc2479d57dc2fc82670f350a2d043e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Lescaudey=20de=20Maneville?= Date: Wed, 24 Jan 2024 10:15:28 +0100 Subject: [PATCH 3/3] rustdoc --- src/orientation.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/orientation.rs b/src/orientation.rs index aac8408..a6925fa 100644 --- a/src/orientation.rs +++ b/src/orientation.rs @@ -99,14 +99,14 @@ impl HexOrientationData { #[must_use] #[inline] - /// Applies [`Self::forward_matrix`] to a point `p` + /// Applies the orientation `forward_matrix` to a point `p` pub fn forward(&self, p: [f32; 2]) -> [f32; 2] { Self::matrix_op(self.forward_matrix, p) } #[must_use] #[inline] - /// Applies [`Self::inverse_matrix`] to a point `p` + /// Applies the orientation `inverse_matrix` to a point `p` pub fn inverse(&self, p: [f32; 2]) -> [f32; 2] { Self::matrix_op(self.inverse_matrix, p) }