1use glam::{Vec3, Vec4};
4use polyscope_core::quantity::{EdgeQuantity, Quantity, QuantityKind, VertexQuantity};
5use polyscope_render::{ColorMap, CurveNetworkRenderData};
6
7pub struct CurveNodeScalarQuantity {
9 name: String,
10 structure_name: String,
11 values: Vec<f32>,
12 enabled: bool,
13 colormap_name: String,
14 range_min: f32,
15 range_max: f32,
16}
17
18impl CurveNodeScalarQuantity {
19 pub fn new(
21 name: impl Into<String>,
22 structure_name: impl Into<String>,
23 values: Vec<f32>,
24 ) -> Self {
25 let min = values.iter().copied().fold(f32::INFINITY, f32::min);
26 let max = values.iter().copied().fold(f32::NEG_INFINITY, f32::max);
27
28 Self {
29 name: name.into(),
30 structure_name: structure_name.into(),
31 values,
32 enabled: false,
33 colormap_name: "viridis".to_string(),
34 range_min: min,
35 range_max: max,
36 }
37 }
38
39 #[must_use]
41 pub fn values(&self) -> &[f32] {
42 &self.values
43 }
44
45 #[must_use]
47 pub fn compute_colors(&self, colormap: &ColorMap) -> Vec<Vec4> {
48 let range = self.range_max - self.range_min;
49 let range = if range.abs() < 1e-10 { 1.0 } else { range };
50
51 self.values
52 .iter()
53 .map(|&v| {
54 let t = (v - self.range_min) / range;
55 colormap.sample(t).extend(1.0)
56 })
57 .collect()
58 }
59
60 #[must_use]
62 pub fn colormap_name(&self) -> &str {
63 &self.colormap_name
64 }
65
66 pub fn set_colormap(&mut self, name: impl Into<String>) {
68 self.colormap_name = name.into();
69 }
70
71 #[must_use]
73 pub fn range_min(&self) -> f32 {
74 self.range_min
75 }
76
77 #[must_use]
79 pub fn range_max(&self) -> f32 {
80 self.range_max
81 }
82
83 pub fn set_range(&mut self, min: f32, max: f32) {
85 self.range_min = min;
86 self.range_max = max;
87 }
88
89 pub fn build_egui_ui(&mut self, ui: &mut egui::Ui) -> bool {
91 let colormaps = ["viridis", "blues", "reds", "coolwarm", "rainbow"];
92 polyscope_ui::build_scalar_quantity_ui(
93 ui,
94 &self.name,
95 &mut self.enabled,
96 &mut self.colormap_name,
97 &mut self.range_min,
98 &mut self.range_max,
99 &colormaps,
100 )
101 }
102}
103
104impl Quantity for CurveNodeScalarQuantity {
105 fn as_any(&self) -> &dyn std::any::Any {
106 self
107 }
108
109 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
110 self
111 }
112
113 fn name(&self) -> &str {
114 &self.name
115 }
116
117 fn structure_name(&self) -> &str {
118 &self.structure_name
119 }
120
121 fn kind(&self) -> QuantityKind {
122 QuantityKind::Scalar
123 }
124
125 fn is_enabled(&self) -> bool {
126 self.enabled
127 }
128
129 fn set_enabled(&mut self, enabled: bool) {
130 self.enabled = enabled;
131 }
132
133 fn build_ui(&mut self, _ui: &dyn std::any::Any) {
134 }
136
137 fn refresh(&mut self) {
138 }
140
141 fn data_size(&self) -> usize {
142 self.values.len()
143 }
144}
145
146impl VertexQuantity for CurveNodeScalarQuantity {}
147
148pub struct CurveEdgeScalarQuantity {
150 name: String,
151 structure_name: String,
152 values: Vec<f32>,
153 enabled: bool,
154 colormap_name: String,
155 range_min: f32,
156 range_max: f32,
157}
158
159impl CurveEdgeScalarQuantity {
160 pub fn new(
162 name: impl Into<String>,
163 structure_name: impl Into<String>,
164 values: Vec<f32>,
165 ) -> Self {
166 let min = values.iter().copied().fold(f32::INFINITY, f32::min);
167 let max = values.iter().copied().fold(f32::NEG_INFINITY, f32::max);
168
169 Self {
170 name: name.into(),
171 structure_name: structure_name.into(),
172 values,
173 enabled: false,
174 colormap_name: "viridis".to_string(),
175 range_min: min,
176 range_max: max,
177 }
178 }
179
180 #[must_use]
182 pub fn values(&self) -> &[f32] {
183 &self.values
184 }
185
186 #[must_use]
188 pub fn compute_colors(&self, colormap: &ColorMap) -> Vec<Vec4> {
189 let range = self.range_max - self.range_min;
190 let range = if range.abs() < 1e-10 { 1.0 } else { range };
191
192 self.values
193 .iter()
194 .map(|&v| {
195 let t = (v - self.range_min) / range;
196 colormap.sample(t).extend(1.0)
197 })
198 .collect()
199 }
200
201 #[must_use]
203 pub fn colormap_name(&self) -> &str {
204 &self.colormap_name
205 }
206
207 pub fn set_colormap(&mut self, name: impl Into<String>) {
209 self.colormap_name = name.into();
210 }
211
212 #[must_use]
214 pub fn range_min(&self) -> f32 {
215 self.range_min
216 }
217
218 #[must_use]
220 pub fn range_max(&self) -> f32 {
221 self.range_max
222 }
223
224 pub fn set_range(&mut self, min: f32, max: f32) {
226 self.range_min = min;
227 self.range_max = max;
228 }
229
230 pub fn build_egui_ui(&mut self, ui: &mut egui::Ui) -> bool {
232 let colormaps = ["viridis", "blues", "reds", "coolwarm", "rainbow"];
233 polyscope_ui::build_scalar_quantity_ui(
234 ui,
235 &self.name,
236 &mut self.enabled,
237 &mut self.colormap_name,
238 &mut self.range_min,
239 &mut self.range_max,
240 &colormaps,
241 )
242 }
243}
244
245impl Quantity for CurveEdgeScalarQuantity {
246 fn as_any(&self) -> &dyn std::any::Any {
247 self
248 }
249
250 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
251 self
252 }
253
254 fn name(&self) -> &str {
255 &self.name
256 }
257
258 fn structure_name(&self) -> &str {
259 &self.structure_name
260 }
261
262 fn kind(&self) -> QuantityKind {
263 QuantityKind::Scalar
264 }
265
266 fn is_enabled(&self) -> bool {
267 self.enabled
268 }
269
270 fn set_enabled(&mut self, enabled: bool) {
271 self.enabled = enabled;
272 }
273
274 fn build_ui(&mut self, _ui: &dyn std::any::Any) {
275 }
277
278 fn refresh(&mut self) {
279 }
281
282 fn data_size(&self) -> usize {
283 self.values.len()
284 }
285}
286
287impl EdgeQuantity for CurveEdgeScalarQuantity {}
288
289pub struct CurveNodeColorQuantity {
291 name: String,
292 structure_name: String,
293 colors: Vec<Vec4>,
294 enabled: bool,
295}
296
297impl CurveNodeColorQuantity {
298 pub fn new(
300 name: impl Into<String>,
301 structure_name: impl Into<String>,
302 colors: Vec<Vec3>,
303 ) -> Self {
304 Self {
305 name: name.into(),
306 structure_name: structure_name.into(),
307 colors: colors.into_iter().map(|c| c.extend(1.0)).collect(),
308 enabled: false,
309 }
310 }
311
312 #[must_use]
314 pub fn colors(&self) -> &[Vec4] {
315 &self.colors
316 }
317
318 pub fn apply_to_render_data(&self, queue: &wgpu::Queue, render_data: &CurveNetworkRenderData) {
320 render_data.update_node_colors(queue, &self.colors);
321 }
322
323 pub fn build_egui_ui(&mut self, ui: &mut egui::Ui) -> bool {
325 polyscope_ui::build_color_quantity_ui(ui, &self.name, &mut self.enabled, self.colors.len())
326 }
327}
328
329impl Quantity for CurveNodeColorQuantity {
330 fn as_any(&self) -> &dyn std::any::Any {
331 self
332 }
333
334 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
335 self
336 }
337
338 fn name(&self) -> &str {
339 &self.name
340 }
341
342 fn structure_name(&self) -> &str {
343 &self.structure_name
344 }
345
346 fn kind(&self) -> QuantityKind {
347 QuantityKind::Color
348 }
349
350 fn is_enabled(&self) -> bool {
351 self.enabled
352 }
353
354 fn set_enabled(&mut self, enabled: bool) {
355 self.enabled = enabled;
356 }
357
358 fn build_ui(&mut self, _ui: &dyn std::any::Any) {
359 }
361
362 fn refresh(&mut self) {
363 }
365
366 fn data_size(&self) -> usize {
367 self.colors.len()
368 }
369}
370
371impl VertexQuantity for CurveNodeColorQuantity {}
372
373pub struct CurveEdgeColorQuantity {
375 name: String,
376 structure_name: String,
377 colors: Vec<Vec4>,
378 enabled: bool,
379}
380
381impl CurveEdgeColorQuantity {
382 pub fn new(
384 name: impl Into<String>,
385 structure_name: impl Into<String>,
386 colors: Vec<Vec3>,
387 ) -> Self {
388 Self {
389 name: name.into(),
390 structure_name: structure_name.into(),
391 colors: colors.into_iter().map(|c| c.extend(1.0)).collect(),
392 enabled: false,
393 }
394 }
395
396 #[must_use]
398 pub fn colors(&self) -> &[Vec4] {
399 &self.colors
400 }
401
402 pub fn apply_to_render_data(&self, queue: &wgpu::Queue, render_data: &CurveNetworkRenderData) {
404 render_data.update_edge_colors(queue, &self.colors);
405 }
406
407 pub fn build_egui_ui(&mut self, ui: &mut egui::Ui) -> bool {
409 polyscope_ui::build_color_quantity_ui(ui, &self.name, &mut self.enabled, self.colors.len())
410 }
411}
412
413impl Quantity for CurveEdgeColorQuantity {
414 fn as_any(&self) -> &dyn std::any::Any {
415 self
416 }
417
418 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
419 self
420 }
421
422 fn name(&self) -> &str {
423 &self.name
424 }
425
426 fn structure_name(&self) -> &str {
427 &self.structure_name
428 }
429
430 fn kind(&self) -> QuantityKind {
431 QuantityKind::Color
432 }
433
434 fn is_enabled(&self) -> bool {
435 self.enabled
436 }
437
438 fn set_enabled(&mut self, enabled: bool) {
439 self.enabled = enabled;
440 }
441
442 fn build_ui(&mut self, _ui: &dyn std::any::Any) {
443 }
445
446 fn refresh(&mut self) {
447 }
449
450 fn data_size(&self) -> usize {
451 self.colors.len()
452 }
453}
454
455impl EdgeQuantity for CurveEdgeColorQuantity {}
456
457pub struct CurveNodeVectorQuantity {
459 name: String,
460 structure_name: String,
461 vectors: Vec<Vec3>,
462 enabled: bool,
463 length_scale: f32,
464 radius: f32,
465 color: Vec4,
466}
467
468impl CurveNodeVectorQuantity {
469 pub fn new(
471 name: impl Into<String>,
472 structure_name: impl Into<String>,
473 vectors: Vec<Vec3>,
474 ) -> Self {
475 Self {
476 name: name.into(),
477 structure_name: structure_name.into(),
478 vectors,
479 enabled: false,
480 length_scale: 1.0,
481 radius: 0.005,
482 color: Vec4::new(0.8, 0.2, 0.2, 1.0),
483 }
484 }
485
486 #[must_use]
488 pub fn vectors(&self) -> &[Vec3] {
489 &self.vectors
490 }
491
492 #[must_use]
494 pub fn length_scale(&self) -> f32 {
495 self.length_scale
496 }
497
498 pub fn set_length_scale(&mut self, scale: f32) {
500 self.length_scale = scale;
501 }
502
503 #[must_use]
505 pub fn radius(&self) -> f32 {
506 self.radius
507 }
508
509 pub fn set_radius(&mut self, r: f32) {
511 self.radius = r;
512 }
513
514 #[must_use]
516 pub fn color(&self) -> Vec4 {
517 self.color
518 }
519
520 pub fn set_color(&mut self, c: Vec3) {
522 self.color = c.extend(1.0);
523 }
524
525 pub fn build_egui_ui(&mut self, ui: &mut egui::Ui) -> bool {
527 let mut color = [self.color.x, self.color.y, self.color.z];
528 let changed = polyscope_ui::build_vector_quantity_ui(
529 ui,
530 &self.name,
531 &mut self.enabled,
532 &mut self.length_scale,
533 &mut self.radius,
534 &mut color,
535 );
536 if changed {
537 self.color = Vec4::new(color[0], color[1], color[2], self.color.w);
538 }
539 changed
540 }
541}
542
543impl Quantity for CurveNodeVectorQuantity {
544 fn as_any(&self) -> &dyn std::any::Any {
545 self
546 }
547
548 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
549 self
550 }
551
552 fn name(&self) -> &str {
553 &self.name
554 }
555
556 fn structure_name(&self) -> &str {
557 &self.structure_name
558 }
559
560 fn kind(&self) -> QuantityKind {
561 QuantityKind::Vector
562 }
563
564 fn is_enabled(&self) -> bool {
565 self.enabled
566 }
567
568 fn set_enabled(&mut self, enabled: bool) {
569 self.enabled = enabled;
570 }
571
572 fn build_ui(&mut self, _ui: &dyn std::any::Any) {
573 }
575
576 fn refresh(&mut self) {
577 }
579
580 fn data_size(&self) -> usize {
581 self.vectors.len()
582 }
583}
584
585impl VertexQuantity for CurveNodeVectorQuantity {}
586
587pub struct CurveEdgeVectorQuantity {
589 name: String,
590 structure_name: String,
591 vectors: Vec<Vec3>,
592 enabled: bool,
593 length_scale: f32,
594 radius: f32,
595 color: Vec4,
596}
597
598impl CurveEdgeVectorQuantity {
599 pub fn new(
601 name: impl Into<String>,
602 structure_name: impl Into<String>,
603 vectors: Vec<Vec3>,
604 ) -> Self {
605 Self {
606 name: name.into(),
607 structure_name: structure_name.into(),
608 vectors,
609 enabled: false,
610 length_scale: 1.0,
611 radius: 0.005,
612 color: Vec4::new(0.2, 0.8, 0.2, 1.0),
613 }
614 }
615
616 #[must_use]
618 pub fn vectors(&self) -> &[Vec3] {
619 &self.vectors
620 }
621
622 #[must_use]
624 pub fn length_scale(&self) -> f32 {
625 self.length_scale
626 }
627
628 pub fn set_length_scale(&mut self, scale: f32) {
630 self.length_scale = scale;
631 }
632
633 #[must_use]
635 pub fn radius(&self) -> f32 {
636 self.radius
637 }
638
639 pub fn set_radius(&mut self, r: f32) {
641 self.radius = r;
642 }
643
644 #[must_use]
646 pub fn color(&self) -> Vec4 {
647 self.color
648 }
649
650 pub fn set_color(&mut self, c: Vec3) {
652 self.color = c.extend(1.0);
653 }
654
655 pub fn build_egui_ui(&mut self, ui: &mut egui::Ui) -> bool {
657 let mut color = [self.color.x, self.color.y, self.color.z];
658 let changed = polyscope_ui::build_vector_quantity_ui(
659 ui,
660 &self.name,
661 &mut self.enabled,
662 &mut self.length_scale,
663 &mut self.radius,
664 &mut color,
665 );
666 if changed {
667 self.color = Vec4::new(color[0], color[1], color[2], self.color.w);
668 }
669 changed
670 }
671}
672
673impl Quantity for CurveEdgeVectorQuantity {
674 fn as_any(&self) -> &dyn std::any::Any {
675 self
676 }
677
678 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
679 self
680 }
681
682 fn name(&self) -> &str {
683 &self.name
684 }
685
686 fn structure_name(&self) -> &str {
687 &self.structure_name
688 }
689
690 fn kind(&self) -> QuantityKind {
691 QuantityKind::Vector
692 }
693
694 fn is_enabled(&self) -> bool {
695 self.enabled
696 }
697
698 fn set_enabled(&mut self, enabled: bool) {
699 self.enabled = enabled;
700 }
701
702 fn build_ui(&mut self, _ui: &dyn std::any::Any) {
703 }
705
706 fn refresh(&mut self) {
707 }
709
710 fn data_size(&self) -> usize {
711 self.vectors.len()
712 }
713}
714
715impl EdgeQuantity for CurveEdgeVectorQuantity {}
716
717#[cfg(test)]
718mod tests {
719 use super::*;
720 use polyscope_core::quantity::QuantityKind;
721
722 #[test]
723 fn test_node_scalar_quantity() {
724 let values = vec![0.0, 0.5, 1.0];
725 let q = CurveNodeScalarQuantity::new("test", "parent", values.clone());
726
727 assert_eq!(q.name(), "test");
728 assert_eq!(q.structure_name(), "parent");
729 assert_eq!(q.values(), &values);
730 assert_eq!(q.range_min(), 0.0);
731 assert_eq!(q.range_max(), 1.0);
732 assert!(!q.is_enabled());
733 }
734
735 #[test]
736 fn test_edge_scalar_quantity() {
737 let values = vec![1.0, 2.0, 3.0];
738 let q = CurveEdgeScalarQuantity::new("edge_scalar", "parent", values.clone());
739
740 assert_eq!(q.name(), "edge_scalar");
741 assert_eq!(q.values(), &values);
742 assert_eq!(q.range_min(), 1.0);
743 assert_eq!(q.range_max(), 3.0);
744 }
745
746 #[test]
747 fn test_node_color_quantity() {
748 let colors = vec![Vec3::X, Vec3::Y, Vec3::Z];
749 let q = CurveNodeColorQuantity::new("colors", "parent", colors);
750
751 assert_eq!(q.name(), "colors");
752 assert_eq!(
753 q.colors(),
754 &[
755 Vec4::new(1.0, 0.0, 0.0, 1.0),
756 Vec4::new(0.0, 1.0, 0.0, 1.0),
757 Vec4::new(0.0, 0.0, 1.0, 1.0)
758 ]
759 );
760 assert_eq!(q.data_size(), 3);
761 }
762
763 #[test]
764 fn test_edge_color_quantity() {
765 let colors = vec![Vec3::ONE, Vec3::ZERO];
766 let q = CurveEdgeColorQuantity::new("edge_colors", "parent", colors);
767
768 assert_eq!(q.name(), "edge_colors");
769 assert_eq!(
770 q.colors(),
771 &[Vec4::new(1.0, 1.0, 1.0, 1.0), Vec4::new(0.0, 0.0, 0.0, 1.0)]
772 );
773 assert_eq!(q.data_size(), 2);
774 }
775
776 #[test]
777 fn test_node_vector_quantity() {
778 let vectors = vec![Vec3::X, Vec3::Y, Vec3::Z];
779 let q = CurveNodeVectorQuantity::new("node_vecs", "parent", vectors.clone());
780
781 assert_eq!(q.name(), "node_vecs");
782 assert_eq!(q.vectors(), &vectors);
783 assert_eq!(q.data_size(), 3);
784 assert_eq!(q.kind(), QuantityKind::Vector);
785 assert!(!q.is_enabled());
786 }
787
788 #[test]
789 fn test_edge_vector_quantity() {
790 let vectors = vec![Vec3::X, Vec3::Y];
791 let q = CurveEdgeVectorQuantity::new("edge_vecs", "parent", vectors.clone());
792
793 assert_eq!(q.name(), "edge_vecs");
794 assert_eq!(q.vectors(), &vectors);
795 assert_eq!(q.data_size(), 2);
796 assert_eq!(q.kind(), QuantityKind::Vector);
797 assert!(!q.is_enabled());
798 }
799}