author | unc0rr |
Wed, 30 Jun 2021 00:18:53 +0200 | |
changeset 15832 | ee84e417d8d0 |
parent 15779 | c7332c7f64cd |
child 15849 | 64b0a5cead86 |
permissions | -rw-r--r-- |
15141 | 1 |
use crate::{ |
2 |
collision::{fppoint_round, CircleBounds, DetectedCollisions}, |
|
3 |
common::GearId, |
|
4 |
}; |
|
5 |
||
6 |
use fpnum::FPPoint; |
|
7 |
use integral_geometry::{GridIndex, Point, Size}; |
|
8 |
||
9 |
struct GridBin { |
|
15282 | 10 |
static_refs: Vec<GearId>, |
15141 | 11 |
static_entries: Vec<CircleBounds>, |
15282 | 12 |
|
13 |
dynamic_refs: Vec<GearId>, |
|
15141 | 14 |
dynamic_entries: Vec<CircleBounds>, |
15 |
} |
|
16 |
||
17 |
impl GridBin { |
|
18 |
fn new() -> Self { |
|
19 |
Self { |
|
15282 | 20 |
static_refs: vec![], |
15141 | 21 |
static_entries: vec![], |
15282 | 22 |
dynamic_refs: vec![], |
15141 | 23 |
dynamic_entries: vec![], |
24 |
} |
|
25 |
} |
|
26 |
} |
|
27 |
||
28 |
const GRID_BIN_SIZE: usize = 128; |
|
29 |
||
30 |
pub struct Grid { |
|
31 |
bins: Vec<GridBin>, |
|
32 |
space_size: Size, |
|
33 |
bins_count: Size, |
|
34 |
index: GridIndex, |
|
35 |
} |
|
36 |
||
37 |
impl Grid { |
|
38 |
pub fn new(size: Size) -> Self { |
|
39 |
assert!(size.is_power_of_two()); |
|
40 |
let bins_count = Size::new(size.width / GRID_BIN_SIZE, size.height / GRID_BIN_SIZE); |
|
41 |
||
42 |
Self { |
|
43 |
bins: (0..bins_count.area()).map(|_| GridBin::new()).collect(), |
|
44 |
space_size: size, |
|
45 |
bins_count, |
|
46 |
index: Size::square(GRID_BIN_SIZE).to_grid_index(), |
|
47 |
} |
|
48 |
} |
|
49 |
||
50 |
fn bin_index(&self, position: &FPPoint) -> Point { |
|
51 |
self.index.map(fppoint_round(position)) |
|
52 |
} |
|
53 |
||
15282 | 54 |
fn get_bin(&mut self, index: Point) -> &mut GridBin { |
15778 | 55 |
&mut self.bins[index.y as usize * self.bins_count.width + index.x as usize] |
15282 | 56 |
} |
57 |
||
15779 | 58 |
fn try_get_bin(&mut self, index: Point) -> Option<&mut GridBin> { |
59 |
self.bins |
|
60 |
.get_mut(index.y as usize * self.bins_count.width + index.x as usize) |
|
61 |
} |
|
62 |
||
15141 | 63 |
fn lookup_bin(&mut self, position: &FPPoint) -> &mut GridBin { |
15282 | 64 |
self.get_bin(self.bin_index(position)) |
15141 | 65 |
} |
66 |
||
67 |
pub fn insert_static(&mut self, gear_id: GearId, bounds: &CircleBounds) { |
|
15282 | 68 |
let bin = self.lookup_bin(&bounds.center); |
69 |
bin.static_refs.push(gear_id); |
|
70 |
bin.static_entries.push(*bounds) |
|
15141 | 71 |
} |
72 |
||
73 |
pub fn insert_dynamic(&mut self, gear_id: GearId, bounds: &CircleBounds) { |
|
15282 | 74 |
let bin = self.lookup_bin(&bounds.center); |
75 |
bin.dynamic_refs.push(gear_id); |
|
76 |
bin.dynamic_entries.push(*bounds); |
|
77 |
} |
|
78 |
||
15295 | 79 |
pub fn remove(&mut self, gear_id: GearId) {} |
80 |
||
15282 | 81 |
pub fn update_position( |
82 |
&mut self, |
|
83 |
gear_id: GearId, |
|
84 |
old_position: &FPPoint, |
|
85 |
new_position: &FPPoint, |
|
86 |
) { |
|
87 |
let old_bin_index = self.bin_index(old_position); |
|
88 |
let new_bin_index = self.bin_index(new_position); |
|
89 |
||
15779 | 90 |
if let Some(old_bin) = self.try_get_bin(old_bin_index) { |
91 |
let bounds = if let Some(index) = |
|
92 |
old_bin.dynamic_refs.iter().position(|id| *id == gear_id) |
|
93 |
{ |
|
94 |
if old_bin_index == new_bin_index { |
|
95 |
old_bin.dynamic_entries[index].center = *new_position; |
|
96 |
None |
|
97 |
} else { |
|
98 |
Some(old_bin.dynamic_entries.swap_remove(index)) |
|
99 |
} |
|
100 |
} else if let Some(index) = old_bin.static_refs.iter().position(|id| *id == gear_id) { |
|
101 |
old_bin.static_refs.swap_remove(index); |
|
102 |
Some(old_bin.static_entries.swap_remove(index)) |
|
15283 | 103 |
} else { |
15779 | 104 |
None |
15282 | 105 |
}; |
106 |
||
15779 | 107 |
if let Some(bounds) = bounds { |
108 |
let new_bin = if old_bin_index == new_bin_index { |
|
109 |
Some(old_bin) |
|
110 |
} else { |
|
111 |
self.try_get_bin(new_bin_index) |
|
112 |
}; |
|
113 |
||
114 |
if let Some(new_bin) = new_bin { |
|
115 |
new_bin.dynamic_refs.push(gear_id); |
|
116 |
new_bin.dynamic_entries.push(CircleBounds { |
|
117 |
center: *new_position, |
|
118 |
..bounds |
|
119 |
}); |
|
120 |
} |
|
121 |
} |
|
15282 | 122 |
} |
15141 | 123 |
} |
124 |
||
125 |
pub fn check_collisions(&self, collisions: &mut DetectedCollisions) { |
|
126 |
for bin in &self.bins { |
|
15284 | 127 |
for (index, bounds) in bin.dynamic_entries.iter().enumerate() { |
128 |
for (other_index, other) in bin.dynamic_entries.iter().enumerate().skip(index + 1) { |
|
15141 | 129 |
if bounds.intersects(other) && bounds != other { |
15284 | 130 |
collisions.push( |
131 |
bin.dynamic_refs[index], |
|
132 |
Some(bin.dynamic_refs[other_index]), |
|
15294
bfd185ad03e7
use better contact point for inter-gear collision
alfadur
parents:
15284
diff
changeset
|
133 |
&((bounds.center + other.center) / 2), |
15284 | 134 |
) |
15141 | 135 |
} |
136 |
} |
|
137 |
||
15284 | 138 |
for (other_index, other) in bin.static_entries.iter().enumerate() { |
15141 | 139 |
if bounds.intersects(other) { |
15284 | 140 |
collisions.push( |
141 |
bin.dynamic_refs[index], |
|
142 |
Some(bin.static_refs[other_index]), |
|
15294
bfd185ad03e7
use better contact point for inter-gear collision
alfadur
parents:
15284
diff
changeset
|
143 |
&((bounds.center + other.center) / 2), |
15284 | 144 |
) |
15141 | 145 |
} |
146 |
} |
|
147 |
} |
|
148 |
} |
|
149 |
} |
|
150 |
} |