Module building_blocks_storage::array [−][src]
N-dimensional arrays, where N is 2 or 3.
The domains of all arrays are located within an ambient space, a signed integer lattice where the elements are Point2i
or
Point3i
. This means they contain data at exactly the set of points in an ExtentN
, and no more.
Indexing
You can index an array with 3 kinds of coordinates, with traits:
Get*<Stride>
: flat array offsetGet*<&LocalN>
: N-dimensional point in extent-local coordinates (i.e. min =[0, 0, 0]
)Get*<PointN>
: N-dimensional point in global (ambient) coordinates
Indexing assumes that the coordinates are in-bounds of the array, panicking otherwise.
Arrays also support fast iteration over extents with ForEach*
trait impls. These methods will only iterate over the
section of the extent which is in-bounds of the array, so it's impossible to index out of bounds.
use building_blocks_core::prelude::*; use building_blocks_storage::prelude::*; let array_extent = Extent3i::from_min_and_shape(PointN([0; 3]), PointN([64; 3])); let mut array = Array3::fill(array_extent, 0); // Write all points in the extent to the same value. let write_extent = Extent3i::from_min_and_lub(PointN([10, 10, 10]), PointN([20, 20, 20])); array.for_each_mut(&write_extent, |_stride: Stride, value| *value = 1); // Only the points in the extent should have been written. array.for_each(array.extent(), |p: Point3i, value| if write_extent.contains(p) { assert_eq!(value, 1); } else { assert_eq!(value, 0); } );
Since Stride
lookups are fast and linear, they are ideal for kernel-based algorithms (like edge/surface detection). Use
the ForEach*<N, Stride>
traits to iterate over an extent and use the linearity of Stride
to access adjacent points.
// Use a more interesting data set, just to show off this constructor. let mut array = Array3::fill_with(extent, |p| if p.x() % 2 == 0 { 1 } else { 0 }); let subextent = Extent3i::from_min_and_shape(PointN([1; 3]), PointN([62; 3])); // Some of these offsets include negative coordinates, which would underflow when translated // into an unsigned index. That's OK though, because Stride is intended to be used with modular // arithmetic. let offsets = Local::localize_points(&Point3i::von_neumann_offsets()); let mut neighbor_strides = [Stride(0); 6]; array.strides_from_local_points(&offsets, &mut neighbor_strides); // Sum up the values in the Von Neumann neighborhood of each point, acting as a sort of blur // filter. array.for_each(&subextent, |stride: Stride, value| { let mut neighborhood_sum = value; for offset in neighbor_strides.iter() { let adjacent_value = array.get(stride + *offset); neighborhood_sum += adjacent_value; } });
This means you keep the performance of simple array indexing, as opposed to indexing with a Point3i
, which requires 2
multiplications to convert to a Stride
. You'd be surprised how important this difference can be in tight loops.
Storage
By default, ArrayN
uses a Vec
to store elements. But any type that implements Deref<Target = [T]>
or DerefMut<Target = [T]>
should be usable. This means you can construct an array with most pointer types.
// Borrow `array`'s values for the lifetime of `other_array`. let array = Array3::fill(extent, 1); let other_array = Array3::new(extent, array.values_slice()); assert_eq!(other_array.get(Stride(0)), 1); // A stack-allocated array. let mut data = [1; 64 * 64 * 64]; let mut stack_array = Array3::new(extent, &mut data[..]); *stack_array.get_mut(Stride(0)) = 2; assert_eq!(data[0], 2); // A boxed array. let data: Box<[u32]> = Box::new([1; 64 * 64 * 64]); // must forget the size let box_array = Array3::new(extent, data); box_array.for_each(&extent, |p: Point3i, value| assert_eq!(value, 1));
Structs
ArrayN | A map from lattice location |
FastArrayCompression | A compression algorithm for arrays that avoid the overhead of serialization but ignores endianness and therefore isn't portable. |
FastCompressedArray | A compressed |
Local | Map-local coordinates. |
Stride | The most efficient coordinates for slice-backed lattice maps. A single number that translates directly to a slice offset. |
Traits
Array | When a lattice map implements |
ArrayIndexer |
Type Definitions
Array2 | A 2-dimensional |
Array3 | A 3-dimensional |