vox_geometry_rust/
physics_animation.rs

1/*
2 * // Copyright (c) 2021 Feng Yang
3 * //
4 * // I am making my contributions/submissions to this project solely in my
5 * // personal capacity and am not conveying any rights to any intellectual
6 * // property of any third parties.
7 */
8
9use std::sync::{RwLock, Arc};
10use log::info;
11use crate::animation::*;
12use std::time::SystemTime;
13
14pub struct PhysicsAnimationData {
15    _current_frame: Frame,
16    _is_using_fixed_sub_time_steps: bool,
17    _number_of_fixed_sub_time_steps: usize,
18    _current_time: f64,
19}
20
21impl PhysicsAnimationData {
22    pub fn new() -> PhysicsAnimationData {
23        return PhysicsAnimationData {
24            _current_frame: Frame::new(-1, 1.0 / 60.0),
25            _is_using_fixed_sub_time_steps: true,
26            _number_of_fixed_sub_time_steps: 1,
27            _current_time: 0.0,
28        };
29    }
30}
31
32///
33/// # Abstract base class for physics-based animation.
34///
35/// This class represents physics-based animation by adding time-integration
36/// specific functions to Animation class.
37///
38pub trait PhysicsAnimation: Animation {
39    ///
40    /// ## Returns true if fixed sub-time stepping is used.
41    ///
42    /// When performing a time-integration, it is often required to take
43    /// sub-time stepping for better results. The sub-stepping can be either
44    /// fixed rate or adaptive, and this function returns which feature is
45    /// currently selected.
46    ///
47    /// \return     True if using fixed sub time steps, false otherwise.
48    ///
49    fn is_using_fixed_sub_time_steps(&self) -> bool {
50        return self.view()._is_using_fixed_sub_time_steps;
51    }
52
53    ///
54    /// ## Sets true if fixed sub-time stepping is used.
55    ///
56    /// When performing a time-integration, it is often required to take
57    /// sub-time stepping for better results. The sub-stepping can be either
58    /// fixed rate or adaptive, and this function sets which feature should be
59    /// selected.
60    ///
61    /// - parameter:   isUsing True to enable fixed sub-stepping.
62    ///
63    fn set_is_using_fixed_sub_time_steps(&mut self, is_using: bool) {
64        self.view_mut()._is_using_fixed_sub_time_steps = is_using;
65    }
66
67    ///
68    /// ## Returns the number of fixed sub-time steps.
69    ///
70    /// When performing a time-integration, it is often required to take
71    /// sub-time stepping for better results. The sub-stepping can be either
72    /// fixed rate or adaptive, and this function returns the number of fixed
73    /// sub-steps.
74    ///
75    /// \return     The number of fixed sub-time steps.
76    ///
77    fn number_of_fixed_sub_time_steps(&self) -> usize {
78        return self.view()._number_of_fixed_sub_time_steps;
79    }
80
81    ///
82    /// ## Sets the number of fixed sub-time steps.
83    ///
84    /// When performing a time-integration, it is often required to take
85    /// sub-time stepping for better results. The sub-stepping can be either
86    /// fixed rate or adaptive, and this function sets the number of fixed
87    /// sub-steps.
88    ///
89    /// - parameter:  numberOfSteps The number of fixed sub-time steps.
90    ///
91    fn set_number_of_fixed_sub_time_steps(&mut self, number_of_steps: usize) {
92        self.view_mut()._number_of_fixed_sub_time_steps = number_of_steps;
93    }
94
95    /// Advances a single frame.
96    fn advance_single_frame(&mut self) {
97        let mut f = self.view_mut()._current_frame.clone();
98        f.advance_single();
99        self.update(&f);
100    }
101
102    ///
103    /// ## Returns current frame.
104    ///
105    fn current_frame(&self) -> Frame {
106        return self.view()._current_frame.clone();
107    }
108
109    ///
110    /// ## Sets current frame cursor (but do not invoke update()).
111    ///
112    fn set_current_frame(&mut self, frame: &Frame) {
113        self.view_mut()._current_frame = frame.clone();
114    }
115
116    ///
117    /// ## Returns current time in seconds.
118    ///
119    /// This function returns the current time which is calculated by adding
120    /// current frame + sub-time steps it passed.
121    ///
122    fn current_time_in_seconds(&self) -> f64 {
123        return self.view()._current_time;
124    }
125
126    ///
127    /// ## Called when a single time-step should be advanced.
128    ///
129    /// When Animation::update function is called, this class will internally
130    /// subdivide a frame into sub-steps if needed. Each sub-step, or time-step,
131    /// is then taken to move forward in time. This function is called for each
132    /// time-step, and a subclass that inherits PhysicsAnimation class should
133    /// implement this function for its own physics model.
134    ///
135    /// - parameter:  timeIntervalInSeconds The time interval in seconds
136    ///
137    fn on_advance_time_step(&mut self, time_interval_in_seconds: f64);
138
139    ///
140    /// ## Returns the required number of sub-time steps for given time interval.
141    ///
142    /// The required number of sub-time step can be different depending on the
143    /// physics model behind the implementation. Override this function to
144    /// implement own logic for model specific sub-time stepping for given
145    /// time interval.
146    ///
147    /// - parameter:  timeIntervalInSeconds The time interval in seconds.
148    ///
149    /// \return     The required number of sub-time steps.
150    ///
151    fn number_of_sub_time_steps(&self, _: f64) -> usize {
152        // Returns number of fixed sub-time steps by default
153        return self.view()._number_of_fixed_sub_time_steps;
154    }
155
156    ///
157    /// ## Called at frame 0 to initialize the physics state.
158    ///
159    /// Inheriting classes can override this function to setup initial condition
160    /// for the simulation.
161    ///
162    fn on_initialize(&mut self) {}
163
164    fn on_update(&mut self, frame: &Frame) {
165        if frame.index > self.view()._current_frame.index {
166            if self.view()._current_frame.index < 0 {
167                self.initialize();
168            }
169
170            let number_of_frames = frame.index - self.view()._current_frame.index;
171
172            for _ in 0..number_of_frames {
173                self.advance_time_step(frame.time_interval_in_seconds);
174            }
175            self.view_mut()._current_frame = frame.clone();
176        }
177    }
178
179    fn advance_time_step(&mut self, time_interval_in_seconds: f64) {
180        self.view_mut()._current_time = self.view()._current_frame.time_in_seconds();
181
182        if self.is_using_fixed_sub_time_steps() {
183            info!("Using fixed sub-timesteps: {}", self.view()._number_of_fixed_sub_time_steps);
184
185            // Perform fixed time-stepping
186            let actual_time_interval = time_interval_in_seconds / self.view()._number_of_fixed_sub_time_steps as f64;
187
188            for _ in 0..self.view()._number_of_fixed_sub_time_steps {
189                info!("Begin onAdvanceTimeStep: {} (1/{}) seconds", actual_time_interval, 1.0 / actual_time_interval);
190
191                let timer = SystemTime::now();
192                self.on_advance_time_step(actual_time_interval);
193
194                info!("End onAdvanceTimeStep (took {} seconds)", timer.elapsed().unwrap().as_secs_f64());
195
196                self.view_mut()._current_time += actual_time_interval;
197            }
198        } else {
199            info!("Using adaptive sub-timesteps");
200
201            // Perform adaptive time-stepping
202            let mut remaining_time = time_interval_in_seconds;
203            while remaining_time > f64::EPSILON {
204                let num_steps = self.number_of_sub_time_steps(remaining_time);
205                let actual_time_interval = remaining_time / num_steps as f64;
206
207                info!("Number of remaining sub-timesteps: {}", num_steps);
208
209                info!("Begin onAdvanceTimeStep: {} (1/{}) seconds", actual_time_interval, 1.0 / actual_time_interval);
210
211                let timer = SystemTime::now();
212                self.on_advance_time_step(actual_time_interval);
213
214                info!("End onAdvanceTimeStep (took {} seconds)", timer.elapsed().unwrap().as_secs_f64());
215
216                remaining_time -= actual_time_interval;
217                self.view_mut()._current_time += actual_time_interval;
218            }
219        }
220    }
221
222    fn initialize(&mut self) {
223        self.on_initialize();
224    }
225
226    fn view(&self) -> &PhysicsAnimationData;
227
228    fn view_mut(&mut self) -> &mut PhysicsAnimationData;
229}
230
231pub type PhysicsAnimationPtr = Arc<RwLock<dyn PhysicsAnimation>>;