diff --git a/crates/build/re_types_builder/src/codegen/cpp/mod.rs b/crates/build/re_types_builder/src/codegen/cpp/mod.rs index dd41590729a6..f8a3a8a82d28 100644 --- a/crates/build/re_types_builder/src/codegen/cpp/mod.rs +++ b/crates/build/re_types_builder/src/codegen/cpp/mod.rs @@ -567,23 +567,27 @@ impl QuotedObject { format!("{}Indicator", obj.fqname).replace("archetypes", "components"); let doc_hide_comment = quote_hide_from_docs(); let deprecation_notice = quote_deprecation_notice(obj); + + // Note that GCC doesn't like using deprecated fields even if the archetype itself is deprecated. + // In that case we're just being generous with the ignore warnings, making it finegrained is hard and not really worth it anyways. + let has_any_deprecated_fields = obj.fields.iter().any(|field| { + field + .typ + .fqname() + .and_then(|fqname| objects.get(fqname)) + .map_or(false, |obj| obj.deprecation_notice().is_some()) + }); let (deprecation_ignore_start, deprecation_ignore_end) = - if obj.deprecation_notice().is_some() { - hpp_includes.insert_rerun("compiler_utils.hpp"); - ( - quote! { - RR_PUSH_WARNINGS #NEWLINE_TOKEN - RR_DISABLE_DEPRECATION_WARNING #NEWLINE_TOKEN - }, - quote! { RR_POP_WARNINGS }, - ) - } else { - (quote!(), quote!()) - }; + quote_deprecation_ignore_start_and_end( + &mut hpp_includes, + obj.deprecation_notice().is_some() || has_any_deprecated_fields, + ); let hpp = quote! { #hpp_includes + #deprecation_ignore_start + namespace rerun::#quoted_namespace { #quoted_docs struct #deprecation_notice #type_ident { @@ -622,9 +626,9 @@ impl QuotedObject { struct AsComponents<#quoted_namespace::#type_ident> { #serialize_hpp }; - - #deprecation_ignore_end } + + #deprecation_ignore_end }; let cpp = quote! { @@ -2591,7 +2595,12 @@ fn quote_loggable_hpp_and_cpp( hpp_includes.insert_rerun("component_descriptor.hpp"); + let (deprecation_ignore_start, deprecation_ignore_end) = + quote_deprecation_ignore_start_and_end(hpp_includes, obj.deprecation_notice().is_some()); + let hpp = quote! { + #deprecation_ignore_start + namespace rerun { #predeclarations_and_static_assertions @@ -2604,6 +2613,8 @@ fn quote_loggable_hpp_and_cpp( #(#methods_hpp)* }; } + + #deprecation_ignore_end }; let cpp = if methods.iter().any(|m| !m.inline) { @@ -2629,3 +2640,21 @@ fn quote_deprecation_notice(obj: &Object) -> TokenStream { quote! {} } } + +fn quote_deprecation_ignore_start_and_end( + includes: &mut Includes, + should_deprecate: bool, +) -> (TokenStream, TokenStream) { + if should_deprecate { + includes.insert_rerun("compiler_utils.hpp"); + ( + quote! { + RR_PUSH_WARNINGS #NEWLINE_TOKEN + RR_DISABLE_DEPRECATION_WARNING #NEWLINE_TOKEN + }, + quote! { RR_POP_WARNINGS }, + ) + } else { + (quote!(), quote!()) + } +} diff --git a/crates/build/re_types_builder/src/codegen/rust/reflection.rs b/crates/build/re_types_builder/src/codegen/rust/reflection.rs index 4ab765164698..d347ba243cfb 100644 --- a/crates/build/re_types_builder/src/codegen/rust/reflection.rs +++ b/crates/build/re_types_builder/src/codegen/rust/reflection.rs @@ -156,6 +156,7 @@ fn generate_component_reflection( #[doc = "Generates reflection about all known components."] #[doc = ""] #[doc = "Call only once and reuse the results."] + #[allow(deprecated)] fn generate_component_reflection() -> Result { re_tracing::profile_function!(); let array = [ diff --git a/crates/store/re_types/definitions/rerun/archetypes/disconnected_space.fbs b/crates/store/re_types/definitions/rerun/archetypes/disconnected_space.fbs index e7b3ad037301..319658c4c319 100644 --- a/crates/store/re_types/definitions/rerun/archetypes/disconnected_space.fbs +++ b/crates/store/re_types/definitions/rerun/archetypes/disconnected_space.fbs @@ -9,6 +9,7 @@ namespace rerun.archetypes; /// /// \example archetypes/disconnected_space title="Disconnected space" image="https://static.rerun.io/disconnected_space/709041fc304b50c74db773b780e32294fe90c95f/1200w.png" table DisconnectedSpace ( + "attr.rerun.deprecated": "Use [archetypes.Transform3D] with an invalid transform instead", "attr.rust.derive": "Copy, PartialEq, Eq", "attr.docs.view_types": "Spatial2DView, Spatial3DView" ) { diff --git a/crates/store/re_types/definitions/rerun/components/disconnected_space.fbs b/crates/store/re_types/definitions/rerun/components/disconnected_space.fbs index 2aef729a83ae..900ed7a3b4b7 100644 --- a/crates/store/re_types/definitions/rerun/components/disconnected_space.fbs +++ b/crates/store/re_types/definitions/rerun/components/disconnected_space.fbs @@ -10,6 +10,7 @@ namespace rerun.components; /// It *only* applies to views that work with spatial transformations, i.e. 2D & 3D views. /// This is useful for specifying that a subgraph is independent of the rest of the scene. struct DisconnectedSpace ( + "attr.rerun.deprecated": "Use [archetypes.Transform3D] with an invalid transform instead.", "attr.python.aliases": "bool", "attr.python.array_aliases": "bool, npt.NDArray[np.bool_]", "attr.rust.derive": "Copy, PartialEq, Eq" diff --git a/crates/store/re_types/definitions/rerun/components/rotation_axis_angle.fbs b/crates/store/re_types/definitions/rerun/components/rotation_axis_angle.fbs index 8036eb79d2e8..2b0b5c0d2a17 100644 --- a/crates/store/re_types/definitions/rerun/components/rotation_axis_angle.fbs +++ b/crates/store/re_types/definitions/rerun/components/rotation_axis_angle.fbs @@ -1,6 +1,8 @@ namespace rerun.components; /// 3D rotation represented by a rotation around a given axis. +/// +/// If normalization of the rotation axis fails the rotation is treated as an invalid transform. table RotationAxisAngle ( "attr.rust.derive": "Default, Copy, PartialEq", "attr.rust.repr": "transparent" @@ -9,6 +11,8 @@ table RotationAxisAngle ( } /// 3D rotation represented by a rotation around a given axis that doesn't propagate in the transform hierarchy. +/// +/// If normalization of the rotation axis fails the rotation is treated as an invalid transform. table PoseRotationAxisAngle ( "attr.rust.derive": "Default, Copy, PartialEq", "attr.rust.repr": "transparent" diff --git a/crates/store/re_types/definitions/rerun/components/rotation_quat.fbs b/crates/store/re_types/definitions/rerun/components/rotation_quat.fbs index 3a8aed1a060e..be3b711662c0 100644 --- a/crates/store/re_types/definitions/rerun/components/rotation_quat.fbs +++ b/crates/store/re_types/definitions/rerun/components/rotation_quat.fbs @@ -4,6 +4,7 @@ namespace rerun.components; /// /// Note: although the x,y,z,w components of the quaternion will be passed through to the /// datastore as provided, when used in the Viewer, quaternions will always be normalized. +/// If normalization fails the rotation is treated as an invalid transform. struct RotationQuat ( "attr.rust.derive": "Default, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable", "attr.rust.repr": "transparent" @@ -15,6 +16,7 @@ struct RotationQuat ( /// /// Note: although the x,y,z,w components of the quaternion will be passed through to the /// datastore as provided, when used in the Viewer, quaternions will always be normalized. +/// If normalization fails the rotation is treated as an invalid transform. struct PoseRotationQuat ( "attr.rust.derive": "Default, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable", "attr.rust.repr": "transparent" diff --git a/crates/store/re_types/definitions/rerun/datatypes/rotation_axis_angle.fbs b/crates/store/re_types/definitions/rerun/datatypes/rotation_axis_angle.fbs index 44dbdf33264e..aeb64292324c 100644 --- a/crates/store/re_types/definitions/rerun/datatypes/rotation_axis_angle.fbs +++ b/crates/store/re_types/definitions/rerun/datatypes/rotation_axis_angle.fbs @@ -9,8 +9,8 @@ table RotationAxisAngle ( /// Axis to rotate around. /// /// This is not required to be normalized. - /// If normalization fails (typically because the vector is length zero), the rotation is silently - /// ignored. + /// However, if normalization of the rotation axis fails (typically due to a zero vector) + /// the rotation is treated as an invalid transform. axis: rerun.datatypes.Vec3D (order: 100); /// How much to rotate around the axis. diff --git a/crates/store/re_types/src/archetypes/disconnected_space.rs b/crates/store/re_types/src/archetypes/disconnected_space.rs index 58d59fa1b79a..642694071edc 100644 --- a/crates/store/re_types/src/archetypes/disconnected_space.rs +++ b/crates/store/re_types/src/archetypes/disconnected_space.rs @@ -11,6 +11,7 @@ #![allow(clippy::redundant_closure)] #![allow(clippy::too_many_arguments)] #![allow(clippy::too_many_lines)] +#![allow(deprecated)] use ::re_types_core::external::arrow2; use ::re_types_core::SerializationResult; @@ -29,6 +30,10 @@ use ::re_types_core::{DeserializationError, DeserializationResult}; /// /// ### Disconnected space /// ```ignore +/// // `DisconnectedSpace` is deprecated and will be removed in the future. +/// // Use an invalid transform (e.g. zeroed out 3x3 matrix) instead. +/// #![allow(deprecated)] +/// /// fn main() -> Result<(), Box> { /// let rec = rerun::RecordingStreamBuilder::new("rerun_example_disconnected_space").spawn()?; /// @@ -62,6 +67,7 @@ use ::re_types_core::{DeserializationError, DeserializationResult}; /// /// #[derive(Clone, Debug, Copy, PartialEq, Eq)] +#[deprecated(note = "Use [archetypes.Transform3D] with an invalid transform instead")] pub struct DisconnectedSpace { /// Whether the entity path at which this is logged is disconnected from its parent. pub disconnected_space: crate::components::DisconnectedSpace, diff --git a/crates/store/re_types/src/archetypes/mod.rs b/crates/store/re_types/src/archetypes/mod.rs index 3bac64ce396e..2915cf90a60a 100644 --- a/crates/store/re_types/src/archetypes/mod.rs +++ b/crates/store/re_types/src/archetypes/mod.rs @@ -68,7 +68,6 @@ pub use self::boxes2d::Boxes2D; pub use self::boxes3d::Boxes3D; pub use self::capsules3d::Capsules3D; pub use self::depth_image::DepthImage; -pub use self::disconnected_space::DisconnectedSpace; pub use self::ellipsoids3d::Ellipsoids3D; pub use self::encoded_image::EncodedImage; pub use self::geo_line_strings::GeoLineStrings; @@ -93,3 +92,6 @@ pub use self::text_log::TextLog; pub use self::transform3d::Transform3D; pub use self::video_frame_reference::VideoFrameReference; pub use self::view_coordinates::ViewCoordinates; + +#[allow(deprecated)] +pub use self::disconnected_space::DisconnectedSpace; diff --git a/crates/store/re_types/src/components/disconnected_space.rs b/crates/store/re_types/src/components/disconnected_space.rs index 0b890cf60318..cec09ea9d318 100644 --- a/crates/store/re_types/src/components/disconnected_space.rs +++ b/crates/store/re_types/src/components/disconnected_space.rs @@ -11,6 +11,7 @@ #![allow(clippy::redundant_closure)] #![allow(clippy::too_many_arguments)] #![allow(clippy::too_many_lines)] +#![allow(deprecated)] use ::re_types_core::external::arrow2; use ::re_types_core::SerializationResult; @@ -25,6 +26,7 @@ use ::re_types_core::{DeserializationError, DeserializationResult}; /// It *only* applies to views that work with spatial transformations, i.e. 2D & 3D views. /// This is useful for specifying that a subgraph is independent of the rest of the scene. #[derive(Clone, Debug, Copy, PartialEq, Eq)] +#[deprecated(note = "Use [archetypes.Transform3D] with an invalid transform instead.")] pub struct DisconnectedSpace( /// Whether the entity path at which this is logged is disconnected from its parent. /// diff --git a/crates/store/re_types/src/components/disconnected_space_ext.rs b/crates/store/re_types/src/components/disconnected_space_ext.rs index aa60226ac9a4..189b5015d0a4 100644 --- a/crates/store/re_types/src/components/disconnected_space_ext.rs +++ b/crates/store/re_types/src/components/disconnected_space_ext.rs @@ -1,3 +1,5 @@ +#![allow(deprecated)] + use super::DisconnectedSpace; impl Default for DisconnectedSpace { diff --git a/crates/store/re_types/src/components/mod.rs b/crates/store/re_types/src/components/mod.rs index c085b8954e44..7273851612a7 100644 --- a/crates/store/re_types/src/components/mod.rs +++ b/crates/store/re_types/src/components/mod.rs @@ -136,7 +136,6 @@ pub use self::class_id::ClassId; pub use self::color::Color; pub use self::colormap::Colormap; pub use self::depth_meter::DepthMeter; -pub use self::disconnected_space::DisconnectedSpace; pub use self::draw_order::DrawOrder; pub use self::entity_path::EntityPath; pub use self::fill_mode::FillMode; @@ -197,3 +196,6 @@ pub use self::vector2d::Vector2D; pub use self::vector3d::Vector3D; pub use self::video_timestamp::VideoTimestamp; pub use self::view_coordinates::ViewCoordinates; + +#[allow(deprecated)] +pub use self::disconnected_space::DisconnectedSpace; diff --git a/crates/store/re_types/src/components/pose_rotation_axis_angle.rs b/crates/store/re_types/src/components/pose_rotation_axis_angle.rs index f04b0666336c..3aa09bef378b 100644 --- a/crates/store/re_types/src/components/pose_rotation_axis_angle.rs +++ b/crates/store/re_types/src/components/pose_rotation_axis_angle.rs @@ -19,6 +19,8 @@ use ::re_types_core::{ComponentDescriptor, ComponentName}; use ::re_types_core::{DeserializationError, DeserializationResult}; /// **Component**: 3D rotation represented by a rotation around a given axis that doesn't propagate in the transform hierarchy. +/// +/// If normalization of the rotation axis fails the rotation is treated as an invalid transform. #[derive(Clone, Debug, Default, Copy, PartialEq)] #[repr(transparent)] pub struct PoseRotationAxisAngle(pub crate::datatypes::RotationAxisAngle); diff --git a/crates/store/re_types/src/components/pose_rotation_axis_angle_ext.rs b/crates/store/re_types/src/components/pose_rotation_axis_angle_ext.rs index 7c1e8f10798b..37f700c5c460 100644 --- a/crates/store/re_types/src/components/pose_rotation_axis_angle_ext.rs +++ b/crates/store/re_types/src/components/pose_rotation_axis_angle_ext.rs @@ -14,14 +14,14 @@ impl PoseRotationAxisAngle { } #[cfg(feature = "glam")] -impl From for glam::Affine3A { +impl TryFrom for glam::Affine3A { + type Error = (); + #[inline] - fn from(val: PoseRotationAxisAngle) -> Self { - if let Some(normalized) = glam::Vec3::from(val.0.axis).try_normalize() { - Self::from_axis_angle(normalized, val.0.angle.radians()) - } else { - // If the axis is zero length, we can't normalize it, so we just use the identity rotation. - Self::IDENTITY - } + fn try_from(val: PoseRotationAxisAngle) -> Result { + glam::Vec3::from(val.0.axis) + .try_normalize() + .map(|normalized| Self::from_axis_angle(normalized, val.0.angle.radians())) + .ok_or(()) } } diff --git a/crates/store/re_types/src/components/pose_rotation_quat.rs b/crates/store/re_types/src/components/pose_rotation_quat.rs index a4e69ae0b83a..964700df594d 100644 --- a/crates/store/re_types/src/components/pose_rotation_quat.rs +++ b/crates/store/re_types/src/components/pose_rotation_quat.rs @@ -22,6 +22,7 @@ use ::re_types_core::{DeserializationError, DeserializationResult}; /// /// Note: although the x,y,z,w components of the quaternion will be passed through to the /// datastore as provided, when used in the Viewer, quaternions will always be normalized. +/// If normalization fails the rotation is treated as an invalid transform. #[derive(Clone, Debug, Default, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)] #[repr(transparent)] pub struct PoseRotationQuat(pub crate::datatypes::Quaternion); diff --git a/crates/store/re_types/src/components/pose_rotation_quat_ext.rs b/crates/store/re_types/src/components/pose_rotation_quat_ext.rs index ffdf95624fe7..0aaa24d74e79 100644 --- a/crates/store/re_types/src/components/pose_rotation_quat_ext.rs +++ b/crates/store/re_types/src/components/pose_rotation_quat_ext.rs @@ -2,13 +2,21 @@ use super::PoseRotationQuat; impl PoseRotationQuat { /// The identity rotation, representing no rotation. + /// + /// Keep in mind that logging an identity rotation is different from logging no rotation at all + /// in thus far that it will write data to the store. pub const IDENTITY: Self = Self(crate::datatypes::Quaternion::IDENTITY); + + /// A rotation that represents an invalid transform. + pub const INVALID: Self = Self(crate::datatypes::Quaternion::INVALID); } #[cfg(feature = "glam")] -impl From for glam::Affine3A { +impl TryFrom for glam::Affine3A { + type Error = (); + #[inline] - fn from(val: PoseRotationQuat) -> Self { - Self::from_quat(val.0.into()) + fn try_from(val: PoseRotationQuat) -> Result { + Ok(Self::from_quat(glam::Quat::try_from(val.0)?)) } } diff --git a/crates/store/re_types/src/components/rotation_axis_angle.rs b/crates/store/re_types/src/components/rotation_axis_angle.rs index feb7bfeba9ac..21dafdc16441 100644 --- a/crates/store/re_types/src/components/rotation_axis_angle.rs +++ b/crates/store/re_types/src/components/rotation_axis_angle.rs @@ -19,6 +19,8 @@ use ::re_types_core::{ComponentDescriptor, ComponentName}; use ::re_types_core::{DeserializationError, DeserializationResult}; /// **Component**: 3D rotation represented by a rotation around a given axis. +/// +/// If normalization of the rotation axis fails the rotation is treated as an invalid transform. #[derive(Clone, Debug, Default, Copy, PartialEq)] #[repr(transparent)] pub struct RotationAxisAngle(pub crate::datatypes::RotationAxisAngle); diff --git a/crates/store/re_types/src/components/rotation_axis_angle_ext.rs b/crates/store/re_types/src/components/rotation_axis_angle_ext.rs index 9738aee10231..7884e2aa3434 100644 --- a/crates/store/re_types/src/components/rotation_axis_angle_ext.rs +++ b/crates/store/re_types/src/components/rotation_axis_angle_ext.rs @@ -14,14 +14,14 @@ impl RotationAxisAngle { } #[cfg(feature = "glam")] -impl From for glam::Affine3A { +impl TryFrom for glam::Affine3A { + type Error = (); + #[inline] - fn from(val: RotationAxisAngle) -> Self { - if let Some(normalized) = glam::Vec3::from(val.0.axis).try_normalize() { - Self::from_axis_angle(normalized, val.0.angle.radians()) - } else { - // If the axis is zero length, we can't normalize it, so we just use the identity rotation. - Self::IDENTITY - } + fn try_from(val: RotationAxisAngle) -> Result { + glam::Vec3::from(val.0.axis) + .try_normalize() + .map(|normalized| Self::from_axis_angle(normalized, val.0.angle.radians())) + .ok_or(()) } } diff --git a/crates/store/re_types/src/components/rotation_quat.rs b/crates/store/re_types/src/components/rotation_quat.rs index 7d64f9639e4b..0ee536178c0b 100644 --- a/crates/store/re_types/src/components/rotation_quat.rs +++ b/crates/store/re_types/src/components/rotation_quat.rs @@ -22,6 +22,7 @@ use ::re_types_core::{DeserializationError, DeserializationResult}; /// /// Note: although the x,y,z,w components of the quaternion will be passed through to the /// datastore as provided, when used in the Viewer, quaternions will always be normalized. +/// If normalization fails the rotation is treated as an invalid transform. #[derive(Clone, Debug, Default, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable)] #[repr(transparent)] pub struct RotationQuat(pub crate::datatypes::Quaternion); diff --git a/crates/store/re_types/src/components/rotation_quat_ext.rs b/crates/store/re_types/src/components/rotation_quat_ext.rs index ef4510515e32..e5b81b29e640 100644 --- a/crates/store/re_types/src/components/rotation_quat_ext.rs +++ b/crates/store/re_types/src/components/rotation_quat_ext.rs @@ -6,12 +6,17 @@ impl RotationQuat { /// Keep in mind that logging an identity rotation is different from logging no rotation at all /// in thus far that it will write data to the store. pub const IDENTITY: Self = Self(crate::datatypes::Quaternion::IDENTITY); + + /// A rotation that represents an invalid transform. + pub const INVALID: Self = Self(crate::datatypes::Quaternion::INVALID); } #[cfg(feature = "glam")] -impl From for glam::Affine3A { +impl TryFrom for glam::Affine3A { + type Error = (); + #[inline] - fn from(val: RotationQuat) -> Self { - Self::from_quat(val.0.into()) + fn try_from(val: RotationQuat) -> Result { + Ok(Self::from_quat(glam::Quat::try_from(val.0)?)) } } diff --git a/crates/store/re_types/src/datatypes/quaternion_ext.rs b/crates/store/re_types/src/datatypes/quaternion_ext.rs index dad46cc4a411..aae7a4b5a006 100644 --- a/crates/store/re_types/src/datatypes/quaternion_ext.rs +++ b/crates/store/re_types/src/datatypes/quaternion_ext.rs @@ -13,6 +13,9 @@ impl Quaternion { /// The identity quaternion representing no rotation. pub const IDENTITY: Self = Self([0.0, 0.0, 0.0, 1.0]); + /// A quaternion that represents an invalid transform. + pub const INVALID: Self = Self([0.0, 0.0, 0.0, 0.0]); + /// From XYZW. #[inline] pub const fn from_xyzw(xyzw: [f32; 4]) -> Self { @@ -33,11 +36,15 @@ impl Quaternion { } #[cfg(feature = "glam")] -impl From for glam::Quat { +impl TryFrom for glam::Quat { + type Error = (); + #[inline] - fn from(q: Quaternion) -> Self { - let [x, y, z, w] = q.0; - Self::from_xyzw(x, y, z, w).normalize() + fn try_from(q: Quaternion) -> Result { + glam::Vec4::from(q.0) + .try_normalize() + .map(Self::from_vec4) + .ok_or(()) } } diff --git a/crates/store/re_types/src/datatypes/rotation_axis_angle.rs b/crates/store/re_types/src/datatypes/rotation_axis_angle.rs index aaec1778f856..59218e9ced58 100644 --- a/crates/store/re_types/src/datatypes/rotation_axis_angle.rs +++ b/crates/store/re_types/src/datatypes/rotation_axis_angle.rs @@ -24,8 +24,8 @@ pub struct RotationAxisAngle { /// Axis to rotate around. /// /// This is not required to be normalized. - /// If normalization fails (typically because the vector is length zero), the rotation is silently - /// ignored. + /// However, if normalization of the rotation axis fails (typically due to a zero vector) + /// the rotation is treated as an invalid transform. pub axis: crate::datatypes::Vec3D, /// How much to rotate around the axis. diff --git a/crates/store/re_types/src/datatypes/rotation_axis_angle_ext.rs b/crates/store/re_types/src/datatypes/rotation_axis_angle_ext.rs index 27ca8e3057c2..1aae9e45e748 100644 --- a/crates/store/re_types/src/datatypes/rotation_axis_angle_ext.rs +++ b/crates/store/re_types/src/datatypes/rotation_axis_angle_ext.rs @@ -9,6 +9,12 @@ impl RotationAxisAngle { angle: Angle::ZERO, }; + /// A rotation that represents an invalid transform. + pub const INVALID: Self = Self { + axis: Vec3D::ZERO, + angle: Angle::ZERO, + }; + /// Create a new rotation from an axis and an angle. #[inline] pub fn new(axis: impl Into, angle: impl Into) -> Self { @@ -26,13 +32,15 @@ impl, A: Into> From<(V, A)> for RotationAxisAngle { } #[cfg(feature = "glam")] -impl From for glam::Quat { +impl TryFrom for glam::Quat { + type Error = (); + #[inline] - fn from(val: RotationAxisAngle) -> Self { + fn try_from(val: RotationAxisAngle) -> Result { let axis: glam::Vec3 = val.axis.into(); axis.try_normalize() .map(|axis| Self::from_axis_angle(axis, val.angle.radians())) - .unwrap_or_default() + .ok_or(()) } } diff --git a/crates/store/re_types/src/reflection/mod.rs b/crates/store/re_types/src/reflection/mod.rs index 13a12e4af4fb..129ea7566c7d 100644 --- a/crates/store/re_types/src/reflection/mod.rs +++ b/crates/store/re_types/src/reflection/mod.rs @@ -29,7 +29,7 @@ pub fn generate_reflection() -> Result { /// Generates reflection about all known components. /// /// Call only once and reuse the results. - +#[allow(deprecated)] fn generate_component_reflection() -> Result { re_tracing::profile_function!(); let array = [ @@ -658,7 +658,7 @@ fn generate_component_reflection() -> Result::name(), ComponentReflection { - docstring_md: "3D rotation represented by a rotation around a given axis that doesn't propagate in the transform hierarchy.", + docstring_md: "3D rotation represented by a rotation around a given axis that doesn't propagate in the transform hierarchy.\n\nIf normalization of the rotation axis fails the rotation is treated as an invalid transform.", custom_placeholder: Some(PoseRotationAxisAngle::default().to_arrow2()?), datatype: PoseRotationAxisAngle::arrow2_datatype(), }, @@ -666,7 +666,7 @@ fn generate_component_reflection() -> Result::name(), ComponentReflection { - docstring_md: "A 3D rotation expressed as a quaternion that doesn't propagate in the transform hierarchy.\n\nNote: although the x,y,z,w components of the quaternion will be passed through to the\ndatastore as provided, when used in the Viewer, quaternions will always be normalized.", + docstring_md: "A 3D rotation expressed as a quaternion that doesn't propagate in the transform hierarchy.\n\nNote: although the x,y,z,w components of the quaternion will be passed through to the\ndatastore as provided, when used in the Viewer, quaternions will always be normalized.\nIf normalization fails the rotation is treated as an invalid transform.", custom_placeholder: Some(PoseRotationQuat::default().to_arrow2()?), datatype: PoseRotationQuat::arrow2_datatype(), }, @@ -746,7 +746,7 @@ fn generate_component_reflection() -> Result::name(), ComponentReflection { - docstring_md: "3D rotation represented by a rotation around a given axis.", + docstring_md: "3D rotation represented by a rotation around a given axis.\n\nIf normalization of the rotation axis fails the rotation is treated as an invalid transform.", custom_placeholder: Some(RotationAxisAngle::default().to_arrow2()?), datatype: RotationAxisAngle::arrow2_datatype(), }, @@ -754,7 +754,7 @@ fn generate_component_reflection() -> Result::name(), ComponentReflection { - docstring_md: "A 3D rotation expressed as a quaternion.\n\nNote: although the x,y,z,w components of the quaternion will be passed through to the\ndatastore as provided, when used in the Viewer, quaternions will always be normalized.", + docstring_md: "A 3D rotation expressed as a quaternion.\n\nNote: although the x,y,z,w components of the quaternion will be passed through to the\ndatastore as provided, when used in the Viewer, quaternions will always be normalized.\nIf normalization fails the rotation is treated as an invalid transform.", custom_placeholder: Some(RotationQuat::default().to_arrow2()?), datatype: RotationQuat::arrow2_datatype(), }, diff --git a/crates/store/re_types/tests/types/disconnected_space.rs b/crates/store/re_types/tests/types/disconnected_space.rs index df3b2156f904..94934f4f1b68 100644 --- a/crates/store/re_types/tests/types/disconnected_space.rs +++ b/crates/store/re_types/tests/types/disconnected_space.rs @@ -1,3 +1,5 @@ +#![allow(deprecated)] + use std::collections::HashMap; use re_types::{archetypes::DisconnectedSpace, Archetype as _, AsComponents as _}; diff --git a/crates/viewer/re_view_spatial/src/contexts/transform_context.rs b/crates/viewer/re_view_spatial/src/contexts/transform_context.rs index 82a596ea58b6..b533536755a7 100644 --- a/crates/viewer/re_view_spatial/src/contexts/transform_context.rs +++ b/crates/viewer/re_view_spatial/src/contexts/transform_context.rs @@ -6,9 +6,9 @@ use re_entity_db::{EntityDb, EntityPath, EntityTree}; use re_types::{ archetypes::{InstancePoses3D, Pinhole, Transform3D}, components::{ - DisconnectedSpace, ImagePlaneDistance, PinholeProjection, PoseRotationAxisAngle, - PoseRotationQuat, PoseScale3D, PoseTransformMat3x3, PoseTranslation3D, RotationAxisAngle, - RotationQuat, Scale3D, TransformMat3x3, TransformRelation, Translation3D, ViewCoordinates, + self, ImagePlaneDistance, PinholeProjection, PoseRotationAxisAngle, PoseRotationQuat, + PoseScale3D, PoseTransformMat3x3, PoseTranslation3D, RotationAxisAngle, RotationQuat, + Scale3D, TransformMat3x3, TransformRelation, Translation3D, ViewCoordinates, }, Archetype, Component as _, ComponentNameSet, }; @@ -169,7 +169,8 @@ impl ViewContextSystem for TransformContext { .map(|descr| descr.component_name) .collect(), std::iter::once(PinholeProjection::name()).collect(), - std::iter::once(DisconnectedSpace::name()).collect(), + #[allow(deprecated)] // `DisconnectedSpace` is on the way out. + std::iter::once(components::DisconnectedSpace::name()).collect(), ] } @@ -550,17 +551,36 @@ fn query_and_resolve_tree_transform_at_entity( if let Some(translation) = result.component_instance::(0) { transform = glam::Affine3A::from(translation); } - if let Some(rotation_quat) = result.component_instance::(0) { - transform *= glam::Affine3A::from(rotation_quat); + if let Some(axis_angle) = result.component_instance::(0) { + if let Ok(axis_angle) = glam::Affine3A::try_from(axis_angle) { + transform *= axis_angle; + } else { + // Invalid transform. + return None; + } } - if let Some(rotation_axis_angle) = result.component_instance::(0) { - transform *= glam::Affine3A::from(rotation_axis_angle); + if let Some(quaternion) = result.component_instance::(0) { + if let Ok(quaternion) = glam::Affine3A::try_from(quaternion) { + transform *= quaternion; + } else { + // Invalid transform. + return None; + } } if let Some(scale) = result.component_instance::(0) { + if scale.x() == 0.0 && scale.y() == 0.0 && scale.z() == 0.0 { + // Invalid scale. + return None; + } transform *= glam::Affine3A::from(scale); } if let Some(mat3x3) = result.component_instance::(0) { - transform *= glam::Affine3A::from(mat3x3); + let affine_transform = glam::Affine3A::from(mat3x3); + if affine_transform.matrix3.determinant() == 0.0 { + // Invalid transform. + return None; + } + transform *= affine_transform; } if result.component_instance::(0) == Some(TransformRelation::ChildFromParent) @@ -647,10 +667,18 @@ fn query_and_resolve_instance_poses_at_entity( transform = glam::Affine3A::from(translation); } if let Some(rotation_quat) = iter_rotation_quat.next() { - transform *= glam::Affine3A::from(rotation_quat); + if let Ok(rotation_quat) = glam::Affine3A::try_from(rotation_quat) { + transform *= rotation_quat; + } else { + transform = glam::Affine3A::ZERO; + } } if let Some(rotation_axis_angle) = iter_rotation_axis_angle.next() { - transform *= glam::Affine3A::from(rotation_axis_angle); + if let Ok(axis_angle) = glam::Affine3A::try_from(rotation_axis_angle) { + transform *= axis_angle; + } else { + transform = glam::Affine3A::ZERO; + } } if let Some(scale) = iter_scale.next() { transform *= glam::Affine3A::from(scale); @@ -802,10 +830,11 @@ fn transforms_at( .instance_from_pinhole_image_plane .is_none(); + #[allow(deprecated)] // `DisconnectedSpace` is on the way out. if no_other_transforms && potential_transform_components.disconnected_space && entity_db - .latest_at_component::(entity_path, query) + .latest_at_component::(entity_path, query) .map_or(false, |(_index, res)| **res) { Err(UnreachableTransformReason::DisconnectedSpace) diff --git a/crates/viewer/re_view_spatial/src/spatial_topology.rs b/crates/viewer/re_view_spatial/src/spatial_topology.rs index 67d3b942ec7c..e33c8ce6ae33 100644 --- a/crates/viewer/re_view_spatial/src/spatial_topology.rs +++ b/crates/viewer/re_view_spatial/src/spatial_topology.rs @@ -1,3 +1,6 @@ +// `DisconnectedSpace` is still around, but to be removed. +#![allow(deprecated)] + use once_cell::sync::OnceCell; use ahash::HashMap; diff --git a/crates/viewer/re_view_spatial/src/transform_component_tracker.rs b/crates/viewer/re_view_spatial/src/transform_component_tracker.rs index bd46be0560cd..a343d2fff3aa 100644 --- a/crates/viewer/re_view_spatial/src/transform_component_tracker.rs +++ b/crates/viewer/re_view_spatial/src/transform_component_tracker.rs @@ -136,6 +136,8 @@ impl PerStoreChunkSubscriber for TransformComponentTrackerStoreSubscriber { .or_default() .pinhole = true; } + // `DisconnectedSpace` is deprecated and will be removed in the future. + #[allow(deprecated)] if component_name == re_types::components::DisconnectedSpace::name() && contains_non_zero_component_array(component_name) { diff --git a/docs/content/reference/migration/migration-0-21.md b/docs/content/reference/migration/migration-0-21.md index 71f9397f22fa..15c149d369f1 100644 --- a/docs/content/reference/migration/migration-0-21.md +++ b/docs/content/reference/migration/migration-0-21.md @@ -65,3 +65,24 @@ Previously, the viewer would show 3 arrows for every logged transform if any of For many usecases this led to too many arrows being shown by default. We therefore removed the last condition - arrows will no longer show by default if they're the only visualizer. The easiest way to opt-in to transform arrows is to set `AxisLength` (`axis_length` field on the `Transform3D` archetype) on your transforms. + +### `DisconnectedSpace` archetype/component deprecated + +The `DisconnectedSpace` archetype and `DisconnectedSpace` component have been deprecated. +To achieve the same effect, you can log any of the following "invalid" transforms: +* zeroed 3x3 matrix +* zero scale +* zeroed quaternion +* zero axis on axis-angle rotation + +Previously, the `DisconnectedSpace` archetype played a double role by governing view spawn heuristics & being used as a transform placeholder. +This led to a lot of complexity and often broke or caused confusion (see https://github.com/rerun-io/rerun/issues/6817, https://github.com/rerun-io/rerun/issues/4465, https://github.com/rerun-io/rerun/issues/4221). +By now, explicit blueprints offer a better way to express which views should be spawned and what content they should query. +(you can learn more about blueprints [here](https://rerun.io/docs/getting-started/configure-the-viewer/through-code-tutorial)). + +`DisconnectedSpace` will be removed in a future release. + +### `RotationAxisAngle` with zero rotation axis is no longer treated as identity + +Previously, `RotationAxisAngle` with a zero rotation axis was treated as identity. +This is no longer the case, instead it makes the transform invalid in the same way a zeroed transformation matrix does. diff --git a/docs/content/reference/types/archetypes.md b/docs/content/reference/types/archetypes.md index 4b6f07b9b037..5176d0a479a3 100644 --- a/docs/content/reference/types/archetypes.md +++ b/docs/content/reference/types/archetypes.md @@ -73,5 +73,5 @@ This page lists all built-in archetypes. * [`AnnotationContext`](archetypes/annotation_context.md): The annotation context provides additional information on how to display entities. * [`Clear`](archetypes/clear.md): Empties all the components of an entity. -* [`DisconnectedSpace`](archetypes/disconnected_space.md): Spatially disconnect this entity from its parent. +* ⚠️ _deprecated_ [`DisconnectedSpace`](archetypes/disconnected_space.md): Spatially disconnect this entity from its parent. diff --git a/docs/content/reference/types/archetypes/disconnected_space.md b/docs/content/reference/types/archetypes/disconnected_space.md index 752465188940..2362dfeb4f6d 100644 --- a/docs/content/reference/types/archetypes/disconnected_space.md +++ b/docs/content/reference/types/archetypes/disconnected_space.md @@ -1,8 +1,11 @@ --- -title: "DisconnectedSpace" +title: "DisconnectedSpace (deprecated)" --- +**⚠️ This type is deprecated and may be removed in future versions** +Use [archetypes.Transform3D] with an invalid transform instead + Spatially disconnect this entity from its parent. Specifies that the entity path at which this is logged is spatially disconnected from its parent, diff --git a/docs/content/reference/types/components.md b/docs/content/reference/types/components.md index c9be262b0fde..0ebd0863ab0c 100644 --- a/docs/content/reference/types/components.md +++ b/docs/content/reference/types/components.md @@ -23,7 +23,7 @@ on [Entities and Components](../../concepts/entity-component.md). * [`Color`](components/color.md): An RGBA color with unmultiplied/separate alpha, in sRGB gamma space with linear alpha. * [`Colormap`](components/colormap.md): Colormap for mapping scalar values within a given range to a color. * [`DepthMeter`](components/depth_meter.md): The world->depth map scaling factor. -* [`DisconnectedSpace`](components/disconnected_space.md): Spatially disconnect this entity from its parent. +* ⚠️ _deprecated_ [`DisconnectedSpace`](components/disconnected_space.md): Spatially disconnect this entity from its parent. * [`DrawOrder`](components/draw_order.md): Draw order of 2D elements. Higher values are drawn on top of lower values. * [`EntityPath`](components/entity_path.md): A path to an entity, usually to reference some data that is part of the target entity. * [`FillMode`](components/fill_mode.md): How a geometric shape is drawn and colored. diff --git a/docs/content/reference/types/components/disconnected_space.md b/docs/content/reference/types/components/disconnected_space.md index fd9447abb871..3fbb0ac3f060 100644 --- a/docs/content/reference/types/components/disconnected_space.md +++ b/docs/content/reference/types/components/disconnected_space.md @@ -1,8 +1,11 @@ --- -title: "DisconnectedSpace" +title: "DisconnectedSpace (deprecated)" --- +**⚠️ This type is deprecated and may be removed in future versions** +Use [archetypes.Transform3D] with an invalid transform instead. + Spatially disconnect this entity from its parent. Specifies that the entity path at which this is logged is spatially disconnected from its parent, diff --git a/docs/content/reference/types/components/pose_rotation_axis_angle.md b/docs/content/reference/types/components/pose_rotation_axis_angle.md index 6361b6f08b1e..fcb951eb7e23 100644 --- a/docs/content/reference/types/components/pose_rotation_axis_angle.md +++ b/docs/content/reference/types/components/pose_rotation_axis_angle.md @@ -5,6 +5,8 @@ title: "PoseRotationAxisAngle" 3D rotation represented by a rotation around a given axis that doesn't propagate in the transform hierarchy. +If normalization of the rotation axis fails the rotation is treated as an invalid transform. + ## Rerun datatype [`RotationAxisAngle`](../datatypes/rotation_axis_angle.md) diff --git a/docs/content/reference/types/components/pose_rotation_quat.md b/docs/content/reference/types/components/pose_rotation_quat.md index 0d02625dbd23..a994e7710507 100644 --- a/docs/content/reference/types/components/pose_rotation_quat.md +++ b/docs/content/reference/types/components/pose_rotation_quat.md @@ -7,6 +7,7 @@ A 3D rotation expressed as a quaternion that doesn't propagate in the transform Note: although the x,y,z,w components of the quaternion will be passed through to the datastore as provided, when used in the Viewer, quaternions will always be normalized. +If normalization fails the rotation is treated as an invalid transform. ## Rerun datatype [`Quaternion`](../datatypes/quaternion.md) diff --git a/docs/content/reference/types/components/rotation_axis_angle.md b/docs/content/reference/types/components/rotation_axis_angle.md index 134b6f59da59..fff45fe16a41 100644 --- a/docs/content/reference/types/components/rotation_axis_angle.md +++ b/docs/content/reference/types/components/rotation_axis_angle.md @@ -5,6 +5,8 @@ title: "RotationAxisAngle" 3D rotation represented by a rotation around a given axis. +If normalization of the rotation axis fails the rotation is treated as an invalid transform. + ## Rerun datatype [`RotationAxisAngle`](../datatypes/rotation_axis_angle.md) diff --git a/docs/content/reference/types/components/rotation_quat.md b/docs/content/reference/types/components/rotation_quat.md index 70898260508c..80cb2ff1e3a4 100644 --- a/docs/content/reference/types/components/rotation_quat.md +++ b/docs/content/reference/types/components/rotation_quat.md @@ -7,6 +7,7 @@ A 3D rotation expressed as a quaternion. Note: although the x,y,z,w components of the quaternion will be passed through to the datastore as provided, when used in the Viewer, quaternions will always be normalized. +If normalization fails the rotation is treated as an invalid transform. ## Rerun datatype [`Quaternion`](../datatypes/quaternion.md) diff --git a/docs/content/reference/types/datatypes/rotation_axis_angle.md b/docs/content/reference/types/datatypes/rotation_axis_angle.md index ef1e7521fad3..546b31e89067 100644 --- a/docs/content/reference/types/datatypes/rotation_axis_angle.md +++ b/docs/content/reference/types/datatypes/rotation_axis_angle.md @@ -12,8 +12,8 @@ Type: [`Vec3D`](../datatypes/vec3d.md) Axis to rotate around. This is not required to be normalized. -If normalization fails (typically because the vector is length zero), the rotation is silently -ignored. +However, if normalization of the rotation axis fails (typically due to a zero vector) +the rotation is treated as an invalid transform. #### `angle` Type: [`Angle`](../datatypes/angle.md) diff --git a/docs/snippets/all/archetypes/disconnected_space.cpp b/docs/snippets/all/archetypes/disconnected_space.cpp index b1e50bba108c..e3053c338b62 100644 --- a/docs/snippets/all/archetypes/disconnected_space.cpp +++ b/docs/snippets/all/archetypes/disconnected_space.cpp @@ -2,6 +2,9 @@ #include +// DisconnectedSpace is deprecated and will be removed in the future. +RR_DISABLE_DEPRECATION_WARNING + int main() { const auto rec = rerun::RecordingStream("rerun_example_disconnected_space"); rec.spawn().exit_on_failure(); diff --git a/docs/snippets/all/archetypes/disconnected_space.rs b/docs/snippets/all/archetypes/disconnected_space.rs index 9f2d49ae2b42..250f8018cbea 100644 --- a/docs/snippets/all/archetypes/disconnected_space.rs +++ b/docs/snippets/all/archetypes/disconnected_space.rs @@ -1,5 +1,9 @@ //! Disconnect two spaces. +// `DisconnectedSpace` is deprecated and will be removed in the future. +// Use an invalid transform (e.g. zeroed out 3x3 matrix) instead. +#![allow(deprecated)] + fn main() -> Result<(), Box> { let rec = rerun::RecordingStreamBuilder::new("rerun_example_disconnected_space").spawn()?; diff --git a/rerun_cpp/src/rerun/archetypes/disconnected_space.cpp b/rerun_cpp/src/rerun/archetypes/disconnected_space.cpp index 3e811827419f..4c1ca31b8df6 100644 --- a/rerun_cpp/src/rerun/archetypes/disconnected_space.cpp +++ b/rerun_cpp/src/rerun/archetypes/disconnected_space.cpp @@ -5,6 +5,9 @@ #include "../collection_adapter_builtins.hpp" +RR_PUSH_WARNINGS +RR_DISABLE_DEPRECATION_WARNING + namespace rerun::archetypes {} namespace rerun { @@ -38,3 +41,5 @@ namespace rerun { return cells; } } // namespace rerun + +RR_POP_WARNINGS diff --git a/rerun_cpp/src/rerun/archetypes/disconnected_space.hpp b/rerun_cpp/src/rerun/archetypes/disconnected_space.hpp index 298fe3c31c7f..19d598b0a5d7 100644 --- a/rerun_cpp/src/rerun/archetypes/disconnected_space.hpp +++ b/rerun_cpp/src/rerun/archetypes/disconnected_space.hpp @@ -4,6 +4,7 @@ #pragma once #include "../collection.hpp" +#include "../compiler_utils.hpp" #include "../component_batch.hpp" #include "../components/disconnected_space.hpp" #include "../indicator_component.hpp" @@ -13,6 +14,9 @@ #include #include +RR_PUSH_WARNINGS +RR_DISABLE_DEPRECATION_WARNING + namespace rerun::archetypes { /// **Archetype**: Spatially disconnect this entity from its parent. /// @@ -29,6 +33,9 @@ namespace rerun::archetypes { /// ```cpp /// #include /// + /// // DisconnectedSpace is deprecated and will be removed in the future. + /// RR_DISABLE_DEPRECATION_WARNING + /// /// int main() { /// const auto rec = rerun::RecordingStream("rerun_example_disconnected_space"); /// rec.spawn().exit_on_failure(); @@ -42,7 +49,8 @@ namespace rerun::archetypes { /// rec.log("world/wormhole/point", rerun::Points3D({{2.0f, 2.0f, 2.0f}})); /// } /// ``` - struct DisconnectedSpace { + struct [[deprecated("Use [archetypes.Transform3D] with an invalid transform instead" + )]] DisconnectedSpace { /// Whether the entity path at which this is logged is disconnected from its parent. rerun::components::DisconnectedSpace disconnected_space; @@ -67,6 +75,8 @@ namespace rerun { /// \private template struct AsComponents; + RR_PUSH_WARNINGS + RR_DISABLE_DEPRECATION_WARNING /// \private template <> @@ -77,3 +87,5 @@ namespace rerun { ); }; } // namespace rerun + +RR_POP_WARNINGS diff --git a/rerun_cpp/src/rerun/archetypes/transform3d.hpp b/rerun_cpp/src/rerun/archetypes/transform3d.hpp index 7ced69fb7342..060b8052e872 100644 --- a/rerun_cpp/src/rerun/archetypes/transform3d.hpp +++ b/rerun_cpp/src/rerun/archetypes/transform3d.hpp @@ -188,6 +188,11 @@ namespace rerun::archetypes { /// Applying this transform does not alter an entity's transformation. RERUN_SDK_EXPORT static const Transform3D IDENTITY; + /// Invalid transformation. + /// + /// Applying this transform will cause this entity and the entire subtree not to be visualized. + RERUN_SDK_EXPORT static const Transform3D INVALID; + /// Creates a new 3D transform from translation and matrix provided as 3 columns. /// /// \param translation_ \çopydoc Transform3D::translation diff --git a/rerun_cpp/src/rerun/archetypes/transform3d_ext.cpp b/rerun_cpp/src/rerun/archetypes/transform3d_ext.cpp index 27fccae48924..9e9b04087e1e 100644 --- a/rerun_cpp/src/rerun/archetypes/transform3d_ext.cpp +++ b/rerun_cpp/src/rerun/archetypes/transform3d_ext.cpp @@ -16,6 +16,11 @@ namespace rerun::archetypes { /// Applying this transform does not alter an entity's transformation. RERUN_SDK_EXPORT static const Transform3D IDENTITY; + /// Invalid transformation. + /// + /// Applying this transform will cause this entity and the entire subtree not to be visualized. + RERUN_SDK_EXPORT static const Transform3D INVALID; + /// Creates a new 3D transform from translation and matrix provided as 3 columns. /// /// \param translation_ \çopydoc Transform3D::translation @@ -338,4 +343,14 @@ namespace rerun::archetypes { // #endif + /// Identity transformation. + /// + /// Applying this transform does not alter an entity's transformation. + const Transform3D Transform3D::IDENTITY = Transform3D(rerun::datatypes::Mat3x3::IDENTITY); + + /// Invalid transformation. + /// + /// Applying this transform will cause this entity and the entire subtree not to be visualized. + const Transform3D Transform3D::INVALID = Transform3D(rerun::datatypes::Mat3x3::INVALID); + } // namespace rerun::archetypes diff --git a/rerun_cpp/src/rerun/components/disconnected_space.hpp b/rerun_cpp/src/rerun/components/disconnected_space.hpp index 24dd0ee0d89f..2c659a40ffbd 100644 --- a/rerun_cpp/src/rerun/components/disconnected_space.hpp +++ b/rerun_cpp/src/rerun/components/disconnected_space.hpp @@ -3,6 +3,7 @@ #pragma once +#include "../compiler_utils.hpp" #include "../component_descriptor.hpp" #include "../datatypes/bool.hpp" #include "../result.hpp" @@ -17,7 +18,8 @@ namespace rerun::components { /// making it impossible to transform the entity path into its parent's space and vice versa. /// It *only* applies to views that work with spatial transformations, i.e. 2D & 3D views. /// This is useful for specifying that a subgraph is independent of the rest of the scene. - struct DisconnectedSpace { + struct [[deprecated("Use [archetypes.Transform3D] with an invalid transform instead." + )]] DisconnectedSpace { /// Whether the entity path at which this is logged is disconnected from its parent. /// /// Set to true to disconnect the entity from its parent. @@ -50,6 +52,9 @@ namespace rerun::components { }; } // namespace rerun::components +RR_PUSH_WARNINGS +RR_DISABLE_DEPRECATION_WARNING + namespace rerun { static_assert(sizeof(rerun::datatypes::Bool) == sizeof(components::DisconnectedSpace)); @@ -83,3 +88,5 @@ namespace rerun { } }; } // namespace rerun + +RR_POP_WARNINGS diff --git a/rerun_cpp/src/rerun/components/pose_rotation_axis_angle.hpp b/rerun_cpp/src/rerun/components/pose_rotation_axis_angle.hpp index d7d9d6490907..f361fa1d96d7 100644 --- a/rerun_cpp/src/rerun/components/pose_rotation_axis_angle.hpp +++ b/rerun_cpp/src/rerun/components/pose_rotation_axis_angle.hpp @@ -12,6 +12,8 @@ namespace rerun::components { /// **Component**: 3D rotation represented by a rotation around a given axis that doesn't propagate in the transform hierarchy. + /// + /// If normalization of the rotation axis fails the rotation is treated as an invalid transform. struct PoseRotationAxisAngle { rerun::datatypes::RotationAxisAngle rotation; diff --git a/rerun_cpp/src/rerun/components/pose_rotation_quat.hpp b/rerun_cpp/src/rerun/components/pose_rotation_quat.hpp index 0ea2f7946076..212cdb630ead 100644 --- a/rerun_cpp/src/rerun/components/pose_rotation_quat.hpp +++ b/rerun_cpp/src/rerun/components/pose_rotation_quat.hpp @@ -15,6 +15,7 @@ namespace rerun::components { /// /// Note: although the x,y,z,w components of the quaternion will be passed through to the /// datastore as provided, when used in the Viewer, quaternions will always be normalized. + /// If normalization fails the rotation is treated as an invalid transform. struct PoseRotationQuat { rerun::datatypes::Quaternion quaternion; diff --git a/rerun_cpp/src/rerun/components/resolution.hpp b/rerun_cpp/src/rerun/components/resolution.hpp index ef7513a9596b..aacef5296c5c 100644 --- a/rerun_cpp/src/rerun/components/resolution.hpp +++ b/rerun_cpp/src/rerun/components/resolution.hpp @@ -20,8 +20,6 @@ namespace rerun::components { rerun::datatypes::Vec2D resolution; public: // START of extensions from resolution_ext.cpp: - RERUN_SDK_EXPORT static const Resolution IDENTITY; - /// Construct resolution from width and height floats. Resolution(float width, float height) : resolution{width, height} {} diff --git a/rerun_cpp/src/rerun/components/resolution_ext.cpp b/rerun_cpp/src/rerun/components/resolution_ext.cpp index acd7f58e5aad..a9251493105e 100644 --- a/rerun_cpp/src/rerun/components/resolution_ext.cpp +++ b/rerun_cpp/src/rerun/components/resolution_ext.cpp @@ -18,8 +18,6 @@ namespace rerun { // - RERUN_SDK_EXPORT static const Resolution IDENTITY; - /// Construct resolution from width and height floats. Resolution(float width, float height) : resolution{width, height} {} diff --git a/rerun_cpp/src/rerun/components/rotation_axis_angle.hpp b/rerun_cpp/src/rerun/components/rotation_axis_angle.hpp index 46fc2a62142f..86bf63be7103 100644 --- a/rerun_cpp/src/rerun/components/rotation_axis_angle.hpp +++ b/rerun_cpp/src/rerun/components/rotation_axis_angle.hpp @@ -12,6 +12,8 @@ namespace rerun::components { /// **Component**: 3D rotation represented by a rotation around a given axis. + /// + /// If normalization of the rotation axis fails the rotation is treated as an invalid transform. struct RotationAxisAngle { rerun::datatypes::RotationAxisAngle rotation; diff --git a/rerun_cpp/src/rerun/components/rotation_quat.hpp b/rerun_cpp/src/rerun/components/rotation_quat.hpp index 809a578f3e9b..a7814558eb50 100644 --- a/rerun_cpp/src/rerun/components/rotation_quat.hpp +++ b/rerun_cpp/src/rerun/components/rotation_quat.hpp @@ -15,6 +15,7 @@ namespace rerun::components { /// /// Note: although the x,y,z,w components of the quaternion will be passed through to the /// datastore as provided, when used in the Viewer, quaternions will always be normalized. + /// If normalization fails the rotation is treated as an invalid transform. struct RotationQuat { rerun::datatypes::Quaternion quaternion; diff --git a/rerun_cpp/src/rerun/datatypes/mat3x3.hpp b/rerun_cpp/src/rerun/datatypes/mat3x3.hpp index d1c5d4caa3fe..a7cd01036079 100644 --- a/rerun_cpp/src/rerun/datatypes/mat3x3.hpp +++ b/rerun_cpp/src/rerun/datatypes/mat3x3.hpp @@ -35,6 +35,7 @@ namespace rerun::datatypes { public: // START of extensions from mat3x3_ext.cpp: static const Mat3x3 IDENTITY; + static const Mat3x3 INVALID; /// Creates a new 3x3 matrix from 3 *columns* of 3 elements each. Mat3x3(const Vec3D (&columns)[3]) diff --git a/rerun_cpp/src/rerun/datatypes/mat3x3_ext.cpp b/rerun_cpp/src/rerun/datatypes/mat3x3_ext.cpp index ecde3c19df89..845c371e3408 100644 --- a/rerun_cpp/src/rerun/datatypes/mat3x3_ext.cpp +++ b/rerun_cpp/src/rerun/datatypes/mat3x3_ext.cpp @@ -13,6 +13,7 @@ namespace rerun { // static const Mat3x3 IDENTITY; + static const Mat3x3 INVALID; /// Creates a new 3x3 matrix from 3 *columns* of 3 elements each. Mat3x3(const Vec3D (&columns)[3]) @@ -51,5 +52,11 @@ namespace rerun { {0.0, 0.0, 1.0}, }); + const Mat3x3 Mat3x3::INVALID = Mat3x3({ + {0.0, 0.0, 0.0}, + {0.0, 0.0, 0.0}, + {0.0, 0.0, 0.0}, + }); + } // namespace datatypes } // namespace rerun diff --git a/rerun_cpp/src/rerun/datatypes/quaternion.hpp b/rerun_cpp/src/rerun/datatypes/quaternion.hpp index cf7115966407..71a35af4f7c6 100644 --- a/rerun_cpp/src/rerun/datatypes/quaternion.hpp +++ b/rerun_cpp/src/rerun/datatypes/quaternion.hpp @@ -27,6 +27,7 @@ namespace rerun::datatypes { public: // START of extensions from quaternion_ext.cpp: RERUN_SDK_EXPORT static const Quaternion IDENTITY; + RERUN_SDK_EXPORT static const Quaternion INVALID; /// Construct Quaternion from x/y/z/w values. static Quaternion from_xyzw(float x, float y, float z, float w) { diff --git a/rerun_cpp/src/rerun/datatypes/quaternion_ext.cpp b/rerun_cpp/src/rerun/datatypes/quaternion_ext.cpp index 39d09d529d22..b9a0c4cfaf6d 100644 --- a/rerun_cpp/src/rerun/datatypes/quaternion_ext.cpp +++ b/rerun_cpp/src/rerun/datatypes/quaternion_ext.cpp @@ -15,6 +15,7 @@ namespace rerun { // RERUN_SDK_EXPORT static const Quaternion IDENTITY; + RERUN_SDK_EXPORT static const Quaternion INVALID; /// Construct Quaternion from x/y/z/w values. static Quaternion from_xyzw(float x, float y, float z, float w) { @@ -68,5 +69,6 @@ namespace rerun { #endif const Quaternion Quaternion::IDENTITY = Quaternion::from_xyzw(0.0f, 0.0f, 0.0f, 1.0f); + const Quaternion Quaternion::INVALID = Quaternion::from_xyzw(0.0f, 0.0f, 0.0f, 0.0f); } // namespace datatypes } // namespace rerun diff --git a/rerun_cpp/src/rerun/datatypes/rotation_axis_angle.hpp b/rerun_cpp/src/rerun/datatypes/rotation_axis_angle.hpp index 4bf17018676f..a1c28310d491 100644 --- a/rerun_cpp/src/rerun/datatypes/rotation_axis_angle.hpp +++ b/rerun_cpp/src/rerun/datatypes/rotation_axis_angle.hpp @@ -23,8 +23,8 @@ namespace rerun::datatypes { /// Axis to rotate around. /// /// This is not required to be normalized. - /// If normalization fails (typically because the vector is length zero), the rotation is silently - /// ignored. + /// However, if normalization of the rotation axis fails (typically due to a zero vector) + /// the rotation is treated as an invalid transform. rerun::datatypes::Vec3D axis; /// How much to rotate around the axis. diff --git a/rerun_cpp/tests/archetypes/disconnected_space.cpp b/rerun_cpp/tests/archetypes/disconnected_space.cpp index 35296b67d53b..e20f3f7c38bf 100644 --- a/rerun_cpp/tests/archetypes/disconnected_space.cpp +++ b/rerun_cpp/tests/archetypes/disconnected_space.cpp @@ -1,5 +1,7 @@ #include "archetype_test.hpp" +RR_DISABLE_DEPRECATION_WARNING + #include using namespace rerun::archetypes; diff --git a/rerun_py/rerun_sdk/rerun/archetypes/disconnected_space.py b/rerun_py/rerun_sdk/rerun/archetypes/disconnected_space.py index bbac1df347ea..4ea38aaf153c 100644 --- a/rerun_py/rerun_sdk/rerun/archetypes/disconnected_space.py +++ b/rerun_py/rerun_sdk/rerun/archetypes/disconnected_space.py @@ -6,6 +6,7 @@ from __future__ import annotations from attrs import define, field +from typing_extensions import deprecated # type: ignore[misc, unused-ignore] from .. import components from .._baseclasses import ( @@ -16,6 +17,7 @@ __all__ = ["DisconnectedSpace"] +@deprecated("""Use [archetypes.Transform3D] with an invalid transform instead""") @define(str=False, repr=False, init=False) class DisconnectedSpace(DisconnectedSpaceExt, Archetype): """ diff --git a/rerun_py/rerun_sdk/rerun/components/disconnected_space.py b/rerun_py/rerun_sdk/rerun/components/disconnected_space.py index 4ca00a3af3c0..40b9886d8c45 100644 --- a/rerun_py/rerun_sdk/rerun/components/disconnected_space.py +++ b/rerun_py/rerun_sdk/rerun/components/disconnected_space.py @@ -5,6 +5,8 @@ from __future__ import annotations +from typing_extensions import deprecated # type: ignore[misc, unused-ignore] + from .. import datatypes from .._baseclasses import ( ComponentBatchMixin, @@ -16,6 +18,7 @@ __all__ = ["DisconnectedSpace", "DisconnectedSpaceBatch"] +@deprecated("""Use [archetypes.Transform3D] with an invalid transform instead.""") class DisconnectedSpace(DisconnectedSpaceExt, datatypes.Bool, ComponentMixin): """ **Component**: Spatially disconnect this entity from its parent. diff --git a/rerun_py/rerun_sdk/rerun/components/pose_rotation_axis_angle.py b/rerun_py/rerun_sdk/rerun/components/pose_rotation_axis_angle.py index a424304836bd..c90afcab6fa7 100644 --- a/rerun_py/rerun_sdk/rerun/components/pose_rotation_axis_angle.py +++ b/rerun_py/rerun_sdk/rerun/components/pose_rotation_axis_angle.py @@ -16,7 +16,11 @@ class PoseRotationAxisAngle(datatypes.RotationAxisAngle, ComponentMixin): - """**Component**: 3D rotation represented by a rotation around a given axis that doesn't propagate in the transform hierarchy.""" + """ + **Component**: 3D rotation represented by a rotation around a given axis that doesn't propagate in the transform hierarchy. + + If normalization of the rotation axis fails the rotation is treated as an invalid transform. + """ _BATCH_TYPE = None # You can define your own __init__ function as a member of PoseRotationAxisAngleExt in pose_rotation_axis_angle_ext.py diff --git a/rerun_py/rerun_sdk/rerun/components/pose_rotation_quat.py b/rerun_py/rerun_sdk/rerun/components/pose_rotation_quat.py index 9f8bc782a7ae..4a5dedd372dc 100644 --- a/rerun_py/rerun_sdk/rerun/components/pose_rotation_quat.py +++ b/rerun_py/rerun_sdk/rerun/components/pose_rotation_quat.py @@ -21,6 +21,7 @@ class PoseRotationQuat(datatypes.Quaternion, ComponentMixin): Note: although the x,y,z,w components of the quaternion will be passed through to the datastore as provided, when used in the Viewer, quaternions will always be normalized. + If normalization fails the rotation is treated as an invalid transform. """ _BATCH_TYPE = None diff --git a/rerun_py/rerun_sdk/rerun/components/rotation_axis_angle.py b/rerun_py/rerun_sdk/rerun/components/rotation_axis_angle.py index 81dfeacd37a0..8d357a3cfc03 100644 --- a/rerun_py/rerun_sdk/rerun/components/rotation_axis_angle.py +++ b/rerun_py/rerun_sdk/rerun/components/rotation_axis_angle.py @@ -16,7 +16,11 @@ class RotationAxisAngle(datatypes.RotationAxisAngle, ComponentMixin): - """**Component**: 3D rotation represented by a rotation around a given axis.""" + """ + **Component**: 3D rotation represented by a rotation around a given axis. + + If normalization of the rotation axis fails the rotation is treated as an invalid transform. + """ _BATCH_TYPE = None # You can define your own __init__ function as a member of RotationAxisAngleExt in rotation_axis_angle_ext.py diff --git a/rerun_py/rerun_sdk/rerun/components/rotation_quat.py b/rerun_py/rerun_sdk/rerun/components/rotation_quat.py index 78e49ae5c8b5..a0ce5b014e94 100644 --- a/rerun_py/rerun_sdk/rerun/components/rotation_quat.py +++ b/rerun_py/rerun_sdk/rerun/components/rotation_quat.py @@ -21,6 +21,7 @@ class RotationQuat(datatypes.Quaternion, ComponentMixin): Note: although the x,y,z,w components of the quaternion will be passed through to the datastore as provided, when used in the Viewer, quaternions will always be normalized. + If normalization fails the rotation is treated as an invalid transform. """ _BATCH_TYPE = None diff --git a/rerun_py/rerun_sdk/rerun/datatypes/quaternion_ext.py b/rerun_py/rerun_sdk/rerun/datatypes/quaternion_ext.py index 29f6290a9c8a..4027612c1dca 100644 --- a/rerun_py/rerun_sdk/rerun/datatypes/quaternion_ext.py +++ b/rerun_py/rerun_sdk/rerun/datatypes/quaternion_ext.py @@ -27,6 +27,12 @@ def identity() -> Quaternion: return Quaternion(xyzw=np.array([0, 0, 0, 1], dtype=np.float32)) + @staticmethod + def invalid() -> Quaternion: + from . import Quaternion + + return Quaternion(xyzw=np.array([0, 0, 0, 0], dtype=np.float32)) + @staticmethod def native_to_pa_array_override(data: QuaternionArrayLike, data_type: pa.DataType) -> pa.Array: # TODO(ab): get rid of this once we drop support for Python 3.8. Make sure to pin numpy>=1.25. diff --git a/rerun_py/rerun_sdk/rerun/datatypes/rotation_axis_angle.py b/rerun_py/rerun_sdk/rerun/datatypes/rotation_axis_angle.py index 2370610fd394..d1e87b29dbe4 100644 --- a/rerun_py/rerun_sdk/rerun/datatypes/rotation_axis_angle.py +++ b/rerun_py/rerun_sdk/rerun/datatypes/rotation_axis_angle.py @@ -36,8 +36,8 @@ class RotationAxisAngle(RotationAxisAngleExt): # Axis to rotate around. # # This is not required to be normalized. - # If normalization fails (typically because the vector is length zero), the rotation is silently - # ignored. + # However, if normalization of the rotation axis fails (typically due to a zero vector) + # the rotation is treated as an invalid transform. # # (Docstring intentionally commented out to hide this field from the docs) diff --git a/rerun_py/tests/unit/test_disconnected_space.py b/rerun_py/tests/unit/test_disconnected_space.py deleted file mode 100644 index d66730f0d136..000000000000 --- a/rerun_py/tests/unit/test_disconnected_space.py +++ /dev/null @@ -1,25 +0,0 @@ -from __future__ import annotations - -import rerun as rr -from rerun.components import DisconnectedSpace, DisconnectedSpaceBatch -from rerun.datatypes.bool import BoolLike - - -def test_disconnected_space() -> None: - disconnected_spaces: list[BoolLike] = [ - # DisconnectedSpaceLike: bool - True, - # DisconnectedSpaceLike: DisconnectedSpace - DisconnectedSpace(), - ] - - for disconnected_space in disconnected_spaces: - print(f"rr.DisconnectedSpace(\n" f" disconnected_space={disconnected_space}\n" f")") - arch = rr.DisconnectedSpace(disconnected_space) - print(f"{arch}\n") - - assert arch.disconnected_space == DisconnectedSpaceBatch([True]) - - -if __name__ == "__main__": - test_disconnected_space() diff --git a/tests/cpp/roundtrips/disconnected_space/main.cpp b/tests/cpp/roundtrips/disconnected_space/main.cpp index 5731ed47a0a1..caba6f07d892 100644 --- a/tests/cpp/roundtrips/disconnected_space/main.cpp +++ b/tests/cpp/roundtrips/disconnected_space/main.cpp @@ -1,3 +1,8 @@ +#include + +// DisconnectedSpace is deprecated and will be removed in the future. +RR_DISABLE_DEPRECATION_WARNING + #include #include diff --git a/tests/rust/roundtrips/disconnected_space/src/main.rs b/tests/rust/roundtrips/disconnected_space/src/main.rs index 27cb7eacf00d..a20b1a92391c 100644 --- a/tests/rust/roundtrips/disconnected_space/src/main.rs +++ b/tests/rust/roundtrips/disconnected_space/src/main.rs @@ -1,5 +1,9 @@ //! Logs a `DisconnectedSpace` archetype for roundtrip checks. +// `DisconnectedSpace` is deprecated and will be removed in the future. +// Use an invalid transform (for instance zero scale or zero matrix) instead. +#![allow(deprecated)] + use rerun::{archetypes::DisconnectedSpace, RecordingStream}; #[derive(Debug, clap::Parser)]