1use crate::traits::{Builder, Grid};
3use std::fs::{self, File};
4use std::io::{BufRead, BufReader, Read};
5
6pub trait GmshExport: Grid {
7 fn to_gmsh_string(&self) -> String;
11
12 fn export_as_gmsh(&self, filename: &str) {
14 let gmsh_s = self.to_gmsh_string();
15 fs::write(filename, gmsh_s).expect("Unable to write file");
16 }
17}
18
19pub trait GmshImport: Builder {
20 fn import_from_gmsh_v1(&mut self, s: String);
24
25 fn import_from_gmsh_string_v2(&mut self, s: String);
27
28 fn import_from_gmsh_binary_v2(
30 &mut self,
31 reader: BufReader<File>,
32 data_size: usize,
33 is_le: bool,
35 );
36
37 fn import_from_gmsh_string_v4(&mut self, s: String);
39
40 fn import_from_gmsh_binary_v4(
42 &mut self,
43 reader: BufReader<File>,
44 data_size: usize,
45 is_le: bool,
47 );
48
49 fn import_from_gmsh(&mut self, filename: &str) {
51 let f = File::open(filename).expect("Unable to open file");
52 let mut reader = BufReader::new(f);
53
54 let mut line = String::new();
55 reader.read_line(&mut line).expect("Unable to read header");
56
57 if line.starts_with("$NOD") {
58 let mut content = String::new();
59 reader
60 .read_to_string(&mut content)
61 .expect("Unable to read mesh");
62
63 content.replace_range(0..0, "$Nodes\n");
64 for (f, r) in [
65 ("$ENDNOD", "$EndNodes"),
66 ("$ELM", "$Elements"),
67 ("$ENDELM", "$EndElements"),
68 ]
69 .iter()
70 {
71 let Some(offset) = content.find(f) else {
72 panic!("Invalid file format");
73 };
74 content.replace_range(offset..offset + f.len(), r);
75 }
76
77 self.import_from_gmsh_v1(content);
78 return;
79 }
80
81 reader.read_line(&mut line).expect("Unable to read header");
82
83 let [version, binary_mode, data_size] = line.split("\n").collect::<Vec<_>>()[1]
84 .split(" ")
85 .collect::<Vec<_>>()[..]
86 else {
87 panic!("Unrecognised format");
88 };
89
90 const GMSH_INT_SIZE: usize = 4;
91
92 if binary_mode == "1" {
93 let data_size = data_size
94 .parse::<usize>()
95 .expect("Unable to parse data size");
96
97 assert!(
98 data_size <= std::mem::size_of::<usize>(),
99 "Unsupported data size"
100 );
101
102 let mut buf = [0u8; GMSH_INT_SIZE];
103 reader
104 .read_exact(&mut buf)
105 .expect("Unable to read endianness");
106
107 let is_le = u32::from_le_bytes(buf) == 1;
108
109 if version.starts_with("2") {
110 self.import_from_gmsh_binary_v2(reader, data_size, is_le);
111 } else {
112 self.import_from_gmsh_binary_v4(reader, data_size, is_le);
113 }
114 } else {
115 let mut content = String::new();
116 reader
117 .read_to_string(&mut content)
118 .expect("Unable to read content");
119
120 if version.starts_with("2") {
121 self.import_from_gmsh_string_v2(content);
122 } else {
123 self.import_from_gmsh_string_v4(content);
124 }
125 }
126 }
127}