[][src]Module building_blocks_storage::array

N-dimensional arrays, where N is 2 or 3.

All arrays are located within an ambient space, a signed integer lattice. 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 offset
  • Get*<&LocalN>: N-dimensional point in local coordinates
  • 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 PointN<N> to data T, stored as a flat array on the heap.

FastLz4

A compression algorithm that decompresses quickly, but only on the same platform where it was compressed.

FastLz4CompressedArrayN

A compressed ArrayN that decompresses quickly, but only on the same platform where it was 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 Array, that means there is some underlying array with the location and shape dictated by the extent.

ArrayIndexer