Struct pasture_core::layout::PointLayout[][src]

pub struct PointLayout { /* fields omitted */ }

Describes the data layout of a single point in a point cloud

Detailed explanation

To understand PointLayout, it is necessary to understand the memory model of Pasture. Pasture is a library for handling point cloud data, so the first thing worth understanding is what ‘point cloud data’ means in the context of Pasture:

A point cloud in Pasture is modeled as a collection of tuples of attributes (a_1, a_2, …, a_n). An attribute can be any datum associated with a point, such as its position in 3D space, an intensity value, an object classification etc. The set of all unique attributes in a point cloud make up the point clouds point layout, which is represented in Pasture by the PointLayout type. The Pasture memory model describes how the attributes for each point in a point cloud are layed out in memory. There are two major memory layouts supported by Pasture: Interleaved and PerAttribute. In an Interleaved layout, all attributes for a single point are stored together in memory:

[a_1(p_1), a_2(p_1), …, a_n(p_1), a_1(p_2), a_2(p_2), …, a_n(p_2), …]

This layout is equivalent to storing a type T inside a Vec, where T has members a_1, a_2, …, a_n and is packed tightly.

In a PerAttribute layout, all attributes of a single type are stored together in memory, often in separate memory regions:

[a_1(p_1), a_1(p_2), …, a_1(p_n)] [a_2(p_1), a_2(p_2), …, a_2(p_n)] … [a_n(p_1), a_n(p_2), …, a_n(p_n)]

These layouts are sometimes called ‘Array of Structs’ (Interleaved) and ‘Struct of Arrays’ (PerAttribute).

Most code in Pasture supports point clouds with either of these memory layouts. To correctly handle memory layout and access in both Interleaved and PerAttribute layout, each buffer in Pasture that stores point cloud data requires a piece of metadata that describes the attributes of the point cloud with their respective Rust types, their order, their memory alignment and their potential offset within a single point entry in Interleaved format. All this information is stored inside the PointLayout structure.

To support the different memory layouts, Pasture buffers store point data as raw binary buffers internally. To work with the data, you will want to use strongly typed Rust structures. Any type T that you want to use for accessing point data in a strongly typed manner must implement the PointType trait and thus provide Pasture with a way of figuring out the attributes and memory layout of this type T.

Implementations

impl PointLayout[src]

pub fn from_attributes(attributes: &[PointAttributeDefinition]) -> Self[src]

Creates a new PointLayout from the given sequence of attributes. The attributes will be aligned using the default alignments for their respective datatypes, in accordance with the Rust alignment rules for repr(C) structs

#Panics

If any two attributes within the sequence share the same attribute name.

let layout = PointLayout::from_attributes(&[attributes::POSITION_3D, attributes::INTENSITY]);

pub fn from_attributes_packed(
    attributes: &[PointAttributeDefinition],
    max_alignment: u64
) -> Self
[src]

Creates a new PointLayout from the given sequence of attributes. The attributes will be aligned to a 1 byte boundary in accordance with the Rust alignment rules for repr(packed) structs

#Panics

If any two attributes within the sequence share the same attribute name.

// Default INTENSITY attribute uses u16 datatype. In a packed(1) struct, the next field will have offset 2
// even though the POSITION_3D attribute has an alignment requirement of 8
let layout_packed_1 = PointLayout::from_attributes_packed(&[attributes::INTENSITY, attributes::POSITION_3D], 1);
assert_eq!(0, layout_packed_1.at(0).offset());
assert_eq!(2, layout_packed_1.at(1).offset());

// If we use packed(4), POSITION_3D will start at byte 4:
let layout_packed_4 = PointLayout::from_attributes_packed(&[attributes::INTENSITY, attributes::POSITION_3D], 4);
assert_eq!(4, layout_packed_4.at(1).offset());

pub fn from_members_and_alignment(
    attributes: &[PointAttributeMember],
    type_alignment: u64
) -> Self
[src]

Creates a new PointLayout from the given PointAttributeMember sequence as well as the given type_alignment.

#Panics

If any two attributes within the sequence share the same attribute name, or if there is overlap between any two attributes based on their sizes and offsets.

let layout = PointLayout::from_members_and_alignment(&[attributes::INTENSITY.at_offset_in_type(2), attributes::POSITION_3D.at_offset_in_type(8)], 8);
assert_eq!(2, layout.at(0).offset());
assert_eq!(8, layout.at(1).offset());
assert_eq!(32, layout.size_of_point_entry());

pub fn add_attribute(
    &mut self,
    point_attribute: PointAttributeDefinition,
    field_alignment: FieldAlignment
)
[src]

Adds the given PointAttributeDefinition to this PointLayout. Sets the offset of the new attribute within the PointLayout based on the given FieldAlignment

#Panics

If an attribute with the same name is already part of this PointLayout.

let mut layout = PointLayout::default();
layout.add_attribute(attributes::INTENSITY, FieldAlignment::Default);
layout.add_attribute(attributes::POSITION_3D, FieldAlignment::Default);
// Default field alignment respects the 8-byte alignment requirement of default POSITION_3D (Vector3<f64>), even though default INTENSITY takes only 2 bytes
assert_eq!(8, layout.at(1).offset());

pub fn has_attribute_with_name(&self, attribute_name: &str) -> bool[src]

Returns true if an attribute with the given name is part of this PointLayout.

let mut layout = PointLayout::default();
layout.add_attribute(attributes::POSITION_3D, FieldAlignment::Default);
assert!(layout.has_attribute_with_name(attributes::POSITION_3D.name()));

pub fn has_attribute(&self, attribute: &PointAttributeDefinition) -> bool[src]

