1#[cfg(feature = "compression")]
7pub mod compression;
8#[cfg(feature = "e57")]
9pub mod e57;
10pub mod error;
11pub mod lidar;
12pub mod mesh_attributes;
13#[cfg(feature = "io-mmap")]
14pub mod mmap;
15pub mod obj;
16#[cfg(feature = "las_laz")]
17pub mod pasture;
18pub mod pcd;
19pub mod ply;
20pub mod registry;
21#[cfg(feature = "ros2")]
22pub mod ros2;
23#[cfg(feature = "rosbag")]
24pub mod rosbag;
25pub mod serialization;
26pub mod stl;
27pub mod xyz_csv;
28
29#[cfg(test)]
30pub mod tests;
31
32#[cfg(feature = "compression")]
33pub use compression::{draco_decode, draco_encode, DracoCompressorPipeline, DracoConfig};
34#[cfg(feature = "e57")]
35pub use e57::{E57WriteOptions, RobustE57Reader, RobustE57Writer};
36pub use error::*;
37pub use lidar::{
38 LivoxLvx2Reader, LivoxLvxReader, OusterPcapReader, VelodyneKittiBinReader, VelodyneModel,
39 VelodynePcapReader,
40};
41pub use mesh_attributes::{ExtendedTriangleMesh, MeshAttributeOptions, MeshMetadata, Tangent, UV};
42pub use obj::{
43 Face, FaceVertex, Group, Material, ObjData, ObjWriteOptions, RobustObjReader, RobustObjWriter,
44};
45pub use pcd::{
46 PcdDataFormat, PcdFieldType, PcdHeader, PcdValue, PcdWriteOptions, RobustPcdReader,
47 RobustPcdWriter,
48};
49pub use ply::{PlyFormat, PlyValue, PlyWriteOptions, RobustPlyReader, RobustPlyWriter};
50pub use registry::{FormatHandler, IoRegistry};
51#[cfg(feature = "ros2")]
52pub use ros2::{
53 colored_normals_to_pointcloud2, colored_to_pointcloud2, normals_to_pointcloud2,
54 organized_xyz_to_pointcloud2, pointcloud2_to_colored, pointcloud2_to_colored_normals,
55 pointcloud2_to_normals, pointcloud2_to_organized_xyz, pointcloud2_to_xyz, xyz_to_pointcloud2,
56 PointCloud2Data, PointCloud2Info, PointField,
57};
58pub use serialization::{
59 AttributePreservingReader, AttributePreservingWriter, SerializationOptions,
60};
61pub use stl::{read_stl, write_stl, StlReader, StlWriteOptions, StlWriter};
62pub use xyz_csv::{
63 ColumnType, Delimiter, XyzCsvPoint, XyzCsvReader, XyzCsvSchema, XyzCsvStreamingReader,
64 XyzCsvWriteOptions, XyzCsvWriter,
65};
66
67use std::path::Path;
68use threecrate_core::{Point3f, PointCloud, Result, TriangleMesh};
69
70pub trait PointCloudReader {
73 fn read_point_cloud<P: AsRef<std::path::Path>>(path: P) -> Result<PointCloud<Point3f>>;
74}
75
76pub trait PointCloudWriter {
78 fn write_point_cloud<P: AsRef<std::path::Path>>(
79 cloud: &PointCloud<Point3f>,
80 path: P,
81 ) -> Result<()>;
82}
83
84pub trait MeshReader {
86 fn read_mesh<P: AsRef<std::path::Path>>(path: P) -> Result<TriangleMesh>;
87}
88
89pub trait MeshWriter {
91 fn write_mesh<P: AsRef<std::path::Path>>(mesh: &TriangleMesh, path: P) -> Result<()>;
92}
93
94lazy_static::lazy_static! {
96 static ref IO_REGISTRY: IoRegistry = {
97 let mut registry = IoRegistry::new();
98
99 registry.register_point_cloud_handler("ply", Box::new(ply::PlyReader));
101 registry.register_mesh_handler("ply", Box::new(ply::PlyReader));
102 registry.register_point_cloud_writer("ply", Box::new(ply::PlyWriter));
103 registry.register_mesh_writer("ply", Box::new(ply::PlyWriter));
104
105 registry.register_mesh_handler("obj", Box::new(obj::ObjReader));
107 registry.register_mesh_writer("obj", Box::new(obj::ObjWriter));
108
109 registry.register_mesh_handler("stl", Box::new(stl::StlReader));
111 registry.register_mesh_writer("stl", Box::new(stl::StlWriter));
112
113 #[cfg(feature = "las_laz")]
115 {
116 registry.register_point_cloud_handler("las", Box::new(pasture::PastureReader));
117 registry.register_point_cloud_handler("laz", Box::new(pasture::PastureReader));
118 registry.register_point_cloud_writer("las", Box::new(pasture::PastureWriter));
119 registry.register_point_cloud_writer("laz", Box::new(pasture::PastureWriter));
120 }
121 registry.register_point_cloud_handler("pcd", Box::new(pcd::PcdReader));
122 registry.register_point_cloud_writer("pcd", Box::new(pcd::PcdWriter));
123
124 registry.register_point_cloud_handler("xyz", Box::new(xyz_csv::XyzCsvReader));
126 registry.register_point_cloud_handler("csv", Box::new(xyz_csv::XyzCsvReader));
127 registry.register_point_cloud_handler("txt", Box::new(xyz_csv::XyzCsvReader));
128 registry.register_point_cloud_writer("xyz", Box::new(xyz_csv::XyzCsvWriter));
129 registry.register_point_cloud_writer("csv", Box::new(xyz_csv::XyzCsvWriter));
130 registry.register_point_cloud_writer("txt", Box::new(xyz_csv::XyzCsvWriter));
131
132 registry.register_point_cloud_handler("bin", Box::new(lidar::VelodyneBinRegistryReader));
134 registry.register_point_cloud_handler("pcap", Box::new(lidar::VelodynePcapRegistryReader));
135 registry.register_point_cloud_handler("lvx", Box::new(lidar::LivoxLvxRegistryReader));
136 registry.register_point_cloud_handler("lvx2", Box::new(lidar::LivoxLvx2RegistryReader));
137
138 #[cfg(feature = "e57")]
140 {
141 registry.register_point_cloud_handler("e57", Box::new(e57::E57Reader));
142 registry.register_mesh_handler("e57", Box::new(e57::E57Reader));
143 registry.register_point_cloud_writer("e57", Box::new(e57::E57Writer));
144 registry.register_mesh_writer("e57", Box::new(e57::E57Writer));
145 }
146
147 #[cfg(feature = "compression")]
149 {
150 registry.register_point_cloud_handler("drc", Box::new(compression::DracoReader));
151 registry.register_point_cloud_writer("drc", Box::new(compression::DracoWriter));
152 }
153
154 registry
155 };
156}
157
158pub fn read_point_cloud<P: AsRef<Path>>(path: P) -> Result<PointCloud<Point3f>> {
160 let path = path.as_ref();
161 let extension = path.extension().and_then(|s| s.to_str()).ok_or_else(|| {
162 threecrate_core::Error::UnsupportedFormat("No file extension found".to_string())
163 })?;
164
165 IO_REGISTRY.read_point_cloud(path, extension)
166}
167
168pub fn read_mesh<P: AsRef<Path>>(path: P) -> Result<TriangleMesh> {
170 let path = path.as_ref();
171 let extension = path.extension().and_then(|s| s.to_str()).ok_or_else(|| {
172 threecrate_core::Error::UnsupportedFormat("No file extension found".to_string())
173 })?;
174
175 IO_REGISTRY.read_mesh(path, extension)
176}
177
178pub fn write_point_cloud<P: AsRef<Path>>(cloud: &PointCloud<Point3f>, path: P) -> Result<()> {
180 let path = path.as_ref();
181 let extension = path.extension().and_then(|s| s.to_str()).ok_or_else(|| {
182 threecrate_core::Error::UnsupportedFormat("No file extension found".to_string())
183 })?;
184
185 IO_REGISTRY.write_point_cloud(cloud, path, extension)
186}
187
188pub fn write_mesh<P: AsRef<Path>>(mesh: &TriangleMesh, path: P) -> Result<()> {
190 let path = path.as_ref();
191 let extension = path.extension().and_then(|s| s.to_str()).ok_or_else(|| {
192 threecrate_core::Error::UnsupportedFormat("No file extension found".to_string())
193 })?;
194
195 IO_REGISTRY.write_mesh(mesh, path, extension)
196}
197
198pub fn get_io_registry() -> &'static IoRegistry {
200 &IO_REGISTRY
201}
202
203pub fn read_point_cloud_iter<P: AsRef<Path>>(
234 path: P,
235 chunk_size: Option<usize>,
236) -> Result<Box<dyn Iterator<Item = Result<Point3f>> + Send + Sync>> {
237 let path = path.as_ref();
238 let extension = path.extension().and_then(|s| s.to_str()).ok_or_else(|| {
239 threecrate_core::Error::UnsupportedFormat("No file extension found".to_string())
240 })?;
241
242 match extension {
243 "ply" => {
244 let iter = ply::PlyStreamingReader::new(path, chunk_size.unwrap_or(1000))?;
245 Ok(Box::new(iter))
246 }
247 "obj" => {
248 let iter = obj::ObjStreamingReader::new(path, chunk_size.unwrap_or(1000))?;
249 Ok(Box::new(iter))
250 }
251 "xyz" | "csv" | "txt" => {
252 let iter = xyz_csv::XyzCsvStreamingReader::new(path, chunk_size.unwrap_or(1000))?;
253 Ok(Box::new(iter))
254 }
255 _ => Err(threecrate_core::Error::UnsupportedFormat(format!(
256 "Streaming not supported for format: {}",
257 extension
258 ))),
259 }
260}
261
262pub fn read_mesh_iter<P: AsRef<Path>>(
293 path: P,
294 chunk_size: Option<usize>,
295) -> Result<Box<dyn Iterator<Item = Result<[usize; 3]>> + Send + Sync>> {
296 let path = path.as_ref();
297 let extension = path.extension().and_then(|s| s.to_str()).ok_or_else(|| {
298 threecrate_core::Error::UnsupportedFormat("No file extension found".to_string())
299 })?;
300
301 match extension {
302 "ply" => {
303 let iter = ply::PlyMeshStreamingReader::new(path, chunk_size.unwrap_or(1000))?;
304 Ok(Box::new(iter))
305 }
306 "obj" => {
307 let iter = obj::ObjMeshStreamingReader::new(path, chunk_size.unwrap_or(1000))?;
308 Ok(Box::new(iter))
309 }
310 _ => Err(threecrate_core::Error::UnsupportedFormat(format!(
311 "Streaming not supported for format: {}",
312 extension
313 ))),
314 }
315}
316
317