generalize adding data to World
authoralfadur
Fri, 09 Nov 2018 03:36:21 +0300
changeset 14200 abbb74b9cb62
parent 14199 a4c17cfaa4c9
child 14203 fae0dd90663b
generalize adding data to World
rust/hwphysics/src/collision.rs
rust/hwphysics/src/common.rs
rust/hwphysics/src/grid.rs
rust/hwphysics/src/lib.rs
rust/hwphysics/src/physics.rs
--- a/rust/hwphysics/src/collision.rs	Fri Nov 09 01:05:34 2018 +0300
+++ b/rust/hwphysics/src/collision.rs	Fri Nov 09 03:36:21 2018 +0300
@@ -3,7 +3,7 @@
 };
 
 use crate::{
-    common::GearId,
+    common::{GearId, GearData, GearDataProcessor},
     physics::PhysicsData,
     grid::Grid
 };
@@ -42,18 +42,29 @@
     pub bounds: CircleBounds
 }
 
+impl GearData for CollisionData {}
+
 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
 pub struct ContactData {
     pub elasticity: FPNum,
     pub friction: FPNum
 }
 
+impl GearData for ContactData {}
+
 struct EnabledCollisionsCollection {
     gear_ids: Vec<GearId>,
     collisions: Vec<CollisionData>
 }
 
 impl EnabledCollisionsCollection {
+    fn new() -> Self {
+        Self {
+            gear_ids: Vec::new(),
+            collisions: Vec::new()
+        }
+    }
+
     fn push(&mut self, gear_id: GearId, collision: CollisionData) {
         self.gear_ids.push(gear_id);
         self.collisions.push(collision);
@@ -86,26 +97,32 @@
 
     pub fn push(&mut self, contact_gear_id1: GearId, contact_gear_id2: GearId, position: &FPPoint) {
         self.pairs.push((contact_gear_id1, contact_gear_id2));
-        self.positions.push(fppoint_round(position));
+        self.positions.push(fppoint_round(&position));
     }
 }
 
 impl CollisionProcessor {
-    pub fn process(&mut self, land: &Land2D<u32>, updates: &crate::physics::PositionUpdate) {
+    pub fn new(size: Size) -> Self {
+        Self {
+            grid: Grid::new(size),
+            enabled_collisions: EnabledCollisionsCollection::new(),
+            detected_collisions: DetectedCollisions::new(0)
+        }
+    }
+
+    pub fn process(&mut self, land: &Land2D<u32>, updates: &crate::physics::PositionUpdates) {
         self.grid.check_collisions(&mut self.detected_collisions);
 
         for (gear_id, collision) in self.enabled_collisions.iter() {
             if collision.bounds.rows().any(|(y, r)| (&land[y][r]).iter().any(|v| *v != 0)) {
-                self.detected_collisions.push(0, 0, &collision.bounds.center)
+                self.detected_collisions.push(gear_id, 0, &collision.bounds.center)
             }
         }
     }
+}
 
-    pub fn push(&mut self, gear_id: GearId, physics_data: PhysicsData, collision_data: CollisionData) {
-        if physics_data.velocity.is_zero() {
-            self.grid.insert_static(0, &physics_data.position, &collision_data.bounds);
-        } else {
-            self.grid.insert_dynamic(0, &physics_data.position, &collision_data.bounds);
-        }
+impl GearDataProcessor<CollisionData> for CollisionProcessor {
+    fn add(&mut self, gear_id: GearId, gear_data: CollisionData) {
+        self.grid.insert_static(gear_id, &gear_data.bounds);
     }
 }
\ No newline at end of file
--- a/rust/hwphysics/src/common.rs	Fri Nov 09 01:05:34 2018 +0300
+++ b/rust/hwphysics/src/common.rs	Fri Nov 09 03:36:21 2018 +0300
@@ -1,1 +1,10 @@
-pub type GearId = u16;
\ No newline at end of file
+pub type GearId = u16;
+pub trait GearData {}
+
+pub trait GearDataProcessor<T: GearData> {
+    fn add(&mut self, gear_id: GearId, gear_data: T);
+}
+
+pub trait GearDataAggregator<T: GearData> {
+    fn find_processor(&mut self) -> &mut GearDataProcessor<T>;
+}
--- a/rust/hwphysics/src/grid.rs	Fri Nov 09 01:05:34 2018 +0300
+++ b/rust/hwphysics/src/grid.rs	Fri Nov 09 03:36:21 2018 +0300
@@ -30,7 +30,7 @@
     }
 }
 
-const GRID_BIN_SIZE: usize = 256;
+const GRID_BIN_SIZE: usize = 128;
 
 pub struct Grid {
     bins: Vec<GridBin>,
@@ -63,12 +63,12 @@
         &mut self.bins[index.x as usize * self.bins_count.width + index.y as usize]
     }
 
-    pub fn insert_static(&mut self, gear_id: GearId, position: &FPPoint, bounds: &CircleBounds) {
-        self.lookup_bin(position).static_entries.push(*bounds)
+    pub fn insert_static(&mut self, gear_id: GearId, bounds: &CircleBounds) {
+        self.lookup_bin(&bounds.center).static_entries.push(*bounds)
     }
 
-    pub fn insert_dynamic(&mut self, gear_id: GearId, position: &FPPoint, bounds: &CircleBounds) {
-        self.lookup_bin(position).dynamic_entries.push(*bounds)
+    pub fn insert_dynamic(&mut self, gear_id: GearId, bounds: &CircleBounds) {
+        self.lookup_bin(&bounds.center).dynamic_entries.push(*bounds)
     }
 
     pub fn check_collisions(&self, collisions: &mut DetectedCollisions) {
--- a/rust/hwphysics/src/lib.rs	Fri Nov 09 01:05:34 2018 +0300
+++ b/rust/hwphysics/src/lib.rs	Fri Nov 09 03:36:21 2018 +0300
@@ -4,10 +4,16 @@
 mod collision;
 
 use fpnum::FPNum;
+use integral_geometry::Size;
 use land2d::Land2D;
 
 use crate::{
-    common::GearId,
+    common::{
+        GearId,
+        GearData,
+        GearDataAggregator,
+        GearDataProcessor
+    },
     physics::{
         PhysicsProcessor,
         PhysicsData
@@ -31,19 +37,72 @@
     collision: CollisionProcessor,
 }
 
+macro_rules! processor_map {
+    ( $data_type: ident => $field: ident ) => {
+        impl GearDataAggregator<$data_type> for World {
+            fn find_processor(&mut self) -> &mut GearDataProcessor<$data_type> {
+                &mut self.$field
+            }
+        }
+    }
+}
+
+processor_map!(PhysicsData => physics);
+processor_map!(CollisionData => collision);
+
 impl World {
+    pub fn new(world_size: Size) -> Self {
+        Self {
+            physics: PhysicsProcessor::new(),
+            collision: CollisionProcessor::new(world_size)
+        }
+    }
+
     pub fn step(&mut self, time_step: FPNum, land: &Land2D<u32>) {
         let updates = self.physics.process(time_step);
         self.collision.process(land, &updates);
     }
 
-    pub fn add_gear(&mut self, data: JoinedData) {
-        self.physics.push(data.gear_id, data.physics);
-        self.collision.push(data.gear_id, data.physics, data.collision);
+    pub fn add_gear_data<T>(&mut self, gear_id: GearId, data: T)
+        where T: GearData,
+              Self: GearDataAggregator<T>
+    {
+        self.find_processor().add(gear_id, data);
     }
 }
 
 #[cfg(test)]
 mod tests {
+    use crate::{
+        World,
+        physics::PhysicsData,
+        collision::{CollisionData, CircleBounds}
+    };
+    use fpnum::{FPNum, FPPoint, fp};
+    use integral_geometry::Size;
+    use land2d::Land2D;
 
+    #[test]
+    fn data_flow() {
+        let world_size = Size::new(2048, 2048);
+
+        let mut world = World::new(world_size);
+        let gear_id = 46631;
+
+        world.add_gear_data(gear_id, PhysicsData {
+            position: FPPoint::zero(),
+            velocity: FPPoint::unit_y()
+        });
+
+        world.add_gear_data(gear_id, CollisionData {
+            bounds: CircleBounds {
+                center: FPPoint::zero(),
+                radius: fp!(10)
+            }
+        });
+
+        let land = Land2D::new(Size::new(world_size.width - 2, world_size.height - 2), 0);
+
+        world.step(fp!(1), &land);
+    }
 }
--- a/rust/hwphysics/src/physics.rs	Fri Nov 09 01:05:34 2018 +0300
+++ b/rust/hwphysics/src/physics.rs	Fri Nov 09 03:36:21 2018 +0300
@@ -1,5 +1,5 @@
 use crate::{
-    common::GearId
+    common::{GearId, GearData, GearDataProcessor}
 };
 use fpnum::*;
 use integral_geometry::{
@@ -12,6 +12,7 @@
     pub velocity: FPPoint,
 }
 
+impl GearData for PhysicsData {}
 
 pub struct DynamicPhysicsCollection {
     gear_ids: Vec<GearId>,
@@ -20,6 +21,14 @@
 }
 
 impl DynamicPhysicsCollection {
+    fn new() -> Self {
+        Self {
+            gear_ids: Vec::new(),
+            positions: Vec::new(),
+            velocities: Vec::new()
+        }
+    }
+
     fn len(&self) -> usize {
         self.gear_ids.len()
     }
@@ -43,6 +52,13 @@
 }
 
 impl StaticPhysicsCollection {
+    fn new() -> Self {
+        Self {
+            gear_ids: Vec::new(),
+            positions: Vec::new()
+        }
+    }
+
     fn push(&mut self, gear_id: GearId, physics: PhysicsData) {
         self.gear_ids.push(gear_id);
         self.positions.push(physics.position);
@@ -54,15 +70,15 @@
     static_physics: StaticPhysicsCollection,
 
     physics_cleanup: Vec<GearId>,
-    position_updates: PositionUpdate
+    position_updates: PositionUpdates
 }
 
-pub struct PositionUpdate {
+pub struct PositionUpdates {
     pub gear_ids: Vec<GearId>,
     pub positions: Vec<FPPoint>
 }
 
-impl PositionUpdate {
+impl PositionUpdates {
     pub fn new(capacity: usize) -> Self {
         Self {
             gear_ids: Vec::with_capacity(capacity),
@@ -77,7 +93,16 @@
 }
 
 impl PhysicsProcessor {
-    pub fn process(&mut self, time_step: FPNum) -> &PositionUpdate {
+    pub fn new() -> Self {
+        PhysicsProcessor {
+            dynamic_physics: DynamicPhysicsCollection::new(),
+            static_physics: StaticPhysicsCollection::new(),
+            physics_cleanup: Vec::new(),
+            position_updates: PositionUpdates::new(0)
+        }
+    }
+
+    pub fn process(&mut self, time_step: FPNum) -> &PositionUpdates {
         for (gear_id, (pos, vel)) in self.dynamic_physics.iter_pos_update() {
             *pos += *vel * time_step;
             if !vel.is_zero() {
@@ -96,4 +121,14 @@
             self.dynamic_physics.push(gear_id, physics_data);
         }
     }
+}
+
+impl GearDataProcessor<PhysicsData> for PhysicsProcessor {
+    fn add(&mut self, gear_id: GearId, gear_data: PhysicsData) {
+        if gear_data.velocity.is_zero() {
+            self.static_physics.push(gear_id, gear_data);
+        } else {
+            self.dynamic_physics.push(gear_id, gear_data);
+        }
+    }
 }
\ No newline at end of file