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]);
pub fn from_attributes_packed(
attributes: &[PointAttributeDefinition],
max_alignment: u64
) -> Self
pub fn from_attributes_packed(
attributes: &[PointAttributeDefinition],
max_alignment: u64
) -> Self
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
pub fn from_members_and_alignment(
attributes: &[PointAttributeMember],
type_alignment: u64
) -> Self
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
)
pub fn add_attribute(
&mut self,
point_attribute: PointAttributeDefinition,
field_alignment: FieldAlignment
)
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));
pub fn get_attribute(
&self,
attribute: &PointAttributeDefinition
) -> Option<&PointAttributeMember>
pub fn get_attribute(
&self,
attribute: &PointAttributeDefinition
) -> Option<&PointAttributeMember>
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]);
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
This method tests for self
and other
values to be equal, and is used
by ==
. Read more
This method tests for !=
.
Auto Trait Implementations
impl RefUnwindSafe for PointLayout
impl Send for PointLayout
impl Sync for PointLayout
impl Unpin for PointLayout
impl UnwindSafe for PointLayout
Blanket Implementations
Mutably borrows from an owned value. Read more
The inverse inclusion map: attempts to construct self
from the equivalent element of its
superset. Read more
pub fn is_in_subset(&self) -> bool
pub fn is_in_subset(&self) -> bool
Checks if self
is actually part of its subset T
(and can be converted to it).
pub fn to_subset_unchecked(&self) -> SS
pub fn to_subset_unchecked(&self) -> SS
Use with care! Same as self.to_subset
but without any property checks. Always succeeds.
pub fn from_subset(element: &SS) -> SP
pub fn from_subset(element: &SS) -> SP
The inclusion map: converts self
to the equivalent element of its superset.