Skip to content

Commit

Permalink
Set visual 2D bounds from code (#6127)
Browse files Browse the repository at this point in the history
### What
* Closes #683
* Closes #6150

Usage:
```py
rrb.Spatial2DView(visual_bounds=rrb.VisualBounds(min=[0.0, 0.0], max=[10.0, 20.0]))
```


### Checklist
* [x] I have read and agree to [Contributor
Guide](https://github.com/rerun-io/rerun/blob/main/CONTRIBUTING.md) and
the [Code of
Conduct](https://github.com/rerun-io/rerun/blob/main/CODE_OF_CONDUCT.md)
* [x] I've included a screenshot or gif (if applicable)
* [x] I have tested the web demo (if applicable):
* Using examples from latest `main` build:
[rerun.io/viewer](https://rerun.io/viewer/pr/6127?manifest_url=https://app.rerun.io/version/main/examples_manifest.json)
* Using full set of examples from `nightly` build:
[rerun.io/viewer](https://rerun.io/viewer/pr/6127?manifest_url=https://app.rerun.io/version/nightly/examples_manifest.json)
* [x] The PR title and labels are set such as to maximize their
usefulness for the next release's CHANGELOG
* [x] If applicable, add a new check to the [release
checklist](https://github.com/rerun-io/rerun/blob/main/tests/python/release_checklist)!

- [PR Build Summary](https://build.rerun.io/pr/6127)
- [Recent benchmark results](https://build.rerun.io/graphs/crates.html)
- [Wasm size tracking](https://build.rerun.io/graphs/sizes.html)

To run all checks from `main`, comment on the PR with `@rerun-bot
full-check`.

---------

Co-authored-by: Andreas Reich <r_andreas2@web.de>
  • Loading branch information
emilk and Wumpf committed Apr 29, 2024
1 parent 845591c commit f7b2bec
Show file tree
Hide file tree
Showing 106 changed files with 1,809 additions and 200 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions crates/re_entity_db/src/entity_db.rs
Expand Up @@ -241,6 +241,14 @@ impl EntityDb {
}
}

/// Get the latest index and value for a given dense [`re_types_core::Component`].
///
/// This assumes that the row we get from the store contains at most one instance for this
/// component; it will log a warning otherwise.
///
/// This should only be used for "mono-components" such as `Transform` and `Tensor`.
///
/// This is a best-effort helper, it will merely log errors on failure.
#[inline]
pub fn latest_at_component<C: re_types_core::Component>(
&self,
Expand All @@ -255,6 +263,14 @@ impl EntityDb {
)
}

/// Get the latest index and value for a given dense [`re_types_core::Component`].
///
/// This assumes that the row we get from the store contains at most one instance for this
/// component; it will log a warning otherwise.
///
/// This should only be used for "mono-components" such as `Transform` and `Tensor`.
///
/// This is a best-effort helper, and will quietly swallow any errors.
#[inline]
pub fn latest_at_component_quiet<C: re_types_core::Component>(
&self,
Expand Down
79 changes: 47 additions & 32 deletions crates/re_query/src/latest_at/helpers.rs
Expand Up @@ -62,7 +62,7 @@ impl LatestAtComponentResults {

/// Returns the component data of the single instance.
///
/// This assumes that the row we get from the store only contains a single instance for this
/// This assumes that the row we get from the store contains at most one instance for this
/// component; it will log a warning otherwise.
///
/// This should only be used for "mono-components" such as `Transform` and `Tensor`.
Expand All @@ -77,14 +77,19 @@ impl LatestAtComponentResults {
re_log::debug_once!("Couldn't deserialize {component_name}: promise still pending",);
None
}
PromiseResult::Ready(data) if data.len() == 1 => Some(data[0].clone()),
PromiseResult::Ready(data) => {
re_log::log_once!(
level,
"Couldn't deserialize {component_name}: not a mono-batch (length: {})",
data.len(),
);
None
match data.len() {
0 => {
None // Empty list = no data.
}
1 => Some(data[0].clone()),
len => {
re_log::log_once!(level,
"Couldn't deserialize {component_name}: not a mono-batch (length: {len})"
);
None
}
}
}
PromiseResult::Error(err) => {
re_log::log_once!(
Expand All @@ -99,7 +104,7 @@ impl LatestAtComponentResults {

/// Returns the component data of the single instance as an arrow array.
///
/// This assumes that the row we get from the store only contains a single instance for this
/// This assumes that the row we get from the store contains at most one instance for this
/// component; it will log a warning otherwise.
///
/// This should only be used for "mono-components" such as `Transform` and `Tensor`.
Expand All @@ -118,16 +123,20 @@ impl LatestAtComponentResults {
re_log::debug_once!("Couldn't get {component_name}: promise still pending");
None
}
PromiseResult::Ready(cell) if cell.as_arrow_ref().len() == 1 => {
Some(cell.as_arrow_ref().sliced(0, 1))
}
PromiseResult::Ready(cell) => {
re_log::log_once!(
level,
"Couldn't get {component_name}: not a mono-batch (length: {})",
cell.as_arrow_ref().len(),
);
None
match cell.as_arrow_ref().len() {
0 => {
None // Empty list = no data.
}
1 => Some(cell.as_arrow_ref().sliced(0, 1)),
len => {
re_log::log_once!(
level,
"Couldn't get {component_name}: not a mono-batch (length: {len})",
);
None
}
}
}
PromiseResult::Error(err) => {
re_log::log_once!(
Expand Down Expand Up @@ -272,7 +281,7 @@ impl Caches {
///
/// Returns `None` if the data is a promise that has yet to be resolved.
///
/// This assumes that the row we get from the store only contains a single instance for this
/// This assumes that the row we get from the store contains at most one instance for this
/// component; it will generate a log message of `level` otherwise.
///
/// This should only be used for "mono-components" such as `Transform` and `Tensor`.
Expand Down Expand Up @@ -303,18 +312,24 @@ impl Caches {
);
None
}
PromiseResult::Ready(data) if data.len() == 1 => Some(LatestAtMonoResult {
index,
value: data[0].clone(),
}),
PromiseResult::Ready(data) => {
re_log::log_once!(
level,
"Couldn't deserialize {entity_path}:{} @ {data_time:?}#{row_id}: not a mono-batch (length: {})",
C::name(),
data.len(),
);
None
match data.len() {
0 => {
None // Empty list = no data.
}
1 => Some(LatestAtMonoResult {
index,
value: data[0].clone(),
}),
len => {
re_log::log_once!(
level,
"Couldn't deserialize {entity_path}:{} @ {data_time:?}#{row_id}: not a mono-batch (length: {len})",
C::name(),
);
None
}
}
}
PromiseResult::Error(err) => {
re_log::log_once!(
Expand All @@ -330,7 +345,7 @@ impl Caches {

/// Get the latest index and value for a given dense [`re_types_core::Component`].
///
/// This assumes that the row we get from the store only contains a single instance for this
/// This assumes that the row we get from the store contains at most one instance for this
/// component; it will log a warning otherwise.
///
/// This should only be used for "mono-components" such as `Transform` and `Tensor`.
Expand All @@ -355,7 +370,7 @@ impl Caches {

/// Get the latest index and value for a given dense [`re_types_core::Component`].
///
/// This assumes that the row we get from the store only contains a single instance for this
/// This assumes that the row we get from the store contains at most one instance for this
/// component; it will return None and log a debug message otherwise.
///
/// This should only be used for "mono-components" such as `Transform` and `Tensor`.
Expand Down
1 change: 1 addition & 0 deletions crates/re_query/src/latest_at/to_archetype/.gitattributes

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/re_query/src/latest_at/to_archetype/mod.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

44 changes: 44 additions & 0 deletions crates/re_query/src/latest_at/to_archetype/visual_bounds.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions crates/re_space_view/src/lib.rs
Expand Up @@ -18,8 +18,9 @@ pub use screenshot::ScreenshotMode;
pub use space_view::SpaceViewBlueprint;
pub use space_view_contents::SpaceViewContents;
pub use sub_archetypes::{
entity_path_for_space_view_sub_archetype, query_space_view_sub_archetype,
query_space_view_sub_archetype_or_default, space_view_sub_archetype,
edit_blueprint_component, entity_path_for_space_view_sub_archetype, get_blueprint_component,
query_space_view_sub_archetype, query_space_view_sub_archetype_or_default,
space_view_sub_archetype,
};
pub use visual_time_range::{
query_visual_history, time_range_boundary_to_visible_history_boundary,
Expand Down
4 changes: 4 additions & 0 deletions crates/re_space_view/src/space_view.rs
Expand Up @@ -553,6 +553,7 @@ mod tests {
let ctx = StoreContext {
app_id: re_log_types::ApplicationId::unknown(),
blueprint: &blueprint,
default_blueprint: None,
recording: &recording,
bundle: &Default::default(),
hub: &re_viewer_context::StoreHub::test_hub(),
Expand Down Expand Up @@ -597,6 +598,7 @@ mod tests {
let ctx = StoreContext {
app_id: re_log_types::ApplicationId::unknown(),
blueprint: &blueprint,
default_blueprint: None,
recording: &recording,
bundle: &Default::default(),
hub: &re_viewer_context::StoreHub::test_hub(),
Expand Down Expand Up @@ -647,6 +649,7 @@ mod tests {
let ctx = StoreContext {
app_id: re_log_types::ApplicationId::unknown(),
blueprint: &blueprint,
default_blueprint: None,
recording: &recording,
bundle: &Default::default(),
hub: &re_viewer_context::StoreHub::test_hub(),
Expand Down Expand Up @@ -920,6 +923,7 @@ mod tests {
let ctx = StoreContext {
app_id: re_log_types::ApplicationId::unknown(),
blueprint: &blueprint,
default_blueprint: None,
recording: &recording,
bundle: &Default::default(),
hub: &re_viewer_context::StoreHub::test_hub(),
Expand Down
1 change: 1 addition & 0 deletions crates/re_space_view/src/space_view_contents.rs
Expand Up @@ -695,6 +695,7 @@ mod tests {
let ctx = StoreContext {
app_id: re_log_types::ApplicationId::unknown(),
blueprint: &blueprint,
default_blueprint: None,
recording: &recording,
bundle: &Default::default(),
hub: &StoreHub::test_hub(),
Expand Down
58 changes: 57 additions & 1 deletion crates/re_space_view/src/sub_archetypes.rs
Expand Up @@ -5,7 +5,7 @@ use re_entity_db::{
};
use re_log_types::EntityPath;
use re_types::Archetype;
use re_viewer_context::{external::re_entity_db::EntityTree, SpaceViewId};
use re_viewer_context::{external::re_entity_db::EntityTree, SpaceViewId, ViewerContext};

pub fn entity_path_for_space_view_sub_archetype<T: Archetype>(
space_view_id: SpaceViewId,
Expand Down Expand Up @@ -69,3 +69,59 @@ where
let (arch, path) = query_space_view_sub_archetype(space_view_id, blueprint_db, query);
(arch.ok().flatten().unwrap_or_default(), path)
}

/// Read a single component of a blueprint archetype in a space view.
pub fn get_blueprint_component<A: re_types::Archetype, C: re_types::Component>(
ctx: &ViewerContext<'_>,
space_view_id: SpaceViewId,
) -> Option<C> {
let blueprint_db = ctx.store_context.blueprint;
let query = ctx.blueprint_query;
let path = entity_path_for_space_view_sub_archetype::<A>(space_view_id, blueprint_db.tree());
blueprint_db
.latest_at_component::<C>(&path, query)
.map(|x| x.value)
}

/// Edit a single component of a blueprint archetype in a space view.
///
/// Set to `None` to reset the value to the value in the default blueprint, if any,
/// else will just store `None` (an empty component list) in the store.
pub fn edit_blueprint_component<A: re_types::Archetype, C: re_types::Component + PartialEq, R>(
ctx: &ViewerContext<'_>,
space_view_id: SpaceViewId,
edit_component: impl FnOnce(&mut Option<C>) -> R,
) -> R {
let active_blueprint = ctx.store_context.blueprint;
let active_path =
entity_path_for_space_view_sub_archetype::<A>(space_view_id, active_blueprint.tree());
let original_value: Option<C> = active_blueprint
.latest_at_component::<C>(&active_path, ctx.blueprint_query)
.map(|x| x.value);

let mut edited_value = original_value.clone();
let ret = edit_component(&mut edited_value);

if edited_value != original_value {
if let Some(edited) = edited_value {
ctx.save_blueprint_component(&active_path, &edited);
} else {
// Reset to the value in the default blueprint, if any.
let default_value = ctx
.store_context
.default_blueprint
.and_then(|default_blueprint| {
let default_path = entity_path_for_space_view_sub_archetype::<A>(
space_view_id,
default_blueprint.tree(),
);
default_blueprint
.latest_at_component::<C>(&default_path, ctx.blueprint_query)
.map(|x| x.value)
});
ctx.save_blueprint_component(&active_path, &default_value);
}
}

ret
}

0 comments on commit f7b2bec

Please sign in to comment.