use crate::{
consts::{DataArray, NUM_TRANS_IN_UNIT},
geometry::{Geometry, Vector3},
Float,
};
use super::super::{adjust_amp, Gain};
pub struct BesselBeamGain {
point: Vector3,
dir: Vector3,
theta_z: Float,
duty: u8,
data: Option<Vec<DataArray>>,
}
impl BesselBeamGain {
pub fn create(point: Vector3, dir: Vector3, theta_z: Float) -> BesselBeamGain {
Self::create_with_duty(point, dir, theta_z, 0xff)
}
pub fn create_with_duty(point: Vector3, dir: Vector3, theta_z: Float, duty: u8) -> Self {
Self {
point,
dir,
theta_z,
duty,
data: None,
}
}
pub fn create_with_amp(point: Vector3, dir: Vector3, theta_z: Float, amp: Float) -> Self {
Self::create_with_duty(point, dir, theta_z, adjust_amp(amp))
}
}
impl Gain for BesselBeamGain {
fn get_data(&self) -> &[DataArray] {
assert!(self.data.is_some());
match &self.data {
Some(data) => data,
None => panic!(),
}
}
fn build(&mut self, geometry: &Geometry) {
if self.data.is_some() {
return;
}
let num_devices = geometry.num_devices();
let mut data = Vec::with_capacity(num_devices);
let dir = self.dir.normalize();
let v = Vector3::new(dir.y, -dir.x, 0.);
let theta_w = v.norm().asin();
let point = self.point;
let theta_z = self.theta_z;
let duty = (self.duty as u16) << 8;
let wavelength = geometry.wavelength();
for dev in 0..num_devices {
let mut buf: DataArray = unsafe { std::mem::zeroed() };
for (i, b) in buf.iter_mut().enumerate().take(NUM_TRANS_IN_UNIT) {
let trp = geometry.position_by_local_idx(dev, i);
let r = trp - point;
let xr = r.cross(&v);
let r =
r * theta_w.cos() + xr * theta_w.sin() + v * (v.dot(&r) * (1. - theta_w.cos()));
let dist = theta_z.sin() * (r.x * r.x + r.y * r.y).sqrt() - theta_z.cos() * r.z;
let phase = (dist % wavelength) / wavelength;
let phase = (255.0 * (1.0 - phase)) as u16;
*b = duty | phase;
}
data.push(buf);
}
self.data = Some(data);
}
}