1pub mod ply;
7pub mod obj;
8#[cfg(feature = "las_laz")]
9pub mod pasture;
10pub mod pcd;
11pub mod xyz_csv;
12#[cfg(feature = "e57")]
13pub mod e57;
14pub mod error;
15pub mod registry;
16pub mod mesh_attributes;
17pub mod serialization;
18#[cfg(feature = "io-mmap")]
19pub mod mmap;
20
21#[cfg(test)]
22pub mod tests;
23
24pub use error::*;
25pub use ply::{RobustPlyReader, RobustPlyWriter, PlyWriteOptions, PlyFormat, PlyValue};
26pub use obj::{RobustObjReader, RobustObjWriter, ObjData, ObjWriteOptions, Material, FaceVertex, Face, Group};
27pub use pcd::{RobustPcdReader, RobustPcdWriter, PcdWriteOptions, PcdDataFormat, PcdFieldType, PcdHeader, PcdValue};
28pub use xyz_csv::{XyzCsvReader, XyzCsvWriter, XyzCsvStreamingReader, XyzCsvWriteOptions, XyzCsvSchema, XyzCsvPoint, Delimiter, ColumnType};
29#[cfg(feature = "e57")]
30pub use e57::{RobustE57Reader, RobustE57Writer, E57WriteOptions};
31pub use registry::{IoRegistry, FormatHandler};
32pub use mesh_attributes::{ExtendedTriangleMesh, MeshAttributeOptions, MeshMetadata, Tangent, UV};
33pub use serialization::{SerializationOptions, AttributePreservingReader, AttributePreservingWriter};
34
35use threecrate_core::{PointCloud, TriangleMesh, Result, Point3f};
36use std::path::Path;
37
38pub trait PointCloudReader {
41 fn read_point_cloud<P: AsRef<std::path::Path>>(path: P) -> Result<PointCloud<Point3f>>;
42}
43
44pub trait PointCloudWriter {
46 fn write_point_cloud<P: AsRef<std::path::Path>>(cloud: &PointCloud<Point3f>, path: P) -> Result<()>;
47}
48
49pub trait MeshReader {
51 fn read_mesh<P: AsRef<std::path::Path>>(path: P) -> Result<TriangleMesh>;
52}
53
54pub trait MeshWriter {
56 fn write_mesh<P: AsRef<std::path::Path>>(mesh: &TriangleMesh, path: P) -> Result<()>;
57}
58
59lazy_static::lazy_static! {
61 static ref IO_REGISTRY: IoRegistry = {
62 let mut registry = IoRegistry::new();
63
64 registry.register_point_cloud_handler("ply", Box::new(ply::PlyReader));
66 registry.register_mesh_handler("ply", Box::new(ply::PlyReader));
67 registry.register_point_cloud_writer("ply", Box::new(ply::PlyWriter));
68 registry.register_mesh_writer("ply", Box::new(ply::PlyWriter));
69
70 registry.register_mesh_handler("obj", Box::new(obj::ObjReader));
72 registry.register_mesh_writer("obj", Box::new(obj::ObjWriter));
73
74 #[cfg(feature = "las_laz")]
76 {
77 registry.register_point_cloud_handler("las", Box::new(pasture::PastureReader));
78 registry.register_point_cloud_handler("laz", Box::new(pasture::PastureReader));
79 registry.register_point_cloud_writer("las", Box::new(pasture::PastureWriter));
80 registry.register_point_cloud_writer("laz", Box::new(pasture::PastureWriter));
81 }
82 registry.register_point_cloud_handler("pcd", Box::new(pcd::PcdReader));
83 registry.register_point_cloud_writer("pcd", Box::new(pcd::PcdWriter));
84
85 registry.register_point_cloud_handler("xyz", Box::new(xyz_csv::XyzCsvReader));
87 registry.register_point_cloud_handler("csv", Box::new(xyz_csv::XyzCsvReader));
88 registry.register_point_cloud_handler("txt", Box::new(xyz_csv::XyzCsvReader));
89 registry.register_point_cloud_writer("xyz", Box::new(xyz_csv::XyzCsvWriter));
90 registry.register_point_cloud_writer("csv", Box::new(xyz_csv::XyzCsvWriter));
91 registry.register_point_cloud_writer("txt", Box::new(xyz_csv::XyzCsvWriter));
92
93 #[cfg(feature = "e57")]
95 {
96 registry.register_point_cloud_handler("e57", Box::new(e57::E57Reader));
97 registry.register_mesh_handler("e57", Box::new(e57::E57Reader));
98 registry.register_point_cloud_writer("e57", Box::new(e57::E57Writer));
99 registry.register_mesh_writer("e57", Box::new(e57::E57Writer));
100 }
101
102 registry
103 };
104}
105
106pub fn read_point_cloud<P: AsRef<Path>>(path: P) -> Result<PointCloud<Point3f>> {
108 let path = path.as_ref();
109 let extension = path.extension()
110 .and_then(|s| s.to_str())
111 .ok_or_else(|| threecrate_core::Error::UnsupportedFormat(
112 "No file extension found".to_string()
113 ))?;
114
115 IO_REGISTRY.read_point_cloud(path, extension)
116}
117
118pub fn read_mesh<P: AsRef<Path>>(path: P) -> Result<TriangleMesh> {
120 let path = path.as_ref();
121 let extension = path.extension()
122 .and_then(|s| s.to_str())
123 .ok_or_else(|| threecrate_core::Error::UnsupportedFormat(
124 "No file extension found".to_string()
125 ))?;
126
127 IO_REGISTRY.read_mesh(path, extension)
128}
129
130pub fn write_point_cloud<P: AsRef<Path>>(cloud: &PointCloud<Point3f>, path: P) -> Result<()> {
132 let path = path.as_ref();
133 let extension = path.extension()
134 .and_then(|s| s.to_str())
135 .ok_or_else(|| threecrate_core::Error::UnsupportedFormat(
136 "No file extension found".to_string()
137 ))?;
138
139 IO_REGISTRY.write_point_cloud(cloud, path, extension)
140}
141
142pub fn write_mesh<P: AsRef<Path>>(mesh: &TriangleMesh, path: P) -> Result<()> {
144 let path = path.as_ref();
145 let extension = path.extension()
146 .and_then(|s| s.to_str())
147 .ok_or_else(|| threecrate_core::Error::UnsupportedFormat(
148 "No file extension found".to_string()
149 ))?;
150
151 IO_REGISTRY.write_mesh(mesh, path, extension)
152}
153
154pub fn get_io_registry() -> &'static IoRegistry {
156 &IO_REGISTRY
157}
158
159pub fn read_point_cloud_iter<P: AsRef<Path>>(
190 path: P,
191 chunk_size: Option<usize>
192) -> Result<Box<dyn Iterator<Item = Result<Point3f>> + Send + Sync>> {
193 let path = path.as_ref();
194 let extension = path.extension()
195 .and_then(|s| s.to_str())
196 .ok_or_else(|| threecrate_core::Error::UnsupportedFormat(
197 "No file extension found".to_string()
198 ))?;
199
200 match extension {
201 "ply" => {
202 let iter = ply::PlyStreamingReader::new(path, chunk_size.unwrap_or(1000))?;
203 Ok(Box::new(iter))
204 }
205 "obj" => {
206 let iter = obj::ObjStreamingReader::new(path, chunk_size.unwrap_or(1000))?;
207 Ok(Box::new(iter))
208 }
209 "xyz" | "csv" | "txt" => {
210 let iter = xyz_csv::XyzCsvStreamingReader::new(path, chunk_size.unwrap_or(1000))?;
211 Ok(Box::new(iter))
212 }
213 _ => Err(threecrate_core::Error::UnsupportedFormat(
214 format!("Streaming not supported for format: {}", extension)
215 ))
216 }
217}
218
219pub fn read_mesh_iter<P: AsRef<Path>>(
250 path: P,
251 chunk_size: Option<usize>
252) -> Result<Box<dyn Iterator<Item = Result<[usize; 3]>> + Send + Sync>> {
253 let path = path.as_ref();
254 let extension = path.extension()
255 .and_then(|s| s.to_str())
256 .ok_or_else(|| threecrate_core::Error::UnsupportedFormat(
257 "No file extension found".to_string()
258 ))?;
259
260 match extension {
261 "ply" => {
262 let iter = ply::PlyMeshStreamingReader::new(path, chunk_size.unwrap_or(1000))?;
263 Ok(Box::new(iter))
264 }
265 "obj" => {
266 let iter = obj::ObjMeshStreamingReader::new(path, chunk_size.unwrap_or(1000))?;
267 Ok(Box::new(iter))
268 }
269 _ => Err(threecrate_core::Error::UnsupportedFormat(
270 format!("Streaming not supported for format: {}", extension)
271 ))
272 }
273}
274
275