1use crate::types::{Point3D, PointSet};
2use nalgebra::{Dyn, Matrix3, OMatrix, Quaternion, Rotation3, UnitQuaternion};
3use ply_rs::parser::Parser;
4use std::fs::File;
5use three_d::FrameOutput;
6use three_d::{
7 degrees, vec3, Axes, Camera, ClearState, ColorMaterial, CpuMesh, Gm, InstancedMesh, Mat4,
8 OrbitControl, PointCloud, Srgba, Vec3, Window, WindowSettings,
9};
10
11pub fn load_ply_as_point_set(
12 file_path: &str,
13) -> Result<PointSet<Point3D>, Box<dyn std::error::Error>> {
14 let file = File::open(file_path)?;
16 let mut f = std::io::BufReader::new(file);
17
18 let point_3d_parser = Parser::<Point3D>::new();
20
21 let header = point_3d_parser.read_header(&mut f).unwrap();
22
23 let mut points = vec![];
24 for (_, element) in &header.elements {
25 match element.name.as_ref() {
27 "vertex" => {
28 points = point_3d_parser
29 .read_payload_for_element(&mut f, &element, &header)
30 .unwrap();
31 }
32 _ => {}
33 }
34 }
35 Ok(PointSet { points })
37}
38
39pub fn visualise_points(model_cloud: &PointSet<Point3D>, target_cloud: &PointSet<Point3D>) {
40 let window = Window::new(WindowSettings {
42 title: "3D Point Cloud Visualization".to_string(),
43 max_size: Some((1280, 720)),
44 ..Default::default()
45 })
46 .unwrap();
47
48 let context = window.gl();
49
50 let mut camera = Camera::new_perspective(
52 window.viewport(),
53 vec3(0.125, -0.25, -0.5),
54 vec3(0.0, 0.0, 0.0),
55 vec3(0.0, 1.0, 0.0),
56 degrees(45.0),
57 0.01,
58 100.0,
59 );
60
61 let mut control = OrbitControl::new(*camera.target(), 0.1, 3.0);
62
63 let model_points: Vec<Vec3> = model_cloud
65 .points
66 .iter()
67 .map(|p| vec3(p.x as f32, p.y as f32, p.z as f32))
68 .collect();
69 let target_points: Vec<Vec3> = target_cloud
70 .points
71 .iter()
72 .map(|p| vec3(p.x as f32, p.y as f32, p.z as f32))
73 .collect();
74
75 let model_cloud = PointCloud {
77 positions: three_d::Positions::F32(model_points.clone()),
78 ..Default::default()
79 };
80
81 let target_cloud = PointCloud {
82 positions: three_d::Positions::F32(target_points.clone()),
83 ..Default::default()
84 };
85
86 let mut point_mesh = CpuMesh::sphere(4);
87 point_mesh.transform(&Mat4::from_scale(0.0001)).unwrap();
88
89 let model_cloud_gm = Gm {
90 geometry: InstancedMesh::new(&context, &model_cloud.into(), &point_mesh),
91 material: ColorMaterial {
92 color: Srgba::new(0, 0, 255, 255), ..Default::default()
94 },
95 };
96 let target_cloud_gm = Gm {
100 geometry: InstancedMesh::new(&context, &target_cloud.into(), &point_mesh),
101 material: ColorMaterial {
102 color: Srgba::new(255, 0, 0, 255), ..Default::default()
104 },
105 };
106
107 window.render_loop(move |mut frame_input| {
109 let mut redraw = frame_input.first_frame;
110 redraw |= camera.set_viewport(frame_input.viewport);
111 redraw |= control.handle_events(&mut camera, &mut frame_input.events);
112
113 if redraw {
114 frame_input
115 .screen()
116 .clear(ClearState::color_and_depth(1.0, 1.0, 1.0, 1.0, 1.0))
117 .render(
118 &camera,
119 model_cloud_gm
120 .into_iter()
121 .chain(&Axes::new(&context, 0.01, 0.1))
122 .chain(target_cloud_gm.into_iter()),
123 &[],
124 );
125 }
126
127 FrameOutput {
128 swap_buffers: redraw,
129 ..Default::default()
130 }
131 });
132}
133
134pub fn get_quaternion_from_dynamic_rotation(rotation: &OMatrix<f32, Dyn, Dyn>) -> Quaternion<f32> {
135 assert!(
136 rotation.nrows() == 3 && rotation.ncols() == 3,
137 "Matrix must be 3x3"
138 );
139
140 let static_rotation = Matrix3::from_iterator(rotation.iter().cloned());
141 let rot = Rotation3::from_matrix(&static_rotation);
142
143 *UnitQuaternion::from_rotation_matrix(&rot)
144}