1use crate::{PointCloudReader, PointCloudWriter, MeshReader, MeshWriter};
12use threecrate_core::{PointCloud, TriangleMesh, Result, Point3f, Vector3f, Error};
13use std::path::Path;
14use std::fs::File;
15use std::io::{BufRead, BufReader, BufWriter, Read};
16use std::collections::HashMap;
17use byteorder::{LittleEndian, BigEndian, ReadBytesExt};
18#[cfg(feature = "io-mmap")]
19use crate::mmap::MmapReader;
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>>(mut self, name: S, values: Vec<PlyValue>) -> Self {
185 self.custom_vertex_properties.push((name.into(), values));
186 self
187 }
188}
189
190pub struct RobustPlyWriter;
192
193impl RobustPlyWriter {
194 pub fn write_point_cloud<P: AsRef<Path>>(
196 cloud: &PointCloud<Point3f>,
197 path: P,
198 options: &PlyWriteOptions
199 ) -> Result<()> {
200 let file = File::create(path)?;
201 let mut writer = BufWriter::new(file);
202 Self::write_point_cloud_to_writer(cloud, &mut writer, options)
203 }
204
205 pub fn write_point_cloud_to_writer<W: std::io::Write>(
207 cloud: &PointCloud<Point3f>,
208 writer: &mut W,
209 options: &PlyWriteOptions,
210 ) -> Result<()> {
211 let mut ply_data = PlyData {
213 header: PlyHeader {
214 format: options.format,
215 version: "1.0".to_string(),
216 elements: Vec::new(),
217 comments: options.comments.clone(),
218 obj_info: options.obj_info.clone(),
219 },
220 elements: HashMap::new(),
221 };
222
223 let mut vertex_properties = Vec::new();
225 let mut vertex_data = Vec::new();
226
227 vertex_properties.push(PlyProperty {
229 name: "x".to_string(),
230 property_type: PlyPropertyType::Float,
231 });
232 vertex_properties.push(PlyProperty {
233 name: "y".to_string(),
234 property_type: PlyPropertyType::Float,
235 });
236 vertex_properties.push(PlyProperty {
237 name: "z".to_string(),
238 property_type: PlyPropertyType::Float,
239 });
240
241 for (prop_name, _) in &options.custom_vertex_properties {
243 if let Some(first_values) = options.custom_vertex_properties.iter()
245 .find(|(name, _)| name == prop_name)
246 .map(|(_, values)| values)
247 {
248 if let Some(first_value) = first_values.first() {
249 let prop_type = Self::value_to_property_type(first_value);
250 vertex_properties.push(PlyProperty {
251 name: prop_name.clone(),
252 property_type: prop_type,
253 });
254 }
255 }
256 }
257
258 if let Some(order) = &options.vertex_property_order {
260 vertex_properties.sort_by_key(|prop| {
261 order.iter().position(|name| name == &prop.name)
262 .unwrap_or(order.len())
263 });
264 }
265
266 for (i, point) in cloud.iter().enumerate() {
268 let mut vertex_instance = HashMap::new();
269 vertex_instance.insert("x".to_string(), PlyValue::Float(point.x));
270 vertex_instance.insert("y".to_string(), PlyValue::Float(point.y));
271 vertex_instance.insert("z".to_string(), PlyValue::Float(point.z));
272
273 for (prop_name, values) in &options.custom_vertex_properties {
275 if i < values.len() {
276 vertex_instance.insert(prop_name.clone(), values[i].clone());
277 }
278 }
279
280 vertex_data.push(vertex_instance);
281 }
282
283 ply_data.header.elements.push(PlyElement {
285 name: "vertex".to_string(),
286 count: cloud.len(),
287 properties: vertex_properties,
288 });
289 ply_data.elements.insert("vertex".to_string(), vertex_data);
290
291 Self::write_ply_data(writer, &ply_data)
293 }
294
295 pub fn write_mesh<P: AsRef<Path>>(
297 mesh: &TriangleMesh,
298 path: P,
299 options: &PlyWriteOptions,
300 ) -> Result<()> {
301 let file = File::create(path)?;
302 let mut writer = BufWriter::new(file);
303 Self::write_mesh_to_writer(mesh, &mut writer, options)
304 }
305
306 pub fn write_mesh_to_writer<W: std::io::Write>(
308 mesh: &TriangleMesh,
309 writer: &mut W,
310 options: &PlyWriteOptions,
311 ) -> Result<()> {
312 let mut ply_data = PlyData {
314 header: PlyHeader {
315 format: options.format,
316 version: "1.0".to_string(),
317 elements: Vec::new(),
318 comments: options.comments.clone(),
319 obj_info: options.obj_info.clone(),
320 },
321 elements: HashMap::new(),
322 };
323
324 let mut vertex_properties = Vec::new();
326 let mut vertex_data = Vec::new();
327
328 vertex_properties.push(PlyProperty {
330 name: "x".to_string(),
331 property_type: PlyPropertyType::Float,
332 });
333 vertex_properties.push(PlyProperty {
334 name: "y".to_string(),
335 property_type: PlyPropertyType::Float,
336 });
337 vertex_properties.push(PlyProperty {
338 name: "z".to_string(),
339 property_type: PlyPropertyType::Float,
340 });
341
342 if options.include_normals && mesh.normals.is_some() {
344 vertex_properties.push(PlyProperty {
345 name: "nx".to_string(),
346 property_type: PlyPropertyType::Float,
347 });
348 vertex_properties.push(PlyProperty {
349 name: "ny".to_string(),
350 property_type: PlyPropertyType::Float,
351 });
352 vertex_properties.push(PlyProperty {
353 name: "nz".to_string(),
354 property_type: PlyPropertyType::Float,
355 });
356 }
357
358 for (prop_name, _) in &options.custom_vertex_properties {
360 if let Some(first_values) = options.custom_vertex_properties.iter()
361 .find(|(name, _)| name == prop_name)
362 .map(|(_, values)| values)
363 {
364 if let Some(first_value) = first_values.first() {
365 let prop_type = Self::value_to_property_type(first_value);
366 vertex_properties.push(PlyProperty {
367 name: prop_name.clone(),
368 property_type: prop_type,
369 });
370 }
371 }
372 }
373
374 if let Some(order) = &options.vertex_property_order {
376 vertex_properties.sort_by_key(|prop| {
377 order.iter().position(|name| name == &prop.name)
378 .unwrap_or(order.len())
379 });
380 }
381
382 for (i, vertex) in mesh.vertices.iter().enumerate() {
384 let mut vertex_instance = HashMap::new();
385 vertex_instance.insert("x".to_string(), PlyValue::Float(vertex.x));
386 vertex_instance.insert("y".to_string(), PlyValue::Float(vertex.y));
387 vertex_instance.insert("z".to_string(), PlyValue::Float(vertex.z));
388
389 if options.include_normals {
391 if let Some(normals) = &mesh.normals {
392 if i < normals.len() {
393 vertex_instance.insert("nx".to_string(), PlyValue::Float(normals[i].x));
394 vertex_instance.insert("ny".to_string(), PlyValue::Float(normals[i].y));
395 vertex_instance.insert("nz".to_string(), PlyValue::Float(normals[i].z));
396 }
397 }
398 }
399
400 for (prop_name, values) in &options.custom_vertex_properties {
402 if i < values.len() {
403 vertex_instance.insert(prop_name.clone(), values[i].clone());
404 }
405 }
406
407 vertex_data.push(vertex_instance);
408 }
409
410 ply_data.header.elements.push(PlyElement {
412 name: "vertex".to_string(),
413 count: mesh.vertices.len(),
414 properties: vertex_properties,
415 });
416 ply_data.elements.insert("vertex".to_string(), vertex_data);
417
418 if !mesh.faces.is_empty() {
420 let face_properties = vec![
421 PlyProperty {
422 name: "vertex_indices".to_string(),
423 property_type: PlyPropertyType::List(
424 Box::new(PlyPropertyType::UChar),
425 Box::new(PlyPropertyType::Int),
426 ),
427 },
428 ];
429
430 let mut face_data = Vec::new();
431 for face in &mesh.faces {
432 let mut face_instance = HashMap::new();
433 let indices = vec![
434 PlyValue::Int(face[0] as i32),
435 PlyValue::Int(face[1] as i32),
436 PlyValue::Int(face[2] as i32),
437 ];
438 face_instance.insert("vertex_indices".to_string(), PlyValue::List(indices));
439 face_data.push(face_instance);
440 }
441
442 ply_data.header.elements.push(PlyElement {
443 name: "face".to_string(),
444 count: mesh.faces.len(),
445 properties: face_properties,
446 });
447 ply_data.elements.insert("face".to_string(), face_data);
448 }
449
450 Self::write_ply_data(writer, &ply_data)
452 }
453
454 fn write_ply_data<W: std::io::Write>(writer: &mut W, ply_data: &PlyData) -> Result<()> {
456 Self::write_header(writer, &ply_data.header)?;
458
459 match ply_data.header.format {
461 PlyFormat::Ascii => Self::write_ascii_data(writer, ply_data)?,
462 PlyFormat::BinaryLittleEndian => Self::write_binary_data::<LittleEndian, _>(writer, ply_data)?,
463 PlyFormat::BinaryBigEndian => Self::write_binary_data::<BigEndian, _>(writer, ply_data)?,
464 }
465
466 Ok(())
467 }
468
469 fn write_header<W: std::io::Write>(writer: &mut W, header: &PlyHeader) -> Result<()> {
471 writeln!(writer, "ply")?;
472
473 let format_str = match header.format {
474 PlyFormat::Ascii => "ascii",
475 PlyFormat::BinaryLittleEndian => "binary_little_endian",
476 PlyFormat::BinaryBigEndian => "binary_big_endian",
477 };
478 writeln!(writer, "format {} {}", format_str, header.version)?;
479
480 for comment in &header.comments {
482 writeln!(writer, "comment {}", comment)?;
483 }
484
485 for info in &header.obj_info {
487 writeln!(writer, "obj_info {}", info)?;
488 }
489
490 for element in &header.elements {
492 writeln!(writer, "element {} {}", element.name, element.count)?;
493 for property in &element.properties {
494 Self::write_property_definition(writer, property)?;
495 }
496 }
497
498 writeln!(writer, "end_header")?;
499 Ok(())
500 }
501
502 fn write_property_definition<W: std::io::Write>(writer: &mut W, property: &PlyProperty) -> Result<()> {
504 match &property.property_type {
505 PlyPropertyType::List(count_type, item_type) => {
506 let count_str = Self::property_type_to_string(count_type);
507 let item_str = Self::property_type_to_string(item_type);
508 writeln!(writer, "property list {} {} {}", count_str, item_str, property.name)?;
509 }
510 _ => {
511 let type_str = Self::property_type_to_string(&property.property_type);
512 writeln!(writer, "property {} {}", type_str, property.name)?;
513 }
514 }
515 Ok(())
516 }
517
518 fn property_type_to_string(prop_type: &PlyPropertyType) -> &'static str {
520 match prop_type {
521 PlyPropertyType::Char => "char",
522 PlyPropertyType::UChar => "uchar",
523 PlyPropertyType::Short => "short",
524 PlyPropertyType::UShort => "ushort",
525 PlyPropertyType::Int => "int",
526 PlyPropertyType::UInt => "uint",
527 PlyPropertyType::Float => "float",
528 PlyPropertyType::Double => "double",
529 PlyPropertyType::List(_, _) => "list", }
531 }
532
533 fn write_ascii_data<W: std::io::Write>(writer: &mut W, ply_data: &PlyData) -> Result<()> {
535 for element_def in &ply_data.header.elements {
536 if let Some(element_data) = ply_data.elements.get(&element_def.name) {
537 for instance in element_data {
538 let mut values = Vec::new();
539
540 for property in &element_def.properties {
541 if let Some(value) = instance.get(&property.name) {
542 Self::format_ascii_value(value, &mut values)?;
543 }
544 }
545
546 writeln!(writer, "{}", values.join(" "))?;
547 }
548 }
549 }
550 Ok(())
551 }
552
553 fn format_ascii_value(value: &PlyValue, output: &mut Vec<String>) -> Result<()> {
555 match value {
556 PlyValue::Char(v) => output.push(v.to_string()),
557 PlyValue::UChar(v) => output.push(v.to_string()),
558 PlyValue::Short(v) => output.push(v.to_string()),
559 PlyValue::UShort(v) => output.push(v.to_string()),
560 PlyValue::Int(v) => output.push(v.to_string()),
561 PlyValue::UInt(v) => output.push(v.to_string()),
562 PlyValue::Float(v) => output.push(v.to_string()),
563 PlyValue::Double(v) => output.push(v.to_string()),
564 PlyValue::List(values) => {
565 output.push(values.len().to_string());
566 for item in values {
567 Self::format_ascii_value(item, output)?;
568 }
569 }
570 }
571 Ok(())
572 }
573
574 fn write_binary_data<E: byteorder::ByteOrder, W: std::io::Write>(
576 writer: &mut W,
577 ply_data: &PlyData,
578 ) -> Result<()> {
579
580 for element_def in &ply_data.header.elements {
581 if let Some(element_data) = ply_data.elements.get(&element_def.name) {
582 for instance in element_data {
583 for property in &element_def.properties {
584 if let Some(value) = instance.get(&property.name) {
585 Self::write_binary_value::<E, _>(writer, value)?;
586 }
587 }
588 }
589 }
590 }
591 Ok(())
592 }
593
594 fn write_binary_value<E: byteorder::ByteOrder, W: std::io::Write>(
596 writer: &mut W,
597 value: &PlyValue,
598 ) -> Result<()> {
599 use byteorder::WriteBytesExt;
600
601 match value {
602 PlyValue::Char(v) => writer.write_i8(*v)?,
603 PlyValue::UChar(v) => writer.write_u8(*v)?,
604 PlyValue::Short(v) => writer.write_i16::<E>(*v)?,
605 PlyValue::UShort(v) => writer.write_u16::<E>(*v)?,
606 PlyValue::Int(v) => writer.write_i32::<E>(*v)?,
607 PlyValue::UInt(v) => writer.write_u32::<E>(*v)?,
608 PlyValue::Float(v) => writer.write_f32::<E>(*v)?,
609 PlyValue::Double(v) => writer.write_f64::<E>(*v)?,
610 PlyValue::List(values) => {
611 writer.write_u8(values.len() as u8)?;
613 for item in values {
614 Self::write_binary_value::<E, _>(writer, item)?;
615 }
616 }
617 }
618 Ok(())
619 }
620
621 fn value_to_property_type(value: &PlyValue) -> PlyPropertyType {
623 match value {
624 PlyValue::Char(_) => PlyPropertyType::Char,
625 PlyValue::UChar(_) => PlyPropertyType::UChar,
626 PlyValue::Short(_) => PlyPropertyType::Short,
627 PlyValue::UShort(_) => PlyPropertyType::UShort,
628 PlyValue::Int(_) => PlyPropertyType::Int,
629 PlyValue::UInt(_) => PlyPropertyType::UInt,
630 PlyValue::Float(_) => PlyPropertyType::Float,
631 PlyValue::Double(_) => PlyPropertyType::Double,
632 PlyValue::List(values) => {
633 let item_type = if let Some(first_item) = values.first() {
634 Self::value_to_property_type(first_item)
635 } else {
636 PlyPropertyType::Int
637 };
638 PlyPropertyType::List(Box::new(PlyPropertyType::UChar), Box::new(item_type))
639 }
640 }
641 }
642}
643
644impl RobustPlyReader {
645 pub fn read_ply_data<R: BufRead>(reader: &mut R) -> Result<PlyData> {
647 let header = Self::read_header(reader)?;
648 let elements = Self::read_elements(reader, &header)?;
649
650 Ok(PlyData { header, elements })
651 }
652
653 pub fn read_ply_file<P: AsRef<Path>>(path: P) -> Result<PlyData> {
655 let path = path.as_ref();
656
657 #[cfg(feature = "io-mmap")]
659 {
660 if let Some(ply_data) = Self::try_read_ply_mmap(path)? {
661 return Ok(ply_data);
662 }
663 }
664
665 let file = File::open(path)?;
667 let mut reader = BufReader::new(file);
668 Self::read_ply_data(&mut reader)
669 }
670
671 #[cfg(feature = "io-mmap")]
673 fn try_read_ply_mmap<P: AsRef<Path>>(path: P) -> Result<Option<PlyData>> {
674 let path = path.as_ref();
675
676 if !crate::mmap::should_use_mmap(path) {
678 return Ok(None);
679 }
680
681 let file = File::open(path)?;
683 let mut reader = BufReader::new(file);
684 let header = Self::read_header(&mut reader)?;
685
686 match header.format {
688 PlyFormat::BinaryLittleEndian | PlyFormat::BinaryBigEndian => {
689 let file = File::open(path)?;
691 let mut reader = BufReader::new(file);
692 let mut header_size = 0;
693 let mut line = String::new();
694
695 loop {
696 let line_start = header_size;
697 line.clear();
698 let bytes_read = reader.read_line(&mut line)?;
699 if bytes_read == 0 {
700 return Err(Error::InvalidData("Unexpected end of file in header".to_string()));
701 }
702 header_size += bytes_read;
703
704 if line.trim() == "end_header" {
705 break;
706 }
707 }
708
709 if let Some(mut mmap_reader) = MmapReader::new(path)? {
711 mmap_reader.seek(header_size)?;
713
714 let elements = Self::read_elements_mmap(&mut mmap_reader, &header)?;
716
717 return Ok(Some(PlyData { header, elements }));
718 }
719 }
720 PlyFormat::Ascii => {
721 return Ok(None);
723 }
724 }
725
726 Ok(None)
727 }
728
729 #[cfg(feature = "io-mmap")]
731 fn read_elements_mmap(
732 reader: &mut MmapReader,
733 header: &PlyHeader
734 ) -> Result<HashMap<String, Vec<HashMap<String, PlyValue>>>> {
735 let mut elements = HashMap::new();
736
737 for element_def in &header.elements {
738 let mut element_data = Vec::with_capacity(element_def.count);
739
740 for _ in 0..element_def.count {
741 let mut instance = HashMap::new();
742
743 match header.format {
744 PlyFormat::BinaryLittleEndian => {
745 for property in &element_def.properties {
746 let value = Self::read_binary_property_value_mmap_le(reader, &property.property_type)?;
747 instance.insert(property.name.clone(), value);
748 }
749 }
750 PlyFormat::BinaryBigEndian => {
751 for property in &element_def.properties {
752 let value = Self::read_binary_property_value_mmap_be(reader, &property.property_type)?;
753 instance.insert(property.name.clone(), value);
754 }
755 }
756 PlyFormat::Ascii => {
757 return Err(Error::InvalidData("ASCII format should not use mmap reader".to_string()));
758 }
759 }
760
761 element_data.push(instance);
762 }
763
764 elements.insert(element_def.name.clone(), element_data);
765 }
766
767 Ok(elements)
768 }
769
770 #[cfg(feature = "io-mmap")]
772 fn read_binary_property_value_mmap_le(reader: &mut MmapReader, property_type: &PlyPropertyType) -> Result<PlyValue> {
773 match property_type {
774 PlyPropertyType::Char => Ok(PlyValue::Char(reader.read_u8()? as i8)),
775 PlyPropertyType::UChar => Ok(PlyValue::UChar(reader.read_u8()?)),
776 PlyPropertyType::Short => Ok(PlyValue::Short(reader.read_u16_le()? as i16)),
777 PlyPropertyType::UShort => Ok(PlyValue::UShort(reader.read_u16_le()?)),
778 PlyPropertyType::Int => Ok(PlyValue::Int(reader.read_u32_le()? as i32)),
779 PlyPropertyType::UInt => Ok(PlyValue::UInt(reader.read_u32_le()?)),
780 PlyPropertyType::Float => Ok(PlyValue::Float(reader.read_f32_le()?)),
781 PlyPropertyType::Double => Ok(PlyValue::Double(reader.read_f64_le()?)),
782 PlyPropertyType::List(count_type, item_type) => {
783 let count_value = Self::read_binary_property_value_mmap_le(reader, count_type)?;
784 let count = count_value.as_usize()?;
785
786 let mut list = Vec::with_capacity(count);
787 for _ in 0..count {
788 let item = Self::read_binary_property_value_mmap_le(reader, item_type)?;
789 list.push(item);
790 }
791
792 Ok(PlyValue::List(list))
793 }
794 }
795 }
796
797 #[cfg(feature = "io-mmap")]
799 fn read_binary_property_value_mmap_be(reader: &mut MmapReader, property_type: &PlyPropertyType) -> Result<PlyValue> {
800 match property_type {
801 PlyPropertyType::Char => Ok(PlyValue::Char(reader.read_u8()? as i8)),
802 PlyPropertyType::UChar => Ok(PlyValue::UChar(reader.read_u8()?)),
803 PlyPropertyType::Short => Ok(PlyValue::Short(reader.read_u16_be()? as i16)),
804 PlyPropertyType::UShort => Ok(PlyValue::UShort(reader.read_u16_be()?)),
805 PlyPropertyType::Int => Ok(PlyValue::Int(reader.read_u32_be()? as i32)),
806 PlyPropertyType::UInt => Ok(PlyValue::UInt(reader.read_u32_be()?)),
807 PlyPropertyType::Float => Ok(PlyValue::Float(reader.read_f32_be()?)),
808 PlyPropertyType::Double => Ok(PlyValue::Double(reader.read_f64_be()?)),
809 PlyPropertyType::List(count_type, item_type) => {
810 let count_value = Self::read_binary_property_value_mmap_be(reader, count_type)?;
811 let count = count_value.as_usize()?;
812
813 let mut list = Vec::with_capacity(count);
814 for _ in 0..count {
815 let item = Self::read_binary_property_value_mmap_be(reader, item_type)?;
816 list.push(item);
817 }
818
819 Ok(PlyValue::List(list))
820 }
821 }
822 }
823
824 fn read_header<R: BufRead>(reader: &mut R) -> Result<PlyHeader> {
826 let mut format = None;
827 let mut version = "1.0".to_string();
828 let mut elements = Vec::new();
829 let mut comments = Vec::new();
830 let mut obj_info = Vec::new();
831
832 let mut line = String::new();
833
834 reader.read_line(&mut line)?;
836 if line.trim() != "ply" {
837 return Err(Error::InvalidData("Not a PLY file - missing magic number".to_string()));
838 }
839
840 loop {
842 line.clear();
843 if reader.read_line(&mut line)? == 0 {
844 return Err(Error::InvalidData("Unexpected end of file in header".to_string()));
845 }
846
847 let line = line.trim();
848 if line == "end_header" {
849 break;
850 }
851
852 let parts: Vec<&str> = line.split_whitespace().collect();
853 if parts.is_empty() {
854 continue;
855 }
856
857 match parts[0] {
858 "format" => {
859 if parts.len() < 3 {
860 return Err(Error::InvalidData("Invalid format line".to_string()));
861 }
862 format = Some(match parts[1] {
863 "ascii" => PlyFormat::Ascii,
864 "binary_little_endian" => PlyFormat::BinaryLittleEndian,
865 "binary_big_endian" => PlyFormat::BinaryBigEndian,
866 _ => return Err(Error::InvalidData(format!("Unknown format: {}", parts[1]))),
867 });
868 version = parts[2].to_string();
869 }
870 "comment" => {
871 if parts.len() > 1 {
872 comments.push(parts[1..].join(" "));
873 }
874 }
875 "obj_info" => {
876 if parts.len() > 1 {
877 obj_info.push(parts[1..].join(" "));
878 }
879 }
880 "element" => {
881 if parts.len() < 3 {
882 return Err(Error::InvalidData("Invalid element line".to_string()));
883 }
884 let name = parts[1].to_string();
885 let count: usize = parts[2].parse()
886 .map_err(|_| Error::InvalidData("Invalid element count".to_string()))?;
887 elements.push(PlyElement {
888 name,
889 count,
890 properties: Vec::new(),
891 });
892 }
893 "property" => {
894 if elements.is_empty() {
895 return Err(Error::InvalidData("Property without element".to_string()));
896 }
897 let property = Self::parse_property(&parts[1..])?;
898 elements.last_mut().unwrap().properties.push(property);
899 }
900 _ => {
901 }
903 }
904 }
905
906 let format = format.ok_or_else(|| Error::InvalidData("Missing format specification".to_string()))?;
907
908 Ok(PlyHeader {
909 format,
910 version,
911 elements,
912 comments,
913 obj_info,
914 })
915 }
916
917 fn parse_property(parts: &[&str]) -> Result<PlyProperty> {
919 if parts.is_empty() {
920 return Err(Error::InvalidData("Empty property definition".to_string()));
921 }
922
923 let property_type = if parts[0] == "list" {
924 if parts.len() < 4 {
925 return Err(Error::InvalidData("Invalid list property definition".to_string()));
926 }
927 let count_type = Self::parse_scalar_type(parts[1])?;
928 let item_type = Self::parse_scalar_type(parts[2])?;
929 PlyPropertyType::List(Box::new(count_type), Box::new(item_type))
930 } else {
931 if parts.len() < 2 {
932 return Err(Error::InvalidData("Invalid property definition".to_string()));
933 }
934 Self::parse_scalar_type(parts[0])?
935 };
936
937 let name = parts.last().unwrap().to_string();
938
939 Ok(PlyProperty { name, property_type })
940 }
941
942 fn parse_scalar_type(type_str: &str) -> Result<PlyPropertyType> {
944 match type_str {
945 "char" | "int8" => Ok(PlyPropertyType::Char),
946 "uchar" | "uint8" => Ok(PlyPropertyType::UChar),
947 "short" | "int16" => Ok(PlyPropertyType::Short),
948 "ushort" | "uint16" => Ok(PlyPropertyType::UShort),
949 "int" | "int32" => Ok(PlyPropertyType::Int),
950 "uint" | "uint32" => Ok(PlyPropertyType::UInt),
951 "float" | "float32" => Ok(PlyPropertyType::Float),
952 "double" | "float64" => Ok(PlyPropertyType::Double),
953 _ => Err(Error::InvalidData(format!("Unknown property type: {}", type_str))),
954 }
955 }
956
957 fn read_elements<R: BufRead>(reader: &mut R, header: &PlyHeader) -> Result<HashMap<String, Vec<HashMap<String, PlyValue>>>> {
959 let mut elements = HashMap::new();
960
961 for element_def in &header.elements {
962 let mut element_data = Vec::with_capacity(element_def.count);
963
964 for _ in 0..element_def.count {
965 let mut instance = HashMap::new();
966
967 match header.format {
968 PlyFormat::Ascii => {
969 let mut line = String::new();
970 reader.read_line(&mut line)?;
971 let values = line.trim().split_whitespace().collect::<Vec<_>>();
972 let mut value_idx = 0;
973
974 for property in &element_def.properties {
975 let value = Self::read_ascii_property_value(&values, &mut value_idx, &property.property_type)?;
976 instance.insert(property.name.clone(), value);
977 }
978 }
979 PlyFormat::BinaryLittleEndian => {
980 for property in &element_def.properties {
981 let value = Self::read_binary_property_value::<LittleEndian, _>(reader, &property.property_type)?;
982 instance.insert(property.name.clone(), value);
983 }
984 }
985 PlyFormat::BinaryBigEndian => {
986 for property in &element_def.properties {
987 let value = Self::read_binary_property_value::<BigEndian, _>(reader, &property.property_type)?;
988 instance.insert(property.name.clone(), value);
989 }
990 }
991 }
992
993 element_data.push(instance);
994 }
995
996 elements.insert(element_def.name.clone(), element_data);
997 }
998
999 Ok(elements)
1000 }
1001
1002 fn read_ascii_property_value(values: &[&str], value_idx: &mut usize, property_type: &PlyPropertyType) -> Result<PlyValue> {
1004 if *value_idx >= values.len() {
1005 return Err(Error::InvalidData("Not enough values in line".to_string()));
1006 }
1007
1008 match property_type {
1009 PlyPropertyType::Char => {
1010 let val = values[*value_idx].parse::<i8>()
1011 .map_err(|_| Error::InvalidData("Invalid char value".to_string()))?;
1012 *value_idx += 1;
1013 Ok(PlyValue::Char(val))
1014 }
1015 PlyPropertyType::UChar => {
1016 let val = values[*value_idx].parse::<u8>()
1017 .map_err(|_| Error::InvalidData("Invalid uchar value".to_string()))?;
1018 *value_idx += 1;
1019 Ok(PlyValue::UChar(val))
1020 }
1021 PlyPropertyType::Short => {
1022 let val = values[*value_idx].parse::<i16>()
1023 .map_err(|_| Error::InvalidData("Invalid short value".to_string()))?;
1024 *value_idx += 1;
1025 Ok(PlyValue::Short(val))
1026 }
1027 PlyPropertyType::UShort => {
1028 let val = values[*value_idx].parse::<u16>()
1029 .map_err(|_| Error::InvalidData("Invalid ushort value".to_string()))?;
1030 *value_idx += 1;
1031 Ok(PlyValue::UShort(val))
1032 }
1033 PlyPropertyType::Int => {
1034 let val = values[*value_idx].parse::<i32>()
1035 .map_err(|_| Error::InvalidData("Invalid int value".to_string()))?;
1036 *value_idx += 1;
1037 Ok(PlyValue::Int(val))
1038 }
1039 PlyPropertyType::UInt => {
1040 let val = values[*value_idx].parse::<u32>()
1041 .map_err(|_| Error::InvalidData("Invalid uint value".to_string()))?;
1042 *value_idx += 1;
1043 Ok(PlyValue::UInt(val))
1044 }
1045 PlyPropertyType::Float => {
1046 let val = values[*value_idx].parse::<f32>()
1047 .map_err(|_| Error::InvalidData("Invalid float value".to_string()))?;
1048 *value_idx += 1;
1049 Ok(PlyValue::Float(val))
1050 }
1051 PlyPropertyType::Double => {
1052 let val = values[*value_idx].parse::<f64>()
1053 .map_err(|_| Error::InvalidData("Invalid double value".to_string()))?;
1054 *value_idx += 1;
1055 Ok(PlyValue::Double(val))
1056 }
1057 PlyPropertyType::List(count_type, item_type) => {
1058 let count_value = Self::read_ascii_property_value(values, value_idx, count_type)?;
1059 let count = count_value.as_usize()?;
1060
1061 let mut list = Vec::with_capacity(count);
1062 for _ in 0..count {
1063 let item = Self::read_ascii_property_value(values, value_idx, item_type)?;
1064 list.push(item);
1065 }
1066
1067 Ok(PlyValue::List(list))
1068 }
1069 }
1070 }
1071
1072 fn read_binary_property_value<E: byteorder::ByteOrder, R: Read>(reader: &mut R, property_type: &PlyPropertyType) -> Result<PlyValue> {
1074 match property_type {
1075 PlyPropertyType::Char => Ok(PlyValue::Char(reader.read_i8()?)),
1076 PlyPropertyType::UChar => Ok(PlyValue::UChar(reader.read_u8()?)),
1077 PlyPropertyType::Short => Ok(PlyValue::Short(reader.read_i16::<E>()?)),
1078 PlyPropertyType::UShort => Ok(PlyValue::UShort(reader.read_u16::<E>()?)),
1079 PlyPropertyType::Int => Ok(PlyValue::Int(reader.read_i32::<E>()?)),
1080 PlyPropertyType::UInt => Ok(PlyValue::UInt(reader.read_u32::<E>()?)),
1081 PlyPropertyType::Float => Ok(PlyValue::Float(reader.read_f32::<E>()?)),
1082 PlyPropertyType::Double => Ok(PlyValue::Double(reader.read_f64::<E>()?)),
1083 PlyPropertyType::List(count_type, item_type) => {
1084 let count_value = Self::read_binary_property_value::<E, _>(reader, count_type)?;
1085 let count = count_value.as_usize()?;
1086
1087 let mut list = Vec::with_capacity(count);
1088 for _ in 0..count {
1089 let item = Self::read_binary_property_value::<E, _>(reader, item_type)?;
1090 list.push(item);
1091 }
1092
1093 Ok(PlyValue::List(list))
1094 }
1095 }
1096 }
1097}
1098
1099impl PlyValue {
1100 pub fn as_f32(&self) -> Result<f32> {
1102 match self {
1103 PlyValue::Char(v) => Ok(*v as f32),
1104 PlyValue::UChar(v) => Ok(*v as f32),
1105 PlyValue::Short(v) => Ok(*v as f32),
1106 PlyValue::UShort(v) => Ok(*v as f32),
1107 PlyValue::Int(v) => Ok(*v as f32),
1108 PlyValue::UInt(v) => Ok(*v as f32),
1109 PlyValue::Float(v) => Ok(*v),
1110 PlyValue::Double(v) => Ok(*v as f32),
1111 _ => Err(Error::InvalidData("Cannot convert list to f32".to_string())),
1112 }
1113 }
1114
1115 pub fn as_usize(&self) -> Result<usize> {
1117 match self {
1118 PlyValue::UChar(v) => Ok(*v as usize),
1119 PlyValue::UShort(v) => Ok(*v as usize),
1120 PlyValue::UInt(v) => Ok(*v as usize),
1121 PlyValue::Int(v) if *v >= 0 => Ok(*v as usize),
1122 _ => Err(Error::InvalidData("Cannot convert value to usize".to_string())),
1123 }
1124 }
1125
1126 pub fn as_usize_list(&self) -> Result<Vec<usize>> {
1128 match self {
1129 PlyValue::List(values) => {
1130 values.iter().map(|v| v.as_usize()).collect()
1131 }
1132 _ => Err(Error::InvalidData("Value is not a list".to_string())),
1133 }
1134 }
1135}
1136
1137pub struct PlyReader;
1139pub struct PlyWriter;
1140
1141impl crate::registry::PointCloudReader for PlyReader {
1143 fn read_point_cloud(&self, path: &Path) -> Result<PointCloud<Point3f>> {
1144 let ply_data = RobustPlyReader::read_ply_file(path)?;
1146
1147 let mut points = Vec::new();
1148
1149 if let Some(vertex_elements) = ply_data.elements.get("vertex") {
1150 for vertex in vertex_elements {
1151 let x = vertex.get("x")
1152 .ok_or_else(|| Error::InvalidData("Missing x coordinate".to_string()))?
1153 .as_f32()?;
1154 let y = vertex.get("y")
1155 .ok_or_else(|| Error::InvalidData("Missing y coordinate".to_string()))?
1156 .as_f32()?;
1157 let z = vertex.get("z")
1158 .ok_or_else(|| Error::InvalidData("Missing z coordinate".to_string()))?
1159 .as_f32()?;
1160
1161 points.push(Point3f::new(x, y, z));
1162 }
1163 }
1164
1165 Ok(PointCloud::from_points(points))
1166 }
1167
1168 fn can_read(&self, path: &Path) -> bool {
1169 if let Ok(mut file) = File::open(path) {
1171 let mut header = [0u8; 4];
1172 if let Ok(_) = file.read(&mut header) {
1173 return header.starts_with(b"ply");
1174 }
1175 }
1176 false
1177 }
1178
1179 fn format_name(&self) -> &'static str {
1180 "ply"
1181 }
1182}
1183
1184impl crate::registry::MeshReader for PlyReader {
1185 fn read_mesh(&self, path: &Path) -> Result<TriangleMesh> {
1186 let ply_data = RobustPlyReader::read_ply_file(path)?;
1187
1188 let mut vertices = Vec::new();
1190 if let Some(vertex_elements) = ply_data.elements.get("vertex") {
1191 for vertex in vertex_elements {
1192 let x = vertex.get("x")
1193 .ok_or_else(|| Error::InvalidData("Missing x coordinate".to_string()))?
1194 .as_f32()?;
1195 let y = vertex.get("y")
1196 .ok_or_else(|| Error::InvalidData("Missing y coordinate".to_string()))?
1197 .as_f32()?;
1198 let z = vertex.get("z")
1199 .ok_or_else(|| Error::InvalidData("Missing z coordinate".to_string()))?
1200 .as_f32()?;
1201
1202 vertices.push(Point3f::new(x, y, z));
1203 }
1204 }
1205
1206 let mut faces = Vec::new();
1208 if let Some(face_elements) = ply_data.elements.get("face") {
1209 for face in face_elements {
1210 let indices = if let Some(vertex_indices) = face.get("vertex_indices") {
1212 vertex_indices.as_usize_list()?
1213 } else if let Some(vertex_index) = face.get("vertex_index") {
1214 vertex_index.as_usize_list()?
1215 } else {
1216 return Err(Error::InvalidData("Face missing vertex indices".to_string()));
1217 };
1218
1219 if indices.len() >= 3 {
1221 faces.push([indices[0], indices[1], indices[2]]);
1222 }
1223 if indices.len() == 4 {
1225 faces.push([indices[0], indices[2], indices[3]]);
1226 }
1227 }
1228 }
1229
1230 let normals = if let Some(vertex_elements) = ply_data.elements.get("vertex") {
1232 let mut normals = Vec::new();
1233 let mut has_normals = true;
1234
1235 for vertex in vertex_elements {
1236 if let (Some(nx), Some(ny), Some(nz)) = (
1237 vertex.get("nx"),
1238 vertex.get("ny"),
1239 vertex.get("nz"),
1240 ) {
1241 normals.push(Vector3f::new(
1242 nx.as_f32()?,
1243 ny.as_f32()?,
1244 nz.as_f32()?,
1245 ));
1246 } else {
1247 has_normals = false;
1248 break;
1249 }
1250 }
1251
1252 if has_normals {
1253 Some(normals)
1254 } else {
1255 None
1256 }
1257 } else {
1258 None
1259 };
1260
1261 let mut mesh = TriangleMesh::from_vertices_and_faces(vertices, faces);
1262 if let Some(normals) = normals {
1263 mesh.set_normals(normals);
1264 }
1265
1266 Ok(mesh)
1267 }
1268
1269 fn can_read(&self, path: &Path) -> bool {
1270 if let Ok(mut file) = File::open(path) {
1272 let mut header = [0u8; 4];
1273 if let Ok(_) = file.read(&mut header) {
1274 return header.starts_with(b"ply");
1275 }
1276 }
1277 false
1278 }
1279
1280 fn format_name(&self) -> &'static str {
1281 "ply"
1282 }
1283}
1284
1285impl crate::registry::PointCloudWriter for PlyWriter {
1286 fn write_point_cloud(&self, cloud: &PointCloud<Point3f>, path: &Path) -> Result<()> {
1287 use ply_rs::{
1289 writer::Writer,
1290 ply::{Property, PropertyDef, PropertyType, ScalarType, ElementDef, Ply, Addable, DefaultElement},
1291 };
1292
1293 let file = File::create(path)?;
1294 let mut writer = BufWriter::new(file);
1295
1296 let mut ply = Ply::<DefaultElement>::new();
1298
1299 let mut vertex_element = ElementDef::new("vertex".to_string());
1301 vertex_element.count = cloud.len();
1302 vertex_element.properties.add(PropertyDef::new(
1303 "x".to_string(),
1304 PropertyType::Scalar(ScalarType::Float),
1305 ));
1306 vertex_element.properties.add(PropertyDef::new(
1307 "y".to_string(),
1308 PropertyType::Scalar(ScalarType::Float),
1309 ));
1310 vertex_element.properties.add(PropertyDef::new(
1311 "z".to_string(),
1312 PropertyType::Scalar(ScalarType::Float),
1313 ));
1314
1315 ply.header.elements.add(vertex_element);
1316
1317 let mut vertices = Vec::new();
1319 for point in &cloud.points {
1320 let mut vertex = DefaultElement::new();
1321 vertex.insert("x".to_string(), Property::Float(point.x));
1322 vertex.insert("y".to_string(), Property::Float(point.y));
1323 vertex.insert("z".to_string(), Property::Float(point.z));
1324 vertices.push(vertex);
1325 }
1326 ply.payload.insert("vertex".to_string(), vertices);
1327
1328 let writer_instance = Writer::new();
1330 writer_instance.write_ply(&mut writer, &mut ply)?;
1331
1332 Ok(())
1333 }
1334
1335 fn format_name(&self) -> &'static str {
1336 "ply"
1337 }
1338}
1339
1340impl crate::registry::MeshWriter for PlyWriter {
1341 fn write_mesh(&self, mesh: &TriangleMesh, path: &Path) -> Result<()> {
1342 use ply_rs::{
1344 writer::Writer,
1345 ply::{Property, PropertyDef, PropertyType, ScalarType, ElementDef, Ply, Addable, DefaultElement},
1346 };
1347
1348 let file = File::create(path)?;
1349 let mut writer = BufWriter::new(file);
1350
1351 let mut ply = Ply::<DefaultElement>::new();
1353
1354 let mut vertex_element = ElementDef::new("vertex".to_string());
1356 vertex_element.count = mesh.vertices.len();
1357 vertex_element.properties.add(PropertyDef::new(
1358 "x".to_string(),
1359 PropertyType::Scalar(ScalarType::Float),
1360 ));
1361 vertex_element.properties.add(PropertyDef::new(
1362 "y".to_string(),
1363 PropertyType::Scalar(ScalarType::Float),
1364 ));
1365 vertex_element.properties.add(PropertyDef::new(
1366 "z".to_string(),
1367 PropertyType::Scalar(ScalarType::Float),
1368 ));
1369
1370 if mesh.normals.is_some() {
1372 vertex_element.properties.add(PropertyDef::new(
1373 "nx".to_string(),
1374 PropertyType::Scalar(ScalarType::Float),
1375 ));
1376 vertex_element.properties.add(PropertyDef::new(
1377 "ny".to_string(),
1378 PropertyType::Scalar(ScalarType::Float),
1379 ));
1380 vertex_element.properties.add(PropertyDef::new(
1381 "nz".to_string(),
1382 PropertyType::Scalar(ScalarType::Float),
1383 ));
1384 }
1385
1386 ply.header.elements.add(vertex_element);
1387
1388 let mut vertices = Vec::new();
1390 for (i, point) in mesh.vertices.iter().enumerate() {
1391 let mut vertex = DefaultElement::new();
1392 vertex.insert("x".to_string(), Property::Float(point.x));
1393 vertex.insert("y".to_string(), Property::Float(point.y));
1394 vertex.insert("z".to_string(), Property::Float(point.z));
1395
1396 if let Some(ref normals) = mesh.normals {
1398 if i < normals.len() {
1399 vertex.insert("nx".to_string(), Property::Float(normals[i].x));
1400 vertex.insert("ny".to_string(), Property::Float(normals[i].y));
1401 vertex.insert("nz".to_string(), Property::Float(normals[i].z));
1402 }
1403 }
1404
1405 vertices.push(vertex);
1406 }
1407 ply.payload.insert("vertex".to_string(), vertices);
1408
1409 if !mesh.faces.is_empty() {
1411 let mut face_element = ElementDef::new("face".to_string());
1412 face_element.count = mesh.faces.len();
1413 face_element.properties.add(PropertyDef::new(
1414 "vertex_indices".to_string(),
1415 PropertyType::List(ScalarType::UChar, ScalarType::Int),
1416 ));
1417
1418 ply.header.elements.add(face_element);
1419
1420 let mut faces = Vec::new();
1422 for face in &mesh.faces {
1423 let mut face_data = DefaultElement::new();
1424 let indices = vec![
1425 face[0] as i32,
1426 face[1] as i32,
1427 face[2] as i32,
1428 ];
1429 face_data.insert("vertex_indices".to_string(), Property::ListInt(indices));
1430 faces.push(face_data);
1431 }
1432 ply.payload.insert("face".to_string(), faces);
1433 }
1434
1435 let writer_instance = Writer::new();
1437 writer_instance.write_ply(&mut writer, &mut ply)?;
1438
1439 Ok(())
1440 }
1441
1442 fn format_name(&self) -> &'static str {
1443 "ply"
1444 }
1445}
1446
1447impl PointCloudReader for PlyReader {
1449 fn read_point_cloud<P: AsRef<Path>>(path: P) -> Result<PointCloud<Point3f>> {
1450 let reader = PlyReader;
1451 crate::registry::PointCloudReader::read_point_cloud(&reader, path.as_ref())
1452 }
1453}
1454
1455impl MeshReader for PlyReader {
1456 fn read_mesh<P: AsRef<Path>>(path: P) -> Result<TriangleMesh> {
1457 let reader = PlyReader;
1458 crate::registry::MeshReader::read_mesh(&reader, path.as_ref())
1459 }
1460}
1461
1462impl PointCloudWriter for PlyWriter {
1463 fn write_point_cloud<P: AsRef<Path>>(cloud: &PointCloud<Point3f>, path: P) -> Result<()> {
1464 let writer = PlyWriter;
1465 crate::registry::PointCloudWriter::write_point_cloud(&writer, cloud, path.as_ref())
1466 }
1467}
1468
1469impl MeshWriter for PlyWriter {
1470 fn write_mesh<P: AsRef<Path>>(mesh: &TriangleMesh, path: P) -> Result<()> {
1471 let writer = PlyWriter;
1472 crate::registry::MeshWriter::write_mesh(&writer, mesh, path.as_ref())
1473 }
1474}
1475
1476pub struct PlyStreamingReader {
1478 reader: BufReader<File>,
1479 current_count: usize,
1480 current_index: usize,
1481 chunk_size: usize,
1482 buffer: Vec<u8>,
1483 format: PlyFormat,
1484}
1485
1486impl PlyStreamingReader {
1487 pub fn new<P: AsRef<Path>>(path: P, chunk_size: usize) -> Result<Self> {
1489 let file = File::open(path)?;
1490 let mut reader = BufReader::new(file);
1491 let header = RobustPlyReader::read_header(&mut reader)?;
1492
1493 let vertex_element = header.elements.iter()
1495 .find(|e| e.name == "vertex")
1496 .ok_or_else(|| Error::InvalidData("No vertex element found in PLY file".to_string()))?;
1497
1498 Ok(Self {
1499 reader,
1500 current_count: vertex_element.count,
1501 current_index: 0,
1502 chunk_size,
1503 buffer: Vec::with_capacity(chunk_size * 12), format: header.format,
1505 })
1506 }
1507}
1508
1509impl Iterator for PlyStreamingReader {
1510 type Item = Result<Point3f>;
1511
1512 fn next(&mut self) -> Option<Self::Item> {
1513 if self.current_index >= self.current_count {
1514 return None;
1515 }
1516
1517 if self.buffer.is_empty() {
1519 let remaining = self.current_count - self.current_index;
1520 let to_read = std::cmp::min(remaining, self.chunk_size);
1521
1522 match self.format {
1523 PlyFormat::Ascii => {
1524 let mut line = String::new();
1526 if let Err(e) = self.reader.read_line(&mut line) {
1527 return Some(Err(Error::Io(e)));
1528 }
1529
1530 let values: Vec<&str> = line.trim().split_whitespace().collect();
1531 if values.len() < 3 {
1532 return Some(Err(Error::InvalidData("Not enough coordinates in vertex line".to_string())));
1533 }
1534
1535 let x = match values[0].parse::<f32>() {
1536 Ok(v) => v,
1537 Err(_) => return Some(Err(Error::InvalidData("Invalid x coordinate".to_string()))),
1538 };
1539 let y = match values[1].parse::<f32>() {
1540 Ok(v) => v,
1541 Err(_) => return Some(Err(Error::InvalidData("Invalid y coordinate".to_string()))),
1542 };
1543 let z = match values[2].parse::<f32>() {
1544 Ok(v) => v,
1545 Err(_) => return Some(Err(Error::InvalidData("Invalid z coordinate".to_string()))),
1546 };
1547
1548 self.current_index += 1;
1549 return Some(Ok(Point3f::new(x, y, z)));
1550 }
1551 PlyFormat::BinaryLittleEndian => {
1552 let bytes_per_vertex = 12; let chunk_bytes = to_read * bytes_per_vertex;
1555 self.buffer.resize(chunk_bytes, 0);
1556
1557 if let Err(e) = self.reader.read_exact(&mut self.buffer[..chunk_bytes]) {
1558 return Some(Err(Error::Io(e)));
1559 }
1560 }
1561 PlyFormat::BinaryBigEndian => {
1562 let bytes_per_vertex = 12; let chunk_bytes = to_read * bytes_per_vertex;
1565 self.buffer.resize(chunk_bytes, 0);
1566
1567 if let Err(e) = self.reader.read_exact(&mut self.buffer[..chunk_bytes]) {
1568 return Some(Err(Error::Io(e)));
1569 }
1570 }
1571 }
1572 }
1573
1574 match self.format {
1576 PlyFormat::Ascii => {
1577 unreachable!()
1579 }
1580 PlyFormat::BinaryLittleEndian => {
1581 if self.buffer.len() < 12 {
1582 return Some(Err(Error::InvalidData("Insufficient data in buffer".to_string())));
1583 }
1584
1585 let x = f32::from_le_bytes([
1586 self.buffer[0], self.buffer[1], self.buffer[2], self.buffer[3]
1587 ]);
1588 let y = f32::from_le_bytes([
1589 self.buffer[4], self.buffer[5], self.buffer[6], self.buffer[7]
1590 ]);
1591 let z = f32::from_le_bytes([
1592 self.buffer[8], self.buffer[9], self.buffer[10], self.buffer[11]
1593 ]);
1594
1595 self.buffer.drain(0..12);
1597 self.current_index += 1;
1598
1599 Some(Ok(Point3f::new(x, y, z)))
1600 }
1601 PlyFormat::BinaryBigEndian => {
1602 if self.buffer.len() < 12 {
1603 return Some(Err(Error::InvalidData("Insufficient data in buffer".to_string())));
1604 }
1605
1606 let x = f32::from_be_bytes([
1607 self.buffer[0], self.buffer[1], self.buffer[2], self.buffer[3]
1608 ]);
1609 let y = f32::from_be_bytes([
1610 self.buffer[4], self.buffer[5], self.buffer[6], self.buffer[7]
1611 ]);
1612 let z = f32::from_be_bytes([
1613 self.buffer[8], self.buffer[9], self.buffer[10], self.buffer[11]
1614 ]);
1615
1616 self.buffer.drain(0..12);
1618 self.current_index += 1;
1619
1620 Some(Ok(Point3f::new(x, y, z)))
1621 }
1622 }
1623 }
1624}
1625
1626pub struct PlyMeshStreamingReader {
1628 reader: BufReader<File>,
1629 current_count: usize,
1630 current_index: usize,
1631 chunk_size: usize,
1632 buffer: Vec<u8>,
1633 format: PlyFormat,
1634 vertices: Vec<Point3f>, }
1636
1637impl PlyMeshStreamingReader {
1638 pub fn new<P: AsRef<Path>>(path: P, chunk_size: usize) -> Result<Self> {
1640 let file = File::open(path)?;
1641 let mut reader = BufReader::new(file);
1642 let header = RobustPlyReader::read_header(&mut reader)?;
1643
1644 let face_element = header.elements.iter()
1646 .find(|e| e.name == "face")
1647 .ok_or_else(|| Error::InvalidData("No face element found in PLY file".to_string()))?;
1648
1649 let vertex_element = header.elements.iter()
1651 .find(|e| e.name == "vertex")
1652 .ok_or_else(|| Error::InvalidData("No vertex element found in PLY file".to_string()))?;
1653
1654 let mut vertices = Vec::with_capacity(vertex_element.count);
1655
1656 for _ in 0..vertex_element.count {
1658 let mut line = String::new();
1659 reader.read_line(&mut line)?;
1660 let values: Vec<&str> = line.trim().split_whitespace().collect();
1661 if values.len() >= 3 {
1662 let x = values[0].parse::<f32>()
1663 .map_err(|_| Error::InvalidData("Invalid x coordinate".to_string()))?;
1664 let y = values[1].parse::<f32>()
1665 .map_err(|_| Error::InvalidData("Invalid y coordinate".to_string()))?;
1666 let z = values[2].parse::<f32>()
1667 .map_err(|_| Error::InvalidData("Invalid z coordinate".to_string()))?;
1668 vertices.push(Point3f::new(x, y, z));
1669 }
1670 }
1671
1672 Ok(Self {
1673 reader,
1674 current_count: face_element.count,
1675 current_index: 0,
1676 chunk_size,
1677 buffer: Vec::with_capacity(chunk_size * 16), format: header.format,
1679 vertices,
1680 })
1681 }
1682}
1683
1684impl Iterator for PlyMeshStreamingReader {
1685 type Item = Result<[usize; 3]>;
1686
1687 fn next(&mut self) -> Option<Self::Item> {
1688 if self.current_index >= self.current_count {
1689 return None;
1690 }
1691
1692 if self.buffer.is_empty() {
1694 let remaining = self.current_count - self.current_index;
1695 let to_read = std::cmp::min(remaining, self.chunk_size);
1696
1697 match self.format {
1698 PlyFormat::Ascii => {
1699 let mut line = String::new();
1701 if let Err(e) = self.reader.read_line(&mut line) {
1702 return Some(Err(Error::Io(e)));
1703 }
1704
1705 let values: Vec<&str> = line.trim().split_whitespace().collect();
1706 if values.len() < 4 { return Some(Err(Error::InvalidData("Not enough values in face line".to_string())));
1708 }
1709
1710 let count = match values[0].parse::<usize>() {
1711 Ok(v) => v,
1712 Err(_) => return Some(Err(Error::InvalidData("Invalid face count".to_string()))),
1713 };
1714
1715 if count != 3 {
1716 return Some(Err(Error::InvalidData("Only triangular faces supported".to_string())));
1717 }
1718
1719 let i1 = match values[1].parse::<usize>() {
1720 Ok(v) => v,
1721 Err(_) => return Some(Err(Error::InvalidData("Invalid face index".to_string()))),
1722 };
1723 let i2 = match values[2].parse::<usize>() {
1724 Ok(v) => v,
1725 Err(_) => return Some(Err(Error::InvalidData("Invalid face index".to_string()))),
1726 };
1727 let i3 = match values[3].parse::<usize>() {
1728 Ok(v) => v,
1729 Err(_) => return Some(Err(Error::InvalidData("Invalid face index".to_string()))),
1730 };
1731
1732 if i1 >= self.vertices.len() || i2 >= self.vertices.len() || i3 >= self.vertices.len() {
1734 return Some(Err(Error::InvalidData("Face index out of range".to_string())));
1735 }
1736
1737 self.current_index += 1;
1738 return Some(Ok([i1, i2, i3]));
1739 }
1740 PlyFormat::BinaryLittleEndian | PlyFormat::BinaryBigEndian => {
1741 let bytes_per_face = 16; let chunk_bytes = to_read * bytes_per_face;
1744 self.buffer.resize(chunk_bytes, 0);
1745
1746 if let Err(e) = self.reader.read_exact(&mut self.buffer[..chunk_bytes]) {
1747 return Some(Err(Error::Io(e)));
1748 }
1749 }
1750 }
1751 }
1752
1753 match self.format {
1755 PlyFormat::Ascii => {
1756 unreachable!()
1758 }
1759 PlyFormat::BinaryLittleEndian => {
1760 if self.buffer.len() < 16 {
1761 return Some(Err(Error::InvalidData("Insufficient data in buffer".to_string())));
1762 }
1763
1764 let count = self.buffer[0] as usize;
1765 if count != 3 {
1766 return Some(Err(Error::InvalidData("Only triangular faces supported".to_string())));
1767 }
1768
1769 let i1 = u32::from_le_bytes([
1770 self.buffer[1], self.buffer[2], self.buffer[3], self.buffer[4]
1771 ]) as usize;
1772 let i2 = u32::from_le_bytes([
1773 self.buffer[5], self.buffer[6], self.buffer[7], self.buffer[8]
1774 ]) as usize;
1775 let i3 = u32::from_le_bytes([
1776 self.buffer[9], self.buffer[10], self.buffer[11], self.buffer[12]
1777 ]) as usize;
1778
1779 if i1 >= self.vertices.len() || i2 >= self.vertices.len() || i3 >= self.vertices.len() {
1781 return Some(Err(Error::InvalidData("Face index out of range".to_string())));
1782 }
1783
1784 self.buffer.drain(0..16);
1786 self.current_index += 1;
1787
1788 Some(Ok([i1, i2, i3]))
1789 }
1790 PlyFormat::BinaryBigEndian => {
1791 if self.buffer.len() < 16 {
1792 return Some(Err(Error::InvalidData("Insufficient data in buffer".to_string())));
1793 }
1794
1795 let count = self.buffer[0] as usize;
1796 if count != 3 {
1797 return Some(Err(Error::InvalidData("Only triangular faces supported".to_string())));
1798 }
1799
1800 let i1 = u32::from_be_bytes([
1801 self.buffer[1], self.buffer[2], self.buffer[3], self.buffer[4]
1802 ]) as usize;
1803 let i2 = u32::from_be_bytes([
1804 self.buffer[5], self.buffer[6], self.buffer[7], self.buffer[8]
1805 ]) as usize;
1806 let i3 = u32::from_be_bytes([
1807 self.buffer[9], self.buffer[10], self.buffer[11], self.buffer[12]
1808 ]) as usize;
1809
1810 if i1 >= self.vertices.len() || i2 >= self.vertices.len() || i3 >= self.vertices.len() {
1812 return Some(Err(Error::InvalidData("Face index out of range".to_string())));
1813 }
1814
1815 self.buffer.drain(0..16);
1817 self.current_index += 1;
1818
1819 Some(Ok([i1, i2, i3]))
1820 }
1821 }
1822 }
1823}