use crate::{FieldAmplitude, InterferenceError, Point3M, Radians, UnitVector3};
#[derive(Clone, Debug, PartialEq)]
pub enum Emitter {
Point {
id: String,
position: Point3M,
amplitude_at_reference: FieldAmplitude,
phase: Radians,
},
ForwardPlane {
id: String,
through: Point3M,
direction: UnitVector3,
amplitude: FieldAmplitude,
phase: Radians,
},
}
impl Emitter {
pub fn id(&self) -> &str {
match self {
Self::Point { id, .. } | Self::ForwardPlane { id, .. } => id,
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct SourceSet {
sources: Vec<Emitter>,
}
impl SourceSet {
pub fn new(mut sources: Vec<Emitter>) -> Result<Self, InterferenceError> {
if sources.is_empty() {
return Err(InterferenceError::EmptySourceSet);
}
if sources.iter().any(|source| source.id().is_empty()) {
return Err(InterferenceError::EmptySourceId);
}
sources.sort_unstable_by(|left, right| left.id().cmp(right.id()));
if let Some(pair) = sources.windows(2).find(|pair| pair[0].id() == pair[1].id()) {
return Err(InterferenceError::DuplicateSourceId {
id: pair[0].id().to_owned(),
});
}
Ok(Self { sources })
}
pub fn len(&self) -> usize {
self.sources.len()
}
pub fn is_empty(&self) -> bool {
self.sources.is_empty()
}
pub fn as_slice(&self) -> &[Emitter] {
&self.sources
}
pub fn iter(&self) -> impl ExactSizeIterator<Item = &Emitter> {
self.sources.iter()
}
}
impl<'a> IntoIterator for &'a SourceSet {
type Item = &'a Emitter;
type IntoIter = std::slice::Iter<'a, Emitter>;
fn into_iter(self) -> Self::IntoIter {
self.sources.iter()
}
}