1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
use re_types::{
    blueprint::{
        archetypes::{ForceCenter, ForceCollisionRadius, ForceLink, ForceManyBody, ForcePosition},
        components::{Enabled, ForceDistance, ForceIterations, ForceStrength},
    },
    components::Position2D,
    Archetype, Component,
};
use re_viewer_context::{ComponentFallbackProvider, ViewQuery, ViewState, ViewerContext};
use re_viewport_blueprint::{ViewProperty, ViewPropertyQueryError};

#[derive(Debug, PartialEq)]
pub struct ForceLayoutParams {
    // Link
    pub(super) force_link_enabled: Enabled,
    pub(super) force_link_distance: ForceDistance,
    pub(super) force_link_iterations: ForceIterations,
    // Many body
    pub(super) force_many_body_enabled: Enabled,
    pub(super) force_many_body_strength: ForceStrength,
    // Position
    pub(super) force_position_enabled: Enabled,
    pub(super) force_position_strength: ForceStrength,
    pub(super) force_position_pos: Position2D,
    // Center
    pub(super) force_center_enabled: Enabled,
    pub(super) force_center_strength: ForceStrength,
    // Collision
    pub(super) force_collision_enabled: Enabled,
    pub(super) force_collision_strength: ForceStrength,
    pub(super) force_collision_iterations: ForceIterations,
}

/// Convenience struct for querying the components of a blueprint archetype or its fallbacks.
struct QueryArchetype<'a, T> {
    ctx: &'a ViewerContext<'a>,
    provider: &'a dyn ComponentFallbackProvider,
    view_state: &'a dyn ViewState,
    property: ViewProperty,
    _marker: std::marker::PhantomData<T>,
}

impl<'a, T: Archetype> QueryArchetype<'a, T> {
    fn new(
        ctx: &'a ViewerContext<'a>,
        query: &'a ViewQuery<'a>,
        provider: &'a dyn ComponentFallbackProvider,
        view_state: &'a dyn ViewState,
    ) -> Self {
        let property = ViewProperty::from_archetype::<T>(
            ctx.blueprint_db(),
            ctx.blueprint_query,
            query.view_id,
        );
        Self {
            ctx,
            provider,
            view_state,
            property,
            _marker: Default::default(),
        }
    }

    fn get<R>(&self) -> Result<R, ViewPropertyQueryError>
    where
        R: Component + Default,
    {
        self.property
            .component_or_fallback(self.ctx, self.provider, self.view_state)
    }
}

impl ForceLayoutParams {
    pub fn get(
        ctx: &ViewerContext<'_>,
        query: &ViewQuery<'_>,
        provider: &dyn ComponentFallbackProvider,
        view_state: &dyn ViewState,
    ) -> Result<Self, ViewPropertyQueryError> {
        // Query the components for the archetype
        let force_link = QueryArchetype::<ForceLink>::new(ctx, query, provider, view_state);
        let force_many = QueryArchetype::<ForceManyBody>::new(ctx, query, provider, view_state);
        let force_position = QueryArchetype::<ForcePosition>::new(ctx, query, provider, view_state);
        let force_center = QueryArchetype::<ForceCenter>::new(ctx, query, provider, view_state);
        let force_collision =
            QueryArchetype::<ForceCollisionRadius>::new(ctx, query, provider, view_state);

        Ok(Self {
            // Link
            force_link_enabled: force_link.get()?,
            force_link_distance: force_link.get()?,
            force_link_iterations: force_link.get()?,
            // Many body
            force_many_body_enabled: force_many.get()?,
            force_many_body_strength: force_many.get()?,
            // Position
            force_position_enabled: force_position.get()?,
            force_position_strength: force_position.get()?,
            force_position_pos: force_position.get()?,
            // Center
            force_center_enabled: force_center.get()?,
            force_center_strength: force_center.get()?,
            // Collision
            force_collision_enabled: force_collision.get()?,
            force_collision_strength: force_collision.get()?,
            force_collision_iterations: force_collision.get()?,
        })
    }
}