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>>;