Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move object property heuristics to heuristics.rs #2764

Merged
merged 1 commit into from
Jul 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
173 changes: 173 additions & 0 deletions crates/re_space_view_spatial/src/heuristics.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
use egui::NumExt as _;
use nohash_hasher::IntSet;

use re_components::{Pinhole, Tensor, TensorDataMeaning, Transform3D};
use re_data_store::EditableAutoValue;
use re_log_types::{EntityPath, Timeline};
use re_viewer_context::{AutoSpawnHeuristic, SpaceViewClassName, ViewerContext};

Expand Down Expand Up @@ -45,3 +49,172 @@ pub fn auto_spawn_heuristic(

AutoSpawnHeuristic::SpawnClassWithHighestScoreForRoot(score)
}

pub fn update_object_property_heuristics(
ctx: &mut ViewerContext<'_>,
ent_paths: &IntSet<EntityPath>,
entity_properties: &mut re_data_store::EntityPropertyMap,
scene_bbox_accum: &macaw::BoundingBox,
spatial_kind: SpatialSpaceViewKind,
) {
re_tracing::profile_function!();

for entity_path in ent_paths {
update_pinhole_property_heuristics(ctx, entity_path, entity_properties, scene_bbox_accum);
update_depth_cloud_property_heuristics(ctx, entity_path, entity_properties, spatial_kind);
update_transform3d_lines_heuristics(ctx, entity_path, entity_properties, scene_bbox_accum);
}
}

pub fn auto_size_world_heuristic(
scene_bbox_accum: &macaw::BoundingBox,
scene_num_primitives: usize,
) -> f32 {
if scene_bbox_accum.is_nothing() || scene_bbox_accum.is_nan() {
return 0.01;
}

// Motivation: Size should be proportional to the scene extent, here covered by its diagonal
let diagonal_length = (scene_bbox_accum.max - scene_bbox_accum.min).length();
let heuristic0 = diagonal_length * 0.0025;

// Motivation: A lot of times we look at the entire scene and expect to see everything on a flat screen with some gaps between.
let size = scene_bbox_accum.size();
let mut sorted_components = size.to_array();
sorted_components.sort_by(|a, b| a.partial_cmp(b).unwrap());
// Median is more robust against outlier in one direction (as such pretty poor still though)
let median_extent = sorted_components[1];
// sqrt would make more sense but using a smaller root works better in practice.
let heuristic1 =
(median_extent / (scene_num_primitives.at_least(1) as f32).powf(1.0 / 1.7)) * 0.25;

heuristic0.min(heuristic1)
}

fn update_pinhole_property_heuristics(
ctx: &mut ViewerContext<'_>,
entity_path: &EntityPath,
entity_properties: &mut re_data_store::EntityPropertyMap,
scene_bbox_accum: &macaw::BoundingBox,
) {
let store = &ctx.store_db.entity_db.data_store;
if store
.query_latest_component::<Pinhole>(entity_path, &ctx.current_query())
.is_some()
{
let mut properties = entity_properties.get(entity_path);
if properties.pinhole_image_plane_distance.is_auto() {
let scene_size = scene_bbox_accum.size().length();
let default_image_plane_distance = if scene_size.is_finite() && scene_size > 0.0 {
scene_size * 0.02 // Works pretty well for `examples/python/open_photogrammetry_format/main.py --no-frames`
} else {
1.0
};
properties.pinhole_image_plane_distance =
EditableAutoValue::Auto(default_image_plane_distance);
entity_properties.set(entity_path.clone(), properties);
}
}
}

fn update_depth_cloud_property_heuristics(
ctx: &mut ViewerContext<'_>,
entity_path: &EntityPath,
entity_properties: &mut re_data_store::EntityPropertyMap,
spatial_kind: SpatialSpaceViewKind,
) -> Option<()> {
let store = &ctx.store_db.entity_db.data_store;
let tensor = store.query_latest_component::<Tensor>(entity_path, &ctx.current_query())?;

let mut properties = entity_properties.get(entity_path);
if properties.backproject_depth.is_auto() {
properties.backproject_depth = EditableAutoValue::Auto(
tensor.meaning == TensorDataMeaning::Depth
&& spatial_kind == SpatialSpaceViewKind::ThreeD,
);
}

if tensor.meaning == TensorDataMeaning::Depth {
if properties.depth_from_world_scale.is_auto() {
let auto = tensor.meter.unwrap_or_else(|| {
if tensor.dtype().is_integer() {
1000.0
} else {
1.0
}
});
properties.depth_from_world_scale = EditableAutoValue::Auto(auto);
}

if properties.backproject_radius_scale.is_auto() {
properties.backproject_radius_scale = EditableAutoValue::Auto(1.0);
}

entity_properties.set(entity_path.clone(), properties);
}

Some(())
}

