1#[cfg(feature = "io-mmap")]
12use crate::mmap::MmapReader;
13use crate::{MeshReader, MeshWriter, PointCloudReader, PointCloudWriter};
14use byteorder::{BigEndian, LittleEndian, ReadBytesExt};
15use std::collections::HashMap;
16use std::fs::File;
17use std::io::{BufRead, BufReader, BufWriter, Read};
18use std::path::Path;
19use threecrate_core::{Error, Point3f, PointCloud, Result, TriangleMesh, Vector3f};
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
23pub enum PlyFormat {
24 Ascii,
25 BinaryLittleEndian,
26 BinaryBigEndian,
27}
28
29#[derive(Debug, Clone, PartialEq)]
31pub enum PlyPropertyType {
32 Char,
33 UChar,
34 Short,
35 UShort,
36 Int,
37 UInt,
38 Float,
39 Double,
40 List(Box<PlyPropertyType>, Box<PlyPropertyType>), }
42
43#[derive(Debug, Clone)]
45pub struct PlyProperty {
46 pub name: String,
47 pub property_type: PlyPropertyType,
48}
49
50#[derive(Debug, Clone)]
52pub struct PlyElement {
53 pub name: String,
54 pub count: usize,
55 pub properties: Vec<PlyProperty>,
56}
57
58#[derive(Debug, Clone)]
60pub enum PlyValue {
61 Char(i8),
62 UChar(u8),
63 Short(i16),
64 UShort(u16),
65 Int(i32),
66 UInt(u32),
67 Float(f32),
68 Double(f64),
69 List(Vec<PlyValue>),
70}
71
72#[derive(Debug, Clone)]
74pub struct PlyHeader {
75 pub format: PlyFormat,
76 pub version: String,
77 pub elements: Vec<PlyElement>,
78 pub comments: Vec<String>,
79 pub obj_info: Vec<String>,
80}
81
82#[derive(Debug)]
84pub struct PlyData {
85 pub header: PlyHeader,
86 pub elements: HashMap<String, Vec<HashMap<String, PlyValue>>>,
87}
88
89pub struct RobustPlyReader;
91
92#[derive(Debug, Clone)]
94pub struct PlyWriteOptions {
95 pub format: PlyFormat,
97 pub comments: Vec<String>,
99 pub obj_info: Vec<String>,
101 pub custom_vertex_properties: Vec<(String, Vec<PlyValue>)>,
103 pub custom_face_properties: Vec<(String, Vec<PlyValue>)>,
105 pub include_normals: bool,
107 pub include_colors: bool,
109 pub vertex_property_order: Option<Vec<String>>,
111}
112
113impl Default for PlyWriteOptions {
114 fn default() -> Self {
115 Self {
116 format: PlyFormat::Ascii,
117 comments: Vec::new(),
118 obj_info: Vec::new(),
119 custom_vertex_properties: Vec::new(),
120 custom_face_properties: Vec::new(),
121 include_normals: true,
122 include_colors: false,
123 vertex_property_order: None,
124 }
125 }
126}
127
128impl PlyWriteOptions {
129 pub fn ascii() -> Self {
131 Self {
132 format: PlyFormat::Ascii,
133 ..Default::default()
134 }
135 }
136
137 pub fn binary_little_endian() -> Self {
139 Self {
140 format: PlyFormat::BinaryLittleEndian,
141 ..Default::default()
142 }
143 }
144
145 pub fn binary_big_endian() -> Self {
147 Self {
148 format: PlyFormat::BinaryBigEndian,
149 ..Default::default()
150 }
151 }
152
153 pub fn with_comment<S: Into<String>>(mut self, comment: S) -> Self {
155 self.comments.push(comment.into());
156 self
157 }
158
159 pub fn with_obj_info<S: Into<String>>(mut self, info: S) -> Self {
161 self.obj_info.push(info.into());
162 self
163 }
164
165 pub fn with_normals(mut self, include: bool) -> Self {
167 self.include_normals = include;
168 self
169 }
170
171 pub fn with_colors(mut self, include: bool) -> Self {
173 self.include_colors = include;
174 self
175 }
176
177 pub fn with_vertex_property_order(mut self, order: Vec<String>) -> Self {
179 self.vertex_property_order = Some(order);
180 self
181 }
182
183 pub fn with_custom_vertex_property<S: Into<String>>(
185 mut self,
186 name: S,
187 values: Vec<PlyValue>,
188 ) -> Self {
189 self.custom_vertex_properties.push((name.into(), values));
190 self
191 }
192}
193
194pub struct RobustPlyWriter;
196
197impl RobustPlyWriter {
198 pub fn write_point_cloud<P: AsRef<Path>>(
200 cloud: &PointCloud<Point3f>,
201 path: P,
202 options: &PlyWriteOptions,
203 ) -> Result<()> {
204 let file = File::create(path)?;
205 let mut writer = BufWriter::new(file);
206 Self::write_point_cloud_to_writer(cloud, &mut writer, options)
207 }
208
209 pub fn write_point_cloud_to_writer<W: std::io::Write>(
211 cloud: &PointCloud<Point3f>,
212 writer: &mut W,
213 options: &PlyWriteOptions,
214 ) -> Result<()> {
215 let mut ply_data = PlyData {
217 header: PlyHeader {
218 format: options.format,
219 version: "1.0".to_string(),
220 elements: Vec::new(),
221 comments: options.comments.clone(),
222 obj_info: options.obj_info.clone(),
223 },
224 elements: HashMap::new(),
225 };
226
227 let mut vertex_properties = Vec::new();
229 let mut vertex_data = Vec::new();
230
231 vertex_properties.push(PlyProperty {
233 name: "x".to_string(),
234 property_type: PlyPropertyType::Float,
235 });
236 vertex_properties.push(PlyProperty {
237 name: "y".to_string(),
238 property_type: PlyPropertyType::Float,
239 });
240 vertex_properties.push(PlyProperty {
241 name: "z".to_string(),
242 property_type: PlyPropertyType::Float,
243 });
244
245 for (prop_name, _) in &options.custom_vertex_properties {
247 if let Some(first_values) = options
249 .custom_vertex_properties
250 .iter()
251 .find(|(name, _)| name == prop_name)
252 .map(|(_, values)| values)
253 {
254 if let Some(first_value) = first_values.first() {
255 let prop_type = Self::value_to_property_type(first_value);
256 vertex_properties.push(PlyProperty {
257 name: prop_name.clone(),
258 property_type: prop_type,
259 });
260 }
261 }
262 }
263
264 if let Some(order) = &options.vertex_property_order {
266 vertex_properties.sort_by_key(|prop| {
267 order
268 .iter()
269 .position(|name| name == &prop.name)
270 .unwrap_or(order.len())
271 });
272 }
273
274 for (i, point) in cloud.iter().enumerate() {
276 let mut vertex_instance = HashMap::new();
277 vertex_instance.insert("x".to_string(), PlyValue::Float(point.x));
278 vertex_instance.insert("y".to_string(), PlyValue::Float(point.y));
279 vertex_instance.insert("z".to_string(), PlyValue::Float(point.z));
280
281 for (prop_name, values) in &options.custom_vertex_properties {
283 if i < values.len() {
284 vertex_instance.insert(prop_name.clone(), values[i].clone());
285 }
286 }
287
288 vertex_data.push(vertex_instance);
289 }
290
291 ply_data.header.elements.push(PlyElement {
293 name: "vertex".to_string(),
294 count: cloud.len(),
295 properties: vertex_properties,
296 });
297 ply_data.elements.insert("vertex".to_string(), vertex_data);
298
299 Self::write_ply_data(writer, &ply_data)
301 }
302
303 pub fn write_mesh<P: AsRef<Path>>(
305 mesh: &TriangleMesh,
306 path: P,
307 options: &PlyWriteOptions,
308 ) -> Result<()> {
309 let file = File::create(path)?;
310 let mut writer = BufWriter::new(file);
311 Self::write_mesh_to_writer(mesh, &mut writer, options)
312 }
313
314 pub fn write_mesh_to_writer<W: std::io::Write>(
316 mesh: &TriangleMesh,
317 writer: &mut W,
318 options: &PlyWriteOptions,
319 ) -> Result<()> {
320 let mut ply_data = PlyData {
322 header: PlyHeader {
323 format: options.format,
324 version: "1.0".to_string(),
325 elements: Vec::new(),
326 comments: options.comments.clone(),
327 obj_info: options.obj_info.clone(),
328 },
329 elements: HashMap::new(),
330 };
331
332 let mut vertex_properties = Vec::new();
334 let mut vertex_data = Vec::new();
335
336 vertex_properties.push(PlyProperty {
338 name: "x".to_string(),
339 property_type: PlyPropertyType::Float,
340 });
341 vertex_properties.push(PlyProperty {
342 name: "y".to_string(),
343 property_type: PlyPropertyType::Float,
344 });
345 vertex_properties.push(PlyProperty {
346 name: "z".to_string(),
347 property_type: PlyPropertyType::Float,
348 });
349
350 if options.include_normals && mesh.normals.is_some() {
352 vertex_properties.push(PlyProperty {
353 name: "nx".to_string(),
354 property_type: PlyPropertyType::Float,
355 });
356 vertex_properties.push(PlyProperty {
357 name: "ny".to_string(),
358 property_type: PlyPropertyType::Float,
359 });
360 vertex_properties.push(PlyProperty {
361 name: "nz".to_string(),
362 property_type: PlyPropertyType::Float,
363 });
364 }
365
366 for (prop_name, _) in &options.custom_vertex_properties {
368 if let Some(first_values) = options
369 .custom_vertex_properties
370 .iter()
371 .find(|(name, _)| name == prop_name)
372 .map(|(_, values)| values)
373 {
374 if let Some(first_value) = first_values.first() {
375 let prop_type = Self::value_to_property_type(first_value);
376 vertex_properties.push(PlyProperty {
377 name: prop_name.clone(),
378 property_type: prop_type,
379 });
380 }
381 }
382 }
383
384 if let Some(order) = &options.vertex_property_order {
386 vertex_properties.sort_by_key(|prop| {
387 order
388 .iter()
389 .position(|name| name == &prop.name)
390 .unwrap_or(order.len())
391 });
392 }
393
394 for (i, vertex) in mesh.vertices.iter().enumerate() {
396 let mut vertex_instance = HashMap::new();
397 vertex_instance.insert("x".to_string(), PlyValue::Float(vertex.x));
398 vertex_instance.insert("y".to_string(), PlyValue::Float(vertex.y));
399 vertex_instance.insert("z".to_string(), PlyValue::Float(vertex.z));
400
401 if options.include_normals {
403 if let Some(normals) = &mesh.normals {
404 if i < normals.len() {
405 vertex_instance.insert("nx".to_string(), PlyValue::Float(normals[i].x));
406 vertex_instance.insert("ny".to_string(), PlyValue::Float(normals[i].y));
407 vertex_instance.insert("nz".to_string(), PlyValue::Float(normals[i].z));
408 }
409 }
410 }
411
412 for (prop_name, values) in &options.custom_vertex_properties {
414 if i < values.len() {
415 vertex_instance.insert(prop_name.clone(), values[i].clone());
416 }
417 }
418
419 vertex_data.push(vertex_instance);
420 }
421
422 ply_data.header.elements.push(PlyElement {
424 name: "vertex".to_string(),
425 count: mesh.vertices.len(),
426 properties: vertex_properties,
427 });
428 ply_data.elements.insert("vertex".to_string(), vertex_data);
429
430 if !mesh.faces.is_empty() {
432 let face_properties = vec![PlyProperty {
433 name: "vertex_indices".to_string(),
434 property_type: PlyPropertyType::List(
435 Box::new(PlyPropertyType::UChar),
436 Box::new(PlyPropertyType::Int),
437 ),
438 }];
439
440 let mut face_data = Vec::new();
441 for face in &mesh.faces {
442 let mut face_instance = HashMap::new();
443 let indices = vec![
444 PlyValue::Int(face[0] as i32),
445 PlyValue::Int(face[1] as i32),
446 PlyValue::Int(face[2] as i32),
447 ];
448 face_instance.insert("vertex_indices".to_string(), PlyValue::List(indices));
449 face_data.push(face_instance);
450 }
451
452 ply_data.header.elements.push(PlyElement {
453 name: "face".to_string(),
454 count: mesh.faces.len(),
455 properties: face_properties,
456 });
457 ply_data.elements.insert("face".to_string(), face_data);
458 }
459
460 Self::write_ply_data(writer, &ply_data)
462 }
463
464 fn write_ply_data<W: std::io::Write>(writer: &mut W, ply_data: &PlyData) -> Result<()> {
466 Self::write_header(writer, &ply_data.header)?;
468
469 match ply_data.header.format {
471 PlyFormat::Ascii => Self::write_ascii_data(writer, ply_data)?,
472 PlyFormat::BinaryLittleEndian => {
473 Self::write_binary_data::<LittleEndian, _>(writer, ply_data)?
474 }
475 PlyFormat::BinaryBigEndian => {
476 Self::write_binary_data::<BigEndian, _>(writer, ply_data)?
477 }
478 }
479
480 Ok(())
481 }
482
483 fn write_header<W: std::io::Write>(writer: &mut W, header: &PlyHeader) -> Result<()> {
485 writeln!(writer, "ply")?;
486
487 let format_str = match header.format {
488 PlyFormat::Ascii => "ascii",
489 PlyFormat::BinaryLittleEndian => "binary_little_endian",
490 PlyFormat::BinaryBigEndian => "binary_big_endian",
491 };
492 writeln!(writer, "format {} {}", format_str, header.version)?;
493
494 for comment in &header.comments {
496 writeln!(writer, "comment {}", comment)?;
497 }
498
499 for info in &header.obj_info {
501 writeln!(writer, "obj_info {}", info)?;
502 }
503
504 for element in &header.elements {
506 writeln!(writer, "element {} {}", element.name, element.count)?;
507 for property in &element.properties {
508 Self::write_property_definition(writer, property)?;
509 }
510 }
511
512 writeln!(writer, "end_header")?;
513 Ok(())
514 }
515
516 fn write_property_definition<W: std::io::Write>(
518 writer: &mut W,
519 property: &PlyProperty,
520 ) -> Result<()> {
521 match &property.property_type {
522 PlyPropertyType::List(count_type, item_type) => {
523 let count_str = Self::property_type_to_string(count_type);
524 let item_str = Self::property_type_to_string(item_type);
525 writeln!(
526 writer,
527 "property list {} {} {}",
528 count_str, item_str, property.name
529 )?;
530 }
531 _ => {
532 let type_str = Self::property_type_to_string(&property.property_type);
533 writeln!(writer, "property {} {}", type_str, property.name)?;
534 }
535 }
536 Ok(())
537 }
538
539 fn property_type_to_string(prop_type: &PlyPropertyType) -> &'static str {
541 match prop_type {
542 PlyPropertyType::Char => "char",
543 PlyPropertyType::UChar => "uchar",
544 PlyPropertyType::Short => "short",
545 PlyPropertyType::UShort => "ushort",
546 PlyPropertyType::Int => "int",
547 PlyPropertyType::UInt => "uint",
548 PlyPropertyType::Float => "float",
549 PlyPropertyType::Double => "double",
550 PlyPropertyType::List(_, _) => "list", }
552 }
553
554 fn write_ascii_data<W: std::io::Write>(writer: &mut W, ply_data: &PlyData) -> Result<()> {
556 for element_def in &ply_data.header.elements {
557 if let Some(element_data) = ply_data.elements.get(&element_def.name) {
558 for instance in element_data {
559 let mut values = Vec::new();
560
561 for property in &element_def.properties {
562 if let Some(value) = instance.get(&property.name) {
563 Self::format_ascii_value(value, &mut values)?;
564 }
565 }
566
567 writeln!(writer, "{}", values.join(" "))?;
568 }
569 }
570 }
571 Ok(())
572 }
573
574 fn format_ascii_value(value: &PlyValue, output: &mut Vec<String>) -> Result<()> {
576 match value {
577 PlyValue::Char(v) => output.push(v.to_string()),
578 PlyValue::UChar(v) => output.push(v.to_string()),
579 PlyValue::Short(v) => output.push(v.to_string()),
580 PlyValue::UShort(v) => output.push(v.to_string()),
581 PlyValue::Int(v) => output.push(v.to_string()),
582 PlyValue::UInt(v) => output.push(v.to_string()),
583 PlyValue::Float(v) => output.push(v.to_string()),
584 PlyValue::Double(v) => output.push(v.to_string()),
585 PlyValue::List(values) => {
586 output.push(values.len().to_string());
587 for item in values {
588 Self::format_ascii_value(item, output)?;
589 }
590 }
591 }
592 Ok(())
593 }
594
595 fn write_binary_data<E: byteorder::ByteOrder, W: std::io::Write>(
597 writer: &mut W,
598 ply_data: &PlyData,
599 ) -> Result<()> {
600 for element_def in &ply_data.header.elements {
601 if let Some(element_data) = ply_data.elements.get(&element_def.name) {
602 for instance in element_data {
603 for property in &element_def.properties {
604 if let Some(value) = instance.get(&property.name) {
605 Self::write_binary_value::<E, _>(writer, value)?;
606 }
607 }
608 }
609 }
610 }
611 Ok(())
612 }
613
614 fn write_binary_value<E: byteorder::ByteOrder, W: std::io::Write>(
616 writer: &mut W,
617 value: &PlyValue,
618 ) -> Result<()> {
619 use byteorder::WriteBytesExt;
620
621 match value {
622 PlyValue::Char(v) => writer.write_i8(*v)?,
623 PlyValue::UChar(v) => writer.write_u8(*v)?,
624 PlyValue::Short(v) => writer.write_i16::<E>(*v)?,
625 PlyValue::UShort(v) => writer.write_u16::<E>(*v)?,
626 PlyValue::Int(v) => writer.write_i32::<E>(*v)?,
627 PlyValue::UInt(v) => writer.write_u32::<E>(*v)?,
628 PlyValue::Float(v) => writer.write_f32::<E>(*v)?,
629 PlyValue::Double(v) => writer.write_f64::<E>(*v)?,
630 PlyValue::List(values) => {
631 writer.write_u8(values.len() as u8)?;
633 for item in values {
634 Self::write_binary_value::<E, _>(writer, item)?;
635 }
636 }
637 }
638 Ok(())
639 }
640
641 fn value_to_property_type(value: &PlyValue) -> PlyPropertyType {
643 match value {
644 PlyValue::Char(_) => PlyPropertyType::Char,
645 PlyValue::UChar(_) => PlyPropertyType::UChar,
646 PlyValue::Short(_) => PlyPropertyType::Short,
647 PlyValue::UShort(_) => PlyPropertyType::UShort,
648 PlyValue::Int(_) => PlyPropertyType::Int,
649 PlyValue::UInt(_) => PlyPropertyType::UInt,
650 PlyValue::Float(_) => PlyPropertyType::Float,
651 PlyValue::Double(_) => PlyPropertyType::Double,
652 PlyValue::List(values) => {
653 let item_type = if let Some(first_item) = values.first() {
654 Self::value_to_property_type(first_item)
655 } else {
656 PlyPropertyType::Int
657 };
658 PlyPropertyType::List(Box::new(PlyPropertyType::UChar), Box::new(item_type))
659 }
660 }
661 }
662}
663
664impl RobustPlyReader {
665 pub fn read_ply_data<R: BufRead>(reader: &mut R) -> Result<PlyData> {
667 let header = Self::read_header(reader)?;
668 let elements = Self::read_elements(reader, &header)?;
669
670 Ok(PlyData { header, elements })
671 }
672
673 pub fn read_ply_file<P: AsRef<Path>>(path: P) -> Result<PlyData> {
675 let path = path.as_ref();
676
677 #[cfg(feature = "io-mmap")]
679 {
680 if let Some(ply_data) = Self::try_read_ply_mmap(path)? {
681 return Ok(ply_data);
682 }
683 }
684
685 let file = File::open(path)?;
687 let mut reader = BufReader::new(file);
688 Self::read_ply_data(&mut reader)
689 }
690
691 #[cfg(feature = "io-mmap")]
693 fn try_read_ply_mmap<P: AsRef<Path>>(path: P) -> Result<Option<PlyData>> {
694 let path = path.as_ref();
695
696 if !crate::mmap::should_use_mmap(path) {
698 return Ok(None);
699 }
700
701 let file = File::open(path)?;
703 let mut reader = BufReader::new(file);
704 let header = Self::read_header(&mut reader)?;
705
706 match header.format {
708 PlyFormat::BinaryLittleEndian | PlyFormat::BinaryBigEndian => {
709 let file = File::open(path)?;
711 let mut reader = BufReader::new(file);
712 let mut header_size = 0;
713 let mut line = String::new();
714
715 loop {
716 let line_start = header_size;
717 line.clear();
718 let bytes_read = reader.read_line(&mut line)?;
719 if bytes_read == 0 {
720 return Err(Error::InvalidData(
721 "Unexpected end of file in header".to_string(),
722 ));
723 }
724 header_size += bytes_read;
725
726 if line.trim() == "end_header" {
727 break;
728 }
729 }
730
731 if let Some(mut mmap_reader) = MmapReader::new(path)? {
733 mmap_reader.seek(header_size)?;
735
736 let elements = Self::read_elements_mmap(&mut mmap_reader, &header)?;
738
739 return Ok(Some(PlyData { header, elements }));
740 }
741 }
742 PlyFormat::Ascii => {
743 return Ok(None);
745 }
746 }
747
748 Ok(None)
749 }
750
751 #[cfg(feature = "io-mmap")]
753 fn read_elements_mmap(
754 reader: &mut MmapReader,
755 header: &PlyHeader,
756 ) -> Result<HashMap<String, Vec<HashMap<String, PlyValue>>>> {
757 let mut elements = HashMap::new();
758
759 for element_def in &header.elements {
760 let mut element_data = Vec::with_capacity(crate::capacity_hint(element_def.count));
761
762 for _ in 0..element_def.count {
763 let mut instance = HashMap::new();
764
765 match header.format {
766 PlyFormat::BinaryLittleEndian => {
767 for property in &element_def.properties {
768 let value = Self::read_binary_property_value_mmap_le(
769 reader,
770 &property.property_type,
771 )?;
772 instance.insert(property.name.clone(), value);
773 }
774 }
775 PlyFormat::BinaryBigEndian => {
776 for property in &element_def.properties {
777 let value = Self::read_binary_property_value_mmap_be(
778 reader,
779 &property.property_type,
780 )?;
781 instance.insert(property.name.clone(), value);
782 }
783 }
784 PlyFormat::Ascii => {
785 return Err(Error::InvalidData(
786 "ASCII format should not use mmap reader".to_string(),
787 ));
788 }
789 }
790
791 element_data.push(instance);
792 }
793
794 elements.insert(element_def.name.clone(), element_data);
795 }
796
797 Ok(elements)
798 }
799
800 #[cfg(feature = "io-mmap")]
802 fn read_binary_property_value_mmap_le(
803 reader: &mut MmapReader,
804 property_type: &PlyPropertyType,
805 ) -> Result<PlyValue> {
806 match property_type {
807 PlyPropertyType::Char => Ok(PlyValue::Char(reader.read_u8()? as i8)),
808 PlyPropertyType::UChar => Ok(PlyValue::UChar(reader.read_u8()?)),
809 PlyPropertyType::Short => Ok(PlyValue::Short(reader.read_u16_le()? as i16)),
810 PlyPropertyType::UShort => Ok(PlyValue::UShort(reader.read_u16_le()?)),
811 PlyPropertyType::Int => Ok(PlyValue::Int(reader.read_u32_le()? as i32)),
812 PlyPropertyType::UInt => Ok(PlyValue::UInt(reader.read_u32_le()?)),
813 PlyPropertyType::Float => Ok(PlyValue::Float(reader.read_f32_le()?)),
814 PlyPropertyType::Double => Ok(PlyValue::Double(reader.read_f64_le()?)),
815 PlyPropertyType::List(count_type, item_type) => {
816 let count_value = Self::read_binary_property_value_mmap_le(reader, count_type)?;
817 let count = count_value.as_usize()?;
818
819 let mut list = Vec::with_capacity(crate::capacity_hint(count));
820 for _ in 0..count {
821 let item = Self::read_binary_property_value_mmap_le(reader, item_type)?;
822 list.push(item);
823 }
824
825 Ok(PlyValue::List(list))
826 }
827 }
828 }
829
830 #[cfg(feature = "io-mmap")]
832 fn read_binary_property_value_mmap_be(
833 reader: &mut MmapReader,
834 property_type: &PlyPropertyType,
835 ) -> Result<PlyValue> {
836 match property_type {
837 PlyPropertyType::Char => Ok(PlyValue::Char(reader.read_u8()? as i8)),
838 PlyPropertyType::UChar => Ok(PlyValue::UChar(reader.read_u8()?)),
839 PlyPropertyType::Short => Ok(PlyValue::Short(reader.read_u16_be()? as i16)),
840 PlyPropertyType::UShort => Ok(PlyValue::UShort(reader.read_u16_be()?)),
841 PlyPropertyType::Int => Ok(PlyValue::Int(reader.read_u32_be()? as i32)),
842 PlyPropertyType::UInt => Ok(PlyValue::UInt(reader.read_u32_be()?)),
843 PlyPropertyType::Float => Ok(PlyValue::Float(reader.read_f32_be()?)),
844 PlyPropertyType::Double => Ok(PlyValue::Double(reader.read_f64_be()?)),
845 PlyPropertyType::List(count_type, item_type) => {
846 let count_value = Self::read_binary_property_value_mmap_be(reader, count_type)?;
847 let count = count_value.as_usize()?;
848
849 let mut list = Vec::with_capacity(crate::capacity_hint(count));
850 for _ in 0..count {
851 let item = Self::read_binary_property_value_mmap_be(reader, item_type)?;
852 list.push(item);
853 }
854
855 Ok(PlyValue::List(list))
856 }
857 }
858 }
859
860 fn read_header<R: BufRead>(reader: &mut R) -> Result<PlyHeader> {
862 let mut format = None;
863 let mut version = "1.0".to_string();
864 let mut elements = Vec::new();
865 let mut comments = Vec::new();
866 let mut obj_info = Vec::new();
867
868 let mut line = String::new();
869
870 reader.read_line(&mut line)?;
872 if line.trim() != "ply" {
873 return Err(Error::InvalidData(
874 "Not a PLY file - missing magic number".to_string(),
875 ));
876 }
877
878 loop {
880 line.clear();
881 if reader.read_line(&mut line)? == 0 {
882 return Err(Error::InvalidData(
883 "Unexpected end of file in header".to_string(),
884 ));
885 }
886
887 let line = line.trim();
888 if line == "end_header" {
889 break;
890 }
891
892 let parts: Vec<&str> = line.split_whitespace().collect();
893 if parts.is_empty() {
894 continue;
895 }
896
897 match parts[0] {
898 "format" => {
899 if parts.len() < 3 {
900 return Err(Error::InvalidData("Invalid format line".to_string()));
901 }
902 format = Some(match parts[1] {
903 "ascii" => PlyFormat::Ascii,
904 "binary_little_endian" => PlyFormat::BinaryLittleEndian,
905 "binary_big_endian" => PlyFormat::BinaryBigEndian,
906 _ => {
907 return Err(Error::InvalidData(format!("Unknown format: {}", parts[1])))
908 }
909 });
910 version = parts[2].to_string();
911 }
912 "comment" => {
913 if parts.len() > 1 {
914 comments.push(parts[1..].join(" "));
915 }
916 }
917 "obj_info" => {
918 if parts.len() > 1 {
919 obj_info.push(parts[1..].join(" "));
920 }
921 }
922 "element" => {
923 if parts.len() < 3 {
924 return Err(Error::InvalidData("Invalid element line".to_string()));
925 }
926 let name = parts[1].to_string();
927 let count: usize = parts[2]
928 .parse()
929 .map_err(|_| Error::InvalidData("Invalid element count".to_string()))?;
930 elements.push(PlyElement {
931 name,
932 count,
933 properties: Vec::new(),
934 });
935 }
936 "property" => {
937 if elements.is_empty() {
938 return Err(Error::InvalidData("Property without element".to_string()));
939 }
940 let property = Self::parse_property(&parts[1..])?;
941 elements.last_mut().unwrap().properties.push(property);
942 }
943 _ => {
944 }
946 }
947 }
948
949 let format =
950 format.ok_or_else(|| Error::InvalidData("Missing format specification".to_string()))?;
951
952 Ok(PlyHeader {
953 format,
954 version,
955 elements,
956 comments,
957 obj_info,
958 })
959 }
960
961 fn parse_property(parts: &[&str]) -> Result<PlyProperty> {
963 if parts.is_empty() {
964 return Err(Error::InvalidData("Empty property definition".to_string()));
965 }
966
967 let property_type = if parts[0] == "list" {
968 if parts.len() < 4 {
969 return Err(Error::InvalidData(
970 "Invalid list property definition".to_string(),
971 ));
972 }
973 let count_type = Self::parse_scalar_type(parts[1])?;
974 let item_type = Self::parse_scalar_type(parts[2])?;
975 PlyPropertyType::List(Box::new(count_type), Box::new(item_type))
976 } else {
977 if parts.len() < 2 {
978 return Err(Error::InvalidData(
979 "Invalid property definition".to_string(),
980 ));
981 }
982 Self::parse_scalar_type(parts[0])?
983 };
984
985 let name = parts.last().unwrap().to_string();
986
987 Ok(PlyProperty {
988 name,
989 property_type,
990 })
991 }
992
993 fn parse_scalar_type(type_str: &str) -> Result<PlyPropertyType> {
995 match type_str {
996 "char" | "int8" => Ok(PlyPropertyType::Char),
997 "uchar" | "uint8" => Ok(PlyPropertyType::UChar),
998 "short" | "int16" => Ok(PlyPropertyType::Short),
999 "ushort" | "uint16" => Ok(PlyPropertyType::UShort),
1000 "int" | "int32" => Ok(PlyPropertyType::Int),
1001 "uint" | "uint32" => Ok(PlyPropertyType::UInt),
1002 "float" | "float32" => Ok(PlyPropertyType::Float),
1003 "double" | "float64" => Ok(PlyPropertyType::Double),
1004 _ => Err(Error::InvalidData(format!(
1005 "Unknown property type: {}",
1006 type_str
1007 ))),
1008 }
1009 }
1010
1011 fn read_elements<R: BufRead>(
1013 reader: &mut R,
1014 header: &PlyHeader,
1015 ) -> Result<HashMap<String, Vec<HashMap<String, PlyValue>>>> {
1016 let mut elements = HashMap::new();
1017
1018 for element_def in &header.elements {
1019 let mut element_data = Vec::with_capacity(crate::capacity_hint(element_def.count));
1020
1021 for _ in 0..element_def.count {
1022 let mut instance = HashMap::new();
1023
1024 match header.format {
1025 PlyFormat::Ascii => {
1026 let mut line = String::new();
1027 reader.read_line(&mut line)?;
1028 let values = line.trim().split_whitespace().collect::<Vec<_>>();
1029 let mut value_idx = 0;
1030
1031 for property in &element_def.properties {
1032 let value = Self::read_ascii_property_value(
1033 &values,
1034 &mut value_idx,
1035 &property.property_type,
1036 )?;
1037 instance.insert(property.name.clone(), value);
1038 }
1039 }
1040 PlyFormat::BinaryLittleEndian => {
1041 for property in &element_def.properties {
1042 let value = Self::read_binary_property_value::<LittleEndian, _>(
1043 reader,
1044 &property.property_type,
1045 )?;
1046 instance.insert(property.name.clone(), value);
1047 }
1048 }
1049 PlyFormat::BinaryBigEndian => {
1050 for property in &element_def.properties {
1051 let value = Self::read_binary_property_value::<BigEndian, _>(
1052 reader,
1053 &property.property_type,
1054 )?;
1055 instance.insert(property.name.clone(), value);
1056 }
1057 }
1058 }
1059
1060 element_data.push(instance);
1061 }
1062
1063 elements.insert(element_def.name.clone(), element_data);
1064 }
1065
1066 Ok(elements)
1067 }
1068
1069 fn read_ascii_property_value(
1071 values: &[&str],
1072 value_idx: &mut usize,
1073 property_type: &PlyPropertyType,
1074 ) -> Result<PlyValue> {
1075 if *value_idx >= values.len() {
1076 return Err(Error::InvalidData("Not enough values in line".to_string()));
1077 }
1078
1079 match property_type {
1080 PlyPropertyType::Char => {
1081 let val = values[*value_idx]
1082 .parse::<i8>()
1083 .map_err(|_| Error::InvalidData("Invalid char value".to_string()))?;
1084 *value_idx += 1;
1085 Ok(PlyValue::Char(val))
1086 }
1087 PlyPropertyType::UChar => {
1088 let val = values[*value_idx]
1089 .parse::<u8>()
1090 .map_err(|_| Error::InvalidData("Invalid uchar value".to_string()))?;
1091 *value_idx += 1;
1092 Ok(PlyValue::UChar(val))
1093 }
1094 PlyPropertyType::Short => {
1095 let val = values[*value_idx]
1096 .parse::<i16>()
1097 .map_err(|_| Error::InvalidData("Invalid short value".to_string()))?;
1098 *value_idx += 1;
1099 Ok(PlyValue::Short(val))
1100 }
1101 PlyPropertyType::UShort => {
1102 let val = values[*value_idx]
1103 .parse::<u16>()
1104 .map_err(|_| Error::InvalidData("Invalid ushort value".to_string()))?;
1105 *value_idx += 1;
1106 Ok(PlyValue::UShort(val))
1107 }
1108 PlyPropertyType::Int => {
1109 let val = values[*value_idx]
1110 .parse::<i32>()
1111 .map_err(|_| Error::InvalidData("Invalid int value".to_string()))?;
1112 *value_idx += 1;
1113 Ok(PlyValue::Int(val))
1114 }
1115 PlyPropertyType::UInt => {
1116 let val = values[*value_idx]
1117 .parse::<u32>()
1118 .map_err(|_| Error::InvalidData("Invalid uint value".to_string()))?;
1119 *value_idx += 1;
1120 Ok(PlyValue::UInt(val))
1121 }
1122 PlyPropertyType::Float => {
1123 let val = values[*value_idx]
1124 .parse::<f32>()
1125 .map_err(|_| Error::InvalidData("Invalid float value".to_string()))?;
1126 *value_idx += 1;
1127 Ok(PlyValue::Float(val))
1128 }
1129 PlyPropertyType::Double => {
1130 let val = values[*value_idx]
1131 .parse::<f64>()
1132 .map_err(|_| Error::InvalidData("Invalid double value".to_string()))?;
1133 *value_idx += 1;
1134 Ok(PlyValue::Double(val))
1135 }
1136 PlyPropertyType::List(count_type, item_type) => {
1137 let count_value = Self::read_ascii_property_value(values, value_idx, count_type)?;
1138 let count = count_value.as_usize()?;
1139
1140 let mut list = Vec::with_capacity(crate::capacity_hint(count));
1141 for _ in 0..count {
1142 let item = Self::read_ascii_property_value(values, value_idx, item_type)?;
1143 list.push(item);
1144 }
1145
1146 Ok(PlyValue::List(list))
1147 }
1148 }
1149 }
1150
1151 fn read_binary_property_value<E: byteorder::ByteOrder, R: Read>(
1153 reader: &mut R,
1154 property_type: &PlyPropertyType,
1155 ) -> Result<PlyValue> {
1156 match property_type {
1157 PlyPropertyType::Char => Ok(PlyValue::Char(reader.read_i8()?)),
1158 PlyPropertyType::UChar => Ok(PlyValue::UChar(reader.read_u8()?)),
1159 PlyPropertyType::Short => Ok(PlyValue::Short(reader.read_i16::<E>()?)),
1160 PlyPropertyType::UShort => Ok(PlyValue::UShort(reader.read_u16::<E>()?)),
1161 PlyPropertyType::Int => Ok(PlyValue::Int(reader.read_i32::<E>()?)),
1162 PlyPropertyType::UInt => Ok(PlyValue::UInt(reader.read_u32::<E>()?)),
1163 PlyPropertyType::Float => Ok(PlyValue::Float(reader.read_f32::<E>()?)),
1164 PlyPropertyType::Double => Ok(PlyValue::Double(reader.read_f64::<E>()?)),
1165 PlyPropertyType::List(count_type, item_type) => {
1166 let count_value = Self::read_binary_property_value::<E, _>(reader, count_type)?;
1167 let count = count_value.as_usize()?;
1168
1169 let mut list = Vec::with_capacity(crate::capacity_hint(count));
1170 for _ in 0..count {
1171 let item = Self::read_binary_property_value::<E, _>(reader, item_type)?;
1172 list.push(item);
1173 }
1174
1175 Ok(PlyValue::List(list))
1176 }
1177 }
1178 }
1179}
1180
1181impl PlyValue {
1182 pub fn as_f32(&self) -> Result<f32> {
1184 match self {
1185 PlyValue::Char(v) => Ok(*v as f32),
1186 PlyValue::UChar(v) => Ok(*v as f32),
1187 PlyValue::Short(v) => Ok(*v as f32),
1188 PlyValue::UShort(v) => Ok(*v as f32),
1189 PlyValue::Int(v) => Ok(*v as f32),
1190 PlyValue::UInt(v) => Ok(*v as f32),
1191 PlyValue::Float(v) => Ok(*v),
1192 PlyValue::Double(v) => Ok(*v as f32),
1193 _ => Err(Error::InvalidData("Cannot convert list to f32".to_string())),
1194 }
1195 }
1196
1197 pub fn as_usize(&self) -> Result<usize> {
1199 match self {
1200 PlyValue::UChar(v) => Ok(*v as usize),
1201 PlyValue::UShort(v) => Ok(*v as usize),
1202 PlyValue::UInt(v) => Ok(*v as usize),
1203 PlyValue::Int(v) if *v >= 0 => Ok(*v as usize),
1204 _ => Err(Error::InvalidData(
1205 "Cannot convert value to usize".to_string(),
1206 )),
1207 }
1208 }
1209
1210 pub fn as_usize_list(&self) -> Result<Vec<usize>> {
1212 match self {
1213 PlyValue::List(values) => values.iter().map(|v| v.as_usize()).collect(),
1214 _ => Err(Error::InvalidData("Value is not a list".to_string())),
1215 }
1216 }
1217}
1218
1219pub struct PlyReader;
1221pub struct PlyWriter;
1222
1223impl crate::registry::PointCloudReader for PlyReader {
1225 fn read_point_cloud(&self, path: &Path) -> Result<PointCloud<Point3f>> {
1226 let ply_data = RobustPlyReader::read_ply_file(path)?;
1228
1229 let mut points = Vec::new();
1230
1231 if let Some(vertex_elements) = ply_data.elements.get("vertex") {
1232 for vertex in vertex_elements {
1233 let x = vertex
1234 .get("x")
1235 .ok_or_else(|| Error::InvalidData("Missing x coordinate".to_string()))?
1236 .as_f32()?;
1237 let y = vertex
1238 .get("y")
1239 .ok_or_else(|| Error::InvalidData("Missing y coordinate".to_string()))?
1240 .as_f32()?;
1241 let z = vertex
1242 .get("z")
1243 .ok_or_else(|| Error::InvalidData("Missing z coordinate".to_string()))?
1244 .as_f32()?;
1245
1246 points.push(Point3f::new(x, y, z));
1247 }
1248 }
1249
1250 Ok(PointCloud::from_points(points))
1251 }
1252
1253 fn can_read(&self, path: &Path) -> bool {
1254 if let Ok(mut file) = File::open(path) {
1256 let mut header = [0u8; 4];
1257 if let Ok(_) = file.read(&mut header) {
1258 return header.starts_with(b"ply");
1259 }
1260 }
1261 false
1262 }
1263
1264 fn format_name(&self) -> &'static str {
1265 "ply"
1266 }
1267}
1268
1269impl crate::registry::MeshReader for PlyReader {
1270 fn read_mesh(&self, path: &Path) -> Result<TriangleMesh> {
1271 let ply_data = RobustPlyReader::read_ply_file(path)?;
1272
1273 let mut vertices = Vec::new();
1275 if let Some(vertex_elements) = ply_data.elements.get("vertex") {
1276 for vertex in vertex_elements {
1277 let x = vertex
1278 .get("x")
1279 .ok_or_else(|| Error::InvalidData("Missing x coordinate".to_string()))?
1280 .as_f32()?;
1281 let y = vertex
1282 .get("y")
1283 .ok_or_else(|| Error::InvalidData("Missing y coordinate".to_string()))?
1284 .as_f32()?;
1285 let z = vertex
1286 .get("z")
1287 .ok_or_else(|| Error::InvalidData("Missing z coordinate".to_string()))?
1288 .as_f32()?;
1289
1290 vertices.push(Point3f::new(x, y, z));
1291 }
1292 }
1293
1294 let mut faces = Vec::new();
1296 if let Some(face_elements) = ply_data.elements.get("face") {
1297 for face in face_elements {
1298 let indices = if let Some(vertex_indices) = face.get("vertex_indices") {
1300 vertex_indices.as_usize_list()?
1301 } else if let Some(vertex_index) = face.get("vertex_index") {
1302 vertex_index.as_usize_list()?
1303 } else {
1304 return Err(Error::InvalidData(
1305 "Face missing vertex indices".to_string(),
1306 ));
1307 };
1308
1309 if indices.len() >= 3 {
1311 faces.push([indices[0], indices[1], indices[2]]);
1312 }
1313 if indices.len() == 4 {
1315 faces.push([indices[0], indices[2], indices[3]]);
1316 }
1317 }
1318 }
1319
1320 let normals = if let Some(vertex_elements) = ply_data.elements.get("vertex") {
1322 let mut normals = Vec::new();
1323 let mut has_normals = true;
1324
1325 for vertex in vertex_elements {
1326 if let (Some(nx), Some(ny), Some(nz)) =
1327 (vertex.get("nx"), vertex.get("ny"), vertex.get("nz"))
1328 {
1329 normals.push(Vector3f::new(nx.as_f32()?, ny.as_f32()?, nz.as_f32()?));
1330 } else {
1331 has_normals = false;
1332 break;
1333 }
1334 }
1335
1336 if has_normals {
1337 Some(normals)
1338 } else {
1339 None
1340 }
1341 } else {
1342 None
1343 };
1344
1345 let mut mesh = TriangleMesh::from_vertices_and_faces(vertices, faces);
1346 if let Some(normals) = normals {
1347 mesh.set_normals(normals);
1348 }
1349
1350 Ok(mesh)
1351 }
1352
1353 fn can_read(&self, path: &Path) -> bool {
1354 if let Ok(mut file) = File::open(path) {
1356 let mut header = [0u8; 4];
1357 if let Ok(_) = file.read(&mut header) {
1358 return header.starts_with(b"ply");
1359 }
1360 }
1361 false
1362 }
1363
1364 fn format_name(&self) -> &'static str {
1365 "ply"
1366 }
1367}
1368
1369impl crate::registry::PointCloudWriter for PlyWriter {
1370 fn write_point_cloud(&self, cloud: &PointCloud<Point3f>, path: &Path) -> Result<()> {
1371 use ply_rs::{
1373 ply::{
1374 Addable, DefaultElement, ElementDef, Ply, Property, PropertyDef, PropertyType,
1375 ScalarType,
1376 },
1377 writer::Writer,
1378 };
1379
1380 let file = File::create(path)?;
1381 let mut writer = BufWriter::new(file);
1382
1383 let mut ply = Ply::<DefaultElement>::new();
1385
1386 let mut vertex_element = ElementDef::new("vertex".to_string());
1388 vertex_element.count = cloud.len();
1389 vertex_element.properties.add(PropertyDef::new(
1390 "x".to_string(),
1391 PropertyType::Scalar(ScalarType::Float),
1392 ));
1393 vertex_element.properties.add(PropertyDef::new(
1394 "y".to_string(),
1395 PropertyType::Scalar(ScalarType::Float),
1396 ));
1397 vertex_element.properties.add(PropertyDef::new(
1398 "z".to_string(),
1399 PropertyType::Scalar(ScalarType::Float),
1400 ));
1401
1402 ply.header.elements.add(vertex_element);
1403
1404 let mut vertices = Vec::new();
1406 for point in &cloud.points {
1407 let mut vertex = DefaultElement::new();
1408 vertex.insert("x".to_string(), Property::Float(point.x));
1409 vertex.insert("y".to_string(), Property::Float(point.y));
1410 vertex.insert("z".to_string(), Property::Float(point.z));
1411 vertices.push(vertex);
1412 }
1413 ply.payload.insert("vertex".to_string(), vertices);
1414
1415 let writer_instance = Writer::new();
1417 writer_instance.write_ply(&mut writer, &mut ply)?;
1418
1419 Ok(())
1420 }
1421
1422 fn format_name(&self) -> &'static str {
1423 "ply"
1424 }
1425}
1426
1427impl crate::registry::MeshWriter for PlyWriter {
1428 fn write_mesh(&self, mesh: &TriangleMesh, path: &Path) -> Result<()> {
1429 use ply_rs::{
1431 ply::{
1432 Addable, DefaultElement, ElementDef, Ply, Property, PropertyDef, PropertyType,
1433 ScalarType,
1434 },
1435 writer::Writer,
1436 };
1437
1438 let file = File::create(path)?;
1439 let mut writer = BufWriter::new(file);
1440
1441 let mut ply = Ply::<DefaultElement>::new();
1443
1444 let mut vertex_element = ElementDef::new("vertex".to_string());
1446 vertex_element.count = mesh.vertices.len();
1447 vertex_element.properties.add(PropertyDef::new(
1448 "x".to_string(),
1449 PropertyType::Scalar(ScalarType::Float),
1450 ));
1451 vertex_element.properties.add(PropertyDef::new(
1452 "y".to_string(),
1453 PropertyType::Scalar(ScalarType::Float),
1454 ));
1455 vertex_element.properties.add(PropertyDef::new(
1456 "z".to_string(),
1457 PropertyType::Scalar(ScalarType::Float),
1458 ));
1459
1460 if mesh.normals.is_some() {
1462 vertex_element.properties.add(PropertyDef::new(
1463 "nx".to_string(),
1464 PropertyType::Scalar(ScalarType::Float),
1465 ));
1466 vertex_element.properties.add(PropertyDef::new(
1467 "ny".to_string(),
1468 PropertyType::Scalar(ScalarType::Float),
1469 ));
1470 vertex_element.properties.add(PropertyDef::new(
1471 "nz".to_string(),
1472 PropertyType::Scalar(ScalarType::Float),
1473 ));
1474 }
1475
1476 ply.header.elements.add(vertex_element);
1477
1478 let mut vertices = Vec::new();
1480 for (i, point) in mesh.vertices.iter().enumerate() {
1481 let mut vertex = DefaultElement::new();
1482 vertex.insert("x".to_string(), Property::Float(point.x));
1483 vertex.insert("y".to_string(), Property::Float(point.y));
1484 vertex.insert("z".to_string(), Property::Float(point.z));
1485
1486 if let Some(ref normals) = mesh.normals {
1488 if i < normals.len() {
1489 vertex.insert("nx".to_string(), Property::Float(normals[i].x));
1490 vertex.insert("ny".to_string(), Property::Float(normals[i].y));
1491 vertex.insert("nz".to_string(), Property::Float(normals[i].z));
1492 }
1493 }
1494
1495 vertices.push(vertex);
1496 }
1497 ply.payload.insert("vertex".to_string(), vertices);
1498
1499 if !mesh.faces.is_empty() {
1501 let mut face_element = ElementDef::new("face".to_string());
1502 face_element.count = mesh.faces.len();
1503 face_element.properties.add(PropertyDef::new(
1504 "vertex_indices".to_string(),
1505 PropertyType::List(ScalarType::UChar, ScalarType::Int),
1506 ));
1507
1508 ply.header.elements.add(face_element);
1509
1510 let mut faces = Vec::new();
1512 for face in &mesh.faces {
1513 let mut face_data = DefaultElement::new();
1514 let indices = vec![face[0] as i32, face[1] as i32, face[2] as i32];
1515 face_data.insert("vertex_indices".to_string(), Property::ListInt(indices));
1516 faces.push(face_data);
1517 }
1518 ply.payload.insert("face".to_string(), faces);
1519 }
1520
1521 let writer_instance = Writer::new();
1523 writer_instance.write_ply(&mut writer, &mut ply)?;
1524
1525 Ok(())
1526 }
1527
1528 fn format_name(&self) -> &'static str {
1529 "ply"
1530 }
1531}
1532
1533impl PointCloudReader for PlyReader {
1535 fn read_point_cloud<P: AsRef<Path>>(path: P) -> Result<PointCloud<Point3f>> {
1536 let reader = PlyReader;
1537 crate::registry::PointCloudReader::read_point_cloud(&reader, path.as_ref())
1538 }
1539}
1540
1541impl MeshReader for PlyReader {
1542 fn read_mesh<P: AsRef<Path>>(path: P) -> Result<TriangleMesh> {
1543 let reader = PlyReader;
1544 crate::registry::MeshReader::read_mesh(&reader, path.as_ref())
1545 }
1546}
1547
1548impl PointCloudWriter for PlyWriter {
1549 fn write_point_cloud<P: AsRef<Path>>(cloud: &PointCloud<Point3f>, path: P) -> Result<()> {
1550 let writer = PlyWriter;
1551 crate::registry::PointCloudWriter::write_point_cloud(&writer, cloud, path.as_ref())
1552 }
1553}
1554
1555impl MeshWriter for PlyWriter {
1556 fn write_mesh<P: AsRef<Path>>(mesh: &TriangleMesh, path: P) -> Result<()> {
1557 let writer = PlyWriter;
1558 crate::registry::MeshWriter::write_mesh(&writer, mesh, path.as_ref())
1559 }
1560}
1561
1562pub struct PlyStreamingReader {
1564 reader: BufReader<File>,
1565 current_count: usize,
1566 current_index: usize,
1567 chunk_size: usize,
1568 buffer: Vec<u8>,
1569 format: PlyFormat,
1570}
1571
1572impl PlyStreamingReader {
1573 pub fn new<P: AsRef<Path>>(path: P, chunk_size: usize) -> Result<Self> {
1575 let file = File::open(path)?;
1576 let mut reader = BufReader::new(file);
1577 let header = RobustPlyReader::read_header(&mut reader)?;
1578
1579 let vertex_element = header
1581 .elements
1582 .iter()
1583 .find(|e| e.name == "vertex")
1584 .ok_or_else(|| Error::InvalidData("No vertex element found in PLY file".to_string()))?;
1585
1586 Ok(Self {
1587 reader,
1588 current_count: vertex_element.count,
1589 current_index: 0,
1590 chunk_size,
1591 buffer: Vec::with_capacity(chunk_size * 12), format: header.format,
1593 })
1594 }
1595}
1596
1597impl Iterator for PlyStreamingReader {
1598 type Item = Result<Point3f>;
1599
1600 fn next(&mut self) -> Option<Self::Item> {
1601 if self.current_index >= self.current_count {
1602 return None;
1603 }
1604
1605 if self.buffer.is_empty() {
1607 let remaining = self.current_count - self.current_index;
1608 let to_read = std::cmp::min(remaining, self.chunk_size);
1609
1610 match self.format {
1611 PlyFormat::Ascii => {
1612 let mut line = String::new();
1614 if let Err(e) = self.reader.read_line(&mut line) {
1615 return Some(Err(Error::Io(e)));
1616 }
1617
1618 let values: Vec<&str> = line.trim().split_whitespace().collect();
1619 if values.len() < 3 {
1620 return Some(Err(Error::InvalidData(
1621 "Not enough coordinates in vertex line".to_string(),
1622 )));
1623 }
1624
1625 let x = match values[0].parse::<f32>() {
1626 Ok(v) => v,
1627 Err(_) => {
1628 return Some(Err(Error::InvalidData(
1629 "Invalid x coordinate".to_string(),
1630 )))
1631 }
1632 };
1633 let y = match values[1].parse::<f32>() {
1634 Ok(v) => v,
1635 Err(_) => {
1636 return Some(Err(Error::InvalidData(
1637 "Invalid y coordinate".to_string(),
1638 )))
1639 }
1640 };
1641 let z = match values[2].parse::<f32>() {
1642 Ok(v) => v,
1643 Err(_) => {
1644 return Some(Err(Error::InvalidData(
1645 "Invalid z coordinate".to_string(),
1646 )))
1647 }
1648 };
1649
1650 self.current_index += 1;
1651 return Some(Ok(Point3f::new(x, y, z)));
1652 }
1653 PlyFormat::BinaryLittleEndian => {
1654 let bytes_per_vertex = 12; let chunk_bytes = to_read * bytes_per_vertex;
1657 self.buffer.resize(chunk_bytes, 0);
1658
1659 if let Err(e) = self.reader.read_exact(&mut self.buffer[..chunk_bytes]) {
1660 return Some(Err(Error::Io(e)));
1661 }
1662 }
1663 PlyFormat::BinaryBigEndian => {
1664 let bytes_per_vertex = 12; let chunk_bytes = to_read * bytes_per_vertex;
1667 self.buffer.resize(chunk_bytes, 0);
1668
1669 if let Err(e) = self.reader.read_exact(&mut self.buffer[..chunk_bytes]) {
1670 return Some(Err(Error::Io(e)));
1671 }
1672 }
1673 }
1674 }
1675
1676 match self.format {
1678 PlyFormat::Ascii => {
1679 unreachable!()
1681 }
1682 PlyFormat::BinaryLittleEndian => {
1683 if self.buffer.len() < 12 {
1684 return Some(Err(Error::InvalidData(
1685 "Insufficient data in buffer".to_string(),
1686 )));
1687 }
1688
1689 let x = f32::from_le_bytes([
1690 self.buffer[0],
1691 self.buffer[1],
1692 self.buffer[2],
1693 self.buffer[3],
1694 ]);
1695 let y = f32::from_le_bytes([
1696 self.buffer[4],
1697 self.buffer[5],
1698 self.buffer[6],
1699 self.buffer[7],
1700 ]);
1701 let z = f32::from_le_bytes([
1702 self.buffer[8],
1703 self.buffer[9],
1704 self.buffer[10],
1705 self.buffer[11],
1706 ]);
1707
1708 self.buffer.drain(0..12);
1710 self.current_index += 1;
1711
1712 Some(Ok(Point3f::new(x, y, z)))
1713 }
1714 PlyFormat::BinaryBigEndian => {
1715 if self.buffer.len() < 12 {
1716 return Some(Err(Error::InvalidData(
1717 "Insufficient data in buffer".to_string(),
1718 )));
1719 }
1720
1721 let x = f32::from_be_bytes([
1722 self.buffer[0],
1723 self.buffer[1],
1724 self.buffer[2],
1725 self.buffer[3],
1726 ]);
1727 let y = f32::from_be_bytes([
1728 self.buffer[4],
1729 self.buffer[5],
1730 self.buffer[6],
1731 self.buffer[7],
1732 ]);
1733 let z = f32::from_be_bytes([
1734 self.buffer[8],
1735 self.buffer[9],
1736 self.buffer[10],
1737 self.buffer[11],
1738 ]);
1739
1740 self.buffer.drain(0..12);
1742 self.current_index += 1;
1743
1744 Some(Ok(Point3f::new(x, y, z)))
1745 }
1746 }
1747 }
1748}
1749
1750pub struct PlyMeshStreamingReader {
1752 reader: BufReader<File>,
1753 current_count: usize,
1754 current_index: usize,
1755 chunk_size: usize,
1756 buffer: Vec<u8>,
1757 format: PlyFormat,
1758 vertices: Vec<Point3f>, }
1760
1761impl PlyMeshStreamingReader {
1762 pub fn new<P: AsRef<Path>>(path: P, chunk_size: usize) -> Result<Self> {
1764 let file = File::open(path)?;
1765 let mut reader = BufReader::new(file);
1766 let header = RobustPlyReader::read_header(&mut reader)?;
1767
1768 let face_element = header
1770 .elements
1771 .iter()
1772 .find(|e| e.name == "face")
1773 .ok_or_else(|| Error::InvalidData("No face element found in PLY file".to_string()))?;
1774
1775 let vertex_element = header
1777 .elements
1778 .iter()
1779 .find(|e| e.name == "vertex")
1780 .ok_or_else(|| Error::InvalidData("No vertex element found in PLY file".to_string()))?;
1781
1782 let mut vertices = Vec::with_capacity(crate::capacity_hint(vertex_element.count));
1783
1784 for _ in 0..vertex_element.count {
1786 let mut line = String::new();
1787 reader.read_line(&mut line)?;
1788 let values: Vec<&str> = line.trim().split_whitespace().collect();
1789 if values.len() >= 3 {
1790 let x = values[0]
1791 .parse::<f32>()
1792 .map_err(|_| Error::InvalidData("Invalid x coordinate".to_string()))?;
1793 let y = values[1]
1794 .parse::<f32>()
1795 .map_err(|_| Error::InvalidData("Invalid y coordinate".to_string()))?;
1796 let z = values[2]
1797 .parse::<f32>()
1798 .map_err(|_| Error::InvalidData("Invalid z coordinate".to_string()))?;
1799 vertices.push(Point3f::new(x, y, z));
1800 }
1801 }
1802
1803 Ok(Self {
1804 reader,
1805 current_count: face_element.count,
1806 current_index: 0,
1807 chunk_size,
1808 buffer: Vec::with_capacity(chunk_size * 16), format: header.format,
1810 vertices,
1811 })
1812 }
1813}
1814
1815impl Iterator for PlyMeshStreamingReader {
1816 type Item = Result<[usize; 3]>;
1817
1818 fn next(&mut self) -> Option<Self::Item> {
1819 if self.current_index >= self.current_count {
1820 return None;
1821 }
1822
1823 if self.buffer.is_empty() {
1825 let remaining = self.current_count - self.current_index;
1826 let to_read = std::cmp::min(remaining, self.chunk_size);
1827
1828 match self.format {
1829 PlyFormat::Ascii => {
1830 let mut line = String::new();
1832 if let Err(e) = self.reader.read_line(&mut line) {
1833 return Some(Err(Error::Io(e)));
1834 }
1835
1836 let values: Vec<&str> = line.trim().split_whitespace().collect();
1837 if values.len() < 4 {
1838 return Some(Err(Error::InvalidData(
1840 "Not enough values in face line".to_string(),
1841 )));
1842 }
1843
1844 let count = match values[0].parse::<usize>() {
1845 Ok(v) => v,
1846 Err(_) => {
1847 return Some(Err(Error::InvalidData("Invalid face count".to_string())))
1848 }
1849 };
1850
1851 if count != 3 {
1852 return Some(Err(Error::InvalidData(
1853 "Only triangular faces supported".to_string(),
1854 )));
1855 }
1856
1857 let i1 = match values[1].parse::<usize>() {
1858 Ok(v) => v,
1859 Err(_) => {
1860 return Some(Err(Error::InvalidData("Invalid face index".to_string())))
1861 }
1862 };
1863 let i2 = match values[2].parse::<usize>() {
1864 Ok(v) => v,
1865 Err(_) => {
1866 return Some(Err(Error::InvalidData("Invalid face index".to_string())))
1867 }
1868 };
1869 let i3 = match values[3].parse::<usize>() {
1870 Ok(v) => v,
1871 Err(_) => {
1872 return Some(Err(Error::InvalidData("Invalid face index".to_string())))
1873 }
1874 };
1875
1876 if i1 >= self.vertices.len()
1878 || i2 >= self.vertices.len()
1879 || i3 >= self.vertices.len()
1880 {
1881 return Some(Err(Error::InvalidData(
1882 "Face index out of range".to_string(),
1883 )));
1884 }
1885
1886 self.current_index += 1;
1887 return Some(Ok([i1, i2, i3]));
1888 }
1889 PlyFormat::BinaryLittleEndian | PlyFormat::BinaryBigEndian => {
1890 let bytes_per_face = 16; let chunk_bytes = to_read * bytes_per_face;
1893 self.buffer.resize(chunk_bytes, 0);
1894
1895 if let Err(e) = self.reader.read_exact(&mut self.buffer[..chunk_bytes]) {
1896 return Some(Err(Error::Io(e)));
1897 }
1898 }
1899 }
1900 }
1901
1902 match self.format {
1904 PlyFormat::Ascii => {
1905 unreachable!()
1907 }
1908 PlyFormat::BinaryLittleEndian => {
1909 if self.buffer.len() < 16 {
1910 return Some(Err(Error::InvalidData(
1911 "Insufficient data in buffer".to_string(),
1912 )));
1913 }
1914
1915 let count = self.buffer[0] as usize;
1916 if count != 3 {
1917 return Some(Err(Error::InvalidData(
1918 "Only triangular faces supported".to_string(),
1919 )));
1920 }
1921
1922 let i1 = u32::from_le_bytes([
1923 self.buffer[1],
1924 self.buffer[2],
1925 self.buffer[3],
1926 self.buffer[4],
1927 ]) as usize;
1928 let i2 = u32::from_le_bytes([
1929 self.buffer[5],
1930 self.buffer[6],
1931 self.buffer[7],
1932 self.buffer[8],
1933 ]) as usize;
1934 let i3 = u32::from_le_bytes([
1935 self.buffer[9],
1936 self.buffer[10],
1937 self.buffer[11],
1938 self.buffer[12],
1939 ]) as usize;
1940
1941 if i1 >= self.vertices.len()
1943 || i2 >= self.vertices.len()
1944 || i3 >= self.vertices.len()
1945 {
1946 return Some(Err(Error::InvalidData(
1947 "Face index out of range".to_string(),
1948 )));
1949 }
1950
1951 self.buffer.drain(0..16);
1953 self.current_index += 1;
1954
1955 Some(Ok([i1, i2, i3]))
1956 }
1957 PlyFormat::BinaryBigEndian => {
1958 if self.buffer.len() < 16 {
1959 return Some(Err(Error::InvalidData(
1960 "Insufficient data in buffer".to_string(),
1961 )));
1962 }
1963
1964 let count = self.buffer[0] as usize;
1965 if count != 3 {
1966 return Some(Err(Error::InvalidData(
1967 "Only triangular faces supported".to_string(),
1968 )));
1969 }
1970
1971 let i1 = u32::from_be_bytes([
1972 self.buffer[1],
1973 self.buffer[2],
1974 self.buffer[3],
1975 self.buffer[4],
1976 ]) as usize;
1977 let i2 = u32::from_be_bytes([
1978 self.buffer[5],
1979 self.buffer[6],
1980 self.buffer[7],
1981 self.buffer[8],
1982 ]) as usize;
1983 let i3 = u32::from_be_bytes([
1984 self.buffer[9],
1985 self.buffer[10],
1986 self.buffer[11],
1987 self.buffer[12],
1988 ]) as usize;
1989
1990 if i1 >= self.vertices.len()
1992 || i2 >= self.vertices.len()
1993 || i3 >= self.vertices.len()
1994 {
1995 return Some(Err(Error::InvalidData(
1996 "Face index out of range".to_string(),
1997 )));
1998 }
1999
2000 self.buffer.drain(0..16);
2002 self.current_index += 1;
2003
2004 Some(Ok([i1, i2, i3]))
2005 }
2006 }
2007 }
2008}