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

pub struct PointLayout { /* fields omitted */ }
Expand description

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

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]);

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());

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());

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());

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()));

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));

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());

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());

Returns the attribute at the given index from the associated PointLayout

Panics

If index is out of bounds

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

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());

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));

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

Returns the offset from an attribute. If the attribute don’t exist in the layout this function returns None.

Trait Implementations

Returns a copy of the value. Read more

Performs copy-assignment from source. Read more

Formats the value using the given formatter. Read more

Creates a new empty PointLayout

let layout = PointLayout::default();

Formats the value using the given formatter. Read more

This method tests for self and other values to be equal, and is used by ==. Read more

This method tests for !=.

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

Immutably borrows from an owned value. Read more

Mutably borrows from an owned value. Read more

Performs the conversion.

Performs the conversion.

The alignment of pointer.

The type for initializers.

Initializes a with the given initializer. Read more

Dereferences the given pointer. Read more

Mutably dereferences the given pointer. Read more

Drops the object pointed to by the given pointer. Read more

Should always be Self

The inverse inclusion map: attempts to construct self from the equivalent element of its superset. Read more

Checks if self is actually part of its subset T (and can be converted to it).

Use with care! Same as self.to_subset but without any property checks. Always succeeds.

The inclusion map: converts self to the equivalent element of its superset.

The resulting type after obtaining ownership.

Creates owned data from borrowed data, usually by cloning. Read more

🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

Uses borrowed data to replace owned data, usually by cloning. Read more

Converts the given value to a String. Read more

The type returned in the event of a conversion error.

Performs the conversion.

The type returned in the event of a conversion error.

Performs the conversion.