hfss_fld/fld_file_data_structs/
fld_file_loader.rs

1mod file_header_utils;
2
3use std::fs::File;
4use std::io::{prelude::BufRead, BufReader};
5use std::path::Path;
6use std::str::FromStr;
7
8pub use file_header_utils::{DataCoordinates, DataDimensionality};
9
10#[derive(Debug)]
11pub struct FileData {
12    pub file_name: String,
13    pub geo_points: Vec<[f64; 3]>,
14    pub fld_points: Vec<Vec<f64>>,
15    pub dimensionality: DataDimensionality,
16    pub coordinates: DataCoordinates,
17    pub num_points: usize,
18}
19
20impl FileData {
21    pub fn load_file(
22        file_path: String,
23        expected_field_data_size: usize,
24    ) -> Result<Self, std::io::Error> {
25        // file
26        let os_file_path = Path::new(&file_path);
27        let file_name = retrieve_file_name(&os_file_path);
28        let file = File::open(os_file_path)?;
29
30        // file reader buffer
31        let file_reader = BufReader::new(file);
32
33        let mut geo_points = Vec::new();
34        let mut fld_points = Vec::new();
35
36        let mut dimensionality = DataDimensionality::new();
37        let mut coordinates = DataCoordinates::None;
38
39        assert!(
40            expected_field_data_size > 0,
41            "FileData cannot expect zero sized data!"
42        );
43
44        for (i, line) in file_reader.lines().enumerate() {
45            match line {
46                Ok(line_text) => {
47                    match i {
48                        0 => {
49                            // first header line -> geometric meta-data
50                            dimensionality = match DataDimensionality::from_file_header(&line_text)
51                            {
52                                Ok(data_dimensionality) => data_dimensionality,
53                                Err(msg) => panic!(
54                                    "Problem Parsing Fld File: `{}` \n Err: {}",
55                                    file_name, msg
56                                ),
57                            };
58                            let num_points = dimensionality.total_num_points();
59
60                            // reserve space for appropriate number of points
61                            geo_points.reserve(num_points);
62                            fld_points.reserve(num_points);
63                        }
64                        1 => {
65                            // second header line -> field type and coordinate system
66                            coordinates = match DataCoordinates::from_file_header(&line_text) {
67                                Ok(data_coordinates) => data_coordinates,
68                                Err(msg) => panic!(
69                                    "Problem Parsing Fld File: `{}` \n Err: {}",
70                                    file_name, msg
71                                ),
72                            };
73                        }
74                        _ => {
75                            // remaining lines => field data points
76                            let mut line_geo_points = [0.0; 3];
77                            let mut line_fld_points = Vec::with_capacity(expected_field_data_size);
78
79                            // split on double space to get text sections for [geo \s\s field] data
80                            let line_text_sections = line_text.split("  ");
81                            for (s, section) in line_text_sections.enumerate() {
82                                // split on singe space to get individual numerical tokens
83                                let tokens = section.split(' ');
84                                for (t, token) in tokens.enumerate() {
85                                    if token == "" {
86                                        continue;
87                                    }
88                                    // attempt to parse each token as an f64
89                                    match f64::from_str(token) {
90                                        // populate appropriate array with geometric or field data
91                                        Ok(value) => match s {
92                                            0 => line_geo_points[t] = value,
93                                            1 => {
94                                                assert!(
95                                                    t < expected_field_data_size,
96                                                    "Unexpected token on line {} of {}",
97                                                    i,
98                                                    file_name
99                                                );
100                                                line_fld_points.push(value);
101                                            }
102                                            _ => {
103                                                panic!(
104                                                    "Unexpected token on line {} of {}",
105                                                    i, file_name
106                                                );
107                                            }
108                                        },
109                                        Err(msg) => panic!(
110                                            "Unable to parse value on line {} of {} as f64! \n {}",
111                                            i, file_name, msg
112                                        ),
113                                    }
114                                }
115                            }
116
117                            // populate data vectors with geo and fld data from line i
118                            geo_points.push(line_geo_points);
119                            fld_points.push(line_fld_points);
120                        }
121                    }
122                }
123                Err(msg) => panic!("Unable to read line {} of {} \n {}", i, file_name, msg),
124            }
125        }
126
127        geo_points.shrink_to_fit();
128        fld_points.shrink_to_fit();
129
130        let num_points = geo_points.len();
131        assert_eq!(
132            num_points,
133            fld_points.len(),
134            "Problem Parsing Fld File: `{}` \n Inconsistent Number of geometric and data points!",
135            file_name
136        );
137
138        dark_yellow!("{} \t", num_points);
139        print!("Data Points successfully loaded from: ");
140        dark_grey_ln!("`{}`", file_name);
141
142        Ok(Self {
143            file_name,
144            geo_points,
145            fld_points,
146            dimensionality,
147            coordinates,
148            num_points,
149        })
150    }
151}
152
153fn retrieve_file_name(os_file_path: &Path) -> String {
154    let name = os_file_path.file_name();
155
156    match name {
157        Some(file_name) => file_name.to_string_lossy().into_owned(),
158        None => String::from("-UNNAMED FLD FILE-"),
159    }
160}