diff --git a/crates/store/re_types/src/components/plane3d_ext.rs b/crates/store/re_types/src/components/plane3d_ext.rs index e51f097de085b..5696bb1cf6738 100644 --- a/crates/store/re_types/src/components/plane3d_ext.rs +++ b/crates/store/re_types/src/components/plane3d_ext.rs @@ -13,6 +13,7 @@ impl Plane3D { /// Create a new plane from a normal and distance. /// /// The plane will not be normalized upon creation. + #[inline] pub fn new(normal: impl Into, d: f32) -> Self { Self(crate::datatypes::Plane3D::new(normal, d)) } diff --git a/crates/store/re_types/src/datatypes/plane3d_ext.rs b/crates/store/re_types/src/datatypes/plane3d_ext.rs index fea40d230effb..b71e5b3d4b5bf 100644 --- a/crates/store/re_types/src/datatypes/plane3d_ext.rs +++ b/crates/store/re_types/src/datatypes/plane3d_ext.rs @@ -11,11 +11,13 @@ impl Plane3D { pub const XY: Self = Self([0.0, 0.0, 1.0, 0.0]); /// The normal of the plane (unnormalized if the plane is unnormalized). + #[inline] pub const fn normal(&self) -> super::Vec3D { super::Vec3D([self.0[0], self.0[1], self.0[2]]) } /// The distance of the plane from the origin (in multiples of the normal if the normal is unnormalized). + #[inline] pub const fn distance(&self) -> f32 { self.0[3] } @@ -23,6 +25,7 @@ impl Plane3D { /// Create a new plane from a normal and distance. /// /// The plane will not be normalized upon creation. + #[inline] pub fn new(normal: impl Into, d: f32) -> Self { let normal = normal.into(); Self([normal.0[0], normal.0[1], normal.0[2], d]) diff --git a/crates/viewer/re_component_ui/src/datatype_uis/vec.rs b/crates/viewer/re_component_ui/src/datatype_uis/vec.rs index b28bf039d3f6d..a0e7fe2eb4dfa 100644 --- a/crates/viewer/re_component_ui/src/datatype_uis/vec.rs +++ b/crates/viewer/re_component_ui/src/datatype_uis/vec.rs @@ -12,7 +12,31 @@ pub fn edit_or_view_vec3d( MaybeMutRef::Ref(value) => MaybeMutRef::Ref(value), MaybeMutRef::MutRef(value) => MaybeMutRef::MutRef(value), }; - edit_or_view_vec3d_raw(ui, &mut value) + edit_or_view_vec3d_raw_immutable(ui, &mut value) +} + +// TODO(#6743): Since overrides are not yet taken into account, editing this value has no effect. +//MaybeMutRef::MutRef(value) => MaybeMutRef::MutRef(&mut value[i]), +fn edit_or_view_vec3d_raw_immutable( + ui: &mut egui::Ui, + value: &mut MaybeMutRef<'_, datatypes::Vec3D>, +) -> egui::Response { + edit_or_view_vector_component_immutable(ui, value, 0) + | edit_or_view_vector_component_immutable(ui, value, 1) + | edit_or_view_vector_component_immutable(ui, value, 2) +} + +fn edit_or_view_vector_component_immutable( + ui: &mut egui::Ui, + value: &mut MaybeMutRef<'_, datatypes::Vec3D>, + i: usize, +) -> egui::Response { + let mut value: MaybeMutRef<'_, f32> = match value { + MaybeMutRef::Ref(value) => MaybeMutRef::Ref(&value[i]), + + MaybeMutRef::MutRef(value) => MaybeMutRef::Ref(&value[i]), + }; + edit_f32_float_raw(ui, &mut value, f32::MIN..=f32::MAX) } pub fn edit_or_view_vec3d_raw( @@ -31,9 +55,7 @@ fn edit_or_view_vector_component( ) -> egui::Response { let mut value: MaybeMutRef<'_, f32> = match value { MaybeMutRef::Ref(value) => MaybeMutRef::Ref(&value[i]), - // TODO(#6743): Since overrides are not yet taken into account, editing this value has no effect. - //MaybeMutRef::MutRef(value) => MaybeMutRef::MutRef(&mut value[i]), - MaybeMutRef::MutRef(value) => MaybeMutRef::Ref(&value[i]), + MaybeMutRef::MutRef(value) => MaybeMutRef::MutRef(&mut value[i]), }; edit_f32_float_raw(ui, &mut value, f32::MIN..=f32::MAX) } diff --git a/crates/viewer/re_component_ui/src/lib.rs b/crates/viewer/re_component_ui/src/lib.rs index 59d49fcb7cb6d..df5bbb2820407 100644 --- a/crates/viewer/re_component_ui/src/lib.rs +++ b/crates/viewer/re_component_ui/src/lib.rs @@ -172,7 +172,8 @@ pub fn create_component_ui_registry() -> re_viewer_context::ComponentUiRegistry registry.add_singleline_edit_or_view(zoom_level::edit_zoom_level); - // TODO: add ui for plane + registry.add_singleline_edit_or_view(plane3d::edit_or_view_plane3d); + registry.add_multiline_edit_or_view(plane3d::multiline_edit_or_view_plane3d); registry } diff --git a/crates/viewer/re_component_ui/src/plane3d.rs b/crates/viewer/re_component_ui/src/plane3d.rs index 9e0433519c110..6d88db644de58 100644 --- a/crates/viewer/re_component_ui/src/plane3d.rs +++ b/crates/viewer/re_component_ui/src/plane3d.rs @@ -1,42 +1,162 @@ -use re_types::datatypes; +use re_types::{components, external::glam}; +use re_ui::UiExt as _; use re_viewer_context::MaybeMutRef; -use crate::datatype_uis::{edit_f32_float_raw, edit_or_view_vec3d_raw}; +use crate::{ + datatype_uis::{edit_f32_float_raw, edit_or_view_vec3d_raw}, + response_utils::response_with_changes_of_inner, +}; + +#[derive(PartialEq, Eq, Copy, Clone)] +enum AxisDirection { + PosX, + PosY, + PosZ, + NegX, + NegY, + NegZ, +} + +impl AxisDirection { + const VARIANTS: [Self; 6] = [ + Self::PosX, + Self::PosY, + Self::PosZ, + Self::NegX, + Self::NegY, + Self::NegZ, + ]; +} + +impl std::fmt::Display for AxisDirection { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::PosX => write!(f, "+X"), + Self::PosY => write!(f, "+Y"), + Self::PosZ => write!(f, "+Z"), + Self::NegX => write!(f, "-X"), + Self::NegY => write!(f, "-Y"), + Self::NegZ => write!(f, "-Z"), + } + } +} + +impl TryFrom for AxisDirection { + type Error = (); + + fn try_from(value: glam::Vec3) -> Result { + match value { + glam::Vec3::X => Ok(Self::PosX), + glam::Vec3::Y => Ok(Self::PosY), + glam::Vec3::Z => Ok(Self::PosZ), + glam::Vec3::NEG_X => Ok(Self::NegX), + glam::Vec3::NEG_Y => Ok(Self::NegY), + glam::Vec3::NEG_Z => Ok(Self::NegZ), + _ => Err(()), + } + } +} + +impl From for glam::Vec3 { + fn from(value: AxisDirection) -> Self { + match value { + AxisDirection::PosX => Self::X, + AxisDirection::PosY => Self::Y, + AxisDirection::PosZ => Self::Z, + AxisDirection::NegX => Self::NEG_X, + AxisDirection::NegY => Self::NEG_Y, + AxisDirection::NegZ => Self::NEG_Z, + } + } +} pub fn edit_or_view_plane3d( _ctx: &re_viewer_context::ViewerContext<'_>, ui: &mut egui::Ui, - value: &mut MaybeMutRef<'_, impl std::ops::DerefMut>, + value: &mut MaybeMutRef<'_, components::Plane3D>, ) -> egui::Response { - let mut value: MaybeMutRef<'_, datatypes::Plane3D> = match value { - MaybeMutRef::Ref(value) => MaybeMutRef::Ref(value), - MaybeMutRef::MutRef(value) => MaybeMutRef::MutRef(value), + let distance = value.distance(); + + ui.label("n"); + // Show simplified combobox if this is is axis aligned. + let normal_response = if let Ok(mut axis_dir) = + AxisDirection::try_from(glam::Vec3::from(value.normal())) + { + response_with_changes_of_inner( + egui::ComboBox::from_id_salt("plane_normal") + .selected_text(format!("{axis_dir}")) + .height(250.0) + .show_ui(ui, |ui| { + let mut variants = AxisDirection::VARIANTS.iter(); + #[allow(clippy::unwrap_used)] // We know there's more than zero variants. + let variant = variants.next().unwrap(); + + let mut response = + ui.selectable_value(&mut axis_dir, *variant, variant.to_string()); + for variant in variants { + response |= + ui.selectable_value(&mut axis_dir, *variant, variant.to_string()); + } + + if let MaybeMutRef::MutRef(value) = value { + **value = components::Plane3D::new(glam::Vec3::from(axis_dir), distance); + } + response + }), + ) + } else { + // Editing for arbitrary normals takes too much space here. + edit_or_view_vec3d_raw(ui, &mut MaybeMutRef::Ref(&value.normal())) + }; + + ui.label("d"); + let mut maybe_mut_distance = match value { + MaybeMutRef::Ref(value) => MaybeMutRef::Ref(&value.0 .0[3]), + MaybeMutRef::MutRef(value) => MaybeMutRef::MutRef(&mut value.0 .0[3]), }; - edit_or_view_plane3d_impl(ui, &mut value) + let distance_response = edit_f32_float_raw(ui, &mut maybe_mut_distance, f32::MIN..=f32::MAX); + + normal_response | distance_response } -fn edit_or_view_plane3d_impl( +pub fn multiline_edit_or_view_plane3d( + _ctx: &re_viewer_context::ViewerContext<'_>, ui: &mut egui::Ui, - value: &mut MaybeMutRef<'_, datatypes::Plane3D>, + value: &mut MaybeMutRef<'_, components::Plane3D>, ) -> egui::Response { - let mut normal = value.normal(); - let mut distance = value.distance(); - let (mut maybe_mut_normal, mut maybe_mutdistance) = match value { - MaybeMutRef::Ref(value) => (MaybeMutRef::Ref(&normal), MaybeMutRef::Ref(&distance)), - MaybeMutRef::MutRef(value) => ( - MaybeMutRef::MutRef(&mut normal), - MaybeMutRef::MutRef(&mut distance), - ), - }; + let mut any_edit = false; - ui.label("n"); - let normal_response = edit_or_view_vec3d_raw(ui, &mut maybe_mut_normal); - ui.label("d"); - let distance_response = edit_f32_float_raw(ui, &mut maybe_mutdistance, f32::MIN..=f32::MAX); + let response_normal = ui.list_item_flat_noninteractive( + re_ui::list_item::PropertyContent::new("Normal").value_fn(|ui, _| { + let mut normal = value.normal(); + let mut maybe_mut_normal = match value { + MaybeMutRef::Ref(_) => MaybeMutRef::Ref(&normal), + MaybeMutRef::MutRef(_) => MaybeMutRef::MutRef(&mut normal), + }; - if let MaybeMutRef::MutRef(value) = value { - **value = datatypes::Plane3D::new(normal, distance); - } + any_edit |= edit_or_view_vec3d_raw(ui, &mut maybe_mut_normal).changed(); + + if let MaybeMutRef::MutRef(value) = value { + **value = components::Plane3D::new(normal, value.distance()); + } + }), + ); - normal_response.union(distance_response) + let response_distance = ui.list_item_flat_noninteractive( + re_ui::list_item::PropertyContent::new("Distance").value_fn(|ui, _| { + let mut maybe_mut_distance = match value { + MaybeMutRef::Ref(value) => MaybeMutRef::Ref(&value.0 .0[3]), + MaybeMutRef::MutRef(value) => MaybeMutRef::MutRef(&mut value.0 .0[3]), + }; + + any_edit |= + edit_f32_float_raw(ui, &mut maybe_mut_distance, f32::MIN..=f32::MAX).changed(); + }), + ); + + let mut response = response_normal | response_distance; + if any_edit { + response.mark_changed(); + } + response } diff --git a/crates/viewer/re_space_view_spatial/src/view_3d_properties.rs b/crates/viewer/re_space_view_spatial/src/view_3d_properties.rs index bae1c97c94a37..3040831710076 100644 --- a/crates/viewer/re_space_view_spatial/src/view_3d_properties.rs +++ b/crates/viewer/re_space_view_spatial/src/view_3d_properties.rs @@ -52,11 +52,7 @@ impl TypedComponentFallbackProvider for SpatialSpaceView3D { .state_3d .scene_view_coordinates .and_then(|view_coordinates| view_coordinates.up()) - .map_or(DEFAULT_PLANE, |up| match up.axis { - re_types::view_coordinates::Axis3::X => Plane3D::YZ, - re_types::view_coordinates::Axis3::Y => Plane3D::ZX, - re_types::view_coordinates::Axis3::Z => Plane3D::XY, - }) + .map_or(DEFAULT_PLANE, |up| Plane3D::new(up.as_vec3(), 0.0)) } }