Skip to content

Commit

Permalink
Introduce a new StrokeWidth component and use it for SeriesLine (#5025)
Browse files Browse the repository at this point in the history
### What
What the title says.

### 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 newly built examples:
[app.rerun.io](https://app.rerun.io/pr/5025/index.html)
* Using examples from latest `main` build:
[app.rerun.io](https://app.rerun.io/pr/5025/index.html?manifest_url=https://app.rerun.io/version/main/examples_manifest.json)
* Using full set of examples from `nightly` build:
[app.rerun.io](https://app.rerun.io/pr/5025/index.html?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

- [PR Build Summary](https://build.rerun.io/pr/5025)
- [Docs
preview](https://rerun.io/preview/2eaa8db88b904d5f68dc4bbb72311ea95c8a090f/docs)
<!--DOCS-PREVIEW-->
- [Examples
preview](https://rerun.io/preview/2eaa8db88b904d5f68dc4bbb72311ea95c8a090f/examples)
<!--EXAMPLES-PREVIEW-->
- [Recent benchmark results](https://build.rerun.io/graphs/crates.html)
- [Wasm size tracking](https://build.rerun.io/graphs/sizes.html)

---------

Co-authored-by: Andreas Reich <[email protected]>
  • Loading branch information
jleibs and Wumpf authored Feb 4, 2024
1 parent 412cd87 commit 0f20b1a
Show file tree
Hide file tree
Showing 28 changed files with 563 additions and 46 deletions.
56 changes: 52 additions & 4 deletions crates/re_data_ui/src/editors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use re_data_store::{DataStore, LatestAtQuery};
use re_log_types::EntityPath;
use re_query::ComponentWithInstances;
use re_types::{
components::{Color, MarkerShape, Radius, ScalarScattering, Text},
components::{Color, MarkerShape, Radius, ScalarScattering, StrokeWidth, Text},
Component, Loggable,
};
use re_viewer_context::{UiVerbosity, ViewerContext};
Expand Down Expand Up @@ -279,6 +279,53 @@ fn paint_marker(

// ----

#[allow(clippy::too_many_arguments)]
fn edit_stroke_width_ui(
ctx: &ViewerContext<'_>,
ui: &mut egui::Ui,
_verbosity: UiVerbosity,
query: &LatestAtQuery,
store: &DataStore,
entity_path: &EntityPath,
override_path: &EntityPath,
component: &ComponentWithInstances,
instance_key: &re_types::components::InstanceKey,
) {
let current_stroke_width = component
.lookup::<StrokeWidth>(instance_key)
.ok()
.unwrap_or_else(|| default_stroke_width(ctx, query, store, entity_path));

let current_stroke_width = current_stroke_width.0;
let mut edit_stroke_width = current_stroke_width;

let speed = (current_stroke_width * 0.01).at_least(0.001);

ui.add(
egui::DragValue::new(&mut edit_stroke_width)
.clamp_range(0.0..=f64::INFINITY)
.speed(speed),
);

if edit_stroke_width != current_stroke_width {
let new_stroke_width = StrokeWidth::from(edit_stroke_width);

ctx.save_blueprint_component(override_path, new_stroke_width);
}
}

#[inline]
fn default_stroke_width(
_ctx: &ViewerContext<'_>,
_query: &LatestAtQuery,
_store: &DataStore,
_entity_path: &EntityPath,
) -> StrokeWidth {
StrokeWidth::from(1.0)
}

// ----

fn register_editor<'a, C: Component + Loggable + 'static>(
registry: &mut re_viewer_context::ComponentUiRegistry,
default: fn(&ViewerContext<'_>, &LatestAtQuery, &DataStore, &EntityPath) -> C,
Expand Down Expand Up @@ -308,8 +355,9 @@ fn register_editor<'a, C: Component + Loggable + 'static>(

pub fn register_editors(registry: &mut re_viewer_context::ComponentUiRegistry) {
register_editor::<Color>(registry, default_color, edit_color_ui);
register_editor::<Text>(registry, default_text, edit_text_ui);
register_editor::<ScalarScattering>(registry, default_scatter, edit_scatter_ui);
register_editor::<Radius>(registry, default_radius, edit_radius_ui);
register_editor::<MarkerShape>(registry, default_marker_shape, edit_marker_shape_ui);
register_editor::<Radius>(registry, default_radius, edit_radius_ui);
register_editor::<ScalarScattering>(registry, default_scatter, edit_scatter_ui);
register_editor::<StrokeWidth>(registry, default_stroke_width, edit_stroke_width_ui);
register_editor::<Text>(registry, default_text, edit_text_ui);
}
23 changes: 14 additions & 9 deletions crates/re_space_view_time_series/src/aggregation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ impl AverageAggregator {
let point = &points[i + j];

acc.value += point.value;
acc.attrs.radius += point.attrs.radius;
acc.attrs.stroke_width += point.attrs.stroke_width;

ratio += 1.0;
j += 1;
Expand All @@ -48,14 +48,14 @@ impl AverageAggregator {

let w = aggregation_factor_fract;
acc.value += point.value * w;
acc.attrs.radius += (point.attrs.radius as f64 * w) as f32;
acc.attrs.stroke_width += (point.attrs.stroke_width as f64 * w) as f32;

ratio += aggregation_factor_fract;
j += 1;
}

acc.value /= ratio;
acc.attrs.radius = (acc.attrs.radius as f64 / ratio) as _;
acc.attrs.stroke_width = (acc.attrs.stroke_width as f64 / ratio) as _;

aggregated.push(acc);

Expand Down Expand Up @@ -124,17 +124,21 @@ impl MinMaxAggregator {
match self {
MinMaxAggregator::MinMax | MinMaxAggregator::MinMaxAverage => {
acc_min.value = f64::min(acc_min.value, point.value);
acc_min.attrs.radius = f32::min(acc_min.attrs.radius, point.attrs.radius);
acc_min.attrs.stroke_width =
f32::min(acc_min.attrs.stroke_width, point.attrs.stroke_width);
acc_max.value = f64::max(acc_max.value, point.value);
acc_max.attrs.radius = f32::max(acc_max.attrs.radius, point.attrs.radius);
acc_max.attrs.stroke_width =
f32::max(acc_max.attrs.stroke_width, point.attrs.stroke_width);
}
MinMaxAggregator::Min => {
acc_min.value = f64::min(acc_min.value, point.value);
acc_min.attrs.radius = f32::min(acc_min.attrs.radius, point.attrs.radius);
acc_min.attrs.stroke_width =
f32::min(acc_min.attrs.stroke_width, point.attrs.stroke_width);
}
MinMaxAggregator::Max => {
acc_max.value = f64::max(acc_max.value, point.value);
acc_max.attrs.radius = f32::max(acc_max.attrs.radius, point.attrs.radius);
acc_max.attrs.stroke_width =
f32::max(acc_max.attrs.stroke_width, point.attrs.stroke_width);
}
}

Expand All @@ -153,7 +157,8 @@ impl MinMaxAggregator {
// Don't average a single point with itself.
if j > 1 {
acc_min.value = (acc_min.value + acc_max.value) * 0.5;
acc_min.attrs.radius = (acc_min.attrs.radius + acc_max.attrs.radius) * 0.5;
acc_min.attrs.stroke_width =
(acc_min.attrs.stroke_width + acc_max.attrs.stroke_width) * 0.5;
}
aggregated.push(acc_min);
}
Expand Down Expand Up @@ -190,7 +195,7 @@ fn are_aggregatable(point1: &PlotPoint, point2: &PlotPoint, window_size: usize)
let PlotPointAttrs {
label,
color,
radius: _,
stroke_width: _,
kind,
} = attrs;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ impl LegacyTimeSeriesSystem {
attrs: PlotPointAttrs {
label: None,
color: egui::Color32::BLACK,
radius: 0.0,
stroke_width: 0.0,
kind: PlotSeriesKind::Clear,
},
});
Expand Down Expand Up @@ -196,7 +196,7 @@ impl LegacyTimeSeriesSystem {
attrs: PlotPointAttrs {
label,
color,
radius,
stroke_width: radius,
kind,
},
});
Expand Down
6 changes: 3 additions & 3 deletions crates/re_space_view_time_series/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pub(crate) fn plot_id(space_view_id: re_viewer_context::SpaceViewId) -> egui::Id
pub struct PlotPointAttrs {
pub label: Option<String>,
pub color: egui::Color32,
pub radius: f32,
pub stroke_width: f32,
pub kind: PlotSeriesKind,
}

Expand All @@ -47,12 +47,12 @@ impl PartialEq for PlotPointAttrs {
let Self {
label,
color,
radius,
stroke_width: radius,
kind,
} = self;
label.eq(&rhs.label)
&& color.eq(&rhs.color)
&& radius.total_cmp(&rhs.radius).is_eq()
&& radius.total_cmp(&rhs.stroke_width).is_eq()
&& kind.eq(&rhs.kind)
}
}
Expand Down
32 changes: 19 additions & 13 deletions crates/re_space_view_time_series/src/line_visualizer_system.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use re_query_cache::{MaybeCachedComponentData, QueryError};
use re_types::archetypes;
use re_types::components::StrokeWidth;
use re_types::{
archetypes::SeriesLine,
components::{Color, Radius, Scalar, Text},
components::{Color, Scalar, Text},
Archetype as _, ComponentNameSet, Loggable,
};
use re_viewer_context::{
Expand All @@ -29,6 +30,8 @@ impl IdentifiedViewSystem for SeriesLineSystem {
}
}

const DEFAULT_STROKE_WIDTH: f32 = 0.75;

impl VisualizerSystem for SeriesLineSystem {
fn visualizer_query_info(&self) -> VisualizerQueryInfo {
let mut query_info = VisualizerQueryInfo::from_archetype::<archetypes::Scalar>();
Expand Down Expand Up @@ -76,6 +79,8 @@ impl VisualizerSystem for SeriesLineSystem {
) -> Option<re_log_types::DataCell> {
if *component == Color::name() {
Some([initial_override_color(entity_path)].into())
} else if *component == StrokeWidth::name() {
Some([StrokeWidth(DEFAULT_STROKE_WIDTH)].into())
} else {
None
}
Expand Down Expand Up @@ -123,18 +128,19 @@ impl SeriesLineSystem {
let override_label =
lookup_override::<Text>(data_result, ctx).map(|t| t.to_string());

let override_radius = lookup_override::<Radius>(data_result, ctx).map(|r| r.0);
let override_stroke_width =
lookup_override::<StrokeWidth>(data_result, ctx).map(|r| r.0);

let query = re_data_store::RangeQuery::new(query.timeline, time_range);

// TODO(jleibs): need to do a "joined" archetype query
query_caches
.query_archetype_pov1_comp2::<archetypes::Scalar, Scalar, Color, Text, _>(
.query_archetype_pov1_comp3::<archetypes::Scalar, Scalar, Color, StrokeWidth, Text, _>(
ctx.app_options.experimental_primary_caching_range,
store,
&query.clone().into(),
&data_result.entity_path,
|((time, _row_id), _, scalars, colors, labels)| {
|((time, _row_id), _, scalars, colors, stroke_width, labels)| {
let Some(time) = time else {
return;
}; // scalars cannot be timeless
Expand All @@ -147,46 +153,46 @@ impl SeriesLineSystem {
attrs: PlotPointAttrs {
label: None,
color: egui::Color32::BLACK,
radius: 0.0,
stroke_width: 0.0,
kind: PlotSeriesKind::Clear,
},
});
return;
}

for (scalar, color, label) in itertools::izip!(
for (scalar, color, stoke_width, label) in itertools::izip!(
scalars.iter(),
MaybeCachedComponentData::iter_or_repeat_opt(
&colors,
scalars.len()
),
MaybeCachedComponentData::iter_or_repeat_opt(
&stroke_width,
scalars.len()
),
//MaybeCachedComponentData::iter_or_repeat_opt(&radii, scalars.len()),
MaybeCachedComponentData::iter_or_repeat_opt(
&labels,
scalars.len()
),
) {
// TODO(jleibs): Replace with StrokeWidth
let radius: Option<Radius> = None;
let color = override_color.unwrap_or_else(|| {
annotation_info
.color(color.map(|c| c.to_array()), default_color)
});
let label = override_label.clone().or_else(|| {
annotation_info.label(label.as_ref().map(|l| l.as_str()))
});
let radius = override_radius
.unwrap_or_else(|| radius.map_or(DEFAULT_RADIUS, |r| r.0));

const DEFAULT_RADIUS: f32 = 0.75;
let stroke_width = override_stroke_width
.unwrap_or_else(|| stoke_width.map_or(DEFAULT_STROKE_WIDTH, |r| r.0));

points.push(PlotPoint {
time: time.as_i64(),
value: scalar.0,
attrs: PlotPointAttrs {
label,
color,
radius,
stroke_width,
kind: PlotSeriesKind::Continuous,
},
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ impl SeriesPointSystem {
attrs: PlotPointAttrs {
label: None,
color: egui::Color32::BLACK,
radius: 0.0,
stroke_width: 0.0,
kind: PlotSeriesKind::Clear,
},
});
Expand Down Expand Up @@ -204,7 +204,7 @@ impl SeriesPointSystem {
attrs: PlotPointAttrs {
label,
color,
radius,
stroke_width: radius,
kind: PlotSeriesKind::Scatter(ScatterAttrs{marker}),
},
});
Expand Down
6 changes: 3 additions & 3 deletions crates/re_space_view_time_series/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ pub fn points_to_series(
all_series.push(PlotSeries {
label: series_label,
color: points[0].attrs.color,
width: 2.0 * points[0].attrs.radius,
width: 2.0 * points[0].attrs.stroke_width,
kind,
points: vec![(points[0].time, points[0].value)],
entity_path: data_result.entity_path.clone(),
Expand Down Expand Up @@ -204,7 +204,7 @@ fn add_series_runs(
let mut series: PlotSeries = PlotSeries {
label: series_label.to_owned(),
color: attrs.color,
width: 2.0 * attrs.radius,
width: 2.0 * attrs.stroke_width,
points: Vec::with_capacity(num_points),
kind: attrs.kind,
entity_path: entity_path.clone(),
Expand All @@ -228,7 +228,7 @@ fn add_series_runs(
PlotSeries {
label: series_label.to_owned(),
color: attrs.color,
width: 2.0 * attrs.radius,
width: 2.0 * attrs.stroke_width,
kind: attrs.kind,
points: Vec::with_capacity(num_points - i),
entity_path: entity_path.clone(),
Expand Down
4 changes: 4 additions & 0 deletions crates/re_types/definitions/rerun/archetypes/series_line.fbs
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,8 @@ table SeriesLine (
/// Color for the corresponding series.
// TODO(jleibs): This should be batch if we make a batch Scalars loggable.
color: rerun.components.Color ("attr.rerun.component_optional", nullable, order: 1000);

/// Stroke width for the corresponding series.
// TODO(jleibs): This should be batch if we make a batch Scalars loggable.
width: rerun.components.StrokeWidth ("attr.rerun.component_optional", nullable, order: 2000);
}
1 change: 1 addition & 0 deletions crates/re_types/definitions/rerun/components.fbs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ include "./components/resolution.fbs";
include "./components/rotation3d.fbs";
include "./components/scalar_scattering.fbs";
include "./components/scalar.fbs";
include "./components/stroke_width.fbs";
include "./components/tensor_data.fbs";
include "./components/texcoord2d.fbs";
include "./components/text_log_level.fbs";
Expand Down
21 changes: 21 additions & 0 deletions crates/re_types/definitions/rerun/components/stroke_width.fbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
include "arrow/attributes.fbs";
include "python/attributes.fbs";
include "rust/attributes.fbs";

include "rerun/datatypes.fbs";
include "rerun/attributes.fbs";

namespace rerun.components;

// ---

/// The width of a stroke specified in UI points.
struct StrokeWidth (
"attr.docs.unreleased",
"attr.python.aliases": "float",
"attr.python.array_aliases": "float, npt.ArrayLike",
"attr.rust.derive": "Copy, PartialEq, PartialOrd, bytemuck::Pod, bytemuck::Zeroable",
"attr.rust.repr": "transparent"
) {
width: float (order: 100);
}
Loading

0 comments on commit 0f20b1a

Please sign in to comment.