use crate::{
GizmoSpace, Mat4, Vec3, add_slice_plane, deselect_structure, remove_slice_plane,
reset_selected_transform, with_context, with_context_mut,
};
use polyscope_core::gizmo::Transform;
pub fn apply_camera_settings(
camera: &mut polyscope_render::Camera,
settings: &polyscope_ui::CameraSettings,
) {
camera.navigation_style = settings.navigation_style.into();
camera.projection_mode = settings.projection_mode.into();
camera.set_up_direction(settings.up_direction.into());
camera.set_fov_degrees(settings.fov_degrees);
camera.set_near(settings.near);
camera.set_far(settings.far);
camera.set_move_speed(settings.move_speed);
camera.set_ortho_scale(settings.ortho_scale);
}
#[must_use]
pub fn camera_to_settings(camera: &polyscope_render::Camera) -> polyscope_ui::CameraSettings {
polyscope_ui::CameraSettings {
navigation_style: camera.navigation_style.into(),
projection_mode: camera.projection_mode.into(),
up_direction: camera.up_direction.into(),
fov_degrees: camera.fov_degrees(),
near: camera.near,
far: camera.far,
move_speed: camera.move_speed,
ortho_scale: camera.ortho_scale,
}
}
#[must_use]
pub fn get_scene_extents() -> polyscope_ui::SceneExtents {
polyscope_core::state::with_context(|ctx| polyscope_ui::SceneExtents {
auto_compute: ctx.options.auto_compute_scene_extents,
length_scale: ctx.length_scale,
bbox_min: ctx.bounding_box.0.to_array(),
bbox_max: ctx.bounding_box.1.to_array(),
})
}
pub fn set_auto_compute_extents(auto: bool) {
polyscope_core::state::with_context_mut(|ctx| {
ctx.options.auto_compute_scene_extents = auto;
if auto {
ctx.recompute_extents();
}
});
}
#[must_use]
pub fn get_slice_plane_settings() -> Vec<polyscope_ui::SlicePlaneSettings> {
with_context(|ctx| {
let selected = ctx.selected_slice_plane();
ctx.slice_planes
.values()
.map(|plane| polyscope_ui::SlicePlaneSettings {
name: plane.name().to_string(),
enabled: plane.is_enabled(),
origin: plane.origin().to_array(),
normal: plane.normal().to_array(),
draw_plane: plane.draw_plane(),
draw_widget: plane.draw_widget(),
color: plane.color().truncate().to_array(),
transparency: plane.transparency(),
plane_size: plane.plane_size(),
is_selected: selected == Some(plane.name()),
})
.collect()
})
}
pub fn apply_slice_plane_settings(settings: &polyscope_ui::SlicePlaneSettings) {
with_context_mut(|ctx| {
if let Some(plane) = ctx.get_slice_plane_mut(&settings.name) {
plane.set_enabled(settings.enabled);
plane.set_origin(Vec3::from_array(settings.origin));
plane.set_normal(Vec3::from_array(settings.normal));
plane.set_draw_plane(settings.draw_plane);
plane.set_draw_widget(settings.draw_widget);
plane.set_color(Vec3::from_array(settings.color));
plane.set_transparency(settings.transparency);
plane.set_plane_size(settings.plane_size);
}
});
}
pub fn handle_slice_plane_action(
action: polyscope_ui::SlicePlanesAction,
current_settings: &mut Vec<polyscope_ui::SlicePlaneSettings>,
) {
match action {
polyscope_ui::SlicePlanesAction::None => {}
polyscope_ui::SlicePlanesAction::Add(name) => {
add_slice_plane(&name);
let settings = with_context(|ctx| {
if let Some(plane) = ctx.get_slice_plane(&name) {
polyscope_ui::SlicePlaneSettings {
name: plane.name().to_string(),
enabled: plane.is_enabled(),
origin: plane.origin().to_array(),
normal: plane.normal().to_array(),
draw_plane: plane.draw_plane(),
draw_widget: plane.draw_widget(),
color: plane.color().truncate().to_array(),
transparency: plane.transparency(),
plane_size: plane.plane_size(),
is_selected: false,
}
} else {
polyscope_ui::SlicePlaneSettings::with_name(&name)
}
});
current_settings.push(settings);
}
polyscope_ui::SlicePlanesAction::Remove(idx) => {
if idx < current_settings.len() {
let name = ¤t_settings[idx].name;
remove_slice_plane(name);
current_settings.remove(idx);
}
}
polyscope_ui::SlicePlanesAction::Modified(idx) => {
if idx < current_settings.len() {
apply_slice_plane_settings(¤t_settings[idx]);
}
}
}
}
#[must_use]
pub fn get_slice_plane_selection_info() -> polyscope_ui::SlicePlaneSelectionInfo {
with_context(|ctx| {
if let Some(name) = ctx.selected_slice_plane() {
if let Some(plane) = ctx.get_slice_plane(name) {
let transform = plane.to_transform();
let (_, rotation, _) = transform.to_scale_rotation_translation();
let euler = rotation.to_euler(glam::EulerRot::XYZ);
polyscope_ui::SlicePlaneSelectionInfo {
has_selection: true,
name: name.to_string(),
origin: plane.origin().to_array(),
rotation_degrees: [
euler.0.to_degrees(),
euler.1.to_degrees(),
euler.2.to_degrees(),
],
}
} else {
polyscope_ui::SlicePlaneSelectionInfo::default()
}
} else {
polyscope_ui::SlicePlaneSelectionInfo::default()
}
})
}
pub fn select_slice_plane_for_gizmo(name: &str) {
with_context_mut(|ctx| {
ctx.select_slice_plane(name);
});
}
pub fn deselect_slice_plane_gizmo() {
with_context_mut(|ctx| {
ctx.deselect_slice_plane();
});
}
pub fn apply_slice_plane_gizmo_transform(origin: [f32; 3], rotation_degrees: [f32; 3]) {
with_context_mut(|ctx| {
if let Some(name) = ctx.selected_slice_plane.clone() {
if let Some(plane) = ctx.get_slice_plane_mut(&name) {
let rotation = glam::Quat::from_euler(
glam::EulerRot::XYZ,
rotation_degrees[0].to_radians(),
rotation_degrees[1].to_radians(),
rotation_degrees[2].to_radians(),
);
let transform =
glam::Mat4::from_rotation_translation(rotation, Vec3::from_array(origin));
plane.set_from_transform(transform);
}
}
});
}
#[must_use]
pub fn get_group_settings() -> Vec<polyscope_ui::GroupSettings> {
with_context(|ctx| {
ctx.groups
.values()
.map(|group| polyscope_ui::GroupSettings {
name: group.name().to_string(),
enabled: group.is_enabled(),
show_child_details: group.show_child_details(),
parent_group: group.parent_group().map(std::string::ToString::to_string),
child_structures: group
.child_structures()
.map(|(t, n)| (t.to_string(), n.to_string()))
.collect(),
child_groups: group
.child_groups()
.map(std::string::ToString::to_string)
.collect(),
})
.collect()
})
}
pub fn apply_group_settings(settings: &polyscope_ui::GroupSettings) {
with_context_mut(|ctx| {
if let Some(group) = ctx.get_group_mut(&settings.name) {
group.set_enabled(settings.enabled);
group.set_show_child_details(settings.show_child_details);
}
});
}
pub fn handle_group_action(
action: polyscope_ui::GroupsAction,
current_settings: &mut [polyscope_ui::GroupSettings],
) {
match action {
polyscope_ui::GroupsAction::None => {}
polyscope_ui::GroupsAction::SyncEnabled(indices) => {
for idx in indices {
if idx < current_settings.len() {
apply_group_settings(¤t_settings[idx]);
}
}
}
}
}
#[must_use]
pub fn get_gizmo_settings() -> polyscope_ui::GizmoSettings {
with_context(|ctx| {
let gizmo = ctx.gizmo();
polyscope_ui::GizmoSettings {
local_space: matches!(gizmo.space, GizmoSpace::Local),
visible: gizmo.visible,
snap_translate: gizmo.snap_translate,
snap_rotate: gizmo.snap_rotate,
snap_scale: gizmo.snap_scale,
}
})
}
pub fn apply_gizmo_settings(settings: &polyscope_ui::GizmoSettings) {
with_context_mut(|ctx| {
let gizmo = ctx.gizmo_mut();
gizmo.space = if settings.local_space {
GizmoSpace::Local
} else {
GizmoSpace::World
};
gizmo.visible = settings.visible;
gizmo.snap_translate = settings.snap_translate;
gizmo.snap_rotate = settings.snap_rotate;
gizmo.snap_scale = settings.snap_scale;
});
}
#[must_use]
pub fn get_selection_info() -> polyscope_ui::SelectionInfo {
with_context(|ctx| {
if let Some((type_name, name)) = ctx.selected_structure() {
let (transform, bbox) = ctx
.registry
.get(type_name, name)
.map_or((Mat4::IDENTITY, None), |s| {
(s.transform(), s.bounding_box())
});
let t = Transform::from_matrix(transform);
let euler = t.euler_angles_degrees();
let centroid = bbox.map_or(t.translation, |(min, max)| (min + max) * 0.5);
polyscope_ui::SelectionInfo {
has_selection: true,
type_name: type_name.to_string(),
name: name.to_string(),
translation: t.translation.to_array(),
rotation_degrees: euler.to_array(),
scale: t.scale.to_array(),
centroid: centroid.to_array(),
}
} else {
polyscope_ui::SelectionInfo::default()
}
})
}
pub fn apply_selection_transform(selection: &polyscope_ui::SelectionInfo) {
if !selection.has_selection {
return;
}
let translation = Vec3::from_array(selection.translation);
let rotation = glam::Quat::from_euler(
glam::EulerRot::XYZ,
selection.rotation_degrees[0].to_radians(),
selection.rotation_degrees[1].to_radians(),
selection.rotation_degrees[2].to_radians(),
);
let scale = Vec3::from_array(selection.scale);
let transform = Mat4::from_scale_rotation_translation(scale, rotation, translation);
with_context_mut(|ctx| {
if let Some((type_name, name)) = ctx.selected_structure.clone() {
if let Some(structure) = ctx.registry.get_mut(&type_name, &name) {
structure.set_transform(transform);
}
}
});
}
pub fn handle_gizmo_action(
action: polyscope_ui::GizmoAction,
settings: &polyscope_ui::GizmoSettings,
selection: &polyscope_ui::SelectionInfo,
) {
match action {
polyscope_ui::GizmoAction::None => {}
polyscope_ui::GizmoAction::SettingsChanged => {
apply_gizmo_settings(settings);
}
polyscope_ui::GizmoAction::TransformChanged => {
apply_selection_transform(selection);
}
polyscope_ui::GizmoAction::Deselect => {
deselect_structure();
}
polyscope_ui::GizmoAction::ResetTransform => {
reset_selected_transform();
}
}
}