polyscope_core/structure.rs
1//! Structure trait and related types.
2//!
3//! A [`Structure`] represents a geometric object in the scene, such as a point cloud,
4//! surface mesh, or curve network.
5
6use std::any::Any;
7
8use glam::{Mat4, Vec3};
9
10use crate::pick::PickResult;
11use crate::quantity::Quantity;
12
13/// A geometric object that can be visualized in polyscope.
14///
15/// Structures are the primary objects managed by polyscope. Each structure has:
16/// - A unique name within its type
17/// - A transform matrix for positioning in the scene
18/// - Visibility state
19/// - Methods for rendering and UI building
20pub trait Structure: Any + Send + Sync {
21 /// Returns a reference to self as `Any` for downcasting.
22 fn as_any(&self) -> &dyn Any;
23
24 /// Returns a mutable reference to self as `Any` for downcasting.
25 fn as_any_mut(&mut self) -> &mut dyn Any;
26 /// Returns the unique name of this structure.
27 fn name(&self) -> &str;
28
29 /// Returns the type name of this structure (e.g., "`PointCloud`", "`SurfaceMesh`").
30 fn type_name(&self) -> &'static str;
31
32 /// Returns the axis-aligned bounding box in world coordinates.
33 ///
34 /// Returns `None` if the structure has no spatial extent.
35 fn bounding_box(&self) -> Option<(Vec3, Vec3)>;
36
37 /// Returns a characteristic length scale for this structure.
38 fn length_scale(&self) -> f32;
39
40 /// Returns the current model transform matrix.
41 fn transform(&self) -> Mat4;
42
43 /// Sets the model transform matrix.
44 fn set_transform(&mut self, transform: Mat4);
45
46 /// Returns whether this structure is currently visible.
47 fn is_enabled(&self) -> bool;
48
49 /// Sets the visibility of this structure.
50 fn set_enabled(&mut self, enabled: bool);
51
52 /// Draws this structure to the scene.
53 ///
54 /// Called during the main render pass.
55 fn draw(&self, ctx: &mut dyn RenderContext);
56
57 /// Draws this structure for picking/selection.
58 ///
59 /// Called during the pick render pass.
60 fn draw_pick(&self, ctx: &mut dyn RenderContext);
61
62 /// Builds the `ImGui` UI for this structure.
63 fn build_ui(&mut self, ui: &dyn std::any::Any);
64
65 /// Builds the `ImGui` UI for a picked element.
66 fn build_pick_ui(&self, ui: &dyn std::any::Any, pick: &PickResult);
67
68 /// Refreshes GPU resources after data changes.
69 fn refresh(&mut self);
70
71 /// Centers the camera on this structure's bounding box.
72 fn center_bounding_box(&mut self) {
73 // Default implementation - can be overridden
74 }
75
76 /// Resets the transform to identity.
77 fn reset_transform(&mut self) {
78 self.set_transform(Mat4::IDENTITY);
79 }
80
81 /// Clears all GPU resources (render data, pick buffers, etc.).
82 ///
83 /// After calling this, the structure's GPU resources will be lazily
84 /// re-initialized on the next render frame. This is needed when switching
85 /// wgpu devices (e.g., between headless render calls).
86 fn clear_gpu_resources(&mut self) {
87 // Default no-op; each structure type overrides this
88 }
89
90 /// Returns the material name for this structure (e.g., "clay", "wax").
91 #[allow(clippy::unnecessary_literal_bound)]
92 fn material(&self) -> &str {
93 "clay"
94 }
95
96 /// Sets the material for this structure by name.
97 fn set_material(&mut self, _material: &str) {
98 // Default no-op; structures that support materials override this
99 }
100}
101
102/// A structure that can have quantities attached to it.
103pub trait HasQuantities: Structure {
104 /// Adds a quantity to this structure.
105 fn add_quantity(&mut self, quantity: Box<dyn Quantity>);
106
107 /// Gets a quantity by name.
108 fn get_quantity(&self, name: &str) -> Option<&dyn Quantity>;
109
110 /// Gets a mutable quantity by name.
111 fn get_quantity_mut(&mut self, name: &str) -> Option<&mut Box<dyn Quantity>>;
112
113 /// Removes a quantity by name.
114 fn remove_quantity(&mut self, name: &str) -> Option<Box<dyn Quantity>>;
115
116 /// Returns all quantities attached to this structure.
117 fn quantities(&self) -> &[Box<dyn Quantity>];
118
119 /// Returns the number of quantities attached.
120 fn num_quantities(&self) -> usize {
121 self.quantities().len()
122 }
123}
124
125/// Trait for render context - will be implemented in polyscope-render.
126///
127/// This is a placeholder trait to avoid circular dependencies.
128pub trait RenderContext: Send + Sync {}