1mod geometry;
4mod intrinsic_vector_quantity;
5mod one_form_quantity;
6mod parameterization_quantity;
7mod quantities;
8mod quantity_methods;
9pub use intrinsic_vector_quantity::*;
10pub use one_form_quantity::*;
11pub use parameterization_quantity::*;
12pub use quantities::*;
13
14use glam::{Mat4, Vec3, Vec4};
15use polyscope_core::pick::PickResult;
16use polyscope_core::quantity::Quantity;
17use polyscope_core::structure::{HasQuantities, RenderContext, Structure};
18use polyscope_render::{ColorMapRegistry, MeshPickUniforms, MeshUniforms, SurfaceMeshRenderData};
19use std::ops::Range;
20
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
23pub enum ShadeStyle {
24 #[default]
26 Smooth,
27 Flat,
29 TriFlat,
31}
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
35pub enum BackfacePolicy {
36 #[default]
38 Identical,
39 Different,
41 Custom,
43 Cull,
45}
46
47pub struct SurfaceMesh {
49 name: String,
51 vertices: Vec<Vec3>,
52 faces: Vec<Vec<u32>>, enabled: bool,
54 transform: Mat4,
55 quantities: Vec<Box<dyn Quantity>>,
56
57 triangulation: Vec<[u32; 3]>,
59 face_to_tri_range: Vec<Range<usize>>,
60 vertex_normals: Vec<Vec3>,
61 face_normals: Vec<Vec3>,
62 corner_normals: Vec<Vec3>,
63 edge_is_real: Vec<Vec3>,
64 edges: Vec<(u32, u32)>,
65 needs_recompute: bool,
66
67 material: String,
69 shade_style: ShadeStyle,
70 edge_width: f32,
71 edge_color: Vec4,
72 show_edges: bool,
73 backface_policy: BackfacePolicy,
74 backface_color: Vec4,
75 surface_color: Vec4,
76 transparency: f32,
77
78 render_data: Option<SurfaceMeshRenderData>,
80
81 pick_uniform_buffer: Option<wgpu::Buffer>,
83 pick_bind_group: Option<wgpu::BindGroup>,
84 pick_face_index_buffer: Option<wgpu::Buffer>,
85 global_start: u32,
86}
87
88impl SurfaceMesh {
89 pub fn new(name: impl Into<String>, vertices: Vec<Vec3>, faces: Vec<Vec<u32>>) -> Self {
94 let mut mesh = Self {
95 name: name.into(),
96 vertices,
97 faces,
98 enabled: true,
99 transform: Mat4::IDENTITY,
100 quantities: Vec::new(),
101
102 triangulation: Vec::new(),
104 face_to_tri_range: Vec::new(),
105 vertex_normals: Vec::new(),
106 face_normals: Vec::new(),
107 corner_normals: Vec::new(),
108 edge_is_real: Vec::new(),
109 edges: Vec::new(),
110 needs_recompute: true,
111
112 material: "clay".to_string(),
114 shade_style: ShadeStyle::default(),
115 edge_width: 1.0,
116 edge_color: Vec4::new(0.0, 0.0, 0.0, 1.0),
117 show_edges: false,
118 backface_policy: BackfacePolicy::default(),
119 backface_color: Vec4::new(0.3, 0.3, 0.3, 1.0),
120 surface_color: Vec4::new(0.5, 0.5, 0.8, 1.0),
121 transparency: 0.0, render_data: None,
124
125 pick_uniform_buffer: None,
126 pick_bind_group: None,
127 pick_face_index_buffer: None,
128 global_start: 0,
129 };
130 mesh.recompute();
131 mesh
132 }
133
134 pub fn from_triangles(
138 name: impl Into<String>,
139 vertices: Vec<Vec3>,
140 triangles: Vec<[u32; 3]>,
141 ) -> Self {
142 let faces: Vec<Vec<u32>> = triangles.into_iter().map(|t| t.to_vec()).collect();
143 Self::new(name, vertices, faces)
144 }
145
146 #[must_use]
148 pub fn num_vertices(&self) -> usize {
149 self.vertices.len()
150 }
151
152 #[must_use]
154 pub fn num_faces(&self) -> usize {
155 self.faces.len()
156 }
157
158 #[must_use]
160 pub fn num_triangles(&self) -> usize {
161 self.triangulation.len()
162 }
163
164 #[must_use]
166 pub fn num_edges(&self) -> usize {
167 self.edges.len()
168 }
169
170 #[must_use]
172 pub fn vertices(&self) -> &[Vec3] {
173 &self.vertices
174 }
175
176 #[must_use]
178 pub fn faces(&self) -> &[Vec<u32>] {
179 &self.faces
180 }
181
182 #[must_use]
184 pub fn triangulation(&self) -> &[[u32; 3]] {
185 &self.triangulation
186 }
187
188 #[must_use]
190 pub fn face_to_tri_range(&self) -> &[Range<usize>] {
191 &self.face_to_tri_range
192 }
193
194 #[must_use]
196 pub fn vertex_normals(&self) -> &[Vec3] {
197 &self.vertex_normals
198 }
199
200 #[must_use]
202 pub fn face_normals(&self) -> &[Vec3] {
203 &self.face_normals
204 }
205
206 #[must_use]
208 pub fn corner_normals(&self) -> &[Vec3] {
209 &self.corner_normals
210 }
211
212 #[must_use]
218 pub fn edge_is_real(&self) -> &[Vec3] {
219 &self.edge_is_real
220 }
221
222 #[must_use]
224 pub fn edges(&self) -> &[(u32, u32)] {
225 &self.edges
226 }
227
228 pub fn update_vertices(&mut self, vertices: Vec<Vec3>) {
230 self.vertices = vertices;
231 self.needs_recompute = true;
232 self.refresh();
233 }
234
235 pub fn update_faces(&mut self, faces: Vec<Vec<u32>>) {
237 self.faces = faces;
238 self.needs_recompute = true;
239 self.refresh();
240 }
241
242 #[must_use]
246 pub fn shade_style(&self) -> ShadeStyle {
247 self.shade_style
248 }
249
250 pub fn set_shade_style(&mut self, style: ShadeStyle) {
252 self.shade_style = style;
253 }
254
255 #[must_use]
257 pub fn edge_width(&self) -> f32 {
258 self.edge_width
259 }
260
261 pub fn set_edge_width(&mut self, width: f32) {
263 self.edge_width = width;
264 }
265
266 #[must_use]
268 pub fn edge_color(&self) -> Vec4 {
269 self.edge_color
270 }
271
272 pub fn set_edge_color(&mut self, color: Vec3) {
274 self.edge_color = color.extend(1.0);
275 }
276
277 #[must_use]
279 pub fn show_edges(&self) -> bool {
280 self.show_edges
281 }
282
283 pub fn set_show_edges(&mut self, show: bool) {
285 self.show_edges = show;
286 }
287
288 #[must_use]
290 pub fn backface_policy(&self) -> BackfacePolicy {
291 self.backface_policy
292 }
293
294 pub fn set_backface_policy(&mut self, policy: BackfacePolicy) {
296 self.backface_policy = policy;
297 }
298
299 #[must_use]
301 pub fn backface_color(&self) -> Vec4 {
302 self.backface_color
303 }
304
305 pub fn set_backface_color(&mut self, color: Vec3) {
307 self.backface_color = color.extend(1.0);
308 }
309
310 #[must_use]
312 pub fn surface_color(&self) -> Vec4 {
313 self.surface_color
314 }
315
316 pub fn set_surface_color(&mut self, color: Vec3) {
318 self.surface_color = color.extend(1.0);
319 }
320
321 #[must_use]
323 pub fn transparency(&self) -> f32 {
324 self.transparency
325 }
326
327 pub fn set_transparency(&mut self, transparency: f32) {
329 self.transparency = transparency.clamp(0.0, 1.0);
330 }
331
332 pub fn build_egui_ui(&mut self, ui: &mut egui::Ui, available_materials: &[&str]) {
334 let mut shade_style = self.shade_style as u32;
335 let mut color = [
336 self.surface_color.x,
337 self.surface_color.y,
338 self.surface_color.z,
339 ];
340 let mut transparency = self.transparency;
341 let mut show_edges = self.show_edges;
342 let mut edge_width = self.edge_width;
343 let mut edge_color = [self.edge_color.x, self.edge_color.y, self.edge_color.z];
344 let mut backface_policy = self.backface_policy as u32;
345
346 if polyscope_ui::build_surface_mesh_ui(
347 ui,
348 self.num_vertices(),
349 self.num_faces(),
350 self.num_edges(),
351 &mut shade_style,
352 &mut color,
353 &mut transparency,
354 &mut show_edges,
355 &mut edge_width,
356 &mut edge_color,
357 &mut backface_policy,
358 &mut self.material,
359 available_materials,
360 ) {
361 self.shade_style = match shade_style {
362 0 => ShadeStyle::Smooth,
363 1 => ShadeStyle::Flat,
364 _ => ShadeStyle::TriFlat,
365 };
366 self.surface_color = Vec4::new(color[0], color[1], color[2], self.surface_color.w);
367 self.transparency = transparency;
368 self.show_edges = show_edges;
369 self.edge_width = edge_width;
370 self.edge_color = Vec4::new(
371 edge_color[0],
372 edge_color[1],
373 edge_color[2],
374 self.edge_color.w,
375 );
376 self.backface_policy = match backface_policy {
377 0 => BackfacePolicy::Identical,
378 1 => BackfacePolicy::Different,
379 2 => BackfacePolicy::Custom,
380 _ => BackfacePolicy::Cull,
381 };
382 }
383
384 if !self.quantities.is_empty() {
386 ui.separator();
387 ui.label("Quantities:");
388 for quantity in &mut self.quantities {
389 if let Some(sq) = quantity
391 .as_any_mut()
392 .downcast_mut::<MeshVertexScalarQuantity>()
393 {
394 sq.build_egui_ui(ui);
395 } else if let Some(sq) = quantity
396 .as_any_mut()
397 .downcast_mut::<MeshFaceScalarQuantity>()
398 {
399 sq.build_egui_ui(ui);
400 } else if let Some(cq) = quantity
401 .as_any_mut()
402 .downcast_mut::<MeshVertexColorQuantity>()
403 {
404 cq.build_egui_ui(ui);
405 } else if let Some(cq) = quantity
406 .as_any_mut()
407 .downcast_mut::<MeshFaceColorQuantity>()
408 {
409 cq.build_egui_ui(ui);
410 } else if let Some(vq) = quantity
411 .as_any_mut()
412 .downcast_mut::<MeshVertexVectorQuantity>()
413 {
414 vq.build_egui_ui(ui);
415 } else if let Some(vq) = quantity
416 .as_any_mut()
417 .downcast_mut::<MeshFaceVectorQuantity>()
418 {
419 vq.build_egui_ui(ui);
420 } else if let Some(pq) = quantity
421 .as_any_mut()
422 .downcast_mut::<MeshVertexParameterizationQuantity>()
423 {
424 pq.build_egui_ui(ui);
425 } else if let Some(pq) = quantity
426 .as_any_mut()
427 .downcast_mut::<MeshCornerParameterizationQuantity>()
428 {
429 pq.build_egui_ui(ui);
430 } else if let Some(iq) = quantity
431 .as_any_mut()
432 .downcast_mut::<MeshVertexIntrinsicVectorQuantity>()
433 {
434 iq.build_egui_ui(ui);
435 } else if let Some(iq) = quantity
436 .as_any_mut()
437 .downcast_mut::<MeshFaceIntrinsicVectorQuantity>()
438 {
439 iq.build_egui_ui(ui);
440 } else if let Some(oq) = quantity.as_any_mut().downcast_mut::<MeshOneFormQuantity>()
441 {
442 oq.build_egui_ui(ui);
443 }
444 }
445 }
446 }
447
448 pub fn init_gpu_resources(
452 &mut self,
453 device: &wgpu::Device,
454 bind_group_layout: &wgpu::BindGroupLayout,
455 camera_buffer: &wgpu::Buffer,
456 ) {
457 self.render_data = Some(SurfaceMeshRenderData::new(
458 device,
459 bind_group_layout,
460 camera_buffer,
461 &self.vertices,
462 &self.triangulation,
463 &self.vertex_normals,
464 &self.edge_is_real,
465 ));
466 }
467
468 #[must_use]
470 pub fn render_data(&self) -> Option<&SurfaceMeshRenderData> {
471 self.render_data.as_ref()
472 }
473
474 pub fn init_shadow_resources(
478 &mut self,
479 device: &wgpu::Device,
480 shadow_bind_group_layout: &wgpu::BindGroupLayout,
481 light_buffer: &wgpu::Buffer,
482 ) {
483 if let Some(render_data) = &mut self.render_data {
484 render_data.init_shadow_resources(device, shadow_bind_group_layout, light_buffer);
485 }
486 }
487
488 #[must_use]
490 pub fn shadow_bind_group(&self) -> Option<&wgpu::BindGroup> {
491 self.render_data.as_ref()?.shadow_bind_group.as_ref()
492 }
493
494 #[must_use]
496 pub fn has_shadow_resources(&self) -> bool {
497 self.render_data
498 .as_ref()
499 .is_some_and(polyscope_render::SurfaceMeshRenderData::has_shadow_resources)
500 }
501
502 pub fn init_pick_resources(
507 &mut self,
508 device: &wgpu::Device,
509 mesh_pick_bind_group_layout: &wgpu::BindGroupLayout,
510 camera_buffer: &wgpu::Buffer,
511 global_start: u32,
512 ) {
513 use wgpu::util::DeviceExt;
514
515 self.global_start = global_start;
516
517 let model = self.transform.to_cols_array_2d();
519 let pick_uniforms = MeshPickUniforms {
520 global_start,
521 _padding: [0.0; 3],
522 model,
523 };
524 let pick_uniform_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
525 label: Some("mesh pick uniforms"),
526 contents: bytemuck::cast_slice(&[pick_uniforms]),
527 usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
528 });
529
530 let mut face_index_data: Vec<u32> = Vec::with_capacity(self.triangulation.len());
533 for (face_idx, range) in self.face_to_tri_range.iter().enumerate() {
534 for _ in range.clone() {
535 face_index_data.push(face_idx as u32);
536 }
537 }
538 let pick_face_index_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
539 label: Some("mesh pick face indices"),
540 contents: bytemuck::cast_slice(&face_index_data),
541 usage: wgpu::BufferUsages::STORAGE,
542 });
543
544 if let Some(render_data) = &self.render_data {
546 let pick_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
547 label: Some("mesh pick bind group"),
548 layout: mesh_pick_bind_group_layout,
549 entries: &[
550 wgpu::BindGroupEntry {
551 binding: 0,
552 resource: camera_buffer.as_entire_binding(),
553 },
554 wgpu::BindGroupEntry {
555 binding: 1,
556 resource: pick_uniform_buffer.as_entire_binding(),
557 },
558 wgpu::BindGroupEntry {
559 binding: 2,
560 resource: render_data.vertex_buffer.as_entire_binding(),
561 },
562 wgpu::BindGroupEntry {
563 binding: 3,
564 resource: pick_face_index_buffer.as_entire_binding(),
565 },
566 ],
567 });
568 self.pick_bind_group = Some(pick_bind_group);
569 }
570
571 self.pick_uniform_buffer = Some(pick_uniform_buffer);
572 self.pick_face_index_buffer = Some(pick_face_index_buffer);
573 }
574
575 #[must_use]
577 pub fn pick_bind_group(&self) -> Option<&wgpu::BindGroup> {
578 self.pick_bind_group.as_ref()
579 }
580
581 pub fn update_pick_uniforms(&self, queue: &wgpu::Queue) {
583 if let Some(buffer) = &self.pick_uniform_buffer {
584 let model = self.transform.to_cols_array_2d();
585 let pick_uniforms = MeshPickUniforms {
586 global_start: self.global_start,
587 _padding: [0.0; 3],
588 model,
589 };
590 queue.write_buffer(buffer, 0, bytemuck::cast_slice(&[pick_uniforms]));
591 }
592 }
593
594 #[must_use]
596 pub fn num_triangulation_vertices(&self) -> u32 {
597 (self.triangulation.len() * 3) as u32
598 }
599
600 pub fn update_gpu_buffers(&self, queue: &wgpu::Queue, color_maps: &ColorMapRegistry) {
602 let Some(render_data) = &self.render_data else {
603 return;
604 };
605
606 let model_matrix = self.transform.to_cols_array_2d();
608
609 let mut use_vertex_color = false;
610
611 if let Some(pq) = self.active_vertex_parameterization_quantity() {
614 use_vertex_color = true;
615 let colors = pq.compute_colors();
616 render_data.update_colors(queue, &colors, &self.triangulation);
617 } else if let Some(pq) = self.active_corner_parameterization_quantity() {
618 use_vertex_color = true;
619 let corner_colors = pq.compute_colors();
622 let mut vertex_colors = vec![Vec4::splat(0.5); self.vertices.len()];
623 let mut counts = vec![0u32; self.vertices.len()];
624 let mut corner_idx = 0;
625 for face in &self.faces {
626 for &vi in face {
627 if corner_idx < corner_colors.len() {
628 vertex_colors[vi as usize] += corner_colors[corner_idx];
629 counts[vi as usize] += 1;
630 corner_idx += 1;
631 }
632 }
633 }
634 for (i, count) in counts.iter().enumerate() {
635 if *count > 0 {
636 vertex_colors[i] /= *count as f32;
637 }
638 }
639 render_data.update_colors(queue, &vertex_colors, &self.triangulation);
640 } else if let Some(cq) = self.active_vertex_color_quantity() {
641 use_vertex_color = true;
642 render_data.update_colors(queue, cq.colors(), &self.triangulation);
644 } else if let Some(cq) = self.active_face_color_quantity() {
645 use_vertex_color = true;
646 let colors = cq.compute_vertex_colors(&self.faces, self.vertices.len());
648 render_data.update_colors(queue, &colors, &self.triangulation);
649 } else if let Some(sq) = self.active_vertex_scalar_quantity() {
650 use_vertex_color = true;
651 if let Some(colormap) = color_maps.get(sq.colormap_name()) {
653 let colors = sq.compute_colors(colormap);
654 render_data.update_colors(queue, &colors, &self.triangulation);
655 }
656 } else if let Some(sq) = self.active_face_scalar_quantity() {
657 use_vertex_color = true;
658 if let Some(colormap) = color_maps.get(sq.colormap_name()) {
660 let colors = sq.compute_vertex_colors(&self.faces, self.vertices.len(), colormap);
661 render_data.update_colors(queue, &colors, &self.triangulation);
662 }
663 } else {
664 render_data.clear_colors(queue);
666 }
667
668 let uniforms = MeshUniforms {
669 model_matrix,
670 shade_style: self.shade_style as u32,
671 show_edges: u32::from(self.show_edges),
672 edge_width: self.edge_width,
673 transparency: self.transparency,
674 surface_color: self.surface_color.to_array(),
675 edge_color: self.edge_color.to_array(),
676 backface_policy: self.backface_policy as u32,
677 slice_planes_enabled: 1,
678 use_vertex_color: u32::from(use_vertex_color),
679 _pad1: 0.0,
680 _pad2: [0.0; 3],
681 _pad3: 0.0,
682 backface_color: self.backface_color.to_array(),
683 };
684 render_data.update_uniforms(queue, &uniforms);
685
686 render_data.update_shadow_model(queue, model_matrix);
688 }
689}
690
691impl Structure for SurfaceMesh {
692 fn as_any(&self) -> &dyn std::any::Any {
693 self
694 }
695
696 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
697 self
698 }
699
700 fn name(&self) -> &str {
701 &self.name
702 }
703
704 fn type_name(&self) -> &'static str {
705 "SurfaceMesh"
706 }
707
708 fn bounding_box(&self) -> Option<(Vec3, Vec3)> {
709 if self.vertices.is_empty() {
710 return None;
711 }
712
713 let mut min = Vec3::splat(f32::MAX);
714 let mut max = Vec3::splat(f32::MIN);
715
716 for &v in &self.vertices {
717 min = min.min(v);
718 max = max.max(v);
719 }
720
721 let transform = self.transform;
723 let corners = [
724 transform.transform_point3(Vec3::new(min.x, min.y, min.z)),
725 transform.transform_point3(Vec3::new(max.x, min.y, min.z)),
726 transform.transform_point3(Vec3::new(min.x, max.y, min.z)),
727 transform.transform_point3(Vec3::new(max.x, max.y, min.z)),
728 transform.transform_point3(Vec3::new(min.x, min.y, max.z)),
729 transform.transform_point3(Vec3::new(max.x, min.y, max.z)),
730 transform.transform_point3(Vec3::new(min.x, max.y, max.z)),
731 transform.transform_point3(Vec3::new(max.x, max.y, max.z)),
732 ];
733
734 let mut world_min = Vec3::splat(f32::MAX);
735 let mut world_max = Vec3::splat(f32::MIN);
736 for corner in corners {
737 world_min = world_min.min(corner);
738 world_max = world_max.max(corner);
739 }
740
741 Some((world_min, world_max))
742 }
743
744 fn length_scale(&self) -> f32 {
745 self.bounding_box()
746 .map_or(1.0, |(min, max)| (max - min).length())
747 }
748
749 fn transform(&self) -> Mat4 {
750 self.transform
751 }
752
753 fn set_transform(&mut self, transform: Mat4) {
754 self.transform = transform;
755 }
756
757 fn is_enabled(&self) -> bool {
758 self.enabled
759 }
760
761 fn set_enabled(&mut self, enabled: bool) {
762 self.enabled = enabled;
763 }
764
765 fn material(&self) -> &str {
766 &self.material
767 }
768
769 fn set_material(&mut self, material: &str) {
770 self.material = material.to_string();
771 }
772
773 fn draw(&self, _ctx: &mut dyn RenderContext) {
774 }
776
777 fn draw_pick(&self, _ctx: &mut dyn RenderContext) {
778 }
780
781 fn build_ui(&mut self, _ui: &dyn std::any::Any) {
782 }
784
785 fn build_pick_ui(&self, _ui: &dyn std::any::Any, _pick: &PickResult) {
786 }
788
789 fn clear_gpu_resources(&mut self) {
790 self.render_data = None;
791 self.pick_uniform_buffer = None;
792 self.pick_bind_group = None;
793 self.pick_face_index_buffer = None;
794 for quantity in &mut self.quantities {
795 quantity.clear_gpu_resources();
796 }
797 }
798
799 fn refresh(&mut self) {
800 self.recompute();
801 for quantity in &mut self.quantities {
802 quantity.refresh();
803 }
804 }
805}
806
807impl HasQuantities for SurfaceMesh {
808 fn add_quantity(&mut self, quantity: Box<dyn Quantity>) {
809 self.quantities.push(quantity);
810 }
811
812 fn get_quantity(&self, name: &str) -> Option<&dyn Quantity> {
813 self.quantities
814 .iter()
815 .find(|q| q.name() == name)
816 .map(std::convert::AsRef::as_ref)
817 }
818
819 fn get_quantity_mut(&mut self, name: &str) -> Option<&mut Box<dyn Quantity>> {
820 self.quantities.iter_mut().find(|q| q.name() == name)
821 }
822
823 fn remove_quantity(&mut self, name: &str) -> Option<Box<dyn Quantity>> {
824 let idx = self.quantities.iter().position(|q| q.name() == name)?;
825 Some(self.quantities.remove(idx))
826 }
827
828 fn quantities(&self) -> &[Box<dyn Quantity>] {
829 &self.quantities
830 }
831}
832
833#[cfg(test)]
834mod tests {
835 use super::*;
836
837 #[test]
839 fn test_surface_mesh_creation_and_triangulation() {
840 let vertices = vec![
842 Vec3::new(0.0, 0.0, 0.0),
843 Vec3::new(1.0, 0.0, 0.0),
844 Vec3::new(0.5, 1.0, 0.0),
845 ];
846 let mesh = SurfaceMesh::new("test_tri", vertices, vec![vec![0, 1, 2]]);
847 assert_eq!(mesh.num_vertices(), 3);
848 assert_eq!(mesh.num_faces(), 1);
849 assert_eq!(mesh.num_triangles(), 1);
850 assert_eq!(mesh.triangulation()[0], [0, 1, 2]);
851
852 let vertices = vec![
854 Vec3::new(0.0, 0.0, 0.0),
855 Vec3::new(1.0, 0.0, 0.0),
856 Vec3::new(1.0, 1.0, 0.0),
857 Vec3::new(0.0, 1.0, 0.0),
858 ];
859 let mesh = SurfaceMesh::new("test_quad", vertices, vec![vec![0, 1, 2, 3]]);
860 assert_eq!(mesh.num_vertices(), 4);
861 assert_eq!(mesh.num_faces(), 1);
862 assert_eq!(mesh.num_triangles(), 2);
863 assert_eq!(mesh.triangulation()[0], [0, 1, 2]);
864 assert_eq!(mesh.triangulation()[1], [0, 2, 3]);
865 assert_eq!(mesh.face_to_tri_range()[0], 0..2);
866 }
867
868 #[test]
870 fn test_face_normals() {
871 let vertices = vec![
873 Vec3::new(0.0, 0.0, 0.0),
874 Vec3::new(1.0, 0.0, 0.0),
875 Vec3::new(0.0, 1.0, 0.0),
876 ];
877 let faces = vec![vec![0, 1, 2]];
878
879 let mesh = SurfaceMesh::new("test_normal", vertices, faces);
880
881 assert_eq!(mesh.face_normals().len(), 1);
882 let normal = mesh.face_normals()[0];
883 assert!(
885 (normal.z - 1.0).abs() < 1e-6,
886 "Normal Z should be 1.0, got {}",
887 normal.z
888 );
889 assert!(
890 normal.x.abs() < 1e-6,
891 "Normal X should be 0.0, got {}",
892 normal.x
893 );
894 assert!(
895 normal.y.abs() < 1e-6,
896 "Normal Y should be 0.0, got {}",
897 normal.y
898 );
899 }
900
901 #[test]
903 fn test_edges() {
904 let vertices = vec![
905 Vec3::new(0.0, 0.0, 0.0),
906 Vec3::new(1.0, 0.0, 0.0),
907 Vec3::new(0.5, 1.0, 0.0),
908 ];
909 let faces = vec![vec![0, 1, 2]];
910
911 let mesh = SurfaceMesh::new("test_edges", vertices, faces);
912
913 assert_eq!(mesh.num_edges(), 3);
915
916 let edges = mesh.edges();
918 assert!(edges.contains(&(0, 1)));
919 assert!(edges.contains(&(1, 2)));
920 assert!(edges.contains(&(0, 2)));
921 }
922
923 #[test]
925 fn test_vertex_normals() {
926 let vertices = vec![
928 Vec3::new(0.0, 0.0, 0.0),
929 Vec3::new(1.0, 0.0, 0.0),
930 Vec3::new(0.0, 1.0, 0.0),
931 ];
932 let faces = vec![vec![0, 1, 2]];
933
934 let mesh = SurfaceMesh::new("test_vnormals", vertices, faces);
935
936 assert_eq!(mesh.vertex_normals().len(), 3);
938 for normal in mesh.vertex_normals() {
939 assert!(
940 (normal.z - 1.0).abs() < 1e-6,
941 "Vertex normal Z should be 1.0"
942 );
943 }
944 }
945
946 #[test]
948 fn test_pentagon_triangulation() {
949 let vertices = vec![
950 Vec3::new(0.0, 0.0, 0.0),
951 Vec3::new(1.0, 0.0, 0.0),
952 Vec3::new(1.5, 0.5, 0.0),
953 Vec3::new(0.75, 1.0, 0.0),
954 Vec3::new(-0.25, 0.5, 0.0),
955 ];
956 let faces = vec![vec![0, 1, 2, 3, 4]];
957
958 let mesh = SurfaceMesh::new("test_pentagon", vertices, faces);
959
960 assert_eq!(mesh.num_triangles(), 3);
962 assert_eq!(mesh.triangulation()[0], [0, 1, 2]);
963 assert_eq!(mesh.triangulation()[1], [0, 2, 3]);
964 assert_eq!(mesh.triangulation()[2], [0, 3, 4]);
965
966 assert_eq!(mesh.num_edges(), 5);
968 }
969
970 #[test]
972 fn test_shared_edges() {
973 let vertices = vec![
975 Vec3::new(0.0, 0.0, 0.0),
976 Vec3::new(1.0, 0.0, 0.0),
977 Vec3::new(0.5, 1.0, 0.0),
978 Vec3::new(0.5, -1.0, 0.0),
979 ];
980 let faces = vec![vec![0, 1, 2], vec![0, 3, 1]];
981
982 let mesh = SurfaceMesh::new("test_shared", vertices, faces);
983
984 assert_eq!(mesh.num_triangles(), 2);
986 assert_eq!(mesh.num_edges(), 5);
987 }
988
989 #[test]
991 fn test_render_options() {
992 let vertices = vec![
993 Vec3::new(0.0, 0.0, 0.0),
994 Vec3::new(1.0, 0.0, 0.0),
995 Vec3::new(0.5, 1.0, 0.0),
996 ];
997 let faces = vec![vec![0, 1, 2]];
998
999 let mut mesh = SurfaceMesh::new("test_options", vertices, faces);
1000
1001 assert_eq!(mesh.shade_style(), ShadeStyle::Smooth);
1003 assert_eq!(mesh.backface_policy(), BackfacePolicy::Identical);
1004 assert!(!mesh.show_edges());
1005 assert_eq!(mesh.transparency(), 0.0); mesh.set_shade_style(ShadeStyle::Flat);
1009 assert_eq!(mesh.shade_style(), ShadeStyle::Flat);
1010
1011 mesh.set_backface_policy(BackfacePolicy::Cull);
1012 assert_eq!(mesh.backface_policy(), BackfacePolicy::Cull);
1013
1014 mesh.set_show_edges(true);
1015 assert!(mesh.show_edges());
1016
1017 mesh.set_edge_width(2.0);
1018 assert_eq!(mesh.edge_width(), 2.0);
1019
1020 mesh.set_edge_color(Vec3::new(1.0, 0.0, 0.0));
1021 assert_eq!(mesh.edge_color(), Vec4::new(1.0, 0.0, 0.0, 1.0));
1022
1023 mesh.set_surface_color(Vec3::new(0.0, 1.0, 0.0));
1024 assert_eq!(mesh.surface_color(), Vec4::new(0.0, 1.0, 0.0, 1.0));
1025
1026 mesh.set_backface_color(Vec3::new(0.0, 0.0, 1.0));
1027 assert_eq!(mesh.backface_color(), Vec4::new(0.0, 0.0, 1.0, 1.0));
1028
1029 mesh.set_transparency(0.5);
1030 assert_eq!(mesh.transparency(), 0.5);
1031
1032 mesh.set_transparency(1.5);
1034 assert_eq!(mesh.transparency(), 1.0);
1035 mesh.set_transparency(-0.5);
1036 assert_eq!(mesh.transparency(), 0.0);
1037 }
1038
1039 #[test]
1041 fn test_surface_mesh_quantities() {
1042 use polyscope_core::quantity::QuantityKind;
1043
1044 let vertices = vec![
1045 Vec3::new(0.0, 0.0, 0.0),
1046 Vec3::new(1.0, 0.0, 0.0),
1047 Vec3::new(0.0, 1.0, 0.0),
1048 ];
1049 let faces = vec![vec![0, 1, 2]];
1050 let mut mesh = SurfaceMesh::new("test", vertices, faces);
1051
1052 mesh.add_vertex_scalar_quantity("height", vec![0.0, 0.5, 1.0]);
1054 mesh.add_vertex_color_quantity("colors", vec![Vec3::X, Vec3::Y, Vec3::Z]);
1055 mesh.add_vertex_vector_quantity("normals", vec![Vec3::Z, Vec3::Z, Vec3::Z]);
1056
1057 mesh.add_face_scalar_quantity("area", vec![1.0]);
1059 mesh.add_face_color_quantity("face_colors", vec![Vec3::new(1.0, 0.0, 0.0)]);
1060 mesh.add_face_vector_quantity("face_normals", vec![Vec3::Z]);
1061
1062 let cases: &[(&str, usize, QuantityKind)] = &[
1063 ("height", 3, QuantityKind::Scalar),
1064 ("colors", 3, QuantityKind::Color),
1065 ("normals", 3, QuantityKind::Vector),
1066 ("area", 1, QuantityKind::Scalar),
1067 ("face_colors", 1, QuantityKind::Color),
1068 ("face_normals", 1, QuantityKind::Vector),
1069 ];
1070
1071 for (name, expected_size, expected_kind) in cases {
1072 let q = mesh
1073 .get_quantity(name)
1074 .unwrap_or_else(|| panic!("quantity '{name}' not found"));
1075 assert_eq!(
1076 q.data_size(),
1077 *expected_size,
1078 "data_size mismatch for {name}"
1079 );
1080 assert_eq!(q.kind(), *expected_kind, "kind mismatch for {name}");
1081 }
1082 }
1083
1084 #[test]
1086 fn test_face_scalar_compute_vertex_colors() {
1087 let fsq = MeshFaceScalarQuantity::new("test", "mesh", vec![0.0, 1.0]);
1088 let faces = vec![vec![0, 1, 2], vec![2, 1, 3]];
1089 let colormap = polyscope_render::ColorMap::new("test", vec![Vec3::ZERO, Vec3::ONE]);
1090
1091 let colors = fsq.compute_vertex_colors(&faces, 4, &colormap);
1092
1093 assert_eq!(colors.len(), 4);
1095 assert!((colors[0] - Vec4::new(0.0, 0.0, 0.0, 1.0)).length() < 1e-5);
1097 assert!((colors[3] - Vec4::new(1.0, 1.0, 1.0, 1.0)).length() < 1e-5);
1099 }
1100
1101 #[test]
1103 fn test_face_color_compute_vertex_colors() {
1104 let fcq = MeshFaceColorQuantity::new(
1105 "test",
1106 "mesh",
1107 vec![Vec3::new(1.0, 0.0, 0.0), Vec3::new(0.0, 1.0, 0.0)],
1108 );
1109 let faces = vec![vec![0, 1, 2], vec![2, 1, 3]];
1110
1111 let colors = fcq.compute_vertex_colors(&faces, 4);
1112
1113 assert_eq!(colors.len(), 4);
1114 assert_eq!(colors[0], Vec4::new(1.0, 0.0, 0.0, 1.0));
1116 assert_eq!(colors[3], Vec4::new(0.0, 1.0, 0.0, 1.0));
1118 }
1119
1120 #[test]
1122 fn test_edge_is_real_triangle() {
1123 let vertices = vec![
1124 Vec3::new(0.0, 0.0, 0.0),
1125 Vec3::new(1.0, 0.0, 0.0),
1126 Vec3::new(0.5, 1.0, 0.0),
1127 ];
1128 let faces = vec![vec![0, 1, 2]];
1129
1130 let mesh = SurfaceMesh::new("test_tri", vertices, faces);
1131
1132 assert_eq!(mesh.edge_is_real().len(), 3);
1134
1135 let expected = Vec3::new(1.0, 1.0, 1.0);
1138 for edge_real in mesh.edge_is_real() {
1139 assert_eq!(*edge_real, expected);
1140 }
1141 }
1142
1143 #[test]
1145 fn test_edge_is_real_quad() {
1146 let vertices = vec![
1147 Vec3::new(0.0, 0.0, 0.0),
1148 Vec3::new(1.0, 0.0, 0.0),
1149 Vec3::new(1.0, 1.0, 0.0),
1150 Vec3::new(0.0, 1.0, 0.0),
1151 ];
1152 let faces = vec![vec![0, 1, 2, 3]];
1153
1154 let mesh = SurfaceMesh::new("test_quad", vertices, faces);
1155
1156 assert_eq!(mesh.edge_is_real().len(), 6);
1158
1159 let tri0_expected = Vec3::new(1.0, 1.0, 0.0);
1165
1166 let tri1_expected = Vec3::new(0.0, 1.0, 1.0);
1171
1172 assert_eq!(mesh.edge_is_real()[0], tri0_expected);
1174 assert_eq!(mesh.edge_is_real()[1], tri0_expected);
1175 assert_eq!(mesh.edge_is_real()[2], tri0_expected);
1176
1177 assert_eq!(mesh.edge_is_real()[3], tri1_expected);
1179 assert_eq!(mesh.edge_is_real()[4], tri1_expected);
1180 assert_eq!(mesh.edge_is_real()[5], tri1_expected);
1181 }
1182
1183 #[test]
1185 fn test_edge_is_real_pentagon() {
1186 let vertices = vec![
1187 Vec3::new(0.0, 0.0, 0.0),
1188 Vec3::new(1.0, 0.0, 0.0),
1189 Vec3::new(1.5, 0.5, 0.0),
1190 Vec3::new(0.75, 1.0, 0.0),
1191 Vec3::new(-0.25, 0.5, 0.0),
1192 ];
1193 let faces = vec![vec![0, 1, 2, 3, 4]];
1194
1195 let mesh = SurfaceMesh::new("test_pentagon", vertices, faces);
1196
1197 assert_eq!(mesh.edge_is_real().len(), 9);
1199
1200 let tri0_expected = Vec3::new(1.0, 1.0, 0.0);
1206 let tri1_expected = Vec3::new(0.0, 1.0, 0.0);
1207 let tri2_expected = Vec3::new(0.0, 1.0, 1.0);
1208
1209 assert_eq!(mesh.edge_is_real()[0], tri0_expected);
1211 assert_eq!(mesh.edge_is_real()[1], tri0_expected);
1212 assert_eq!(mesh.edge_is_real()[2], tri0_expected);
1213
1214 assert_eq!(mesh.edge_is_real()[3], tri1_expected);
1216 assert_eq!(mesh.edge_is_real()[4], tri1_expected);
1217 assert_eq!(mesh.edge_is_real()[5], tri1_expected);
1218
1219 assert_eq!(mesh.edge_is_real()[6], tri2_expected);
1221 assert_eq!(mesh.edge_is_real()[7], tri2_expected);
1222 assert_eq!(mesh.edge_is_real()[8], tri2_expected);
1223 }
1224}