cherry_rs/specs/
fields.rs1use anyhow::Result;
2use serde::{Deserialize, Serialize};
3
4use crate::core::Float;
5
6#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
8pub enum PupilSampling {
9 SquareGrid { spacing: Float },
16
17 ChiefAndMarginalRays,
19}
20
21#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
23pub enum FieldSpec {
24 Angle {
26 angle: Float,
27 pupil_sampling: PupilSampling,
28 },
29
30 ObjectHeight {
32 height: Float,
33 pupil_sampling: PupilSampling,
34 },
35}
36
37impl PupilSampling {
38 pub fn validate(&self) -> Result<()> {
40 match self {
41 PupilSampling::SquareGrid { spacing } => {
42 if spacing.is_nan() {
43 anyhow::bail!("Pupil grid spacing must be a number");
44 }
45 if *spacing < 0.0 || *spacing > 1.0 {
46 anyhow::bail!("Pupil grid spacing must be in the range [0, 1]");
47 }
48 }
49 PupilSampling::ChiefAndMarginalRays => {}
50 }
51 Ok(())
52 }
53}
54
55impl Default for PupilSampling {
56 fn default() -> Self {
57 Self::SquareGrid { spacing: 0.1 }
58 }
59}
60
61impl FieldSpec {
62 pub fn validate(&self) -> Result<()> {
64 match self {
65 FieldSpec::Angle {
66 angle,
67 pupil_sampling,
68 } => {
69 if angle.is_nan() {
70 anyhow::bail!("Field angle must be a number");
71 }
72 if *angle < -90.0 || *angle > 90.0 {
73 anyhow::bail!("Field angle must be in the range [-90.0, 90]");
74 }
75 pupil_sampling.validate()?;
76 }
77 FieldSpec::ObjectHeight {
78 height,
79 pupil_sampling,
80 } => {
81 if height.is_nan() {
82 anyhow::bail!("Field height must be a number");
83 }
84 pupil_sampling.validate()?;
85 }
86 }
87 Ok(())
88 }
89}
90
91#[cfg(test)]
92mod test {
93 use super::*;
94
95 #[test]
96 fn test_pupil_sampling_validate() {
97 let square_grid = PupilSampling::SquareGrid { spacing: 0.1 };
98 assert!(square_grid.validate().is_ok());
99
100 let square_grid = PupilSampling::SquareGrid { spacing: 1.1 };
101 assert!(square_grid.validate().is_err());
102
103 let square_grid = PupilSampling::SquareGrid { spacing: -0.1 };
104 assert!(square_grid.validate().is_err());
105
106 let square_grid = PupilSampling::SquareGrid {
107 spacing: Float::NAN,
108 };
109 assert!(square_grid.validate().is_err());
110 }
111
112 #[test]
113 fn test_field_spec_validate() {
114 let angle = FieldSpec::Angle {
115 angle: 45.0,
116 pupil_sampling: PupilSampling::SquareGrid { spacing: 0.1 },
117 };
118 assert!(angle.validate().is_ok());
119
120 let angle = FieldSpec::Angle {
121 angle: 95.0,
122 pupil_sampling: PupilSampling::SquareGrid { spacing: 0.1 },
123 };
124 assert!(angle.validate().is_err());
125
126 let angle = FieldSpec::Angle {
127 angle: -5.0,
128 pupil_sampling: PupilSampling::SquareGrid { spacing: 0.1 },
129 };
130 assert!(angle.validate().is_ok());
131
132 let angle = FieldSpec::Angle {
133 angle: 45.0,
134 pupil_sampling: PupilSampling::SquareGrid { spacing: 1.1 },
135 };
136 assert!(angle.validate().is_err());
137
138 let angle = FieldSpec::Angle {
139 angle: 45.0,
140 pupil_sampling: PupilSampling::SquareGrid { spacing: -0.1 },
141 };
142 assert!(angle.validate().is_err());
143
144 let angle = FieldSpec::Angle {
145 angle: 45.0,
146 pupil_sampling: PupilSampling::SquareGrid {
147 spacing: Float::NAN,
148 },
149 };
150 assert!(angle.validate().is_err());
151
152 let height = FieldSpec::ObjectHeight {
153 height: 0.1,
154 pupil_sampling: PupilSampling::SquareGrid { spacing: 0.1 },
155 };
156 assert!(height.validate().is_ok());
157
158 let height = FieldSpec::ObjectHeight {
159 height: 0.1,
160 pupil_sampling: PupilSampling::SquareGrid { spacing: 1.1 },
161 };
162 assert!(height.validate().is_err());
163 }
164}