sim_lib_interference_core/
emitter.rs1use crate::{FieldAmplitude, InterferenceError, Point3M, Radians, UnitVector3};
4
5#[derive(Clone, Debug, PartialEq)]
10pub enum Emitter {
11 Point {
13 id: String,
15 position: Point3M,
17 amplitude_at_reference: FieldAmplitude,
20 phase: Radians,
22 },
23 ForwardPlane {
25 id: String,
27 through: Point3M,
29 direction: UnitVector3,
31 amplitude: FieldAmplitude,
33 phase: Radians,
35 },
36}
37
38impl Emitter {
39 pub fn id(&self) -> &str {
41 match self {
42 Self::Point { id, .. } | Self::ForwardPlane { id, .. } => id,
43 }
44 }
45}
46
47#[derive(Clone, Debug, PartialEq)]
49pub struct SourceSet {
50 sources: Vec<Emitter>,
51}
52
53impl SourceSet {
54 pub fn new(mut sources: Vec<Emitter>) -> Result<Self, InterferenceError> {
56 if sources.is_empty() {
57 return Err(InterferenceError::EmptySourceSet);
58 }
59 if sources.iter().any(|source| source.id().is_empty()) {
60 return Err(InterferenceError::EmptySourceId);
61 }
62
63 sources.sort_unstable_by(|left, right| left.id().cmp(right.id()));
64 if let Some(pair) = sources.windows(2).find(|pair| pair[0].id() == pair[1].id()) {
65 return Err(InterferenceError::DuplicateSourceId {
66 id: pair[0].id().to_owned(),
67 });
68 }
69
70 Ok(Self { sources })
71 }
72
73 pub fn len(&self) -> usize {
75 self.sources.len()
76 }
77
78 pub fn is_empty(&self) -> bool {
82 self.sources.is_empty()
83 }
84
85 pub fn as_slice(&self) -> &[Emitter] {
87 &self.sources
88 }
89
90 pub fn iter(&self) -> impl ExactSizeIterator<Item = &Emitter> {
92 self.sources.iter()
93 }
94}
95
96impl<'a> IntoIterator for &'a SourceSet {
97 type Item = &'a Emitter;
98 type IntoIter = std::slice::Iter<'a, Emitter>;
99
100 fn into_iter(self) -> Self::IntoIter {
101 self.sources.iter()
102 }
103}