1use crate::ids::{LumpedVibrationCaseId, VibrationCaseId};
6
7#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
9pub enum VibrationThDir {
10 X,
11 Y,
12 Xy,
13}
14
15#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
17pub enum LumpedVibrationDir {
18 X,
19 Y,
20}
21
22#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
24pub enum LumpedVibrationDim {
25 Planar,
27 Spatial,
29}
30
31#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
33pub struct VibrationCase {
34 pub id: VibrationCaseId,
35 pub name: String,
36 pub wave_name: String,
37 pub dir: VibrationThDir,
38 pub nonlinear: bool,
39}
40
41#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
43pub struct LumpedVibrationCase {
44 pub id: LumpedVibrationCaseId,
45 pub name: String,
46 pub wave_name: String,
47 pub dir: LumpedVibrationDir,
48 pub nonlinear: bool,
49 pub dim: LumpedVibrationDim,
50}
51
52fn dir_label_th(dir: VibrationThDir) -> &'static str {
53 match dir {
54 VibrationThDir::X => "X",
55 VibrationThDir::Y => "Y",
56 VibrationThDir::Xy => "X+Y",
57 }
58}
59
60fn dir_label_lumped(dir: LumpedVibrationDir) -> &'static str {
61 match dir {
62 LumpedVibrationDir::X => "X",
63 LumpedVibrationDir::Y => "Y",
64 }
65}
66
67fn linearity_label(nonlinear: bool) -> &'static str {
68 if nonlinear {
69 "非線形"
70 } else {
71 "線形"
72 }
73}
74
75fn dim_label(dim: LumpedVibrationDim) -> &'static str {
76 match dim {
77 LumpedVibrationDim::Planar => "2次元",
78 LumpedVibrationDim::Spatial => "3次元",
79 }
80}
81
82pub fn spatial_vibration_case_name(
84 wave_name: &str,
85 dir: VibrationThDir,
86 nonlinear: bool,
87) -> String {
88 format!(
89 "{} {} ({})",
90 wave_name,
91 dir_label_th(dir),
92 linearity_label(nonlinear)
93 )
94}
95
96pub fn lumped_vibration_case_name(
98 wave_name: &str,
99 dir: LumpedVibrationDir,
100 nonlinear: bool,
101 dim: LumpedVibrationDim,
102) -> String {
103 format!(
104 "{} {} ({}・{})",
105 wave_name,
106 dir_label_lumped(dir),
107 linearity_label(nonlinear),
108 dim_label(dim)
109 )
110}
111
112fn next_vibration_case_id(cases: &[VibrationCase]) -> VibrationCaseId {
113 let next = cases
114 .iter()
115 .map(|c| c.id.0)
116 .max()
117 .map(|m| m + 1)
118 .unwrap_or(0);
119 VibrationCaseId(next)
120}
121
122fn next_lumped_vibration_case_id(cases: &[LumpedVibrationCase]) -> LumpedVibrationCaseId {
123 let next = cases
124 .iter()
125 .map(|c| c.id.0)
126 .max()
127 .map(|m| m + 1)
128 .unwrap_or(0);
129 LumpedVibrationCaseId(next)
130}
131
132impl super::Model {
133 pub fn upsert_vibration_case(
135 &mut self,
136 wave_name: String,
137 dir: VibrationThDir,
138 nonlinear: bool,
139 ) -> VibrationCaseId {
140 let name = spatial_vibration_case_name(&wave_name, dir, nonlinear);
141 if let Some(pos) = self.vibration_cases.iter().position(|c| c.name == name) {
142 let id = self.vibration_cases[pos].id;
143 self.vibration_cases[pos].wave_name = wave_name;
144 self.vibration_cases[pos].dir = dir;
145 self.vibration_cases[pos].nonlinear = nonlinear;
146 return id;
147 }
148 let id = next_vibration_case_id(&self.vibration_cases);
149 self.vibration_cases.push(VibrationCase {
150 id,
151 name,
152 wave_name,
153 dir,
154 nonlinear,
155 });
156 id
157 }
158
159 pub fn upsert_lumped_vibration_case(
161 &mut self,
162 wave_name: String,
163 dir: LumpedVibrationDir,
164 nonlinear: bool,
165 dim: LumpedVibrationDim,
166 ) -> LumpedVibrationCaseId {
167 let name = lumped_vibration_case_name(&wave_name, dir, nonlinear, dim);
168 if let Some(pos) = self
169 .lumped_vibration_cases
170 .iter()
171 .position(|c| c.name == name)
172 {
173 let id = self.lumped_vibration_cases[pos].id;
174 self.lumped_vibration_cases[pos].wave_name = wave_name;
175 self.lumped_vibration_cases[pos].dir = dir;
176 self.lumped_vibration_cases[pos].nonlinear = nonlinear;
177 self.lumped_vibration_cases[pos].dim = dim;
178 return id;
179 }
180 let id = next_lumped_vibration_case_id(&self.lumped_vibration_cases);
181 self.lumped_vibration_cases.push(LumpedVibrationCase {
182 id,
183 name,
184 wave_name,
185 dir,
186 nonlinear,
187 dim,
188 });
189 id
190 }
191}
192
193#[cfg(test)]
194mod tests {
195 use super::*;
196
197 #[test]
198 fn spatial_vibration_case_name_format() {
199 assert_eq!(
200 spatial_vibration_case_name("サンプル", VibrationThDir::X, false),
201 "サンプル X (線形)"
202 );
203 assert_eq!(
204 spatial_vibration_case_name("elcentro", VibrationThDir::Y, true),
205 "elcentro Y (非線形)"
206 );
207 assert_eq!(
208 spatial_vibration_case_name("wave", VibrationThDir::Xy, false),
209 "wave X+Y (線形)"
210 );
211 }
212
213 #[test]
214 fn lumped_vibration_case_name_format() {
215 assert_eq!(
216 lumped_vibration_case_name(
217 "サンプル",
218 LumpedVibrationDir::X,
219 false,
220 LumpedVibrationDim::Planar
221 ),
222 "サンプル X (線形・2次元)"
223 );
224 assert_eq!(
225 lumped_vibration_case_name(
226 "wave",
227 LumpedVibrationDir::Y,
228 true,
229 LumpedVibrationDim::Spatial
230 ),
231 "wave Y (非線形・3次元)"
232 );
233 }
234
235 #[test]
236 fn upsert_vibration_case_preserves_id_on_same_name() {
237 let mut model = super::super::Model::default();
238 let id1 = model.upsert_vibration_case("サンプル".into(), VibrationThDir::X, false);
239 let id2 = model.upsert_vibration_case("サンプル".into(), VibrationThDir::X, false);
240 assert_eq!(id1, id2);
241 assert_eq!(model.vibration_cases.len(), 1);
242 }
243
244 #[test]
245 fn upsert_vibration_case_distinct_names_get_distinct_ids() {
246 let mut model = super::super::Model::default();
247 let id1 = model.upsert_vibration_case("サンプル".into(), VibrationThDir::X, false);
248 let id2 = model.upsert_vibration_case("サンプル".into(), VibrationThDir::Y, false);
249 assert_ne!(id1, id2);
250 assert_eq!(model.vibration_cases.len(), 2);
251 }
252}