Skip to main content

polyscope_rs/
slice_plane.rs

1//! Slice plane management.
2//!
3//! Slice planes cut through geometry to reveal interior structure.
4//! They can be positioned interactively via gizmos or programmatically.
5//!
6//! # Example
7//!
8//! ```no_run
9//! use polyscope_rs::*;
10//!
11//! fn main() -> Result<()> {
12//!     init()?;
13//!
14//!     // Register some geometry first...
15//!     register_point_cloud("points", vec![Vec3::ZERO, Vec3::X, Vec3::Y]);
16//!
17//!     // Add a slice plane
18//!     let plane = add_slice_plane("my slice");
19//!     plane.set_pose(Vec3::ZERO, Vec3::X); // origin and normal
20//!     plane.set_draw_plane(true);
21//!     plane.set_draw_widget(true);
22//!
23//!     show();
24//!     Ok(())
25//! }
26//! ```
27
28use crate::{Vec3, Vec4, with_context, with_context_mut};
29
30/// Adds a new slice plane to cut through geometry.
31///
32/// Slice planes allow visualizing the interior of 3D geometry by
33/// discarding fragments on one side of the plane.
34///
35/// The plane is created at the scene center with a size proportional to the
36/// scene's length scale, ensuring it's visible regardless of the scene scale.
37pub fn add_slice_plane(name: impl Into<String>) -> SlicePlaneHandle {
38    let name = name.into();
39    with_context_mut(|ctx| {
40        let length_scale = ctx.length_scale;
41        // Get scene center before creating the plane (to avoid borrow issues)
42        let center = (ctx.bounding_box.0 + ctx.bounding_box.1) * 0.5;
43        let plane = ctx.add_slice_plane(&name);
44        // Set plane_size to be visible relative to the scene
45        // Using length_scale * 0.25 gives a reasonably sized plane
46        plane.set_plane_size(length_scale * 0.25);
47        // Position the plane at the scene center
48        plane.set_origin(center);
49    });
50    SlicePlaneHandle { name }
51}
52
53/// Adds a slice plane with a specific pose.
54pub fn add_slice_plane_with_pose(
55    name: impl Into<String>,
56    origin: Vec3,
57    normal: Vec3,
58) -> SlicePlaneHandle {
59    let name = name.into();
60    with_context_mut(|ctx| {
61        let plane = ctx.add_slice_plane(&name);
62        plane.set_pose(origin, normal);
63    });
64    SlicePlaneHandle { name }
65}
66
67/// Gets an existing slice plane by name.
68#[must_use]
69pub fn get_slice_plane(name: &str) -> Option<SlicePlaneHandle> {
70    with_context(|ctx| {
71        if ctx.has_slice_plane(name) {
72            Some(SlicePlaneHandle {
73                name: name.to_string(),
74            })
75        } else {
76            None
77        }
78    })
79}
80
81/// Removes a slice plane by name.
82pub fn remove_slice_plane(name: &str) {
83    with_context_mut(|ctx| {
84        ctx.remove_slice_plane(name);
85    });
86}
87
88/// Removes all slice planes.
89pub fn remove_all_slice_planes() {
90    with_context_mut(|ctx| {
91        ctx.slice_planes.clear();
92    });
93}
94
95/// Returns all slice plane names.
96#[must_use]
97pub fn get_all_slice_planes() -> Vec<String> {
98    with_context(|ctx| {
99        ctx.slice_plane_names()
100            .into_iter()
101            .map(std::string::ToString::to_string)
102            .collect()
103    })
104}
105
106/// Handle for a slice plane.
107#[derive(Clone)]
108pub struct SlicePlaneHandle {
109    name: String,
110}
111
112impl SlicePlaneHandle {
113    /// Returns the name of this slice plane.
114    #[must_use]
115    pub fn name(&self) -> &str {
116        &self.name
117    }
118
119    /// Sets the pose (origin and normal) of the slice plane.
120    pub fn set_pose(&self, origin: Vec3, normal: Vec3) -> &Self {
121        with_context_mut(|ctx| {
122            if let Some(plane) = ctx.get_slice_plane_mut(&self.name) {
123                plane.set_pose(origin, normal);
124            }
125        });
126        self
127    }
128
129    /// Sets the origin point of the plane.
130    pub fn set_origin(&self, origin: Vec3) -> &Self {
131        with_context_mut(|ctx| {
132            if let Some(plane) = ctx.get_slice_plane_mut(&self.name) {
133                plane.set_origin(origin);
134            }
135        });
136        self
137    }
138
139    /// Gets the origin point of the plane.
140    #[must_use]
141    pub fn origin(&self) -> Vec3 {
142        with_context(|ctx| {
143            ctx.get_slice_plane(&self.name)
144                .map_or(Vec3::ZERO, polyscope_core::SlicePlane::origin)
145        })
146    }
147
148    /// Sets the normal direction of the plane.
149    pub fn set_normal(&self, normal: Vec3) -> &Self {
150        with_context_mut(|ctx| {
151            if let Some(plane) = ctx.get_slice_plane_mut(&self.name) {
152                plane.set_normal(normal);
153            }
154        });
155        self
156    }
157
158    /// Gets the normal direction of the plane.
159    #[must_use]
160    pub fn normal(&self) -> Vec3 {
161        with_context(|ctx| {
162            ctx.get_slice_plane(&self.name)
163                .map_or(Vec3::Y, polyscope_core::SlicePlane::normal)
164        })
165    }
166
167    /// Sets whether the slice plane is enabled.
168    pub fn set_enabled(&self, enabled: bool) -> &Self {
169        with_context_mut(|ctx| {
170            if let Some(plane) = ctx.get_slice_plane_mut(&self.name) {
171                plane.set_enabled(enabled);
172            }
173        });
174        self
175    }
176
177    /// Returns whether the slice plane is enabled.
178    #[must_use]
179    pub fn is_enabled(&self) -> bool {
180        with_context(|ctx| {
181            ctx.get_slice_plane(&self.name)
182                .is_some_and(polyscope_core::SlicePlane::is_enabled)
183        })
184    }
185
186    /// Sets whether to draw the plane visualization.
187    pub fn set_draw_plane(&self, draw: bool) -> &Self {
188        with_context_mut(|ctx| {
189            if let Some(plane) = ctx.get_slice_plane_mut(&self.name) {
190                plane.set_draw_plane(draw);
191            }
192        });
193        self
194    }
195
196    /// Returns whether the plane visualization is drawn.
197    #[must_use]
198    pub fn draw_plane(&self) -> bool {
199        with_context(|ctx| {
200            ctx.get_slice_plane(&self.name)
201                .is_some_and(polyscope_core::SlicePlane::draw_plane)
202        })
203    }
204
205    /// Sets whether to draw the widget.
206    pub fn set_draw_widget(&self, draw: bool) -> &Self {
207        with_context_mut(|ctx| {
208            if let Some(plane) = ctx.get_slice_plane_mut(&self.name) {
209                plane.set_draw_widget(draw);
210            }
211        });
212        self
213    }
214
215    /// Returns whether the widget is drawn.
216    #[must_use]
217    pub fn draw_widget(&self) -> bool {
218        with_context(|ctx| {
219            ctx.get_slice_plane(&self.name)
220                .is_some_and(polyscope_core::SlicePlane::draw_widget)
221        })
222    }
223
224    /// Sets the color of the plane visualization.
225    pub fn set_color(&self, color: Vec3) -> &Self {
226        with_context_mut(|ctx| {
227            if let Some(plane) = ctx.get_slice_plane_mut(&self.name) {
228                plane.set_color(color);
229            }
230        });
231        self
232    }
233
234    /// Gets the color of the plane visualization.
235    #[must_use]
236    pub fn color(&self) -> Vec4 {
237        with_context(|ctx| {
238            ctx.get_slice_plane(&self.name).map_or(
239                Vec4::new(0.5, 0.5, 0.5, 1.0),
240                polyscope_core::SlicePlane::color,
241            )
242        })
243    }
244
245    /// Sets the transparency of the plane visualization.
246    pub fn set_transparency(&self, transparency: f32) -> &Self {
247        with_context_mut(|ctx| {
248            if let Some(plane) = ctx.get_slice_plane_mut(&self.name) {
249                plane.set_transparency(transparency);
250            }
251        });
252        self
253    }
254
255    /// Gets the transparency of the plane visualization.
256    #[must_use]
257    pub fn transparency(&self) -> f32 {
258        with_context(|ctx| {
259            ctx.get_slice_plane(&self.name)
260                .map_or(0.3, polyscope_core::SlicePlane::transparency)
261        })
262    }
263
264    /// Sets the size of the plane visualization (half-extent in each direction).
265    pub fn set_plane_size(&self, size: f32) -> &Self {
266        with_context_mut(|ctx| {
267            if let Some(plane) = ctx.get_slice_plane_mut(&self.name) {
268                plane.set_plane_size(size);
269            }
270        });
271        self
272    }
273
274    /// Gets the size of the plane visualization (half-extent in each direction).
275    #[must_use]
276    pub fn plane_size(&self) -> f32 {
277        with_context(|ctx| {
278            ctx.get_slice_plane(&self.name)
279                .map_or(0.1, polyscope_core::SlicePlane::plane_size)
280        })
281    }
282}