Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fractional hex on HexLayout #141

Merged
merged 3 commits into from
Jan 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
18 changes: 17 additions & 1 deletion src/hex/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
///
Expand All @@ -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
Expand Down
40 changes: 27 additions & 13 deletions src/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
26 changes: 26 additions & 0 deletions src/orientation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 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 the orientation `inverse_matrix` to a point `p`
pub fn inverse(&self, p: [f32; 2]) -> [f32; 2] {
Self::matrix_op(self.inverse_matrix, p)
}
}