Skip to content

Commit

Permalink
Add math::Axis and replace uses of integers for axis selection.
Browse files Browse the repository at this point in the history
I've wanted to do this for a while, but the immediate motivation is that
I am considering switching vector libraries, and the replacement does
not have `impl Index<usize> for Vector3` and such.
  • Loading branch information
kpreid committed Sep 9, 2023
1 parent 3858aba commit df55a89
Show file tree
Hide file tree
Showing 19 changed files with 239 additions and 94 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
### Added

- `all-is-cubes` library:
- `math::Axis` is an enum of coordinate axes.

- `math::Cube` represents a unit cube on the grid; it replaces many previous uses of `GridPoint` to identify cubes.

- `math::Gridgid` represents rigid transformations, a useful subset of what `GridMatrix` already could do.
Expand All @@ -23,6 +25,9 @@

- All functions manipulating volume data in `Space`, `GridArray`, `Evoxels`, etc. have changed signature to use the new type `math::Cube` instead of `math::GridPoint`.

- All functions using `usize` to identify a coordinate axis now use `math::Axis` instead.
`Face6::axis_number()` and `Face7::axis_number()` are now called `axis()`.

- The following functions have changed signature to use the new type `math::Gridgid`:
- `math::GridAab::transform()`
- `math::GridMatrix::decompose()`
Expand Down
4 changes: 2 additions & 2 deletions all-is-cubes-content/src/atrium.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use all_is_cubes::character::Spawn;
use all_is_cubes::content::{free_editing_starter_inventory, palette};
use all_is_cubes::linking::{BlockModule, BlockProvider, InGenError};
use all_is_cubes::math::{
Cube, Face6, FaceMap, FreeCoordinate, GridAab, GridArray, GridCoordinate, GridPoint,
Axis, Cube, Face6, FaceMap, FreeCoordinate, GridAab, GridArray, GridCoordinate, GridPoint,
GridRotation, GridVector, Gridgid, Rgb, Rgba,
};
use all_is_cubes::space::{SetCubeError, Space, SpacePhysics, SpaceTransaction};
Expand Down Expand Up @@ -333,7 +333,7 @@ fn arch_row(
for i in 0..section_count {
let column_base = first_column_base + offset * (i + 1);

let banner_color = if parallel.axis_number() == 2 {
let banner_color = if parallel.axis() == Axis::Y {
match i.rem_euclid(3) {
0 => Some(BannerColor::Red),
1 => Some(BannerColor::Green),
Expand Down
17 changes: 9 additions & 8 deletions all-is-cubes-content/src/dungeon/demo_dungeon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ use all_is_cubes::drawing::VoxelBrush;
use all_is_cubes::inv::Tool;
use all_is_cubes::linking::{BlockModule, BlockProvider, GenError, InGenError};
use all_is_cubes::math::{
Cube, Face6, FaceMap, GridAab, GridArray, GridCoordinate, GridPoint, GridRotation, GridVector,
Rgb, Rgba,
Axis, Cube, Face6, FaceMap, GridAab, GridArray, GridCoordinate, GridPoint, GridRotation,
GridVector, Rgb, Rgba,
};
use all_is_cubes::space::{LightPhysics, Space};
use all_is_cubes::time;
Expand Down Expand Up @@ -117,7 +117,7 @@ impl DemoTheme {
face: Face6,
has_gate: bool,
) -> Result<(), InGenError> {
let passage_axis = face.axis_number();
let passage_axis = face.axis();

let mut room_1_box = self.actual_room_box(
room_position,
Expand All @@ -136,8 +136,8 @@ impl DemoTheme {
}

let wall_parallel = GridRotation::CLOCKWISE.transform(face);
let parallel_axis = wall_parallel.axis_number();
assert!(parallel_axis != 1);
let parallel_axis = wall_parallel.axis();
assert!(parallel_axis != Axis::Y);

let rotate_nz_to_face = GridRotation::from_to(Face6::NZ, face, Face6::PY).unwrap();

Expand Down Expand Up @@ -173,9 +173,10 @@ impl DemoTheme {

// Gate
if has_gate {
let gate_box = doorway_box.abut(face, -1).unwrap().translate(
face.opposite().normal_vector() * doorway_box.size()[face.axis_number()] / 2,
);
let gate_box = doorway_box
.abut(face, -1)
.unwrap()
.translate(face.opposite().normal_vector() * doorway_box.size()[face.axis()] / 2);
let gate_side_1 = gate_box.abut(wall_parallel.opposite(), -1).unwrap();
let gate_side_2 = gate_box.abut(wall_parallel, -1).unwrap();
space.fill_uniform(
Expand Down
2 changes: 1 addition & 1 deletion all-is-cubes-content/src/dungeon/generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ impl DungeonGrid {
face,
GridCoordinate::from(self.room_wall_thickness[face])
+ GridCoordinate::from(self.room_wall_thickness[face.opposite()])
+ GridCoordinate::from(self.gap_between_walls[face.axis_number()]),
+ GridCoordinate::from(self.gap_between_walls[face.axis()]),
)
.unwrap()
}
Expand Down
15 changes: 8 additions & 7 deletions all-is-cubes-content/src/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ pub(crate) fn make_tree(
use graph::Growph;
mod graph {
use super::*;
use all_is_cubes::math::Axis;

/// A graph of connections between adjacent blocks of a tree we're going to grow.
///
Expand All @@ -234,11 +235,11 @@ mod graph {
// TODO: could, theoretically, numeric overflow
self.data
.get(cube + neighbor_face.normal_vector())
.map(|cell| cell.pos_neighbors[neighbor_face.axis_number()])
.map(|cell| cell.pos_neighbors[neighbor_face.axis()])
} else {
self.data
.get(cube)
.map(|cell| cell.pos_neighbors[neighbor_face.axis_number()])
.map(|cell| cell.pos_neighbors[neighbor_face.axis()])
}
}

Expand All @@ -252,12 +253,12 @@ mod graph {
// TODO: could, theoretically, numeric overflow
self.data
.get_mut(cube + neighbor_face.normal_vector())
.map(|cell| &mut cell.pos_neighbors[neighbor_face.axis_number()])
.map(|cell| &mut cell.pos_neighbors[neighbor_face.axis()])
} else {
// TODO: reject attempts to modify the extraneous edges exiting the upper bounds
self.data
.get_mut(cube)
.map(|cell| &mut cell.pos_neighbors[neighbor_face.axis_number()])
.map(|cell| &mut cell.pos_neighbors[neighbor_face.axis()])
}
}

Expand Down Expand Up @@ -310,7 +311,7 @@ mod graph {

impl petgraph::visit::GraphBase for Growph {
type NodeId = Cube;
type EdgeId = (Cube, usize); // TODO: this is evidence for wanting an axis-ID enum
type EdgeId = (Cube, Axis);
}
impl petgraph::visit::Data for Growph {
type NodeWeight = Option<TreeGrowth>;
Expand Down Expand Up @@ -376,7 +377,7 @@ mod graph {
}
impl petgraph::visit::EdgeRef for GrowphEdgeRef {
type NodeId = Cube;
type EdgeId = (Cube, usize);
type EdgeId = (Cube, Axis);
type Weight = Option<TreeGrowth>;

fn source(&self) -> Self::NodeId {
Expand All @@ -397,7 +398,7 @@ mod graph {
} else {
self.source()
},
self.face.axis_number(),
self.face.axis(),
)
}
}
Expand Down
4 changes: 2 additions & 2 deletions all-is-cubes-mesh/src/planar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use all_is_cubes::block::Resolution;
use all_is_cubes::cgmath::{
ElementWise as _, EuclideanSpace as _, Matrix4, Point2, Point3, Transform as _, Vector2,
};
use all_is_cubes::math::{Face6, FreeCoordinate, GridCoordinate, Rgba};
use all_is_cubes::math::{Axis, Face6, FreeCoordinate, GridCoordinate, Rgba};

use crate::texture::{self, TextureCoordinate};
use crate::{BlockVertex, Coloring, IndexVec};
Expand Down Expand Up @@ -198,7 +198,7 @@ pub(super) fn push_quad<V: From<BlockVertex<Tex::Point>>, Tex: texture::Plane>(
});

// Ensure the transformed clamp range is not inverted.
for axis in 0..3 {
for axis in Axis::ALL {
all_is_cubes::math::sort_two(&mut clamp_min[axis], &mut clamp_max[axis]);
}

Expand Down
14 changes: 8 additions & 6 deletions all-is-cubes-ui/src/vui/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ use std::rc::Rc;
use std::sync::Arc;

use all_is_cubes::cgmath::{Vector3, Zero as _};
use all_is_cubes::math::{Cube, Face6, FaceMap, GridAab, GridCoordinate, GridPoint, GridVector};
use all_is_cubes::math::{
Axis, Cube, Face6, FaceMap, GridAab, GridCoordinate, GridPoint, GridVector,
};
use all_is_cubes::space::{Space, SpaceBuilder, SpaceTransaction};
use all_is_cubes::transaction::{self, Merge as _, Transaction as _};

Expand Down Expand Up @@ -92,7 +94,7 @@ impl LayoutGrant {
);

if enlarge_for_symmetry {
for axis in 0..3 {
for axis in Axis::ALL {
if self.gravity[axis] == Align::Center
&& self.bounds.size()[axis].rem_euclid(2) != sizes[axis].rem_euclid(2)
{
Expand All @@ -105,7 +107,7 @@ impl LayoutGrant {
let sizes = sizes.zip(self.bounds.size(), GridCoordinate::min);

let mut origin = GridPoint::new(0, 0, 0);
for axis in 0..3 {
for axis in Axis::ALL {
let l = self.bounds.lower_bounds()[axis];
let h = self.bounds.upper_bounds()[axis] - sizes[axis];
origin[axis] = match self.gravity[axis] {
Expand Down Expand Up @@ -309,7 +311,7 @@ impl<W: Layoutable + Clone> LayoutTree<W> {
let mut bounds = grant.bounds;
for child in children {
let requirements = child.requirements();
let axis = direction.axis_number();
let axis = direction.axis();
let size_on_axis = requirements.minimum[axis];
let available_size = bounds.size()[axis];
if size_on_axis > available_size {
Expand Down Expand Up @@ -445,10 +447,10 @@ impl<W: Layoutable> Layoutable for LayoutTree<W> {
ref children,
} => {
let mut accumulator = GridVector::zero();
let stack_axis = direction.axis_number();
let stack_axis = direction.axis();
for child in children {
let child_req = child.requirements();
for axis in 0..3 {
for axis in Axis::ALL {
if axis == stack_axis {
accumulator[axis] += child_req.minimum[axis];
} else {
Expand Down
4 changes: 2 additions & 2 deletions all-is-cubes/src/camera.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use itertools::Itertools as _;
use ordered_float::NotNan;

use crate::chunking::OctantMask;
use crate::math::{Aab, FreeCoordinate, GridAab, Rgba};
use crate::math::{Aab, Axis, FreeCoordinate, GridAab, Rgba};
use crate::raycast::Ray;

mod flaws;
Expand Down Expand Up @@ -503,7 +503,7 @@ pub fn eye_for_look_at(
direction: Vector3<FreeCoordinate>,
) -> Point3<FreeCoordinate> {
let mut space_radius: FreeCoordinate = 0.0;
for axis in 0..3 {
for axis in Axis::ALL {
space_radius = space_radius.max(bounds.size()[axis].into());
}
bounds.center() + direction.normalize() * space_radius // TODO: allow for camera FoV
Expand Down
11 changes: 3 additions & 8 deletions all-is-cubes/src/content.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,19 +179,14 @@ pub fn make_slab(
/// ```
pub fn axes(space: &mut Space) -> Result<(), SetCubeError> {
for face in Face6::ALL {
let axis = face.axis_number();
let axis_color = [
palette::UNIFORM_LUMINANCE_RED,
palette::UNIFORM_LUMINANCE_GREEN,
palette::UNIFORM_LUMINANCE_BLUE,
][axis];
let axis = face.axis();
let direction = face.normal_vector::<GridCoordinate>()[axis];
let raycaster = Raycaster::new([0.5, 0.5, 0.5], face.normal_vector::<FreeCoordinate>())
.within(space.bounds());
for step in raycaster {
let i = step.cube_ahead().lower_bounds()[axis] * direction; // always positive
let (color, display_name): (Rgb, Cow<'static, str>) = if i.rem_euclid(2) == 0 {
(axis_color, i.rem_euclid(10).to_string().into())
(axis.color(), i.rem_euclid(10).to_string().into())
} else {
if direction > 0 {
(rgb_const!(1.0, 1.0, 1.0), ["X", "Y", "Z"][axis].into())
Expand All @@ -204,7 +199,7 @@ pub fn axes(space: &mut Space) -> Result<(), SetCubeError> {
Block::builder()
.display_name(display_name)
.color(color.with_alpha_one())
.light_emission(axis_color * 3.0)
.light_emission(axis.color() * 3.0)
.build(),
)?;
}
Expand Down
4 changes: 2 additions & 2 deletions all-is-cubes/src/math.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
//! Mathematical utilities and decisions.
use std::fmt;

use cgmath::{Point3, Vector3};
use num_traits::identities::Zero;
pub use ordered_float::{FloatIsNan, NotNan};
Expand All @@ -10,6 +8,8 @@ use crate::util::{ConciseDebug, CustomFormat};

mod aab;
pub use aab::*;
mod axis;
pub use axis::*;
#[macro_use]
mod color;
pub use color::*;
Expand Down
12 changes: 7 additions & 5 deletions all-is-cubes/src/math/aab.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::iter::FusedIterator;

use cgmath::{EuclideanSpace as _, Point3, Vector3, Zero as _};

use crate::math::{Face6, FreeCoordinate, Geometry, GridAab, GridCoordinate, LineVertex};
use crate::math::{Axis, Face6, FreeCoordinate, Geometry, GridAab, GridCoordinate, LineVertex};

/// Axis-Aligned Box data type.
///
Expand Down Expand Up @@ -175,7 +175,9 @@ impl Aab {
///
/// TODO: example + tests
pub fn contains(&self, point: Point3<FreeCoordinate>) -> bool {
for axis in 0..3 {
// I tried changing this to an Iterator::all() and the asm was longer.
// I tried changing this to be completely unrolled and it was more or less the same.
for axis in Axis::ALL {
if !(self.lower_bounds[axis] <= point[axis] && point[axis] <= self.upper_bounds[axis]) {
return false;
}
Expand All @@ -187,7 +189,7 @@ impl Aab {
///
/// TODO: example + tests
pub fn intersects(&self, other: Aab) -> bool {
for axis in 0..3 {
for axis in Axis::ALL {
let intersection_min = self.lower_bounds[axis].max(other.lower_bounds[axis]);
let intersection_max = self.upper_bounds[axis].min(other.upper_bounds[axis]);
match intersection_min.partial_cmp(&intersection_max) {
Expand Down Expand Up @@ -252,7 +254,7 @@ impl Aab {
direction: Vector3<FreeCoordinate>,
) -> Vector3<FreeCoordinate> {
let mut leading_corner = Vector3::zero();
for axis in 0..3 {
for axis in Axis::ALL {
if direction[axis] >= 0.0 {
leading_corner[axis] = self.upper_bounds[axis];
} else {
Expand Down Expand Up @@ -482,7 +484,7 @@ mod tests {
{
let leading_corner = aab.leading_corner(direction);

for axis in 0..3 {
for axis in Axis::ALL {
// Note that this condition is not true in general, but only if the AAB
// contains the origin.
assert_eq!(leading_corner[axis].signum(), direction[axis].signum());
Expand Down
Loading

0 comments on commit df55a89

Please sign in to comment.