feagi_brain_development/connectivity/rules/
vectors.rs1use crate::types::{BduResult, Position};
9
10type Dimensions = (usize, usize, usize);
11
12#[cfg(feature = "parallel")]
13use rayon::prelude::*;
14
15pub fn apply_vector_offset(
19 src_position: Position,
20 vector: (i32, i32, i32),
21 morphology_scalar: f32,
22 dst_dimensions: Dimensions,
23) -> Option<Position> {
24 let (src_x, src_y, src_z) = src_position;
25 let (vec_x, vec_y, vec_z) = vector;
26
27 let scaled_x = (vec_x as f32 * morphology_scalar) as i32;
29 let scaled_y = (vec_y as f32 * morphology_scalar) as i32;
30 let scaled_z = (vec_z as f32 * morphology_scalar) as i32;
31
32 let dst_x = src_x as i32 + scaled_x;
34 let dst_y = src_y as i32 + scaled_y;
35 let dst_z = src_z as i32 + scaled_z;
36
37 let dims_x = dst_dimensions.0 as i32;
38 let dims_y = dst_dimensions.1 as i32;
39 let dims_z = dst_dimensions.2 as i32;
40
41 if dst_x < 0 || dst_x >= dims_x || dst_y < 0 || dst_y >= dims_y || dst_z < 0 || dst_z >= dims_z
42 {
43 return None;
44 }
45
46 let dst_x = dst_x as u32;
47 let dst_y = dst_y as u32;
48 let dst_z = dst_z as u32;
49
50 Some((dst_x, dst_y, dst_z))
51}
52
53pub(super) fn apply_vector_offset_clamped(
55 src_position: Position,
56 vector: (i32, i32, i32),
57 morphology_scalar: f32,
58 dst_dimensions: Dimensions,
59) -> BduResult<Position> {
60 let (src_x, src_y, src_z) = src_position;
61 let (vec_x, vec_y, vec_z) = vector;
62
63 let scaled_x = (vec_x as f32 * morphology_scalar) as i32;
65 let scaled_y = (vec_y as f32 * morphology_scalar) as i32;
66 let scaled_z = (vec_z as f32 * morphology_scalar) as i32;
67
68 let dst_x = (src_x as i32 + scaled_x)
70 .max(0)
71 .min(dst_dimensions.0 as i32 - 1) as u32;
72 let dst_y = (src_y as i32 + scaled_y)
73 .max(0)
74 .min(dst_dimensions.1 as i32 - 1) as u32;
75 let dst_z = (src_z as i32 + scaled_z)
76 .max(0)
77 .min(dst_dimensions.2 as i32 - 1) as u32;
78
79 Ok((dst_x, dst_y, dst_z))
80}
81
82pub fn match_vectors_batch(
84 src_positions: &[Position],
85 vector: (i32, i32, i32),
86 morphology_scalar: f32,
87 dst_dimensions: Dimensions,
88) -> BduResult<Vec<Position>> {
89 #[cfg(feature = "parallel")]
91 let results: Vec<_> = src_positions
92 .par_iter()
93 .filter_map(|&src_pos| {
94 apply_vector_offset(src_pos, vector, morphology_scalar, dst_dimensions)
95 })
96 .collect();
97
98 #[cfg(not(feature = "parallel"))]
99 let results: Vec<_> = src_positions
100 .iter()
101 .filter_map(|&src_pos| {
102 apply_vector_offset(src_pos, vector, morphology_scalar, dst_dimensions)
103 })
104 .collect();
105
106 Ok(results)
107}
108
109#[cfg(test)]
110mod tests {
111 use super::*;
112
113 #[test]
114 fn test_vector_offset() {
115 let result = apply_vector_offset((5, 5, 5), (1, 0, 0), 1.0, (10, 10, 10));
116 assert_eq!(result, Some((6, 5, 5)));
117 }
118
119 #[test]
120 fn test_vector_offset_with_scalar() {
121 let result = apply_vector_offset((5, 5, 5), (2, 2, 2), 2.0, (20, 20, 20));
122 assert_eq!(result, Some((9, 9, 9)));
123 }
124
125 #[test]
126 fn test_vector_offset_out_of_bounds() {
127 let result = apply_vector_offset((8, 8, 8), (5, 5, 5), 1.0, (10, 10, 10));
129 assert_eq!(result, None);
130 }
131
132 #[test]
133 fn test_vector_offset_clamped() {
134 let result = apply_vector_offset_clamped((8, 8, 8), (5, 5, 5), 1.0, (10, 10, 10));
136 assert!(result.is_ok());
137 assert_eq!(result.unwrap(), (9, 9, 9)); }
139
140 #[test]
141 fn test_batch_vectors() {
142 let positions = vec![(0, 0, 0), (1, 1, 1), (2, 2, 2)];
143
144 let results = match_vectors_batch(&positions, (1, 0, 0), 1.0, (10, 10, 10));
145
146 assert!(results.is_ok());
147 let results = results.unwrap();
148 assert_eq!(results.len(), 3);
149 assert_eq!(results[0], (1, 0, 0));
150 assert_eq!(results[1], (2, 1, 1));
151 assert_eq!(results[2], (3, 2, 2));
152 }
153
154 #[test]
155 fn test_batch_vectors_skips_out_of_bounds() {
156 let positions = vec![(8, 0, 0), (9, 0, 0)];
157 let results = match_vectors_batch(&positions, (1, 0, 0), 1.0, (10, 10, 10));
158 assert!(results.is_ok());
159 let results = results.unwrap();
160 assert_eq!(results.len(), 1);
161 assert_eq!(results[0], (9, 0, 0));
162 }
163}