Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions lidarserv-input-file/src/commands/replay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use lidarserv_common::geometry::coordinate_system::CoordinateSystem;
use lidarserv_common::tracy_client::{plot, span};
use lidarserv_input_file::extractors::AttributeExtractor;
use lidarserv_input_file::extractors::basic_flags::LasBasicFlagsExtractor;
use lidarserv_input_file::extractors::color::ColorExtractor;
use lidarserv_input_file::extractors::copy::CopyExtractor;
use lidarserv_input_file::extractors::extended_flags::LasExtendedFlagsExtractor;
use lidarserv_input_file::extractors::position::PositionExtractor;
Expand Down Expand Up @@ -238,6 +239,14 @@ impl FrameManager {
continue;
}

// color
if let Some(extractor) =
ColorExtractor::check(dst_attribute, dst_point_size, src_layout)
{
extractors.push(Box::new(extractor));
continue;
}

// most normal attributes: bitwise copy
if let Some(extractor) = CopyExtractor::check(dst_attribute, dst_point_size, src_layout)
{
Expand Down
159 changes: 159 additions & 0 deletions lidarserv-input-file/src/extractors/color.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
use pasture_core::layout::attributes::COLOR_RGB;
use pasture_core::layout::{PointAttributeDataType, PointAttributeMember, PointLayout};

use super::AttributeExtractor;

pub struct ColorExtractor {
src_offset: usize,
src_stride: usize,
dst_offset: usize,
dst_stride: usize,
conversion: Conversion,
}

enum Conversion {
Copy { len: usize },
Vec3u16ToVec3u8,
U32ToVec3u8,
U64ToVec3u16,
}

impl ColorExtractor {
pub fn check(
dst_attribute: &PointAttributeMember,
dst_point_size: usize,
src_layout: &PointLayout,
) -> Option<Self> {
if !is_color_attribute(dst_attribute) {
return None;
}

let dst_datatype = dst_attribute.datatype();
if !matches!(
dst_datatype,
PointAttributeDataType::Vec3u8 | PointAttributeDataType::Vec3u16
) {
return None;
}

let src_attribute = src_layout
.get_attribute(dst_attribute.attribute_definition())
.or_else(|| src_layout.get_attribute_by_name(dst_attribute.name()))
.or_else(|| {
let dst_name = dst_attribute.name().to_ascii_lowercase();
src_layout
.attributes()
.find(|attr| attr.name().to_ascii_lowercase() == dst_name)
})?;

let conversion = match (src_attribute.datatype(), dst_datatype) {
(PointAttributeDataType::Vec3u8, PointAttributeDataType::Vec3u8) => {
Conversion::Copy {
len: dst_attribute.size() as usize,
}
}
(PointAttributeDataType::Vec3u16, PointAttributeDataType::Vec3u16) => {
Conversion::Copy {
len: dst_attribute.size() as usize,
}
}
(PointAttributeDataType::Vec3u16, PointAttributeDataType::Vec3u8) => {
Conversion::Vec3u16ToVec3u8
}
(PointAttributeDataType::U32, PointAttributeDataType::Vec3u8) => {
Conversion::U32ToVec3u8
}
(PointAttributeDataType::U64, PointAttributeDataType::Vec3u16) => {
Conversion::U64ToVec3u16
}
_ => return None,
};

Some(ColorExtractor {
src_offset: src_attribute.byte_range_within_point().start,
src_stride: src_layout.size_of_point_entry() as usize,
dst_offset: dst_attribute.byte_range_within_point().start,
dst_stride: dst_point_size,
conversion,
})
}
}

impl AttributeExtractor for ColorExtractor {
fn extract(&self, src: &[u8], dst: &mut [u8]) {
let nr_points = src.len() / self.src_stride;
assert_eq!(src.len(), nr_points * self.src_stride);
assert_eq!(dst.len(), nr_points * self.dst_stride);

match self.conversion {
Conversion::Copy { len } => {
for i in 0..nr_points {
let src_start = i * self.src_stride + self.src_offset;
let dst_start = i * self.dst_stride + self.dst_offset;
dst[dst_start..dst_start + len]
.copy_from_slice(&src[src_start..src_start + len]);
}
}
Conversion::Vec3u16ToVec3u8 => {
for i in 0..nr_points {
let src_start = i * self.src_stride + self.src_offset;
let dst_start = i * self.dst_stride + self.dst_offset;
for c in 0..3 {
let s = src_start + c * 2;
let value = u16::from_le_bytes([src[s], src[s + 1]]);
dst[dst_start + c] = value as u8;
}
}
}
Conversion::U32ToVec3u8 => {
for i in 0..nr_points {
let src_start = i * self.src_stride + self.src_offset;
let dst_start = i * self.dst_stride + self.dst_offset;
let bytes = [
src[src_start],
src[src_start + 1],
src[src_start + 2],
src[src_start + 3],
];
let packed = u32::from_le_bytes(bytes);
dst[dst_start] = (packed & 0xFF) as u8;
dst[dst_start + 1] = ((packed >> 8) & 0xFF) as u8;
dst[dst_start + 2] = ((packed >> 16) & 0xFF) as u8;
}
}
Conversion::U64ToVec3u16 => {
for i in 0..nr_points {
let src_start = i * self.src_stride + self.src_offset;
let dst_start = i * self.dst_stride + self.dst_offset;
let bytes = [
src[src_start],
src[src_start + 1],
src[src_start + 2],
src[src_start + 3],
src[src_start + 4],
src[src_start + 5],
src[src_start + 6],
src[src_start + 7],
];
let packed = u64::from_le_bytes(bytes);
for c in 0..3 {
let value = ((packed >> (c * 16)) & 0xFFFF) as u16;
let le = value.to_le_bytes();
let dst_idx = dst_start + c * 2;
dst[dst_idx] = le[0];
dst[dst_idx + 1] = le[1];
}
}
}
}
}
}

fn is_color_attribute(attribute: &PointAttributeMember) -> bool {
if *attribute.attribute_definition() == COLOR_RGB {
return true;
}

let name = attribute.name().to_ascii_lowercase();
name.contains("color") || name.ends_with("rgb") || name == "rgb"
}
1 change: 1 addition & 0 deletions lidarserv-input-file/src/extractors/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ pub mod scan_angle;
pub mod scan_angle_rank;
pub mod scan_direction_flag;
pub mod scanner_channel;
pub mod color;

pub trait AttributeExtractor {
fn extract(&self, src: &[u8], dst: &mut [u8]);
Expand Down
12 changes: 11 additions & 1 deletion lidarserv-server/src/index/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,17 @@ fn get_data_folder_settings_file(path: &Path) -> PathBuf {
impl IndexSettings {
pub fn load_from_file(file_name: &Path) -> Result<Self, IndexSettingIoError> {
let file = File::open(file_name)?;
let settings = serde_json::from_reader(file)?;
let mut settings: IndexSettings = serde_json::from_reader(file)?;

// Rebuild the point layout from the attribute definitions to eliminate
// stale offset/size metadata lingering in older settings files.
let attributes: Vec<_> = settings
.point_layout
.attributes()
.map(|member| member.attribute_definition().clone())
.collect();
settings.point_layout = PointLayout::from_attributes(&attributes);

Ok(settings)
}

Expand Down