azalea_physics/collision/
mergers.rs1use std::cmp::{self, Ordering};
2
3use azalea_core::math::{EPSILON, gcd, lcm};
4
5use super::CubePointRange;
6
7#[derive(Debug)]
8pub enum IndexMerger {
9 Identical {
10 coords: Vec<f64>,
11 },
12 DiscreteCube {
13 result: CubePointRange,
14 first_div: u32,
15 second_div: u32,
16 },
17 NonOverlapping {
18 lower: Vec<f64>,
19 upper: Vec<f64>,
20 swap: bool,
21 },
22 Indirect {
23 result: Vec<f64>,
24 first_indices: Vec<isize>,
25 second_indices: Vec<isize>,
26 result_length: usize,
27 },
28}
29
30impl IndexMerger {
31 pub fn get_list(&self) -> Vec<f64> {
32 match self {
33 IndexMerger::Identical { coords } => coords.clone(),
34 IndexMerger::DiscreteCube { result, .. } => result.iter(),
35 IndexMerger::NonOverlapping { lower, upper, .. } => (0..self.size())
36 .map(|i| {
37 if i < lower.len() {
38 lower[i]
39 } else {
40 upper[i - lower.len()]
41 }
42 })
43 .collect(),
44 IndexMerger::Indirect {
45 result,
46 result_length,
47 ..
48 } => {
49 if *result_length <= 1 {
50 vec![]
51 } else {
52 result[..*result_length].to_vec()
53 }
54 }
55 }
56 }
57 pub fn for_merged_indexes(&self, mut consumer: impl IndexConsumer) -> bool {
58 match self {
59 IndexMerger::Identical { coords } => {
60 for coord in 0..(coords.len() - 1) {
61 if !consumer(coord as i32, coord as i32, coord as i32) {
62 return false;
63 }
64 }
65 true
66 }
67 IndexMerger::DiscreteCube {
68 result,
69 first_div,
70 second_div,
71 } => {
72 for var3 in 0..(result.size() - 1) {
73 if !consumer(
74 (var3 / second_div).try_into().unwrap(),
75 (var3 / first_div).try_into().unwrap(),
76 var3.try_into().unwrap(),
77 ) {
78 return false;
79 }
80 }
81 true
82 }
83 IndexMerger::NonOverlapping { lower, upper, swap } => {
84 if *swap {
85 for_non_swapped_indexes(lower, upper, move |var1x, var2, var3| {
86 consumer(var2, var1x, var3)
87 })
88 } else {
89 for_non_swapped_indexes(lower, upper, consumer)
90 }
91 }
92 IndexMerger::Indirect {
93 first_indices,
94 second_indices,
95 result_length,
96 ..
97 } => {
98 let var2 = result_length - 1;
99
100 for var3 in 0..var2 {
101 if !consumer(
102 first_indices[var3].try_into().unwrap(),
103 second_indices[var3].try_into().unwrap(),
104 var3.try_into().unwrap(),
105 ) {
106 return false;
107 }
108 }
109
110 true
111 }
112 }
113 }
114 pub fn size(&self) -> usize {
115 match self {
116 IndexMerger::Identical { coords } => coords.len(),
117 IndexMerger::DiscreteCube { result, .. } => result.size().try_into().unwrap(),
118 IndexMerger::NonOverlapping { lower, upper, .. } => lower.len() + upper.len(),
119 IndexMerger::Indirect { result_length, .. } => *result_length,
120 }
121 }
122
123 pub fn new_discrete_cube(a: u32, b: u32) -> Self {
124 let result = CubePointRange {
125 parts: (u32::try_from(lcm(a, b)).expect("lcm should be able to fit in a u32"))
126 .try_into()
127 .expect("lcm should not be 0"),
128 };
129 let gcd = gcd(a, b);
130 let first_div = a / gcd;
131 let second_div = b / gcd;
132 Self::DiscreteCube {
133 result,
134 first_div,
135 second_div,
136 }
137 }
138
139 pub fn new_indirect(coords1: &[f64], coords2: &[f64], var3: bool, var4: bool) -> Self {
140 let mut var5 = f64::NAN;
141 let coords1_len = coords1.len();
142 let coords2_len = coords2.len();
143 let number_of_indices = coords1_len + coords2_len;
144 let mut result = vec![0.0; number_of_indices];
145 let mut first_indices: Vec<isize> = vec![0; number_of_indices];
146 let mut second_indices: Vec<isize> = vec![0; number_of_indices];
147 let var10 = !var3;
148 let var11 = !var4;
149 let mut var12 = 0;
150 let mut coords1_index = 0;
151 let mut coords2_index = 0;
152
153 loop {
154 let mut iterating_coords1: bool;
155 loop {
156 let at_end_of_coords1 = coords1_index >= coords1_len;
157 let at_end_of_coords2 = coords2_index >= coords2_len;
158 if at_end_of_coords1 && at_end_of_coords2 {
159 let result_length = cmp::max(1, var12);
160 return Self::Indirect {
161 result,
162 first_indices,
163 second_indices,
164 result_length,
165 };
166 }
167
168 iterating_coords1 = !at_end_of_coords1
169 && (at_end_of_coords2
170 || coords1[coords1_index] < coords2[coords2_index] + EPSILON);
171 if iterating_coords1 {
172 coords1_index += 1;
173 if !var10 || coords2_index != 0 && !at_end_of_coords2 {
174 break;
175 }
176 } else {
177 coords2_index += 1;
178 if !var11 || coords1_index != 0 && !at_end_of_coords1 {
179 break;
180 }
181 }
182 }
183
184 let var18: isize = (coords1_index as isize) - 1;
185 let var19: isize = (coords2_index as isize) - 1;
186 let var20 = if iterating_coords1 {
187 coords1[usize::try_from(var18).unwrap()]
188 } else {
189 coords2[usize::try_from(var19).unwrap()]
190 };
191 match var5.partial_cmp(&(var20 - EPSILON)) {
192 None | Some(Ordering::Less) => {
193 result[var12] = var20;
194 first_indices[var12] = var18;
195 second_indices[var12] = var19;
196 var12 += 1;
197 var5 = var20;
198 }
199 _ => {
200 first_indices[var12 - 1] = var18;
201 second_indices[var12 - 1] = var19;
202 }
203 }
204 }
205 }
206}
207
208pub trait IndexConsumer = FnMut(i32, i32, i32) -> bool;
209
210fn for_non_swapped_indexes(lower: &[f64], upper: &[f64], mut consumer: impl IndexConsumer) -> bool {
211 let var2 = lower.len();
212 for var3 in 0..var2 {
213 if !consumer(var3.try_into().unwrap(), -1, var3.try_into().unwrap()) {
214 return false;
215 }
216 }
217 let var3 = upper.len() - 1;
218 for var4 in 0..var3 {
219 if !consumer(
220 (var2 - 1).try_into().unwrap(),
221 var4.try_into().unwrap(),
222 (var2 + var4).try_into().unwrap(),
223 ) {
224 return false;
225 }
226 }
227 true
228}
229
230#[cfg(test)]
231mod tests {
232 use super::*;
233
234 #[test]
235 fn test_indirect_index_merger() {
236 IndexMerger::new_indirect(&[0.0, 1.0], &[0.0, 0.5, 1.0], true, true);
237 }
238}