fn update_transform3d_lines_heuristics(
ctx: &ViewerContext<'_>,
ent_path: &EntityPath,
entity_properties: &mut re_data_store::EntityPropertyMap,
scene_bbox_accum: &macaw::BoundingBox,
) {
if ctx
.store_db
.store()
.query_latest_component::<Transform3D>(ent_path, &ctx.current_query())
.is_none()
{
return;
}

let mut properties = entity_properties.get(ent_path);
if properties.transform_3d_visible.is_auto() {
fn path_or_child_has_pinhole(
store: &re_arrow_store::DataStore,
ent_path: &EntityPath,
ctx: &ViewerContext<'_>,
) -> bool {
if store
.query_latest_component::<Pinhole>(ent_path, &ctx.current_query())
.is_some()
{
return true;
} else {
// Any direct child has a pinhole camera?
if let Some(child_tree) = ctx.store_db.entity_db.tree.subtree(ent_path) {
for child in child_tree.children.values() {
if store
.query_latest_component::<Pinhole>(&child.path, &ctx.current_query())
.is_some()
{
return true;
}
}
}
}

false
}
// By default show the transform if it is a camera extrinsic or if it's the only component on this entity path.
let single_component = ctx
.store_db
.store()
.all_components(&ctx.current_query().timeline, ent_path)
.map_or(false, |c| c.len() == 1);
properties.transform_3d_visible = EditableAutoValue::Auto(
single_component || path_or_child_has_pinhole(ctx.store_db.store(), ent_path, ctx),
);
}

if properties.transform_3d_size.is_auto() {
// Size should be proportional to the scene extent, here covered by its diagonal
let diagonal_length = (scene_bbox_accum.max - scene_bbox_accum.min).length();
properties.transform_3d_size = EditableAutoValue::Auto(diagonal_length * 0.01);
}

entity_properties.set(ent_path.clone(), properties);
}
5 changes: 3 additions & 2 deletions crates/re_space_view_spatial/src/space_view_2d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use re_viewer_context::{

use crate::{
contexts::{register_contexts, PrimitiveCounter},
heuristics::auto_spawn_heuristic,
heuristics::{auto_spawn_heuristic, update_object_property_heuristics},
parts::{calculate_bounding_box, register_parts},
ui::SpatialSpaceViewState,
view_kind::SpatialSpaceViewKind,
Expand Down Expand Up @@ -57,10 +57,11 @@ impl SpaceViewClass for SpatialSpaceView2D {
ent_paths: &IntSet<EntityPath>,
entity_properties: &mut re_data_store::EntityPropertyMap,
) {
state.update_object_property_heuristics(
update_object_property_heuristics(
ctx,
ent_paths,
entity_properties,
&state.scene_bbox_accum,
SpatialSpaceViewKind::TwoD,
);
}
Expand Down
5 changes: 3 additions & 2 deletions crates/re_space_view_spatial/src/space_view_3d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use re_viewer_context::{

use crate::{
contexts::{register_contexts, PrimitiveCounter},
heuristics::auto_spawn_heuristic,
heuristics::{auto_spawn_heuristic, update_object_property_heuristics},
parts::{calculate_bounding_box, register_parts},
ui::SpatialSpaceViewState,
view_kind::SpatialSpaceViewKind,
Expand Down Expand Up @@ -93,10 +93,11 @@ impl SpaceViewClass for SpatialSpaceView3D {
ent_paths: &IntSet<EntityPath>,
entity_properties: &mut re_data_store::EntityPropertyMap,
) {
state.update_object_property_heuristics(
update_object_property_heuristics(
ctx,
ent_paths,
entity_properties,
&state.scene_bbox_accum,
SpatialSpaceViewKind::ThreeD,
);
}
Expand Down
Loading