pub struct GridAab { /* private fields */ }Implementations§
Source§impl GridAab
impl GridAab
Sourcepub const ORIGIN_CUBE: GridAab
pub const ORIGIN_CUBE: GridAab
Box containing the unit cube from [0, 0, 0] to [1, 1, 1].
This constant is for convenience; there are several other ways that this box could be constructed, but they’re all kind of verbose:
use all_is_cubes::block::Resolution;
use all_is_cubes::math::{GridAab, Cube};
assert_eq!(GridAab::ORIGIN_CUBE, GridAab::from_lower_upper([0, 0, 0], [1, 1, 1]));
// Note that GridAab::for_block() is const too.
assert_eq!(GridAab::ORIGIN_CUBE, GridAab::for_block(Resolution::R1));
assert_eq!(GridAab::ORIGIN_CUBE, GridAab::single_cube(Cube::ORIGIN));Sourcepub const ORIGIN_EMPTY: GridAab
pub const ORIGIN_EMPTY: GridAab
Box of zero size at [0, 0, 0].
Use this box as the canonical placeholder “nothing” value when it is necessary to have some box.
Sourcepub const EVERYWHERE: GridAab
pub const EVERYWHERE: GridAab
Box that covers everything every other box does.
Sourcepub fn from_lower_size(
lower_bounds: impl Into<GridPoint>,
sizes: impl Into<GridSize>,
) -> Self
pub fn from_lower_size( lower_bounds: impl Into<GridPoint>, sizes: impl Into<GridSize>, ) -> Self
Constructs a GridAab from coordinate lower bounds and sizes.
For example, if on one axis the lower bound is 5 and the size is 10, then the positions where blocks can exist are numbered 5 through 14 (inclusive) and the occupied volume (from a perspective of continuous rather than discrete coordinates) spans 5 to 15.
Panics if the sizes are negative or the resulting range would cause
numeric overflow. Use GridAab::checked_from_lower_upper to avoid panics.
Sourcepub fn checked_from_lower_upper(
lower_bounds: impl Into<GridPoint>,
upper_bounds: impl Into<GridPoint>,
) -> Result<Self, GridOverflowError>
pub fn checked_from_lower_upper( lower_bounds: impl Into<GridPoint>, upper_bounds: impl Into<GridPoint>, ) -> Result<Self, GridOverflowError>
Constructs a GridAab from inclusive lower bounds and exclusive upper bounds.
For example, if on one axis the lower bound is 5 and the upper bound is 10, then the positions where blocks can exist are numbered 5 through 9 (inclusive) and the occupied volume (from a perspective of continuous rather than discrete coordinates) spans 5 to 10.
Returns Err if any of the upper_bounds are less than the lower_bounds.
Sourcepub fn from_lower_upper(
lower_bounds: impl Into<GridPoint>,
upper_bounds: impl Into<GridPoint>,
) -> GridAab
pub fn from_lower_upper( lower_bounds: impl Into<GridPoint>, upper_bounds: impl Into<GridPoint>, ) -> GridAab
Constructs a GridAab from inclusive lower bounds and exclusive upper bounds.
For example, if on one axis the lower bound is 5 and the upper bound is 10, then the positions where blocks can exist are numbered 5 through 9 (inclusive) and the occupied volume (from a perspective of continuous rather than discrete coordinates) spans 5 to 10.
Panics if any of the upper_bounds are less than the lower_bounds.
Sourcepub fn from_ranges(
ranges: impl Into<Vector3D<Range<GridCoordinate>, Cube>>,
) -> GridAab
pub fn from_ranges( ranges: impl Into<Vector3D<Range<GridCoordinate>, Cube>>, ) -> GridAab
Constructs a GridAab from Ranges.
This is identical to GridAab::from_lower_upper() except for the input type.
Sourcepub fn checked_from_lower_size(
lower_bounds: impl Into<GridPoint>,
size: impl Into<GridSize>,
) -> Result<Self, GridOverflowError>
pub fn checked_from_lower_size( lower_bounds: impl Into<GridPoint>, size: impl Into<GridSize>, ) -> Result<Self, GridOverflowError>
Sourcepub fn single_cube(cube: Cube) -> GridAab
pub fn single_cube(cube: Cube) -> GridAab
Constructs a GridAab with a volume of 1, containing the specified cube.
Panics if cube has any coordinates equal to GridCoordinate::MAX
since that is not valid, as per GridAab::from_lower_size().
This function is identical to Cube::grid_aab().
Sourcepub const fn for_block(resolution: Resolution) -> GridAab
pub const fn for_block(resolution: Resolution) -> GridAab
Constructs a GridAab with a cubical volume in the positive octant, as is used
for recursive blocks.
If you need such a box at a position other than the origin, use
GridAab::translate().
Sourcepub fn volume(&self) -> Option<usize>
pub fn volume(&self) -> Option<usize>
Computes the volume of this box in cubes, i.e. the product of all sizes.
Returns None if the volume does not fit in a usize.
(If this fallibility is undesirable, consider using a Vol<()> instead of [GridAab.])
use all_is_cubes::math::GridAab;
let a = GridAab::from_lower_size([-10, 3, 7], [100, 200, 300]);
assert_eq!(a.volume(), Some(6_000_000));
let b = GridAab::from_lower_size([0, 0, 0], [100, 200, 0]);
assert_eq!(b.volume(), Some(0));Sourcepub fn volume_f64(&self) -> f64
pub fn volume_f64(&self) -> f64
Computes the approximate volume of this box in cubes, i.e. the product of all sizes
converted to f64.
Sourcepub fn surface_area_f64(&self) -> f64
pub fn surface_area_f64(&self) -> f64
Computes the surface area of this box; 1 unit of area = 1 cube-face.
Returns f64 to avoid needing overflow considerations, and because all internal uses
want float anyway.
Sourcepub fn is_empty(&self) -> bool
pub fn is_empty(&self) -> bool
Returns whether the box contains no cubes (its volume is zero).
This does not necessarily mean that its size is zero on all axes.
Sourcepub fn lower_bounds(&self) -> GridPoint
pub fn lower_bounds(&self) -> GridPoint
Inclusive upper bounds on cube coordinates, or the most negative corner of the box.
Sourcepub fn upper_bounds(&self) -> GridPoint
pub fn upper_bounds(&self) -> GridPoint
Exclusive upper bounds on cube coordinates, or the most positive corner of the box.
Sourcepub fn size(&self) -> GridSize
pub fn size(&self) -> GridSize
Size of the box in each axis; equivalent to
self.upper_bounds() - self.lower_bounds(), except that the result is
unsigned (which is necessary so that it cannot overflow).
Sourcepub fn x_range(&self) -> Range<GridCoordinate>
pub fn x_range(&self) -> Range<GridCoordinate>
The range of X coordinates for unit cubes within the box.
Sourcepub fn y_range(&self) -> Range<GridCoordinate>
pub fn y_range(&self) -> Range<GridCoordinate>
The range of Y coordinates for unit cubes within the box.
Sourcepub fn z_range(&self) -> Range<GridCoordinate>
pub fn z_range(&self) -> Range<GridCoordinate>
The range of Z coordinates for unit cubes within the box.
Sourcepub fn axis_range(&self, axis: Axis) -> Range<GridCoordinate>
pub fn axis_range(&self, axis: Axis) -> Range<GridCoordinate>
The range of coordinates for cubes within the box along the given axis.
Sourcepub fn center(&self) -> FreePoint
pub fn center(&self) -> FreePoint
The center of the enclosed volume. Returns FreeCoordinates since the center
may be at a half-block position.
use all_is_cubes::math::{FreePoint, GridAab};
let b = GridAab::from_lower_size([0, 0, -2], [10, 3, 4]);
assert_eq!(b.center(), FreePoint::new(5.0, 1.5, 0.0));Sourcepub fn interior_iter(self) -> GridIter ⓘ
pub fn interior_iter(self) -> GridIter ⓘ
Iterate over all cubes that this contains.
The order of iteration is deterministic, but not guaranteed to be anything in particular,
and may change in later versions. If order matters, use Vol::iter_cubes() instead.
use all_is_cubes::math::{GridAab, Cube};
let b = GridAab::from_lower_size([10, 20, 30], [1, 2, 3]);
assert_eq!(
b.interior_iter().collect::<Vec<Cube>>(),
&[
Cube::new(10, 20, 30),
Cube::new(10, 20, 31),
Cube::new(10, 20, 32),
Cube::new(10, 21, 30),
Cube::new(10, 21, 31),
Cube::new(10, 21, 32),
])Sourcepub fn contains_cube(&self, cube: Cube) -> bool
pub fn contains_cube(&self, cube: Cube) -> bool
Returns whether the box includes the given cube position in its volume.
use all_is_cubes::math::{GridAab, Cube};
let b = GridAab::from_lower_size([4, 4, 4], [6, 6, 6]);
assert!(!b.contains_cube([3, 5, 5].into()));
assert!(b.contains_cube([4, 5, 5].into()));
assert!(b.contains_cube([9, 5, 5].into()));
assert!(!b.contains_cube([10, 5, 5].into()));Sourcepub fn contains_box(&self, other: GridAab) -> bool
pub fn contains_box(&self, other: GridAab) -> bool
Returns whether this box includes every cube in the other box.
TODO: Precisely define the behavior on zero volume boxes.
use all_is_cubes::math::GridAab;
let b46 = GridAab::from_lower_size([4, 4, 4], [6, 6, 6]);
assert!(b46.contains_box(b46));
assert!(!b46.contains_box(GridAab::from_lower_size([4, 4, 4], [7, 6, 6])));
assert!(!GridAab::from_lower_size((0, 0, 0), (6, 6, 6)).contains_box(b46));Sourcepub fn intersection_cubes(self, other: GridAab) -> Option<GridAab>
pub fn intersection_cubes(self, other: GridAab) -> Option<GridAab>
Returns the intersection of self and other, defined as the box which contains
every cube that both self and other do, and no others.
Returns None if there are no such cubes.
In other words, if a box is returned, then its volume will always be nonzero;
this definition of intersection is suitable when the intent is to take action on
the intersecting cubes. For applications which are more concerned with preserving
the box coordinates, call GridAab::intersection_box() instead.
use all_is_cubes::math::GridAab;
// Simple example of an intersection.
assert_eq!(
GridAab::from_lower_size([0, 0, 0], [2, 2, 2])
.intersection_cubes(GridAab::from_lower_size([1, 0, 0], [2, 1, 2])),
Some(GridAab::from_lower_size([1, 0, 0], [1, 1, 2])),
);
// A box's intersection with itself is equal to itself...
let b = GridAab::from_lower_size([1, 2, 3], [4, 5, 6]);
assert_eq!(b.intersection_cubes(b), Some(b));
// ...unless it has zero volume.
let bz = GridAab::from_lower_size([1, 2, 3], [4, 5, 0]);
assert_eq!(bz.intersection_cubes(bz), None);
// Boxes which only touch on their faces are not considered to intersect.
assert_eq!(
GridAab::from_lower_size([0, 0, 0], [2, 2, 2])
.intersection_cubes(GridAab::from_lower_size([2, 0, 0], [2, 1, 2])),
None,
);Sourcepub fn intersection_box(self, other: GridAab) -> Option<GridAab>
pub fn intersection_box(self, other: GridAab) -> Option<GridAab>
Returns the intersection of self and other, defined as the box which is as large as
possible while not extending beyond the bounds of self or the bounds of other.
Returns None if that is impossible, i.e. if the two boxes do not touch.
This definition of intersection is suitable when the intent is to constrain the bounds
of a box to fit in another, while preserving their coordinates as much as possible.
For applications which are more concerned with processing the overlapping volume when there
is overlap, call GridAab::intersection_cubes() instead for a tighter bound.
use all_is_cubes::math::GridAab;
// Simple example of an intersection.
assert_eq!(
GridAab::from_lower_size([0, 0, 0], [2, 2, 2])
.intersection_box(GridAab::from_lower_size([1, 0, 0], [2, 1, 2])),
Some(GridAab::from_lower_size([1, 0, 0], [1, 1, 2])),
);
// A box's intersection with itself is always equal to itself...
let b = GridAab::from_lower_size([1, 2, 3], [4, 5, 6]);
assert_eq!(b.intersection_box(b), Some(b));
// ...even when it has zero volume.
let bz = GridAab::from_lower_size([1, 2, 3], [4, 5, 0]);
assert_eq!(bz.intersection_box(bz), Some(bz));
// Boxes which only touch on their faces yield their shared boundary surface.
assert_eq!(
GridAab::from_lower_size([0, 0, 0], [2, 2, 2])
.intersection_box(GridAab::from_lower_size([2, 0, 0], [2, 1, 2])),
Some(GridAab::from_lower_size([2, 0, 0], [0, 1, 2])),
);Sourcepub fn union_cubes(self, other: Self) -> Self
pub fn union_cubes(self, other: Self) -> Self
Returns the smallest GridAab which fully encloses the two inputs’ cubes.
The boundaries of empty boxes are ignored.
If this is not desired, call GridAab::union_box() instead.
If both inputs are empty, then self is returned.
use all_is_cubes::math::GridAab;
let g1 = GridAab::from_lower_size([1, 2, 3], [1, 1, 1]);
assert_eq!(g1.union_cubes(g1), g1);
let g2 = GridAab::from_lower_size([4, 7, 11], [1, 1, 1]);
assert_eq!(g1.union_cubes(g2), GridAab::from_lower_upper([1, 2, 3], [5, 8, 12]));
// Empty boxes (any size equal to zero) have no effect.
let empty = GridAab::from_lower_size([0, 0, 0], [0, 1, 7]);
assert_eq!(g1.union_cubes(empty), g1);Sourcepub fn union_box(self, other: Self) -> Self
pub fn union_box(self, other: Self) -> Self
Returns the smallest GridAab which fully encloses the two inputs’ boundaries.
The boundaries of empty boxes are included.
If this is not desired, call GridAab::union_cubes() instead for a tighter bound.
use all_is_cubes::math::GridAab;
let g1 = GridAab::from_lower_size([1, 2, 3], [1, 1, 1]);
assert_eq!(g1.union_box(g1), g1);
let g2 = GridAab::from_lower_size([4, 7, 11], [1, 1, 1]);
assert_eq!(g1.union_box(g2), GridAab::from_lower_upper([1, 2, 3], [5, 8, 12]));
// Empty boxes (any size equal to zero) are included even though they contain no cubes.
let empty = GridAab::from_lower_size([0, 0, 0], [0, 1, 7]);
assert_eq!(g1.union_box(empty), GridAab::from_lower_upper([0, 0, 0], [2, 3, 7]));
// A union of empty boxes can become non-empty by including the volume within.
assert_eq!(
empty.union_box(empty.translate([3, 0, 0])),
GridAab::from_lower_upper([0, 0, 0], [3, 1, 7]),
)Sourcepub fn union_cube(self, other: Cube) -> GridAab
pub fn union_cube(self, other: Cube) -> GridAab
Extend the bounds of self as needed to enclose other.
Equivalent to self.union_box(GridAab::single_cube(other)).
Note in particular that it does not discard the bounds of an empty self,
like GridAab::union_cubes() would.
use all_is_cubes::math::{Cube, GridAab};
let accumulation =
GridAab::single_cube(Cube::new(1, 10, 7))
.union_cube(Cube::new(2, 5, 10));
assert_eq!(accumulation, GridAab::from_lower_upper([1, 5, 7], [3, 11, 11]));Sourcepub fn random_cube(&self, rng: &mut impl Rng) -> Option<Cube>
pub fn random_cube(&self, rng: &mut impl Rng) -> Option<Cube>
Returns a random cube contained by the box, if there are any.
use all_is_cubes::math::GridAab;
use rand::SeedableRng;
let mut rng = &mut rand_xoshiro::Xoshiro256Plus::seed_from_u64(0);
let b = GridAab::from_lower_size([4, 4, 4], [6, 6, 6]);
for _ in 0..50 {
assert!(b.contains_cube(b.random_cube(rng).unwrap()));
}
let empty = GridAab::from_lower_size([1, 2, 3], [0, 9, 9]);
assert_eq!(empty.random_cube(rng), None);Sourcepub fn to_vol<O: Default>(self) -> Result<Vol<(), O>, VolLengthError>
pub fn to_vol<O: Default>(self) -> Result<Vol<(), O>, VolLengthError>
Creates a Vol with self as the bounds and no data.
This introduces a particular linear ordering of the cubes in the volume.
Returns an error if the volume of self is greater than usize::MAX.
Sourcepub fn to_free(self) -> Aab
pub fn to_free(self) -> Aab
Converts this box to floating-point coordinates.
This conversion is also available via the From trait.
Sourcepub fn translate(&self, offset: impl Into<GridVector>) -> Self
pub fn translate(&self, offset: impl Into<GridVector>) -> Self
Displaces the box by the given offset, leaving its size unchanged
(unless that is impossible due to numeric overflow).
use all_is_cubes::math::GridAab;
assert_eq!(
GridAab::from_lower_size([0, 0, 0], [10, 20, 30]).translate([-10, 0, 0]),
GridAab::from_lower_size([-10, 0, 0], [10, 20, 30]),
);Sourcepub fn transform(self, transform: Gridgid) -> Option<Self>
pub fn transform(self, transform: Gridgid) -> Option<Self>
Translate and rotate the box according to the given transform.
TODO: Fail nicely on numeric overflow.
The Option return is not currently used.
Sourcepub fn divide(self, divisor: GridCoordinate) -> Self
pub fn divide(self, divisor: GridCoordinate) -> Self
Scales the box down by the given factor, rounding outward.
For example, this may be used to convert from voxels (subcubes) to blocks or blocks to chunks.
Panics if the divisor is not positive.
use all_is_cubes::math::GridAab;
assert_eq!(
GridAab::from_lower_size([-10, -10, -10], [20, 20, 20]).divide(10),
GridAab::from_lower_size([-1, -1, -1], [2, 2, 2]),
);
assert_eq!(
GridAab::from_lower_size([-10, -10, -10], [21, 21, 21]).divide(10),
GridAab::from_lower_size([-1, -1, -1], [3, 3, 3]),
);
assert_eq!(
GridAab::from_lower_size([-11, -11, -11], [20, 20, 20]).divide(10),
GridAab::from_lower_size([-2, -2, -2], [3, 3, 3]),
);Sourcepub fn multiply(self, scale: GridCoordinate) -> Self
pub fn multiply(self, scale: GridCoordinate) -> Self
Scales the box up by the given factor.
Panics on numeric overflow.
assert_eq!(
GridAab::from_lower_size([-1, 2, 3], [4, 5, 6]).multiply(10),
GridAab::from_lower_size([-10, 20, 30], [40, 50, 60]),
);Sourcepub fn expand(self, deltas: FaceMap<GridSizeCoord>) -> Self
pub fn expand(self, deltas: FaceMap<GridSizeCoord>) -> Self
Moves all bounds outward by the specified distances.
If the result’s coordinates would overflow, they are as large as possible instead.
use all_is_cubes::math::{GridAab, FaceMap};
assert_eq!(
GridAab::from_lower_upper([10, 10, 10], [20, 20, 20])
.expand(FaceMap {
nx: 1, ny: 2, nz: 3,
px: 4, py: 5, pz: 6,
}),
GridAab::from_lower_upper([9, 8, 7], [24, 25, 26]),
);Sourcepub fn shrink(self, deltas: FaceMap<GridSizeCoord>) -> Option<Self>
pub fn shrink(self, deltas: FaceMap<GridSizeCoord>) -> Option<Self>
Moves all bounds inward by the specified distances.
Returns None if the result would have less than zero size.
use all_is_cubes::math::{GridAab, FaceMap};
assert_eq!(
GridAab::from_lower_upper([10, 10, 10], [20, 20, 20])
.shrink(FaceMap {
nx: 1, ny: 2, nz: 3,
px: 4, py: 5, pz: 6,
}),
Some(GridAab::from_lower_upper([11, 12, 13], [16, 15, 14])),
);Sourcepub fn abut(
self,
face: Face6,
thickness: GridCoordinate,
) -> Result<Self, GridOverflowError>
pub fn abut( self, face: Face6, thickness: GridCoordinate, ) -> Result<Self, GridOverflowError>
Returns a GridAab which includes the volume between the given face rectangle
of self and the same rectangle translated thickness cubes outward from it
(inward if negative).
Edge cases:
- If
thicknessis negative and greater than the size of the input, it is clamped (so that the returnedGridAabnever extends beyond the opposite face ofself).
For example, it may be used to construct the walls of a room:
use all_is_cubes::math::{GridAab, Face6};
let interior = GridAab::from_lower_upper([10, 10, 10], [20, 20, 20]);
let left_wall = interior.abut(Face6::NX, 2)?;
let right_wall = interior.abut(Face6::PX, 2)?;
assert_eq!(left_wall, GridAab::from_lower_upper([8, 10, 10], [10, 20, 20]));
assert_eq!(right_wall, GridAab::from_lower_upper([20, 10, 10], [22, 20, 20]));Example of negative thickness:
let b = GridAab::from_lower_upper([10, 10, 10], [20, 20, 20]);
assert_eq!(
b.abut(Face6::PX, -3)?,
GridAab::from_lower_upper([17, 10, 10], [20, 20, 20]),
);
assert_eq!(
// Thicker than the input, therefore clamped.
b.abut(Face6::PX, -30)?,
GridAab::from_lower_upper([10, 10, 10], [20, 20, 20]),
);Trait Implementations§
Source§impl From<GridAab> for Aab
impl From<GridAab> for Aab
Source§fn from(value: GridAab) -> Self
fn from(value: GridAab) -> Self
Converts value to floating-point coordinates.
This conversion is also available as GridAab::to_free(),
which may be more convenient in a method chain.