autd3_core/geometry/
mod.rs1pub(crate) mod device;
2mod rotation;
3mod transducer;
4
5#[cfg(feature = "use_nalgebra")]
6mod math {
7 pub type Complex = nalgebra::Complex<f32>;
9 pub type Vector3 = nalgebra::Vector3<f32>;
11 pub type UnitVector3 = nalgebra::UnitVector3<f32>;
13 pub type Point3 = nalgebra::Point3<f32>;
15 pub type Quaternion = nalgebra::Quaternion<f32>;
17 pub type UnitQuaternion = nalgebra::UnitQuaternion<f32>;
19 pub type Translation3 = nalgebra::Translation3<f32>;
21 pub type Isometry3 = nalgebra::Isometry3<f32>;
23}
24
25#[cfg(not(feature = "use_nalgebra"))]
26mod math;
27
28pub use math::*;
29
30pub use device::*;
31pub use rotation::*;
32pub use transducer::*;
33
34pub struct Geometry {
36 pub(crate) devices: Vec<Device>,
37 version: usize,
38}
39
40impl Geometry {
41 #[must_use]
43 pub fn new(devices: Vec<Device>) -> Self {
44 let mut geometry = Self {
45 devices,
46 version: 0,
47 };
48 geometry.assign_idx();
49 geometry
50 }
51
52 fn assign_idx(&mut self) {
53 self.devices
54 .iter_mut()
55 .enumerate()
56 .for_each(|(dev_idx, dev)| {
57 dev.idx = dev_idx as _;
58 dev.transducers.iter_mut().for_each(|tr| {
59 tr.dev_idx = dev_idx as _;
60 });
61 });
62 }
63
64 #[must_use]
66 pub fn num_devices(&self) -> usize {
67 self.devices.len()
68 }
69
70 #[must_use]
72 pub fn num_transducers(&self) -> usize {
73 self.iter().map(|dev| dev.num_transducers()).sum()
74 }
75
76 #[must_use]
78 pub fn center(&self) -> Point3 {
79 Point3::from(
80 self.iter().map(|d| d.center().coords).sum::<Vector3>() / self.devices.len() as f32,
81 )
82 }
83
84 #[doc(hidden)]
85 pub fn version(&self) -> usize {
86 self.version
87 }
88
89 pub fn reconfigure<D: Into<Device>, F: Fn(Device) -> D>(&mut self, f: F) {
91 self.devices = self.devices.drain(..).map(|dev| f(dev).into()).collect();
92 self.assign_idx();
93 self.version += 1;
94 }
95}
96
97impl<'a> IntoIterator for &'a Geometry {
98 type Item = &'a Device;
99 type IntoIter = core::slice::Iter<'a, Device>;
100
101 fn into_iter(self) -> Self::IntoIter {
102 self.devices.iter()
103 }
104}
105
106impl<'a> IntoIterator for &'a mut Geometry {
107 type Item = &'a mut Device;
108 type IntoIter = core::slice::IterMut<'a, Device>;
109
110 fn into_iter(self) -> Self::IntoIter {
111 self.version += 1;
112 self.devices.iter_mut()
113 }
114}
115
116impl core::ops::Deref for Geometry {
117 type Target = Vec<Device>;
118
119 fn deref(&self) -> &Self::Target {
120 &self.devices
121 }
122}
123
124impl core::ops::DerefMut for Geometry {
125 fn deref_mut(&mut self) -> &mut Self::Target {
126 self.version += 1;
127 &mut self.devices
128 }
129}
130
131#[cfg(test)]
132pub(crate) mod tests {
133
134 use rand::Rng;
135
136 use crate::common::mm;
137
138 use super::*;
139
140 macro_rules! assert_approx_eq_vec3 {
141 ($a:expr, $b:expr) => {
142 approx::assert_abs_diff_eq!($a.x, $b.x, epsilon = 1e-3);
143 approx::assert_abs_diff_eq!($a.y, $b.y, epsilon = 1e-3);
144 approx::assert_abs_diff_eq!($a.z, $b.z, epsilon = 1e-3);
145 };
146 }
147
148 pub struct TestDevice {
149 pub rotation: UnitQuaternion,
150 pub transducers: Vec<Transducer>,
151 }
152
153 impl TestDevice {
154 pub fn new_autd3(pos: Point3) -> Self {
155 Self::new_autd3_with_rot(pos, UnitQuaternion::identity())
156 }
157
158 pub fn new_autd3_with_rot(pos: Point3, rot: impl Into<UnitQuaternion>) -> Self {
159 let rotation = rot.into();
160 let isometry = Isometry3 {
161 rotation,
162 translation: Translation3::from(pos),
163 };
164 Self {
165 rotation,
166 transducers: (0..14)
167 .flat_map(|y| {
168 (0..18).map(move |x| {
169 Transducer::new(
170 isometry * (10.16 * mm * Point3::new(x as f32, y as f32, 0.)),
171 )
172 })
173 })
174 .collect(),
175 }
176 }
177 }
178
179 impl From<TestDevice> for Device {
180 fn from(dev: TestDevice) -> Self {
181 Self::new(dev.rotation, dev.transducers)
182 }
183 }
184
185 pub fn create_device(n: u8) -> Device {
186 Device::new(
187 UnitQuaternion::identity(),
188 (0..n).map(|_| Transducer::new(Point3::origin())).collect(),
189 )
190 }
191
192 pub fn create_geometry(n: u16, num_trans_in_unit: u8) -> Geometry {
193 Geometry::new((0..n).map(|_| create_device(num_trans_in_unit)).collect())
194 }
195
196 #[rstest::rstest]
197 #[case(1, vec![create_device(249)])]
198 #[case(2, vec![create_device(249), create_device(249)])]
199 fn num_devices(#[case] expected: usize, #[case] devices: Vec<Device>) {
200 let geometry = Geometry::new(devices);
201 assert_eq!(0, geometry.version());
202 assert_eq!(expected, geometry.num_devices());
203 assert_eq!(0, geometry.version());
204 }
205
206 #[rstest::rstest]
207 #[case(249, vec![create_device(249)])]
208 #[case(498, vec![create_device(249), create_device(249)])]
209 fn num_transducers(#[case] expected: usize, #[case] devices: Vec<Device>) {
210 let geometry = Geometry::new(devices);
211 assert_eq!(0, geometry.version());
212 assert_eq!(expected, geometry.num_transducers());
213 assert_eq!(0, geometry.version());
214 }
215
216 #[test]
217 fn center() {
218 let geometry = Geometry::new(vec![
219 TestDevice::new_autd3(Point3::origin()).into(),
220 TestDevice::new_autd3(Point3::new(10., 20., 30.)).into(),
221 ]);
222 let expect = geometry
223 .iter()
224 .map(|dev| dev.center().coords)
225 .sum::<Vector3>()
226 / geometry.num_devices() as f32;
227 assert_eq!(0, geometry.version());
228 assert_approx_eq_vec3!(expect, geometry.center());
229 assert_eq!(0, geometry.version());
230 }
231
232 #[test]
233 fn into_iter() {
234 let mut geometry = create_geometry(1, 1);
235 assert_eq!(0, geometry.version());
236 (&geometry).into_iter().for_each(|dev| {
237 _ = dev;
238 });
239 assert_eq!(0, geometry.version());
240 (&mut geometry).into_iter().for_each(|dev| {
241 _ = dev;
242 });
243 assert_eq!(1, geometry.version());
244 }
245
246 #[test]
247 fn idx() {
248 let geometry = Geometry::new(vec![
249 TestDevice::new_autd3_with_rot(Point3::origin(), UnitQuaternion::identity()).into(),
250 TestDevice::new_autd3_with_rot(Point3::origin(), UnitQuaternion::identity()).into(),
251 ]);
252 (0..2).for_each(|dev_idx| {
253 assert_eq!(dev_idx, geometry[dev_idx].idx());
254 (0..14 * 18).for_each(|tr_idx| {
255 assert_eq!(tr_idx, geometry[dev_idx][tr_idx].idx());
256 assert_eq!(dev_idx, geometry[dev_idx][tr_idx].dev_idx());
257 });
258 });
259 }
260
261 #[test]
262 fn reconfigure() {
263 let mut geometry = Geometry::new(vec![
264 TestDevice::new_autd3_with_rot(Point3::origin(), UnitQuaternion::identity()).into(),
265 TestDevice::new_autd3_with_rot(Point3::origin(), UnitQuaternion::identity()).into(),
266 ]);
267
268 let mut rng = rand::rng();
269 let t = Point3::new(rng.random(), rng.random(), rng.random());
270 let rot = UnitQuaternion::new_normalize(Quaternion::new(
271 rng.random(),
272 rng.random(),
273 rng.random(),
274 rng.random(),
275 ));
276
277 geometry.reconfigure(|dev| match dev.idx() {
278 0 => TestDevice::new_autd3_with_rot(t, rot),
279 _ => TestDevice::new_autd3_with_rot(dev[0].position(), dev.rotation()),
280 });
281
282 assert_eq!(1, geometry.version());
283 assert_eq!(t, geometry[0][0].position());
284 assert_eq!(rot, geometry[0].rotation());
285 assert_eq!(Point3::origin(), geometry[1][0].position());
286 assert_eq!(UnitQuaternion::identity(), geometry[1].rotation());
287 }
288}