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
1223fn read_positions_fast(path: &Path) -> Result<Option<Vec<Point3f>>> {
1228 use crate::records::{read_ascii_xyz, read_binary_xyz, BinaryXyz, Scalar};
1229 let mut reader = BufReader::new(File::open(path)?);
1230 let header = RobustPlyReader::read_header(&mut reader)?;
1231 let Some(vertex) = header.elements.first().filter(|e| e.name == "vertex") else {
1232 return Ok(None);
1233 };
1234 let mut offset = 0;
1235 let mut found = [None; 3];
1236 for (column, property) in vertex.properties.iter().enumerate() {
1237 let scalar = match property.property_type {
1238 PlyPropertyType::Char => Scalar::I8,
1239 PlyPropertyType::UChar => Scalar::U8,
1240 PlyPropertyType::Short => Scalar::I16,
1241 PlyPropertyType::UShort => Scalar::U16,
1242 PlyPropertyType::Int => Scalar::I32,
1243 PlyPropertyType::UInt => Scalar::U32,
1244 PlyPropertyType::Float => Scalar::F32,
1245 PlyPropertyType::Double => Scalar::F64,
1246 PlyPropertyType::List(..) => return Ok(None),
1247 };
1248 if let Some(axis) = ["x", "y", "z"].iter().position(|n| *n == property.name) {
1249 found[axis] = Some((column, offset, scalar));
1250 }
1251 offset += scalar.size();
1252 }
1253 let [Some(x), Some(y), Some(z)] = found else {
1254 return Err(Error::InvalidData(
1255 "PLY vertex element is missing x, y or z".to_string(),
1256 ));
1257 };
1258 let points = match header.format {
1259 PlyFormat::Ascii => read_ascii_xyz(&mut reader, [x.0, y.0, z.0], vertex.count)?,
1260 PlyFormat::BinaryLittleEndian | PlyFormat::BinaryBigEndian => {
1261 let layout = BinaryXyz {
1262 record_size: offset,
1263 xyz: [(x.1, x.2), (y.1, y.2), (z.1, z.2)],
1264 big_endian: header.format == PlyFormat::BinaryBigEndian,
1265 };
1266 read_binary_xyz(&mut reader, &layout, vertex.count)?
1267 }
1268 };
1269 Ok(Some(points))
1270}
1271
1272impl crate::registry::PointCloudReader for PlyReader {
1273 fn read_point_cloud(&self, path: &Path) -> Result<PointCloud<Point3f>> {
1274 if let Some(points) = read_positions_fast(path)? {
1275 return Ok(PointCloud::from_points(points));
1276 }
1277 let ply_data = RobustPlyReader::read_ply_file(path)?;
1279
1280 let mut points = Vec::new();
1281
1282 if let Some(vertex_elements) = ply_data.elements.get("vertex") {
1283 for vertex in vertex_elements {
1284 let x = vertex
1285 .get("x")
1286 .ok_or_else(|| Error::InvalidData("Missing x coordinate".to_string()))?
1287 .as_f32()?;
1288 let y = vertex
1289 .get("y")
1290 .ok_or_else(|| Error::InvalidData("Missing y coordinate".to_string()))?
1291 .as_f32()?;
1292 let z = vertex
1293 .get("z")
1294 .ok_or_else(|| Error::InvalidData("Missing z coordinate".to_string()))?
1295 .as_f32()?;
1296
1297 points.push(Point3f::new(x, y, z));
1298 }
1299 }
1300
1301 Ok(PointCloud::from_points(points))
1302 }
1303
1304 fn can_read(&self, path: &Path) -> bool {
1305 if let Ok(mut file) = File::open(path) {
1307 let mut header = [0u8; 4];
1308 if let Ok(_) = file.read(&mut header) {
1309 return header.starts_with(b"ply");
1310 }
1311 }
1312 false
1313 }
1314
1315 fn format_name(&self) -> &'static str {
1316 "ply"
1317 }
1318}
1319
1320impl crate::registry::MeshReader for PlyReader {
1321 fn read_mesh(&self, path: &Path) -> Result<TriangleMesh> {
1322 let ply_data = RobustPlyReader::read_ply_file(path)?;
1323
1324 let mut vertices = Vec::new();
1326 if let Some(vertex_elements) = ply_data.elements.get("vertex") {
1327 for vertex in vertex_elements {
1328 let x = vertex
1329 .get("x")
1330 .ok_or_else(|| Error::InvalidData("Missing x coordinate".to_string()))?
1331 .as_f32()?;
1332 let y = vertex
1333 .get("y")
1334 .ok_or_else(|| Error::InvalidData("Missing y coordinate".to_string()))?
1335 .as_f32()?;
1336 let z = vertex
1337 .get("z")
1338 .ok_or_else(|| Error::InvalidData("Missing z coordinate".to_string()))?
1339 .as_f32()?;
1340
1341 vertices.push(Point3f::new(x, y, z));
1342 }
1343 }
1344
1345 let mut faces = Vec::new();
1347 if let Some(face_elements) = ply_data.elements.get("face") {
1348 for face in face_elements {
1349 let indices = if let Some(vertex_indices) = face.get("vertex_indices") {
1351 vertex_indices.as_usize_list()?
1352 } else if let Some(vertex_index) = face.get("vertex_index") {
1353 vertex_index.as_usize_list()?
1354 } else {
1355 return Err(Error::InvalidData(
1356 "Face missing vertex indices".to_string(),
1357 ));
1358 };
1359
1360 if indices.len() >= 3 {
1362 faces.push([indices[0], indices[1], indices[2]]);
1363 }
1364 if indices.len() == 4 {
1366 faces.push([indices[0], indices[2], indices[3]]);
1367 }
1368 }
1369 }
1370
1371 let normals = if let Some(vertex_elements) = ply_data.elements.get("vertex") {
1373 let mut normals = Vec::new();
1374 let mut has_normals = true;
1375
1376 for vertex in vertex_elements {
1377 if let (Some(nx), Some(ny), Some(nz)) =
1378 (vertex.get("nx"), vertex.get("ny"), vertex.get("nz"))
1379 {
1380 normals.push(Vector3f::new(nx.as_f32()?, ny.as_f32()?, nz.as_f32()?));
1381 } else {
1382 has_normals = false;
1383 break;
1384 }
1385 }
1386
1387 if has_normals {
1388 Some(normals)
1389 } else {
1390 None
1391 }
1392 } else {
1393 None
1394 };
1395
1396 let mut mesh = TriangleMesh::from_vertices_and_faces(vertices, faces);
1397 if let Some(normals) = normals {
1398 mesh.set_normals(normals);
1399 }
1400
1401 Ok(mesh)
1402 }
1403
1404 fn can_read(&self, path: &Path) -> bool {
1405 if let Ok(mut file) = File::open(path) {
1407 let mut header = [0u8; 4];
1408 if let Ok(_) = file.read(&mut header) {
1409 return header.starts_with(b"ply");
1410 }
1411 }
1412 false
1413 }
1414
1415 fn format_name(&self) -> &'static str {
1416 "ply"
1417 }
1418}
1419
1420impl crate::registry::PointCloudWriter for PlyWriter {
1421 fn write_point_cloud(&self, cloud: &PointCloud<Point3f>, path: &Path) -> Result<()> {
1422 use ply_rs::{
1424 ply::{
1425 Addable, DefaultElement, ElementDef, Ply, Property, PropertyDef, PropertyType,
1426 ScalarType,
1427 },
1428 writer::Writer,
1429 };
1430
1431 let file = File::create(path)?;
1432 let mut writer = BufWriter::new(file);
1433
1434 let mut ply = Ply::<DefaultElement>::new();
1436
1437 let mut vertex_element = ElementDef::new("vertex".to_string());
1439 vertex_element.count = cloud.len();
1440 vertex_element.properties.add(PropertyDef::new(
1441 "x".to_string(),
1442 PropertyType::Scalar(ScalarType::Float),
1443 ));
1444 vertex_element.properties.add(PropertyDef::new(
1445 "y".to_string(),
1446 PropertyType::Scalar(ScalarType::Float),
1447 ));
1448 vertex_element.properties.add(PropertyDef::new(
1449 "z".to_string(),
1450 PropertyType::Scalar(ScalarType::Float),
1451 ));
1452
1453 ply.header.elements.add(vertex_element);
1454
1455 let mut vertices = Vec::new();
1457 for point in &cloud.points {
1458 let mut vertex = DefaultElement::new();
1459 vertex.insert("x".to_string(), Property::Float(point.x));
1460 vertex.insert("y".to_string(), Property::Float(point.y));
1461 vertex.insert("z".to_string(), Property::Float(point.z));
1462 vertices.push(vertex);
1463 }
1464 ply.payload.insert("vertex".to_string(), vertices);
1465
1466 let writer_instance = Writer::new();
1468 writer_instance.write_ply(&mut writer, &mut ply)?;
1469
1470 Ok(())
1471 }
1472
1473 fn format_name(&self) -> &'static str {
1474 "ply"
1475 }
1476}
1477
1478impl crate::registry::MeshWriter for PlyWriter {
1479 fn write_mesh(&self, mesh: &TriangleMesh, path: &Path) -> Result<()> {
1480 use ply_rs::{
1482 ply::{
1483 Addable, DefaultElement, ElementDef, Ply, Property, PropertyDef, PropertyType,
1484 ScalarType,
1485 },
1486 writer::Writer,
1487 };
1488
1489 let file = File::create(path)?;
1490 let mut writer = BufWriter::new(file);
1491
1492 let mut ply = Ply::<DefaultElement>::new();
1494
1495 let mut vertex_element = ElementDef::new("vertex".to_string());
1497 vertex_element.count = mesh.vertices.len();
1498 vertex_element.properties.add(PropertyDef::new(
1499 "x".to_string(),
1500 PropertyType::Scalar(ScalarType::Float),
1501 ));
1502 vertex_element.properties.add(PropertyDef::new(
1503 "y".to_string(),
1504 PropertyType::Scalar(ScalarType::Float),
1505 ));
1506 vertex_element.properties.add(PropertyDef::new(
1507 "z".to_string(),
1508 PropertyType::Scalar(ScalarType::Float),
1509 ));
1510
1511 if mesh.normals.is_some() {
1513 vertex_element.properties.add(PropertyDef::new(
1514 "nx".to_string(),
1515 PropertyType::Scalar(ScalarType::Float),
1516 ));
1517 vertex_element.properties.add(PropertyDef::new(
1518 "ny".to_string(),
1519 PropertyType::Scalar(ScalarType::Float),
1520 ));
1521 vertex_element.properties.add(PropertyDef::new(
1522 "nz".to_string(),
1523 PropertyType::Scalar(ScalarType::Float),
1524 ));
1525 }
1526
1527 ply.header.elements.add(vertex_element);
1528
1529 let mut vertices = Vec::new();
1531 for (i, point) in mesh.vertices.iter().enumerate() {
1532 let mut vertex = DefaultElement::new();
1533 vertex.insert("x".to_string(), Property::Float(point.x));
1534 vertex.insert("y".to_string(), Property::Float(point.y));
1535 vertex.insert("z".to_string(), Property::Float(point.z));
1536
1537 if let Some(ref normals) = mesh.normals {
1539 if i < normals.len() {
1540 vertex.insert("nx".to_string(), Property::Float(normals[i].x));
1541 vertex.insert("ny".to_string(), Property::Float(normals[i].y));
1542 vertex.insert("nz".to_string(), Property::Float(normals[i].z));
1543 }
1544 }
1545
1546 vertices.push(vertex);
1547 }
1548 ply.payload.insert("vertex".to_string(), vertices);
1549
1550 if !mesh.faces.is_empty() {
1552 let mut face_element = ElementDef::new("face".to_string());
1553 face_element.count = mesh.faces.len();
1554 face_element.properties.add(PropertyDef::new(
1555 "vertex_indices".to_string(),
1556 PropertyType::List(ScalarType::UChar, ScalarType::Int),
1557 ));
1558
1559 ply.header.elements.add(face_element);
1560
1561 let mut faces = Vec::new();
1563 for face in &mesh.faces {
1564 let mut face_data = DefaultElement::new();
1565 let indices = vec![face[0] as i32, face[1] as i32, face[2] as i32];
1566 face_data.insert("vertex_indices".to_string(), Property::ListInt(indices));
1567 faces.push(face_data);
1568 }
1569 ply.payload.insert("face".to_string(), faces);
1570 }
1571
1572 let writer_instance = Writer::new();
1574 writer_instance.write_ply(&mut writer, &mut ply)?;
1575
1576 Ok(())
1577 }
1578
1579 fn format_name(&self) -> &'static str {
1580 "ply"
1581 }
1582}
1583
1584impl PointCloudReader for PlyReader {
1586 fn read_point_cloud<P: AsRef<Path>>(path: P) -> Result<PointCloud<Point3f>> {
1587 let reader = PlyReader;
1588 crate::registry::PointCloudReader::read_point_cloud(&reader, path.as_ref())
1589 }
1590}
1591
1592impl MeshReader for PlyReader {
1593 fn read_mesh<P: AsRef<Path>>(path: P) -> Result<TriangleMesh> {
1594 let reader = PlyReader;
1595 crate::registry::MeshReader::read_mesh(&reader, path.as_ref())
1596 }
1597}
1598
1599impl PointCloudWriter for PlyWriter {
1600 fn write_point_cloud<P: AsRef<Path>>(cloud: &PointCloud<Point3f>, path: P) -> Result<()> {
1601 let writer = PlyWriter;
1602 crate::registry::PointCloudWriter::write_point_cloud(&writer, cloud, path.as_ref())
1603 }
1604}
1605
1606impl MeshWriter for PlyWriter {
1607 fn write_mesh<P: AsRef<Path>>(mesh: &TriangleMesh, path: P) -> Result<()> {
1608 let writer = PlyWriter;
1609 crate::registry::MeshWriter::write_mesh(&writer, mesh, path.as_ref())
1610 }
1611}
1612
1613pub struct PlyStreamingReader {
1615 reader: BufReader<File>,
1616 current_count: usize,
1617 current_index: usize,
1618 chunk_size: usize,
1619 buffer: Vec<u8>,
1620 format: PlyFormat,
1621}
1622
1623impl PlyStreamingReader {
1624 pub fn new<P: AsRef<Path>>(path: P, chunk_size: usize) -> Result<Self> {
1626 let file = File::open(path)?;
1627 let mut reader = BufReader::new(file);
1628 let header = RobustPlyReader::read_header(&mut reader)?;
1629
1630 let vertex_element = header
1632 .elements
1633 .iter()
1634 .find(|e| e.name == "vertex")
1635 .ok_or_else(|| Error::InvalidData("No vertex element found in PLY file".to_string()))?;
1636
1637 Ok(Self {
1638 reader,
1639 current_count: vertex_element.count,
1640 current_index: 0,
1641 chunk_size,
1642 buffer: Vec::with_capacity(chunk_size * 12), format: header.format,
1644 })
1645 }
1646}
1647
1648impl Iterator for PlyStreamingReader {
1649 type Item = Result<Point3f>;
1650
1651 fn next(&mut self) -> Option<Self::Item> {
1652 if self.current_index >= self.current_count {
1653 return None;
1654 }
1655
1656 if self.buffer.is_empty() {
1658 let remaining = self.current_count - self.current_index;
1659 let to_read = std::cmp::min(remaining, self.chunk_size);
1660
1661 match self.format {
1662 PlyFormat::Ascii => {
1663 let mut line = String::new();
1665 if let Err(e) = self.reader.read_line(&mut line) {
1666 return Some(Err(Error::Io(e)));
1667 }
1668
1669 let values: Vec<&str> = line.trim().split_whitespace().collect();
1670 if values.len() < 3 {
1671 return Some(Err(Error::InvalidData(
1672 "Not enough coordinates in vertex line".to_string(),
1673 )));
1674 }
1675
1676 let x = match values[0].parse::<f32>() {
1677 Ok(v) => v,
1678 Err(_) => {
1679 return Some(Err(Error::InvalidData(
1680 "Invalid x coordinate".to_string(),
1681 )))
1682 }
1683 };
1684 let y = match values[1].parse::<f32>() {
1685 Ok(v) => v,
1686 Err(_) => {
1687 return Some(Err(Error::InvalidData(
1688 "Invalid y coordinate".to_string(),
1689 )))
1690 }
1691 };
1692 let z = match values[2].parse::<f32>() {
1693 Ok(v) => v,
1694 Err(_) => {
1695 return Some(Err(Error::InvalidData(
1696 "Invalid z coordinate".to_string(),
1697 )))
1698 }
1699 };
1700
1701 self.current_index += 1;
1702 return Some(Ok(Point3f::new(x, y, z)));
1703 }
1704 PlyFormat::BinaryLittleEndian => {
1705 let bytes_per_vertex = 12; let chunk_bytes = to_read * bytes_per_vertex;
1708 self.buffer.resize(chunk_bytes, 0);
1709
1710 if let Err(e) = self.reader.read_exact(&mut self.buffer[..chunk_bytes]) {
1711 return Some(Err(Error::Io(e)));
1712 }
1713 }
1714 PlyFormat::BinaryBigEndian => {
1715 let bytes_per_vertex = 12; let chunk_bytes = to_read * bytes_per_vertex;
1718 self.buffer.resize(chunk_bytes, 0);
1719
1720 if let Err(e) = self.reader.read_exact(&mut self.buffer[..chunk_bytes]) {
1721 return Some(Err(Error::Io(e)));
1722 }
1723 }
1724 }
1725 }
1726
1727 match self.format {
1729 PlyFormat::Ascii => {
1730 unreachable!()
1732 }
1733 PlyFormat::BinaryLittleEndian => {
1734 if self.buffer.len() < 12 {
1735 return Some(Err(Error::InvalidData(
1736 "Insufficient data in buffer".to_string(),
1737 )));
1738 }
1739
1740 let x = f32::from_le_bytes([
1741 self.buffer[0],
1742 self.buffer[1],
1743 self.buffer[2],
1744 self.buffer[3],
1745 ]);
1746 let y = f32::from_le_bytes([
1747 self.buffer[4],
1748 self.buffer[5],
1749 self.buffer[6],
1750 self.buffer[7],
1751 ]);
1752 let z = f32::from_le_bytes([
1753 self.buffer[8],
1754 self.buffer[9],
1755 self.buffer[10],
1756 self.buffer[11],
1757 ]);
1758
1759 self.buffer.drain(0..12);
1761 self.current_index += 1;
1762
1763 Some(Ok(Point3f::new(x, y, z)))
1764 }
1765 PlyFormat::BinaryBigEndian => {
1766 if self.buffer.len() < 12 {
1767 return Some(Err(Error::InvalidData(
1768 "Insufficient data in buffer".to_string(),
1769 )));
1770 }
1771
1772 let x = f32::from_be_bytes([
1773 self.buffer[0],
1774 self.buffer[1],
1775 self.buffer[2],
1776 self.buffer[3],
1777 ]);
1778 let y = f32::from_be_bytes([
1779 self.buffer[4],
1780 self.buffer[5],
1781 self.buffer[6],
1782 self.buffer[7],
1783 ]);
1784 let z = f32::from_be_bytes([
1785 self.buffer[8],
1786 self.buffer[9],
1787 self.buffer[10],
1788 self.buffer[11],
1789 ]);
1790
1791 self.buffer.drain(0..12);
1793 self.current_index += 1;
1794
1795 Some(Ok(Point3f::new(x, y, z)))
1796 }
1797 }
1798 }
1799}
1800
1801pub struct PlyMeshStreamingReader {
1803 reader: BufReader<File>,
1804 current_count: usize,
1805 current_index: usize,
1806 chunk_size: usize,
1807 buffer: Vec<u8>,
1808 format: PlyFormat,
1809 vertices: Vec<Point3f>, }
1811
1812impl PlyMeshStreamingReader {
1813 pub fn new<P: AsRef<Path>>(path: P, chunk_size: usize) -> Result<Self> {
1815 let file = File::open(path)?;
1816 let mut reader = BufReader::new(file);
1817 let header = RobustPlyReader::read_header(&mut reader)?;
1818
1819 let face_element = header
1821 .elements
1822 .iter()
1823 .find(|e| e.name == "face")
1824 .ok_or_else(|| Error::InvalidData("No face element found in PLY file".to_string()))?;
1825
1826 let vertex_element = header
1828 .elements
1829 .iter()
1830 .find(|e| e.name == "vertex")
1831 .ok_or_else(|| Error::InvalidData("No vertex element found in PLY file".to_string()))?;
1832
1833 let mut vertices = Vec::with_capacity(crate::capacity_hint(vertex_element.count));
1834
1835 for _ in 0..vertex_element.count {
1837 let mut line = String::new();
1838 reader.read_line(&mut line)?;
1839 let values: Vec<&str> = line.trim().split_whitespace().collect();
1840 if values.len() >= 3 {
1841 let x = values[0]
1842 .parse::<f32>()
1843 .map_err(|_| Error::InvalidData("Invalid x coordinate".to_string()))?;
1844 let y = values[1]
1845 .parse::<f32>()
1846 .map_err(|_| Error::InvalidData("Invalid y coordinate".to_string()))?;
1847 let z = values[2]
1848 .parse::<f32>()
1849 .map_err(|_| Error::InvalidData("Invalid z coordinate".to_string()))?;
1850 vertices.push(Point3f::new(x, y, z));
1851 }
1852 }
1853
1854 Ok(Self {
1855 reader,
1856 current_count: face_element.count,
1857 current_index: 0,
1858 chunk_size,
1859 buffer: Vec::with_capacity(chunk_size * 16), format: header.format,
1861 vertices,
1862 })
1863 }
1864}
1865
1866impl Iterator for PlyMeshStreamingReader {
1867 type Item = Result<[usize; 3]>;
1868
1869 fn next(&mut self) -> Option<Self::Item> {
1870 if self.current_index >= self.current_count {
1871 return None;
1872 }
1873
1874 if self.buffer.is_empty() {
1876 let remaining = self.current_count - self.current_index;
1877 let to_read = std::cmp::min(remaining, self.chunk_size);
1878
1879 match self.format {
1880 PlyFormat::Ascii => {
1881 let mut line = String::new();
1883 if let Err(e) = self.reader.read_line(&mut line) {
1884 return Some(Err(Error::Io(e)));
1885 }
1886
1887 let values: Vec<&str> = line.trim().split_whitespace().collect();
1888 if values.len() < 4 {
1889 return Some(Err(Error::InvalidData(
1891 "Not enough values in face line".to_string(),
1892 )));
1893 }
1894
1895 let count = match values[0].parse::<usize>() {
1896 Ok(v) => v,
1897 Err(_) => {
1898 return Some(Err(Error::InvalidData("Invalid face count".to_string())))
1899 }
1900 };
1901
1902 if count != 3 {
1903 return Some(Err(Error::InvalidData(
1904 "Only triangular faces supported".to_string(),
1905 )));
1906 }
1907
1908 let i1 = match values[1].parse::<usize>() {
1909 Ok(v) => v,
1910 Err(_) => {
1911 return Some(Err(Error::InvalidData("Invalid face index".to_string())))
1912 }
1913 };
1914 let i2 = match values[2].parse::<usize>() {
1915 Ok(v) => v,
1916 Err(_) => {
1917 return Some(Err(Error::InvalidData("Invalid face index".to_string())))
1918 }
1919 };
1920 let i3 = match values[3].parse::<usize>() {
1921 Ok(v) => v,
1922 Err(_) => {
1923 return Some(Err(Error::InvalidData("Invalid face index".to_string())))
1924 }
1925 };
1926
1927 if i1 >= self.vertices.len()
1929 || i2 >= self.vertices.len()
1930 || i3 >= self.vertices.len()
1931 {
1932 return Some(Err(Error::InvalidData(
1933 "Face index out of range".to_string(),
1934 )));
1935 }
1936
1937 self.current_index += 1;
1938 return Some(Ok([i1, i2, i3]));
1939 }
1940 PlyFormat::BinaryLittleEndian | PlyFormat::BinaryBigEndian => {
1941 let bytes_per_face = 16; let chunk_bytes = to_read * bytes_per_face;
1944 self.buffer.resize(chunk_bytes, 0);
1945
1946 if let Err(e) = self.reader.read_exact(&mut self.buffer[..chunk_bytes]) {
1947 return Some(Err(Error::Io(e)));
1948 }
1949 }
1950 }
1951 }
1952
1953 match self.format {
1955 PlyFormat::Ascii => {
1956 unreachable!()
1958 }
1959 PlyFormat::BinaryLittleEndian => {
1960 if self.buffer.len() < 16 {
1961 return Some(Err(Error::InvalidData(
1962 "Insufficient data in buffer".to_string(),
1963 )));
1964 }
1965
1966 let count = self.buffer[0] as usize;
1967 if count != 3 {
1968 return Some(Err(Error::InvalidData(
1969 "Only triangular faces supported".to_string(),
1970 )));
1971 }
1972
1973 let i1 = u32::from_le_bytes([
1974 self.buffer[1],
1975 self.buffer[2],
1976 self.buffer[3],
1977 self.buffer[4],
1978 ]) as usize;
1979 let i2 = u32::from_le_bytes([
1980 self.buffer[5],
1981 self.buffer[6],
1982 self.buffer[7],
1983 self.buffer[8],
1984 ]) as usize;
1985 let i3 = u32::from_le_bytes([
1986 self.buffer[9],
1987 self.buffer[10],
1988 self.buffer[11],
1989 self.buffer[12],
1990 ]) as usize;
1991
1992 if i1 >= self.vertices.len()
1994 || i2 >= self.vertices.len()
1995 || i3 >= self.vertices.len()
1996 {
1997 return Some(Err(Error::InvalidData(
1998 "Face index out of range".to_string(),
1999 )));
2000 }
2001
2002 self.buffer.drain(0..16);
2004 self.current_index += 1;
2005
2006 Some(Ok([i1, i2, i3]))
2007 }
2008 PlyFormat::BinaryBigEndian => {
2009 if self.buffer.len() < 16 {
2010 return Some(Err(Error::InvalidData(
2011 "Insufficient data in buffer".to_string(),
2012 )));
2013 }
2014
2015 let count = self.buffer[0] as usize;
2016 if count != 3 {
2017 return Some(Err(Error::InvalidData(
2018 "Only triangular faces supported".to_string(),
2019 )));
2020 }
2021
2022 let i1 = u32::from_be_bytes([
2023 self.buffer[1],
2024 self.buffer[2],
2025 self.buffer[3],
2026 self.buffer[4],
2027 ]) as usize;
2028 let i2 = u32::from_be_bytes([
2029 self.buffer[5],
2030 self.buffer[6],
2031 self.buffer[7],
2032 self.buffer[8],
2033 ]) as usize;
2034 let i3 = u32::from_be_bytes([
2035 self.buffer[9],
2036 self.buffer[10],
2037 self.buffer[11],
2038 self.buffer[12],
2039 ]) as usize;
2040
2041 if i1 >= self.vertices.len()
2043 || i2 >= self.vertices.len()
2044 || i3 >= self.vertices.len()
2045 {
2046 return Some(Err(Error::InvalidData(
2047 "Face index out of range".to_string(),
2048 )));
2049 }
2050
2051 self.buffer.drain(0..16);
2053 self.current_index += 1;
2054
2055 Some(Ok([i1, i2, i3]))
2056 }
2057 }
2058 }
2059}