[−][src]Module building_blocks_storage::array
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.
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.
Structs
ArrayCopySrc | |
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 |