1use std::{
26 collections::HashMap,
27 hash::{Hash, Hasher},
28};
29
30use crate::*;
31
32pub fn to_words_skip_empty(line: &[u8]) -> impl Iterator<Item = &[u8]> {
36 line.split(|x| *x == b' ' || *x == b'\t').skip_empty()
37}
38
39pub fn until<'a>(line: &'a str, delimiter: &str) -> &'a str {
41 line.split(delimiter).next().unwrap_or("")
42}
43
44pub fn until_bytes<'a>(line: &'a [u8], delimiter: u8) -> &'a [u8] {
46 line.split(|x| *x == delimiter).next().unwrap_or(&[])
47}
48
49pub fn max_f64(a: f64, b: f64) -> f64 {
51 if a > b {
52 return a;
53 }
54 b
55}
56
57pub fn contains<T>(haystack: &[T], needle: &[T]) -> bool
59where
60 T: PartialEq,
61{
62 haystack.windows(needle.len()).any(|x| x == needle)
63}
64
65pub fn max_f64_3(a: f64, b: f64, c: f64) -> f64 {
67 max_f64(max_f64(a, b), c)
68}
69
70#[inline(always)]
72pub fn hash_f64<H>(x: f64, state: &mut H)
73where
74 H: Hasher,
75{
76 x.to_bits().hash(state);
77}
78
79pub fn pack_dupes_indexed<'a, I, T>(idata: I) -> (Vec<T>, Vec<usize>)
81where
82 I: Iterator<Item = &'a T>,
83 T: 'a + Eq + Hash + Clone,
84{
85 let mut map = HashMap::new();
86 let mut packed_data = Vec::new();
87 let mut ids = Vec::new();
88 for x in idata {
89 let id = map.entry(x).or_insert_with(|| {
90 let value = packed_data.len();
91 packed_data.push(x.clone());
92 value
93 });
94 ids.push(*id);
95 }
96
97 (packed_data, ids)
98}
99
100pub fn normals_of_mesh<P, M>(mesh: &M) -> Vec<Norm3D>
102where
103 M: IsMesh<P, Face3>,
104 P: IsBuildable3D + Default + Clone,
105{
106 let n = mesh.num_vertices();
107 let nf = mesh.num_faces();
108 let mut ns = vec![P::default(); n];
109
110 for i in 0..nf {
111 let face = mesh.face_vertex_ids(FId { val: i }).unwrap(); let [v1, v2, v3] = mesh.face_vertices(FId { val: i }).unwrap(); let v12 = conn(&v1, &v2);
114 let v13 = conn(&v1, &v3);
115 let n = Norm3D::new(cross(&v12, &v13)).unwrap_or(Norm3D::norm_z());
116 for j in 0..3 {
117 let new = add(&ns[face.vid(j).unwrap().val], &n); ns[face.vid(j).unwrap().val] = new; }
120 }
121
122 ns.into_iter()
123 .map(|x| Norm3D::new(x).unwrap_or(Norm3D::norm_z()))
124 .collect()
125}
126
127pub fn estimate_delimiter(minimum_count: usize, line: &[u8]) -> Option<u8> {
129 for candidate in [b' ', b';', b',', b'\t'].iter() {
130 if line.iter().filter(|c| **c == *candidate).count() >= minimum_count {
131 return Some(*candidate);
132 }
133 }
134 None
135}
136
137pub fn add<P, Q>(p: &P, q: &Q) -> P
139where
140 P: IsBuildable3D,
141 Q: Is3D,
142{
143 P::new(p.x() + q.x(), p.y() + q.y(), p.z() + q.z())
144}