Returns true if the associated PointLayout contains the given attribute. Both the name of attribute as well as its datatype must match for this method to return true. This is a more strict form of has_attribute_with_name

Example

let mut layout = PointLayout::default();
layout.add_attribute(attributes::POSITION_3D, FieldAlignment::Default);
assert!(layout.has_attribute(&attributes::POSITION_3D));

layout.add_attribute(attributes::INTENSITY.with_custom_datatype(PointAttributeDataType::U32), FieldAlignment::Default);
assert!(!layout.has_attribute(&attributes::INTENSITY));

pub fn get_attribute(
    &self,
    attribute: &PointAttributeDefinition
) -> Option<&PointAttributeMember>
[src]

Returns the attribute that matches the given attribute in name and datatype from the associated PointLayout. Returns None if no attribute with the same name and datatype exists

let mut layout = PointLayout::default();
layout.add_attribute(attributes::POSITION_3D, FieldAlignment::Default);
let attribute = layout.get_attribute(&attributes::POSITION_3D);
assert!(attribute.is_some());
let invalid_attribute = layout.get_attribute(&attributes::POSITION_3D.with_custom_datatype(PointAttributeDataType::U32));
assert!(invalid_attribute.is_none());

pub fn get_attribute_by_name(
    &self,
    attribute_name: &str
) -> Option<&PointAttributeMember>
[src]

Returns the attribute with the given name from this PointLayout. Returns None if no such attribute exists.

let mut layout = PointLayout::default();
layout.add_attribute(attributes::POSITION_3D, FieldAlignment::Default);
let attribute = layout.get_attribute_by_name(attributes::POSITION_3D.name());
assert_eq!(attributes::POSITION_3D.at_offset_in_type(0), *attribute.unwrap());

pub fn at(&self, index: usize) -> &PointAttributeMember[src]

Returns the attribute at the given index from the associated PointLayout

Panics

If index is out of bounds

pub fn attributes<'a>(
    &'a self
) -> impl Iterator<Item = &'a PointAttributeMember> + 'a
[src]

Returns an iterator over all attributes in this PointLayout. The attributes are returned in the order in which they were added to this PointLayout:

let mut layout = PointLayout::default();
layout.add_attribute(attributes::POSITION_3D, FieldAlignment::Default);
layout.add_attribute(attributes::INTENSITY, FieldAlignment::Default);
let attributes = layout.attributes().collect::<Vec<_>>();
assert_eq!(attributes::POSITION_3D.at_offset_in_type(0), *attributes[0]);
assert_eq!(attributes::INTENSITY.at_offset_in_type(24), *attributes[1]);

pub fn size_of_point_entry(&self) -> u64[src]

Returns the size in bytes of a single point entry with the associated PointLayout. Note that the size can be larger than the sum of the sizes of all attributes because of alignment requirements!

Example

let layout = PointLayout::from_attributes(&[attributes::POSITION_3D, attributes::INTENSITY]);
// from_attributes respects the alignment requirements of each attribute. Default POSITION_3D uses Vector3<f64> and as such
// has an 8-byte minimum alignment, so the whole PointLayout is aligned to an 8-byte boundary. This is reflected in its size:
assert_eq!(32, layout.size_of_point_entry());

pub fn index_of(&self, attribute: &PointAttributeDefinition) -> Option<usize>[src]

Returns the index of the given attribute within the associated PointLayout, or None if the attribute is not part of the PointLayout. The index depends on the order in which the attributes have been added to the associated PointLayout, but does not necessarily reflect the order of the attributes in memory.

Example

let layout = PointLayout::from_attributes(&[attributes::POSITION_3D, attributes::INTENSITY]);
assert_eq!(Some(0), layout.index_of(&attributes::POSITION_3D));
assert_eq!(Some(1), layout.index_of(&attributes::INTENSITY));

// Create a layout where we add INTENSITY as first attribute, however in memory, INTENSITY comes after POSITION_3D
let reordered_layout = PointLayout::from_members_and_alignment(&[attributes::INTENSITY.at_offset_in_type(24), attributes::POSITION_3D.at_offset_in_type(0)], 8);
assert_eq!(Some(0), reordered_layout.index_of(&attributes::INTENSITY));
assert_eq!(Some(1), reordered_layout.index_of(&attributes::POSITION_3D));

pub fn compare_without_offsets(&self, other: &PointLayout) -> bool[src]

Compares the associated PointLayout with the other layout, ignoring the attribute offsets. This way, only the names and datatypes of the attributes are compared. This method is useful when dealing with data in a non-interleaved format, where offsets are irrelevant

Trait Implementations

impl Clone for PointLayout[src]

impl Debug for PointLayout[src]

impl Default for PointLayout[src]

fn default() -> Self[src]

Creates a new empty PointLayout

let layout = PointLayout::default();

impl Display for PointLayout[src]

impl PartialEq<PointLayout> for PointLayout[src]

impl StructuralPartialEq for PointLayout[src]

Auto Trait Implementations

Blanket Implementations

impl<T> Any for T where
    T: 'static + ?Sized
[src]

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> From<T> for T[src]

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> Pointable for T

type Init = T

The type for initializers.

impl<T> Same<T> for T

type Output = T

Should always be Self

impl<SS, SP> SupersetOf<SS> for SP where
    SS: SubsetOf<SP>, 

impl<T> ToOwned for T where
    T: Clone
[src]

type Owned = T

The resulting type after obtaining ownership.

impl<T> ToString for T where
    T: Display + ?Sized
[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = Infallible

The type returned in the event of a conversion error.

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.

impl<V, T> VZip<V> for T where
    V: MultiLane<T>,