From 530539f2a76c9bbad02f3ca71fc678abf01a7912 Mon Sep 17 00:00:00 2001 From: Jeremy Leibs Date: Wed, 5 Apr 2023 18:04:34 +0200 Subject: [PATCH 1/3] auto_color class-ids if they are present --- crates/re_viewer/src/ui/annotations.rs | 43 ++++++++++++++------------ 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/crates/re_viewer/src/ui/annotations.rs b/crates/re_viewer/src/ui/annotations.rs index 2e5ab34c8394..12a6280bd2fb 100644 --- a/crates/re_viewer/src/ui/annotations.rs +++ b/crates/re_viewer/src/ui/annotations.rs @@ -23,37 +23,41 @@ pub struct Annotations { impl Annotations { pub fn class_description(&self, class_id: Option) -> ResolvedClassDescription<'_> { ResolvedClassDescription( + class_id, class_id.and_then(|class_id| self.context.class_map.get(&class_id)), ) } } -pub struct ResolvedClassDescription<'a>(pub Option<&'a ClassDescription>); +pub struct ResolvedClassDescription<'a>(pub Option, pub Option<&'a ClassDescription>); impl<'a> ResolvedClassDescription<'a> { pub fn annotation_info(&self) -> ResolvedAnnotationInfo { - ResolvedAnnotationInfo(self.0.map(|desc| desc.info.clone())) + ResolvedAnnotationInfo(self.0, self.1.map(|desc| desc.info.clone())) } /// Merges class annotation info with keypoint annotation info (if existing respectively). pub fn annotation_info_with_keypoint(&self, keypoint_id: KeypointId) -> ResolvedAnnotationInfo { - if let Some(desc) = self.0 { + if let Some(desc) = self.1 { // Assuming that keypoint annotation is the rarer case, merging the entire annotation ahead of time // is cheaper than doing it lazily (which would cause more branches down the line for callsites without keypoints) if let Some(keypoint_annotation_info) = desc.keypoint_map.get(&keypoint_id) { - ResolvedAnnotationInfo(Some(AnnotationInfo { - id: keypoint_id.0, - label: keypoint_annotation_info - .label - .clone() - .or_else(|| desc.info.label.clone()), - color: keypoint_annotation_info.color.or(desc.info.color), - })) + ResolvedAnnotationInfo( + self.0, + Some(AnnotationInfo { + id: keypoint_id.0, + label: keypoint_annotation_info + .label + .clone() + .or_else(|| desc.info.label.clone()), + color: keypoint_annotation_info.color.or(desc.info.color), + }), + ) } else { self.annotation_info() } } else { - ResolvedAnnotationInfo(None) + ResolvedAnnotationInfo(self.0, None) } } } @@ -66,7 +70,7 @@ pub enum DefaultColor<'a> { } #[derive(Clone)] -pub struct ResolvedAnnotationInfo(pub Option); +pub struct ResolvedAnnotationInfo(pub Option, pub Option); impl ResolvedAnnotationInfo { pub fn color( @@ -76,17 +80,18 @@ impl ResolvedAnnotationInfo { ) -> re_renderer::Color32 { if let Some([r, g, b, a]) = color { re_renderer::Color32::from_rgba_premultiplied(*r, *g, *b, *a) - } else if let Some(color) = self.0.as_ref().and_then(|info| { + } else if let Some(color) = self.1.as_ref().and_then(|info| { info.color .map(|c| c.into()) .or_else(|| Some(auto_color(info.id))) }) { color } else { - match default_color { - DefaultColor::TransparentBlack => re_renderer::Color32::TRANSPARENT, - DefaultColor::OpaqueWhite => re_renderer::Color32::WHITE, - DefaultColor::EntityPath(entity_path) => { + match (self.0, default_color) { + (Some(class_id), _) if class_id.0 != 0 => auto_color(class_id.0), + (_, DefaultColor::TransparentBlack) => re_renderer::Color32::TRANSPARENT, + (_, DefaultColor::OpaqueWhite) => re_renderer::Color32::WHITE, + (_, DefaultColor::EntityPath(entity_path)) => { auto_color((entity_path.hash64() % std::u16::MAX as u64) as u16) } } @@ -97,7 +102,7 @@ impl ResolvedAnnotationInfo { if let Some(label) = label { Some(label.clone()) } else { - self.0 + self.1 .as_ref() .and_then(|info| info.label.as_ref().map(|label| label.0.clone())) } From ccea730d06fa4a633a7f5aba11fc23ed84cc9f1c Mon Sep 17 00:00:00 2001 From: Jeremy Leibs Date: Wed, 5 Apr 2023 18:07:42 +0200 Subject: [PATCH 2/3] Update log line in segmentation demo --- examples/python/api_demo/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/python/api_demo/main.py b/examples/python/api_demo/main.py index ba10c4f18514..daaa448677da 100755 --- a/examples/python/api_demo/main.py +++ b/examples/python/api_demo/main.py @@ -43,7 +43,7 @@ def run_segmentation() -> None: class_ids=np.array([42], dtype=np.uint8), ) - rr.log_text_entry("logs/seg_demo_log", "no rects, default colored points, a single point has a label") + rr.log_text_entry("logs/seg_demo_log", "default colored rects, default colored points, a single point has a label") # Log an initial segmentation map with arbitrary colors rr.set_time_seconds("sim_time", 2) From 29e48b6866ab92fec5db1dfbe7549b324366a44c Mon Sep 17 00:00:00 2001 From: Jeremy Leibs Date: Wed, 5 Apr 2023 19:40:01 +0200 Subject: [PATCH 3/3] Avoid tuple structs --- crates/re_viewer/src/ui/annotations.rs | 42 +++++++++++++++++--------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/crates/re_viewer/src/ui/annotations.rs b/crates/re_viewer/src/ui/annotations.rs index 12a6280bd2fb..3a25bc132fd1 100644 --- a/crates/re_viewer/src/ui/annotations.rs +++ b/crates/re_viewer/src/ui/annotations.rs @@ -22,29 +22,35 @@ pub struct Annotations { impl Annotations { pub fn class_description(&self, class_id: Option) -> ResolvedClassDescription<'_> { - ResolvedClassDescription( + ResolvedClassDescription { class_id, - class_id.and_then(|class_id| self.context.class_map.get(&class_id)), - ) + class_description: class_id.and_then(|class_id| self.context.class_map.get(&class_id)), + } } } -pub struct ResolvedClassDescription<'a>(pub Option, pub Option<&'a ClassDescription>); +pub struct ResolvedClassDescription<'a> { + pub class_id: Option, + pub class_description: Option<&'a ClassDescription>, +} impl<'a> ResolvedClassDescription<'a> { pub fn annotation_info(&self) -> ResolvedAnnotationInfo { - ResolvedAnnotationInfo(self.0, self.1.map(|desc| desc.info.clone())) + ResolvedAnnotationInfo { + class_id: self.class_id, + annotation_info: self.class_description.map(|desc| desc.info.clone()), + } } /// Merges class annotation info with keypoint annotation info (if existing respectively). pub fn annotation_info_with_keypoint(&self, keypoint_id: KeypointId) -> ResolvedAnnotationInfo { - if let Some(desc) = self.1 { + if let Some(desc) = self.class_description { // Assuming that keypoint annotation is the rarer case, merging the entire annotation ahead of time // is cheaper than doing it lazily (which would cause more branches down the line for callsites without keypoints) if let Some(keypoint_annotation_info) = desc.keypoint_map.get(&keypoint_id) { - ResolvedAnnotationInfo( - self.0, - Some(AnnotationInfo { + ResolvedAnnotationInfo { + class_id: self.class_id, + annotation_info: Some(AnnotationInfo { id: keypoint_id.0, label: keypoint_annotation_info .label @@ -52,12 +58,15 @@ impl<'a> ResolvedClassDescription<'a> { .or_else(|| desc.info.label.clone()), color: keypoint_annotation_info.color.or(desc.info.color), }), - ) + } } else { self.annotation_info() } } else { - ResolvedAnnotationInfo(self.0, None) + ResolvedAnnotationInfo { + class_id: self.class_id, + annotation_info: None, + } } } } @@ -70,7 +79,10 @@ pub enum DefaultColor<'a> { } #[derive(Clone)] -pub struct ResolvedAnnotationInfo(pub Option, pub Option); +pub struct ResolvedAnnotationInfo { + pub class_id: Option, + pub annotation_info: Option, +} impl ResolvedAnnotationInfo { pub fn color( @@ -80,14 +92,14 @@ impl ResolvedAnnotationInfo { ) -> re_renderer::Color32 { if let Some([r, g, b, a]) = color { re_renderer::Color32::from_rgba_premultiplied(*r, *g, *b, *a) - } else if let Some(color) = self.1.as_ref().and_then(|info| { + } else if let Some(color) = self.annotation_info.as_ref().and_then(|info| { info.color .map(|c| c.into()) .or_else(|| Some(auto_color(info.id))) }) { color } else { - match (self.0, default_color) { + match (self.class_id, default_color) { (Some(class_id), _) if class_id.0 != 0 => auto_color(class_id.0), (_, DefaultColor::TransparentBlack) => re_renderer::Color32::TRANSPARENT, (_, DefaultColor::OpaqueWhite) => re_renderer::Color32::WHITE, @@ -102,7 +114,7 @@ impl ResolvedAnnotationInfo { if let Some(label) = label { Some(label.clone()) } else { - self.1 + self.annotation_info .as_ref() .and_then(|info| info.label.as_ref().map(|label| label.0.clone())) }