1use autd3_core::derive::*;
2
3use autd3_driver::{common::rad, geometry::UnitVector3};
4
5#[derive(Debug, Clone, Copy, PartialEq)]
7#[repr(C)]
8pub struct PlaneOption {
9 pub intensity: Intensity,
11 pub phase_offset: Phase,
13}
14
15impl Default for PlaneOption {
16 fn default() -> Self {
17 Self {
18 intensity: Intensity::MAX,
19 phase_offset: Phase::ZERO,
20 }
21 }
22}
23
24#[derive(Gain, Clone, PartialEq, Debug)]
26pub struct Plane {
27 pub dir: UnitVector3,
29 pub option: PlaneOption,
31}
32
33impl Plane {
34 #[must_use]
36 pub const fn new(dir: UnitVector3, option: PlaneOption) -> Self {
37 Self { dir, option }
38 }
39}
40
41#[derive(Clone, Copy)]
42pub struct Impl {
43 dir: UnitVector3,
44 intensity: Intensity,
45 phase_offset: Phase,
46 wavenumber: f32,
47}
48
49impl GainCalculator<'_> for Impl {
50 fn calc(&self, tr: &Transducer) -> Drive {
51 Drive {
52 phase: Phase::from(-self.dir.dot(&tr.position().coords) * self.wavenumber * rad)
53 + self.phase_offset,
54 intensity: self.intensity,
55 }
56 }
57}
58
59impl GainCalculatorGenerator<'_> for Impl {
60 type Calculator = Impl;
61
62 fn generate(&mut self, _: &Device) -> Self::Calculator {
63 *self
64 }
65}
66
67impl Gain<'_> for Plane {
68 type G = Impl;
69
70 fn init(
71 self,
72 _: &Geometry,
73 env: &Environment,
74 _: &TransducerMask,
75 ) -> Result<Self::G, GainError> {
76 Ok(Impl {
77 dir: self.dir,
78 intensity: self.option.intensity,
79 phase_offset: self.option.phase_offset,
80 wavenumber: env.wavenumber(),
81 })
82 }
83}
84
85#[cfg(test)]
86mod tests {
87 use rand::Rng;
88
89 use super::*;
90
91 use crate::tests::{create_geometry, random_vector3};
92
93 fn plane_check(
94 mut b: Impl,
95 dir: UnitVector3,
96 intensity: Intensity,
97 phase_offset: Phase,
98 geometry: &Geometry,
99 env: &Environment,
100 ) {
101 geometry.iter().for_each(|dev| {
102 let d = b.generate(dev);
103 dev.iter().for_each(|tr| {
104 let expected_phase =
105 Phase::from(-dir.dot(&tr.position().coords) * env.wavenumber() * rad)
106 + phase_offset;
107 let d = d.calc(tr);
108 assert_eq!(expected_phase, d.phase);
109 assert_eq!(intensity, d.intensity);
110 });
111 });
112 }
113
114 #[test]
115 fn plane() {
116 let mut rng = rand::rng();
117
118 let geometry = create_geometry(1);
119 let env = Environment::new();
120
121 let dir = UnitVector3::new_normalize(random_vector3(-1.0..1.0, -1.0..1.0, -1.0..1.0));
122 let g = Plane::new(dir, PlaneOption::default());
123 plane_check(
124 g.init(&geometry, &env, &TransducerMask::AllEnabled)
125 .unwrap(),
126 dir,
127 Intensity::MAX,
128 Phase::ZERO,
129 &geometry,
130 &env,
131 );
132
133 let dir = UnitVector3::new_normalize(random_vector3(-1.0..1.0, -1.0..1.0, -1.0..1.0));
134 let intensity = Intensity(rng.random());
135 let phase_offset = Phase(rng.random());
136 let g = Plane {
137 dir,
138 option: PlaneOption {
139 intensity,
140 phase_offset,
141 },
142 };
143 plane_check(
144 g.init(&geometry, &env, &TransducerMask::AllEnabled)
145 .unwrap(),
146 dir,
147 intensity,
148 phase_offset,
149 &geometry,
150 &env,
151 );
152 }
153}