1pub mod ply;
7pub mod obj;
8#[cfg(feature = "las_laz")]
9pub mod pasture;
10pub mod pcd;
11pub mod xyz_csv;
12pub mod error;
13pub mod registry;
14pub mod mesh_attributes;
15pub mod serialization;
16#[cfg(feature = "io-mmap")]
17pub mod mmap;
18
19#[cfg(test)]
20pub mod tests;
21
22pub use error::*;
23pub use ply::{RobustPlyReader, RobustPlyWriter, PlyWriteOptions, PlyFormat, PlyValue};
24pub use obj::{RobustObjReader, RobustObjWriter, ObjData, ObjWriteOptions, Material, FaceVertex, Face, Group};
25pub use pcd::{RobustPcdReader, RobustPcdWriter, PcdWriteOptions, PcdDataFormat, PcdFieldType, PcdHeader, PcdValue};
26pub use xyz_csv::{XyzCsvReader, XyzCsvWriter, XyzCsvStreamingReader, XyzCsvWriteOptions, XyzCsvSchema, XyzCsvPoint, Delimiter, ColumnType};
27pub use registry::{IoRegistry, FormatHandler};
28pub use mesh_attributes::{ExtendedTriangleMesh, MeshAttributeOptions, MeshMetadata, Tangent, UV};
29pub use serialization::{SerializationOptions, AttributePreservingReader, AttributePreservingWriter};
30
31use threecrate_core::{PointCloud, TriangleMesh, Result, Point3f};
32use std::path::Path;
33
34pub trait PointCloudReader {
37 fn read_point_cloud<P: AsRef<std::path::Path>>(path: P) -> Result<PointCloud<Point3f>>;
38}
39
40pub trait PointCloudWriter {
42 fn write_point_cloud<P: AsRef<std::path::Path>>(cloud: &PointCloud<Point3f>, path: P) -> Result<()>;
43}
44
45pub trait MeshReader {
47 fn read_mesh<P: AsRef<std::path::Path>>(path: P) -> Result<TriangleMesh>;
48}
49
50pub trait MeshWriter {
52 fn write_mesh<P: AsRef<std::path::Path>>(mesh: &TriangleMesh, path: P) -> Result<()>;
53}
54
55lazy_static::lazy_static! {
57 static ref IO_REGISTRY: IoRegistry = {
58 let mut registry = IoRegistry::new();
59
60 registry.register_point_cloud_handler("ply", Box::new(ply::PlyReader));
62 registry.register_mesh_handler("ply", Box::new(ply::PlyReader));
63 registry.register_point_cloud_writer("ply", Box::new(ply::PlyWriter));
64 registry.register_mesh_writer("ply", Box::new(ply::PlyWriter));
65
66 registry.register_mesh_handler("obj", Box::new(obj::ObjReader));
68 registry.register_mesh_writer("obj", Box::new(obj::ObjWriter));
69
70 #[cfg(feature = "las_laz")]
72 {
73 registry.register_point_cloud_handler("las", Box::new(pasture::PastureReader));
74 registry.register_point_cloud_handler("laz", Box::new(pasture::PastureReader));
75 registry.register_point_cloud_writer("las", Box::new(pasture::PastureWriter));
76 registry.register_point_cloud_writer("laz", Box::new(pasture::PastureWriter));
77 }
78 registry.register_point_cloud_handler("pcd", Box::new(pcd::PcdReader));
79 registry.register_point_cloud_writer("pcd", Box::new(pcd::PcdWriter));
80
81 registry.register_point_cloud_handler("xyz", Box::new(xyz_csv::XyzCsvReader));
83 registry.register_point_cloud_handler("csv", Box::new(xyz_csv::XyzCsvReader));
84 registry.register_point_cloud_handler("txt", Box::new(xyz_csv::XyzCsvReader));
85 registry.register_point_cloud_writer("xyz", Box::new(xyz_csv::XyzCsvWriter));
86 registry.register_point_cloud_writer("csv", Box::new(xyz_csv::XyzCsvWriter));
87 registry.register_point_cloud_writer("txt", Box::new(xyz_csv::XyzCsvWriter));
88
89 registry
90 };
91}
92
93pub fn read_point_cloud<P: AsRef<Path>>(path: P) -> Result<PointCloud<Point3f>> {
95 let path = path.as_ref();
96 let extension = path.extension()
97 .and_then(|s| s.to_str())
98 .ok_or_else(|| threecrate_core::Error::UnsupportedFormat(
99 "No file extension found".to_string()
100 ))?;
101
102 IO_REGISTRY.read_point_cloud(path, extension)
103}
104
105pub fn read_mesh<P: AsRef<Path>>(path: P) -> Result<TriangleMesh> {
107 let path = path.as_ref();
108 let extension = path.extension()
109 .and_then(|s| s.to_str())
110 .ok_or_else(|| threecrate_core::Error::UnsupportedFormat(
111 "No file extension found".to_string()
112 ))?;
113
114 IO_REGISTRY.read_mesh(path, extension)
115}
116
117pub fn write_point_cloud<P: AsRef<Path>>(cloud: &PointCloud<Point3f>, path: P) -> Result<()> {
119 let path = path.as_ref();
120 let extension = path.extension()
121 .and_then(|s| s.to_str())
122 .ok_or_else(|| threecrate_core::Error::UnsupportedFormat(
123 "No file extension found".to_string()
124 ))?;
125
126 IO_REGISTRY.write_point_cloud(cloud, path, extension)
127}
128
129pub fn write_mesh<P: AsRef<Path>>(mesh: &TriangleMesh, path: P) -> Result<()> {
131 let path = path.as_ref();
132 let extension = path.extension()
133 .and_then(|s| s.to_str())
134 .ok_or_else(|| threecrate_core::Error::UnsupportedFormat(
135 "No file extension found".to_string()
136 ))?;
137
138 IO_REGISTRY.write_mesh(mesh, path, extension)
139}
140
141pub fn get_io_registry() -> &'static IoRegistry {
143 &IO_REGISTRY
144}
145
146pub fn read_point_cloud_iter<P: AsRef<Path>>(
177 path: P,
178 chunk_size: Option<usize>
179) -> Result<Box<dyn Iterator<Item = Result<Point3f>> + Send + Sync>> {
180 let path = path.as_ref();
181 let extension = path.extension()
182 .and_then(|s| s.to_str())
183 .ok_or_else(|| threecrate_core::Error::UnsupportedFormat(
184 "No file extension found".to_string()
185 ))?;
186
187 match extension {
188 "ply" => {
189 let iter = ply::PlyStreamingReader::new(path, chunk_size.unwrap_or(1000))?;
190 Ok(Box::new(iter))
191 }
192 "obj" => {
193 let iter = obj::ObjStreamingReader::new(path, chunk_size.unwrap_or(1000))?;
194 Ok(Box::new(iter))
195 }
196 "xyz" | "csv" | "txt" => {
197 let iter = xyz_csv::XyzCsvStreamingReader::new(path, chunk_size.unwrap_or(1000))?;
198 Ok(Box::new(iter))
199 }
200 _ => Err(threecrate_core::Error::UnsupportedFormat(
201 format!("Streaming not supported for format: {}", extension)
202 ))
203 }
204}
205
206pub fn read_mesh_iter<P: AsRef<Path>>(
237 path: P,
238 chunk_size: Option<usize>
239) -> Result<Box<dyn Iterator<Item = Result<[usize; 3]>> + Send + Sync>> {
240 let path = path.as_ref();
241 let extension = path.extension()
242 .and_then(|s| s.to_str())
243 .ok_or_else(|| threecrate_core::Error::UnsupportedFormat(
244 "No file extension found".to_string()
245 ))?;
246
247 match extension {
248 "ply" => {
249 let iter = ply::PlyMeshStreamingReader::new(path, chunk_size.unwrap_or(1000))?;
250 Ok(Box::new(iter))
251 }
252 "obj" => {
253 let iter = obj::ObjMeshStreamingReader::new(path, chunk_size.unwrap_or(1000))?;
254 Ok(Box::new(iter))
255 }
256 _ => Err(threecrate_core::Error::UnsupportedFormat(
257 format!("Streaming not supported for format: {}", extension)
258 ))
259 }
260}
261
262