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