#![allow(unused_macros)]
#![allow(unused_unsafe)]
#![allow(non_camel_case_types)]
#![allow(unused_imports)]
use std::fs::File;
use std::io::{BufRead, BufReader, Read, Write};
use std::path::Path;
use std::env;
use std::fmt;
use paste::paste;
use pcd_rs::{PcdDeserialize, Reader};
use eyre::Result;
extern crate ply_rs_bw;
use ply_rs_bw as ply;
use ply_rs_bw::ply::Property;
use crate::common::impls;
use crate::common::PointCloud;
use crate::common::{
Axis, BRISKSignature512, BorderDescription, BorderTraits, Boundary, CPPFSignature,
ESFSignature640, FPFHSignature33, GASDSignature512, GASDSignature7992, GASDSignature984,
GFPFHSignature16, GRSDSignature21, Histogram, Intensity, Intensity32u, Intensity8u,
IntensityGradient, InterestPoint, Label, MomentInvariants, Narf36, Normal,
NormalBasedSignature12, PFHRGBSignature250, PFHSignature125, PPFRGBSignature, PPFSignature,
PointDEM, PointNormal, PointSurfel, PointUV, PointWithRange, PointWithScale,
PointWithViewpoint, PointXY, PointXYZ, PointXYZHSV, PointXYZI, PointXYZINormal, PointXYZL,
PointXYZLAB, PointXYZLNormal, PointXYZRGB, PointXYZRGBA, PointXYZRGBL, PointXYZRGBNormal,
PrincipalCurvatures, PrincipalRadiiRSD, ReferenceFrame, ShapeContext1980,
UniqueShapeContext1960, VFHSignature308, RGB, SHOT1344, SHOT352,
};
pub struct PcdMeta {
pub version: String,
pub width: u64,
pub height: u64,
pub viewpoint: ViewPoint,
pub num_points: u64,
pub data: PcdDataKind,
pub field_defs: pcd_rs::Schema,
}
#[derive(Debug, Clone, PartialEq)]
pub struct ViewPoint {
pub tx: f64,
pub ty: f64,
pub tz: f64,
pub qw: f64,
pub qx: f64,
pub qy: f64,
pub qz: f64,
}
impl Default for ViewPoint {
fn default() -> Self {
ViewPoint {
tx: 0.0,
ty: 0.0,
tz: 0.0,
qw: 1.0,
qx: 0.0,
qy: 0.0,
qz: 0.0,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PcdDataKind {
Ascii,
Binary,
}
macro_rules! impl_point_cloud_pcd {
($($type:ty),*) => {
$(
paste! {
impl PointCloud<$type> {
pub fn load_from_pcd(path: &str) -> Result<Self, std::io::Error> {
let path = Path::new(path);
let current_dir = env::current_dir().expect("Failed to get current directory");
println!("工作目录: {}\n", current_dir.display());
let absolute_path = std::fs::canonicalize(&path).expect("Failed to get absolute path");
println!("PCD文件: {}\n", absolute_path.display());
let reader = pcd_rs::Reader::open(path)
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
let collected_points: eyre::Result<Vec<$type>, _> = reader.collect();
Ok(PointCloud::from_points_vec(collected_points.unwrap()))
}
}
}
)*
};
}
impl_point_cloud_pcd!(
PointDEM, PointNormal, PointSurfel, PointUV, PointWithRange, PointWithScale,
PointWithViewpoint, PointXY, PointXYZ, PointXYZHSV, PointXYZI, PointXYZINormal, PointXYZL,
PointXYZLAB, PointXYZLNormal, PointXYZRGB, PointXYZRGBA, PointXYZRGBL, PointXYZRGBNormal
);
macro_rules! impl_point_cloud_ply {
($($type:ty),*) => {
$(
paste! {
impl PointCloud<$type> {
pub fn load_from_ply(path: &str) -> Result<Self, std::io::Error> {
let path = Path::new(path);
let current_dir = env::current_dir().expect("Failed to get current directory");
println!("工作目录: {}\n", current_dir.display());
let absolute_path = std::fs::canonicalize(&path).expect("Failed to get absolute path");
println!("PLY文件: {}\n", absolute_path.display());
let mut f = std::fs::File::open(path).unwrap();
let p = ply::parser::Parser::<ply::ply::DefaultElement>::new();
let ply = p.read_ply(&mut f);
if ply.is_err() {
return Err(std::io::Error::new(std::io::ErrorKind::Other, "Failed to read PLY file"));
}
let ply = ply.unwrap();
let points: Vec<$type> = ply.payload.into_iter()
.flat_map(|element| {
let mut valid_points = Vec::new();
match stringify!($type) {
"PointXYZRGB" => {
if !element.1.is_empty() {
let mut i: usize = 0;
for map in &element.1 {
i += 1;
let mut x = f32::NAN;
let mut y = f32::NAN;
let mut z = f32::NAN;
let mut red = 0u8;
let mut green = 0u8;
let mut blue = 0u8;
for (key, value) in map {
match key.as_str() {
"x" | "y" | "z" => {
if let Property::Float(f) = value {
if !f.is_nan() {
match key.as_str() {
"x" => x = *f,
"y" => y = *f,
"z" => z = *f,
_ => {}
}
}
}
},
"red" => {
if let Property::UChar(u) = value {
red = *u;
}
},
"green" => {
if let Property::UChar(u) = value {
green = *u;
}
},
"blue" => {
if let Property::UChar(u) = value {
blue = *u;
}
},
_ => {}
}
}
if !x.is_nan() && !y.is_nan() && !z.is_nan() {
let rgb = ((red as u32) << 16) | ((green as u32) << 8) | (blue as u32);
valid_points.push($type::new(x, y, z, rgb));
}
}
}
},
_ => panic!("不支持的点类型: {}", stringify!($type)),
}
valid_points
})
.collect();
Ok(PointCloud::from_points_vec(points))
}
}
}
)*
};
}
impl_point_cloud_ply!(
PointXYZRGB
);
#[cfg(test)]
mod tests1 {
use super::*;
use std::path::Path;
#[test]
fn test_load_pcd_binary_compressed() {
let path = "./assets/office1.pcd";
let result = PointCloud::<PointXYZRGB>::load_from_pcd(path);
assert!(result.is_ok(), "加载PCD文件失败: {:?}", result.err());
let point_cloud = result.unwrap();
assert!(!point_cloud.points.is_empty(), "点云数据为空");
println!("成功加载 {} 个点", point_cloud.points.len());
}
#[test]
fn test_load_ply() {
let path = "./assets/office1.ply";
let result = PointCloud::<PointXYZRGB>::load_from_ply(path);
assert!(result.is_ok(), "加载PLY文件失败: {:?}", result.err());
let point_cloud = result.unwrap();
assert!(!point_cloud.points.is_empty(), "点云数据为空");
println!("成功加载 {} 个点", point_cloud.points.len());
}
}