1use std;
4use log;
5use vec_map::VecMap;
6use rs_utils::for_sequence;
7#[cfg(feature = "derive_serdes")]
8use serde::{Deserialize, Serialize};
9
10use crate::{collision, event, force, geometry, integrator, math, object,
11 Collision, Integrator};
12
13#[cfg_attr(feature = "derive_serdes", derive(Deserialize, Serialize))]
21#[derive(Clone, Debug, Default)]
22pub struct System <INTG : Integrator> {
23 step : u64,
25 objects_static : VecMap <object::Static>,
27 objects_dynamic : VecMap <object::Dynamic>,
29 objects_nodetect : VecMap <object::Nodetect>,
31 gravity : Option <force::Gravity>,
33 collision : Collision,
35 #[cfg_attr(feature = "derive_serdes", serde(skip))]
36 _phantom_data : std::marker::PhantomData <INTG>
37}
38
39impl <INTG : Integrator> System <INTG> {
40 #[inline]
41 pub fn new() -> Self where INTG : Default {
42 std::default::Default::default()
43 }
44 #[inline]
45 pub fn step (&self) -> u64 {
46 self.step
47 }
48 #[inline]
49 pub fn objects_dynamic (&self) -> &VecMap <object::Dynamic> {
50 &self.objects_dynamic
51 }
52 #[inline]
53 pub fn objects_nodetect (&self) -> &VecMap <object::Nodetect> {
54 &self.objects_nodetect
55 }
56 #[inline]
57 pub fn objects_static (&self) -> &VecMap <object::Static> {
58 &self.objects_static
59 }
60
61 #[allow(mismatched_lifetime_syntaxes)]
62 pub fn get_object (&self, id : object::Id) -> object::VariantRef {
63 match id.kind {
64 object::Kind::Static => (&self.objects_static[id.key.index()]).into(),
65 object::Kind::Dynamic => (&self.objects_dynamic[id.key.index()]).into(),
66 object::Kind::Nodetect => (&self.objects_nodetect[id.key.index()]).into()
67 }
68 }
69
70 pub fn segment_query (&self,
71 segment : geometry::Segment3 <f64>,
72 ignore_list : &[object::Id]
73 ) -> Vec <(f64, math::Point3 <f64>, object::Id)> {
74 use object::Bounded;
75 let mut out : Vec <(f64, math::Point3 <f64>, object::Id)> = vec![];
76 let aabb = segment.aabb3();
77 let mut overlaps : Vec <object::Id> = self.collision.broad()
78 .overlaps_discrete (aabb).into_iter().map (|id| id.into()).collect();
79 overlaps.retain (|id| !ignore_list.contains (id));
80 for object_id in overlaps {
81 if let Some ((frac, point)) = match object_id.kind {
82 object::Kind::Static =>
83 self.objects_static[object_id.key.index()].hit_test (segment),
84 object::Kind::Dynamic =>
85 self.objects_dynamic[object_id.key.index()].hit_test (segment),
86 _ => unreachable!()
87 } {
88 out.insert (
89 out.binary_search_by (|(f, _, _)| f.partial_cmp (&frac).unwrap())
90 .unwrap_or_else (|i| i),
91 (frac, point, object_id)
92 );
93 }
94 }
95 out
96 }
97
98 pub fn handle_event (&mut self, input : event::Input) -> Vec <event::Output> {
123 let input_step = self.step;
124 log::debug!(step=input_step, input=input.to_string().as_str();
125 "input event");
126 let mut output = Vec::new();
127 match input {
128
129 event::Input::CreateObject (object, key) => {
133 let key = key.unwrap_or_else (
134 || self.new_object_key (object.kind()).unwrap());
135 match object {
136 object::Variant::Static (object) => {
137 self.create_object_static (object, key, &mut output);
138 }
139 object::Variant::Dynamic (object) => {
140 self.create_object_dynamic (object, key, &mut output);
141 }
142 object::Variant::Nodetect (object) => {
143 self.create_object_nodetect (object, key);
144 }
145 }
146 }
147
148 event::Input::ModifyObject (object_modify_event) => {
152 match object_modify_event {
153 event::ObjectModify::Dynamic (key, event) => {
154 self.modify_object_dynamic (key, event);
155 }
156 event::ObjectModify::Static (key, event) => {
157 self.modify_object_static (key, event);
158 }
159 }
160 }
161
162 event::Input::DestroyObject (object::Id { kind, key }) => {
166 match kind {
167 object::Kind::Static => {
168 self.collision.remove_object_static (key);
169 assert!(self.objects_static.remove (key.index()).is_some());
170 }
171 object::Kind::Dynamic => {
172 self.collision.remove_object_dynamic (key);
173 assert!(self.objects_dynamic.remove (key.index()).is_some());
174 }
175 object::Kind::Nodetect =>
176 assert!(self.objects_nodetect.remove (key.index()).is_some())
177 }
178 }
179
180 event::Input::SetGravity (gravity) => {
184 assert!(self.gravity.is_none());
185 self.gravity = Some (gravity);
186 }
187
188 event::Input::ClearGravity => {
192 assert!(self.gravity.is_some());
193 self.gravity = None;
194 }
195
196 event::Input::Step => {
200 #[cfg(feature = "debug_dump")]
201 let s = self.clone();
202
203 self.derivative_evaluation();
206 self.integrate_velocity();
208 self.constrain_velocity();
210 self.integrate_position();
212 self.constrain_position();
214 self.collision (&mut output);
216
217 #[cfg(feature = "debug_dump")]
218 if collision::DEBUG_DUMP
219 .swap (false, std::sync::atomic::Ordering::SeqCst)
220 {
221 if std::env::var ("LINEAR_SIM_DEBUG_DUMP").is_ok() {
222 let p = format!("linear-sim-{}.dump", s.step);
223 log::info!(filepath=p.as_str(); "dumping system");
224 let mut f = std::fs::File::create (&p).unwrap();
225 bincode::serde::encode_into_std_write (
226 &s, &mut f, bincode::config::standard()
227 ).unwrap();
228 }
229 }
230
231 self.step += 1;
232 }
233
234 }
235 log::debug!(
236 step=input_step,
237 output:?=output.iter().map (ToString::to_string).collect::<Vec<_>>();
238 "output events");
239 output
240 }
241
242 pub fn new_object_key (&self, kind : object::Kind) -> Option <object::Key> {
244 fn next_available_key <T> (map : &VecMap <T>) -> Option <object::Key> {
245 for i in 0..object::KEY_MAX as usize {
246 if !map.contains_key (i) {
247 return Some (i.into())
248 }
249 }
250 None
251 }
252 match kind {
253 object::Kind::Static => next_available_key (&self.objects_static),
254 object::Kind::Dynamic => next_available_key (&self.objects_dynamic),
255 object::Kind::Nodetect => next_available_key (&self.objects_nodetect)
256 }
257 }
258
259 pub fn contacts (&self)
260 -> Vec <Vec <(object::Id, object::Id, collision::Contact)>>
261 {
262 let mut groups = vec![];
263 for (_, group) in self.collision.contact_groups().iter() {
264 let mut v = vec![];
265 for (object_pair, contact) in group.contacts.iter().cloned() {
266 let (object_id_a, object_id_b) = object_pair.into();
267 v.push ((object_id_a.into(), object_id_b.into(), contact));
268 }
269 groups.push (v);
270 }
271 groups
272 }
273
274 fn create_object_static (&mut self,
279 object : object::Static,
280 key : object::Key,
281 output : &mut Vec <event::Output>
282 ) {
283 let object_id = object::Id { kind: object::Kind::Static, key };
284 match self.collision.try_add_object_static (
286 &self.objects_dynamic, &object, key
287 ) {
288 Ok (()) => {
289 assert!(self.objects_static.insert (key.index(), object).is_none());
291 output.push (event::CreateObjectResult::Created (object_id).into());
292 }
293 Err (intersections) => {
294 debug_assert!(!intersections.is_empty());
295 output.push (
296 event::CreateObjectResult::Intersection (intersections).into());
297 }
298 }
299 }
300
301 fn create_object_dynamic (&mut self,
302 object : object::Dynamic,
303 key : object::Key,
304 output : &mut Vec <event::Output>
305 ) {
306 let object_id = object::Id { kind: object::Kind::Dynamic, key };
307 match self.collision.try_add_object_dynamic (
309 &self.objects_static, &self.objects_dynamic, &object, key
310 ) {
311 Ok (()) => {
312 assert!(self.objects_dynamic.insert (key.index(), object).is_none());
314 output.push (event::CreateObjectResult::Created (object_id).into());
315 }
316 Err (intersections) => {
317 debug_assert!(!intersections.is_empty());
318 output.push (
319 event::CreateObjectResult::Intersection (intersections).into());
320 }
321 }
322 }
323
324 fn create_object_nodetect (&mut self,
325 object : object::Nodetect,
326 key : object::Key,
327 ) {
328 assert!(self.objects_nodetect.insert (key.index(), object).is_none());
329 }
330
331 fn modify_object_dynamic (&mut self,
333 key : object::Key,
334 event : event::ObjectModifyDynamic
335 ) {
336 let object = &mut self.objects_dynamic[key.index()];
337 match event {
338 event::ObjectModifyDynamic::ApplyImpulse (impulse) =>
339 object.derivatives.velocity += impulse,
340 event::ObjectModifyDynamic::SetForceFlags (force_flags) =>
341 object.derivatives.force_flags = force_flags,
342 event::ObjectModifyDynamic::SetDrag (drag) => object.drag.0 = drag,
343 event::ObjectModifyDynamic::SetPosition (position) => {
344 object.position = position;
345 self.collision.update_object_dynamic (&object, key);
346 log::warn!("TODO: dynamic object set position results");
347 }
348 }
349 }
350
351 fn modify_object_static (&mut self,
353 key : object::Key,
354 event : event::ObjectModifyStatic
355 ) {
356 let object = &mut self.objects_static[key.index()];
357 match event {
358 event::ObjectModifyStatic::Move (move_vector) => {
360 object.position.0 += move_vector;
361 self.collision.update_object_static (&object, key);
362 unimplemented!("TODO: move static object results");
363 }
364 }
365 }
366
367 fn derivative_evaluation (&mut self) {
369 for_sequence!{
371 (_, object) in (
372 self.objects_dynamic.iter_mut(), self.objects_nodetect.iter_mut()
373 ) {
374 object.derivatives.force = [0.0, 0.0, 0.0].into();
375 }
376 }
377
378 if let Some (gravity) = &self.gravity {
380 for_sequence!{
381 (_, object) in (
382 self.objects_dynamic.iter_mut(), self.objects_nodetect.iter_mut()
383 ) {
384 if object.derivatives.force_flags.contains (force::Flag::Gravity) {
385 use crate::Force;
386 let impulse = gravity.impulse (object, self.step, 1.0);
387 object.derivatives.force += impulse;
388 }
389 }
390 }
391 }
392
393 for_sequence!{
395 (_, object) in (
396 self.objects_dynamic.iter_mut(), self.objects_nodetect.iter_mut()
397 ) {
398 use object::Inertial;
399 object.compute_acceleration_inplace();
400 }
401 }
402 }
403
404 fn integrate_velocity (&mut self) {
406 for_sequence!{
407 (_, object) in (
408 self.objects_dynamic.iter_mut(), self.objects_nodetect.iter_mut()
409 ) {
410 INTG::integrate_velocity (object);
411 object.derivatives.velocity *= 1.0 - object.drag.0;
416 }
417 }
418 }
419
420 fn constrain_velocity (&mut self) {
422 self.collision.constrain_contact_velocities (
423 &mut self.objects_static, &mut self.objects_dynamic);
424 }
425
426 fn integrate_position (&mut self) {
428 for_sequence!{
429 (_, object) in (
430 self.objects_dynamic.iter_mut(), self.objects_nodetect.iter_mut()
431 ) {
432 INTG::integrate_position (object);
433 }
434 }
435 }
436
437 fn constrain_position (&mut self) {
439 self.collision.constrain_contact_positions (
440 &mut self.objects_static, &mut self.objects_dynamic);
441 }
442
443 fn collision (&mut self, output : &mut Vec <event::Output>) {
445 self.collision.detect_resolve_loop (
446 &mut self.objects_static, &mut self.objects_dynamic, self.step, output);
447 }
448
449}
450
451pub fn report_sizes() {
453 use std::mem::size_of;
454 println!("system report sizes...");
455
456 println!(" size of System <integrator::SemiImplicitEuler>: {}",
457 size_of::<System <integrator::SemiImplicitEuler>>());
458
459 println!("...system report sizes");
460}
461
462#[cfg(test)]
463mod tests {
464 use super::*;
465 use crate::component;
466 use crate::geometry::{self, shape};
467 #[test]
468 fn segment_query() {
469 let segment = geometry::Segment3::new (
470 [-1.0, 0.0, 0.5].into(),
471 [ 2.0, 0.0, 0.5].into());
472 let mut system = System::<integrator::SemiImplicitEuler>::new();
473 let sphere1 = {
474 let position = component::Position ([0.5, 0.0, 0.5].into());
475 let mass = component::Mass::new (20.0);
476 let derivatives = component::Derivatives::zero();
477 let drag = component::Drag::zero();
478 let bound = component::Bound (shape::Bounded::from (
479 shape::Sphere::noisy (0.5)).into());
480 let material = component::MATERIAL_STONE;
481 let collidable = true;
482 object::Dynamic {
483 position, mass, derivatives, drag, bound, material, collidable
484 }.into()
485 };
486 let mut result = system
487 .handle_event (event::Input::CreateObject (sphere1, None));
488 let sphere1_id = match result.pop().unwrap() {
489 event::Output::CreateObjectResult (event::CreateObjectResult::Created (id))
490 => id,
491 _ => unreachable!()
492 };
493 assert!(result.pop().is_none());
494 let block1 = {
495 let position = component::Position ([1.5, 0.0, 0.5].into());
496 let bound = component::Bound (shape::Bounded::from (
497 shape::Cuboid::noisy ([0.5, 0.5, 0.5].into())).into());
498 let material = component::MATERIAL_STONE;
499 let collidable = true;
500 object::Static { position, bound, material, collidable }.into()
501 };
502 let mut result = system
503 .handle_event (event::Input::CreateObject (block1, None));
504 let block1_id = match result.pop().unwrap() {
505 event::Output::CreateObjectResult (event::CreateObjectResult::Created (id))
506 => id,
507 _ => unreachable!()
508 };
509 assert!(result.pop().is_none());
510 let result = system.segment_query (segment, &[]);
511 let (frac, point, id) = result.get (0).unwrap();
512 assert_eq!(*frac, 1.0/3.0);
513 assert_eq!(*point, [0.0, 0.0, 0.5].into());
514 assert_eq!(*id, sphere1_id);
515 let (frac, point, id) = result.get (1).unwrap();
516 assert_eq!(*frac, 2.0/3.0);
517 assert_eq!(*point, [1.0, 0.0, 0.5].into());
518 assert_eq!(*id, block1_id);
519 }
520}