1use crate::{
2 GizmoSpace, Mat4, Vec3, add_slice_plane, deselect_structure, remove_slice_plane,
3 reset_selected_transform, with_context, with_context_mut,
4};
5use polyscope_core::gizmo::Transform;
6
7pub fn apply_camera_settings(
9 camera: &mut polyscope_render::Camera,
10 settings: &polyscope_ui::CameraSettings,
11) {
12 camera.navigation_style = settings.navigation_style.into();
13 camera.projection_mode = settings.projection_mode.into();
14 camera.set_up_direction(settings.up_direction.into());
15 camera.set_fov_degrees(settings.fov_degrees);
16 camera.set_near(settings.near);
17 camera.set_far(settings.far);
18 camera.set_move_speed(settings.move_speed);
19 camera.set_ortho_scale(settings.ortho_scale);
20}
21
22#[must_use]
24pub fn camera_to_settings(camera: &polyscope_render::Camera) -> polyscope_ui::CameraSettings {
25 polyscope_ui::CameraSettings {
26 navigation_style: camera.navigation_style.into(),
27 projection_mode: camera.projection_mode.into(),
28 up_direction: camera.up_direction.into(),
29 fov_degrees: camera.fov_degrees(),
30 near: camera.near,
31 far: camera.far,
32 move_speed: camera.move_speed,
33 ortho_scale: camera.ortho_scale,
34 }
35}
36
37#[must_use]
39pub fn get_scene_extents() -> polyscope_ui::SceneExtents {
40 polyscope_core::state::with_context(|ctx| polyscope_ui::SceneExtents {
41 auto_compute: ctx.options.auto_compute_scene_extents,
42 length_scale: ctx.length_scale,
43 bbox_min: ctx.bounding_box.0.to_array(),
44 bbox_max: ctx.bounding_box.1.to_array(),
45 })
46}
47
48pub fn set_auto_compute_extents(auto: bool) {
53 polyscope_core::state::with_context_mut(|ctx| {
54 ctx.options.auto_compute_scene_extents = auto;
55 if auto {
56 ctx.recompute_extents();
57 }
58 });
59}
60
61#[must_use]
67pub fn get_slice_plane_settings() -> Vec<polyscope_ui::SlicePlaneSettings> {
68 with_context(|ctx| {
69 let selected = ctx.selected_slice_plane();
70 ctx.slice_planes
71 .values()
72 .map(|plane| polyscope_ui::SlicePlaneSettings {
73 name: plane.name().to_string(),
74 enabled: plane.is_enabled(),
75 origin: plane.origin().to_array(),
76 normal: plane.normal().to_array(),
77 draw_plane: plane.draw_plane(),
78 draw_widget: plane.draw_widget(),
79 color: plane.color().truncate().to_array(),
80 transparency: plane.transparency(),
81 plane_size: plane.plane_size(),
82 is_selected: selected == Some(plane.name()),
83 })
84 .collect()
85 })
86}
87
88pub fn apply_slice_plane_settings(settings: &polyscope_ui::SlicePlaneSettings) {
90 with_context_mut(|ctx| {
91 if let Some(plane) = ctx.get_slice_plane_mut(&settings.name) {
92 plane.set_enabled(settings.enabled);
93 plane.set_origin(Vec3::from_array(settings.origin));
94 plane.set_normal(Vec3::from_array(settings.normal));
95 plane.set_draw_plane(settings.draw_plane);
96 plane.set_draw_widget(settings.draw_widget);
97 plane.set_color(Vec3::from_array(settings.color));
98 plane.set_transparency(settings.transparency);
99 plane.set_plane_size(settings.plane_size);
100 }
101 });
102}
103
104pub fn handle_slice_plane_action(
107 action: polyscope_ui::SlicePlanesAction,
108 current_settings: &mut Vec<polyscope_ui::SlicePlaneSettings>,
109) {
110 match action {
111 polyscope_ui::SlicePlanesAction::None => {}
112 polyscope_ui::SlicePlanesAction::Add(name) => {
113 add_slice_plane(&name);
114 let settings = with_context(|ctx| {
116 if let Some(plane) = ctx.get_slice_plane(&name) {
117 polyscope_ui::SlicePlaneSettings {
118 name: plane.name().to_string(),
119 enabled: plane.is_enabled(),
120 origin: plane.origin().to_array(),
121 normal: plane.normal().to_array(),
122 draw_plane: plane.draw_plane(),
123 draw_widget: plane.draw_widget(),
124 color: plane.color().truncate().to_array(),
125 transparency: plane.transparency(),
126 plane_size: plane.plane_size(),
127 is_selected: false,
128 }
129 } else {
130 polyscope_ui::SlicePlaneSettings::with_name(&name)
131 }
132 });
133 current_settings.push(settings);
134 }
135 polyscope_ui::SlicePlanesAction::Remove(idx) => {
136 if idx < current_settings.len() {
137 let name = ¤t_settings[idx].name;
138 remove_slice_plane(name);
139 current_settings.remove(idx);
140 }
141 }
142 polyscope_ui::SlicePlanesAction::Modified(idx) => {
143 if idx < current_settings.len() {
144 apply_slice_plane_settings(¤t_settings[idx]);
145 }
146 }
147 }
148}
149
150#[must_use]
156pub fn get_slice_plane_selection_info() -> polyscope_ui::SlicePlaneSelectionInfo {
157 with_context(|ctx| {
158 if let Some(name) = ctx.selected_slice_plane() {
159 if let Some(plane) = ctx.get_slice_plane(name) {
160 let transform = plane.to_transform();
161 let (_, rotation, _) = transform.to_scale_rotation_translation();
162 let euler = rotation.to_euler(glam::EulerRot::XYZ);
163
164 polyscope_ui::SlicePlaneSelectionInfo {
165 has_selection: true,
166 name: name.to_string(),
167 origin: plane.origin().to_array(),
168 rotation_degrees: [
169 euler.0.to_degrees(),
170 euler.1.to_degrees(),
171 euler.2.to_degrees(),
172 ],
173 }
174 } else {
175 polyscope_ui::SlicePlaneSelectionInfo::default()
176 }
177 } else {
178 polyscope_ui::SlicePlaneSelectionInfo::default()
179 }
180 })
181}
182
183pub fn select_slice_plane_for_gizmo(name: &str) {
185 with_context_mut(|ctx| {
186 ctx.select_slice_plane(name);
187 });
188}
189
190pub fn deselect_slice_plane_gizmo() {
192 with_context_mut(|ctx| {
193 ctx.deselect_slice_plane();
194 });
195}
196
197pub fn apply_slice_plane_gizmo_transform(origin: [f32; 3], rotation_degrees: [f32; 3]) {
199 with_context_mut(|ctx| {
200 if let Some(name) = ctx.selected_slice_plane.clone() {
201 if let Some(plane) = ctx.get_slice_plane_mut(&name) {
202 let rotation = glam::Quat::from_euler(
204 glam::EulerRot::XYZ,
205 rotation_degrees[0].to_radians(),
206 rotation_degrees[1].to_radians(),
207 rotation_degrees[2].to_radians(),
208 );
209 let transform =
210 glam::Mat4::from_rotation_translation(rotation, Vec3::from_array(origin));
211 plane.set_from_transform(transform);
212 }
213 }
214 });
215}
216
217#[must_use]
223pub fn get_group_settings() -> Vec<polyscope_ui::GroupSettings> {
224 with_context(|ctx| {
225 ctx.groups
226 .values()
227 .map(|group| polyscope_ui::GroupSettings {
228 name: group.name().to_string(),
229 enabled: group.is_enabled(),
230 show_child_details: group.show_child_details(),
231 parent_group: group.parent_group().map(std::string::ToString::to_string),
232 child_structures: group
233 .child_structures()
234 .map(|(t, n)| (t.to_string(), n.to_string()))
235 .collect(),
236 child_groups: group
237 .child_groups()
238 .map(std::string::ToString::to_string)
239 .collect(),
240 })
241 .collect()
242 })
243}
244
245pub fn apply_group_settings(settings: &polyscope_ui::GroupSettings) {
247 with_context_mut(|ctx| {
248 if let Some(group) = ctx.get_group_mut(&settings.name) {
249 group.set_enabled(settings.enabled);
250 group.set_show_child_details(settings.show_child_details);
251 }
252 });
253}
254
255pub fn handle_group_action(
257 action: polyscope_ui::GroupsAction,
258 current_settings: &mut [polyscope_ui::GroupSettings],
259) {
260 match action {
261 polyscope_ui::GroupsAction::None => {}
262 polyscope_ui::GroupsAction::SyncEnabled(indices) => {
263 for idx in indices {
264 if idx < current_settings.len() {
265 apply_group_settings(¤t_settings[idx]);
266 }
267 }
268 }
269 }
270}
271
272#[must_use]
278pub fn get_gizmo_settings() -> polyscope_ui::GizmoSettings {
279 with_context(|ctx| {
280 let gizmo = ctx.gizmo();
281 polyscope_ui::GizmoSettings {
282 local_space: matches!(gizmo.space, GizmoSpace::Local),
283 visible: gizmo.visible,
284 snap_translate: gizmo.snap_translate,
285 snap_rotate: gizmo.snap_rotate,
286 snap_scale: gizmo.snap_scale,
287 }
288 })
289}
290
291pub fn apply_gizmo_settings(settings: &polyscope_ui::GizmoSettings) {
293 with_context_mut(|ctx| {
294 let gizmo = ctx.gizmo_mut();
295 gizmo.space = if settings.local_space {
296 GizmoSpace::Local
297 } else {
298 GizmoSpace::World
299 };
300 gizmo.visible = settings.visible;
301 gizmo.snap_translate = settings.snap_translate;
302 gizmo.snap_rotate = settings.snap_rotate;
303 gizmo.snap_scale = settings.snap_scale;
304 });
305}
306
307#[must_use]
309pub fn get_selection_info() -> polyscope_ui::SelectionInfo {
310 with_context(|ctx| {
311 if let Some((type_name, name)) = ctx.selected_structure() {
312 let (transform, bbox) = ctx
314 .registry
315 .get(type_name, name)
316 .map_or((Mat4::IDENTITY, None), |s| {
317 (s.transform(), s.bounding_box())
318 });
319
320 let t = Transform::from_matrix(transform);
321 let euler = t.euler_angles_degrees();
322
323 let centroid = bbox.map_or(t.translation, |(min, max)| (min + max) * 0.5);
325
326 polyscope_ui::SelectionInfo {
327 has_selection: true,
328 type_name: type_name.to_string(),
329 name: name.to_string(),
330 translation: t.translation.to_array(),
331 rotation_degrees: euler.to_array(),
332 scale: t.scale.to_array(),
333 centroid: centroid.to_array(),
334 }
335 } else {
336 polyscope_ui::SelectionInfo::default()
337 }
338 })
339}
340
341pub fn apply_selection_transform(selection: &polyscope_ui::SelectionInfo) {
343 if !selection.has_selection {
344 return;
345 }
346
347 let translation = Vec3::from_array(selection.translation);
348 let rotation = glam::Quat::from_euler(
349 glam::EulerRot::XYZ,
350 selection.rotation_degrees[0].to_radians(),
351 selection.rotation_degrees[1].to_radians(),
352 selection.rotation_degrees[2].to_radians(),
353 );
354 let scale = Vec3::from_array(selection.scale);
355
356 let transform = Mat4::from_scale_rotation_translation(scale, rotation, translation);
357
358 with_context_mut(|ctx| {
359 if let Some((type_name, name)) = ctx.selected_structure.clone() {
360 if let Some(structure) = ctx.registry.get_mut(&type_name, &name) {
361 structure.set_transform(transform);
362 }
363 }
364 });
365}
366
367pub fn handle_gizmo_action(
369 action: polyscope_ui::GizmoAction,
370 settings: &polyscope_ui::GizmoSettings,
371 selection: &polyscope_ui::SelectionInfo,
372) {
373 match action {
374 polyscope_ui::GizmoAction::None => {}
375 polyscope_ui::GizmoAction::SettingsChanged => {
376 apply_gizmo_settings(settings);
377 }
378 polyscope_ui::GizmoAction::TransformChanged => {
379 apply_selection_transform(selection);
380 }
381 polyscope_ui::GizmoAction::Deselect => {
382 deselect_structure();
383 }
384 polyscope_ui::GizmoAction::ResetTransform => {
385 reset_selected_transform();
386 }
387 }
388}