session_rust/
mesh.rs

1use crate::{Color, Point, Tolerance, Vector, Xform};
2use serde::{Deserialize, Serialize};
3use std::collections::{HashMap, HashSet};
4
5/// Weighting scheme for vertex normal computation
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
7pub enum NormalWeighting {
8    Area,
9    Angle,
10    Uniform,
11}
12
13/// A halfedge mesh data structure for representing polygonal surfaces
14#[derive(Debug, Clone, Serialize, Deserialize)]
15#[serde(tag = "type", rename = "Mesh")]
16pub struct Mesh {
17    pub halfedge: HashMap<usize, HashMap<usize, Option<usize>>>, // Halfedge connectivity
18    pub vertex: HashMap<usize, VertexData>,                      // Vertex data
19    pub face: HashMap<usize, Vec<usize>>,                        // Face vertex lists
20    pub facedata: HashMap<usize, HashMap<String, f32>>,          // Face attributes
21    pub edgedata: HashMap<(usize, usize), HashMap<String, f32>>, // Edge attributes
22    pub default_vertex_attributes: HashMap<String, f32>,         // Default vertex attrs
23    pub default_face_attributes: HashMap<String, f32>,           // Default face attrs
24    pub default_edge_attributes: HashMap<String, f32>,           // Default edge attrs
25    #[serde(skip)]
26    pub triangulation: HashMap<usize, Vec<[usize; 3]>>, // Cached triangulations
27    max_vertex: usize,                                           // Next vertex key
28    max_face: usize,                                             // Next face key
29    pub guid: String,                                            // Unique identifier
30    pub name: String,                                            // Mesh name
31    #[serde(skip)]
32    pub pointcolors: Vec<Color>,               // Vertex colors
33    #[serde(skip)]
34    pub facecolors: Vec<Color>,                // Face colors
35    #[serde(skip)]
36    pub linecolors: Vec<Color>,                // Edge colors
37    #[serde(skip)]
38    pub widths: Vec<f32>,                      // Edge widths
39    #[serde(default = "Xform::identity")]
40    pub xform: Xform,   // Transformation matrix
41}
42
43/// Vertex data containing position and attributes
44#[derive(Debug, Clone, Serialize, Deserialize)]
45pub struct VertexData {
46    pub x: f32,                           // X coordinate
47    pub y: f32,                           // Y coordinate
48    pub z: f32,                           // Z coordinate
49    pub attributes: HashMap<String, f32>, // Vertex attributes
50}
51
52impl VertexData {
53    pub fn new(point: Point) -> Self {
54        Self {
55            x: point.x(),
56            y: point.y(),
57            z: point.z(),
58            attributes: HashMap::new(),
59        }
60    }
61
62    pub fn position(&self) -> Point {
63        Point::new(self.x, self.y, self.z)
64    }
65
66    pub fn set_position(&mut self, point: Point) {
67        self.x = point.x();
68        self.y = point.y();
69        self.z = point.z();
70    }
71
72    pub fn color(&self) -> [f32; 3] {
73        [
74            self.attributes.get("r").copied().unwrap_or(0.5),
75            self.attributes.get("g").copied().unwrap_or(0.5),
76            self.attributes.get("b").copied().unwrap_or(0.5),
77        ]
78    }
79
80    pub fn set_color(&mut self, r: f32, g: f32, b: f32) {
81        self.attributes.insert("r".to_string(), r);
82        self.attributes.insert("g".to_string(), g);
83        self.attributes.insert("b".to_string(), b);
84    }
85
86    pub fn normal(&self) -> Option<[f32; 3]> {
87        let nx = self.attributes.get("nx")?;
88        let ny = self.attributes.get("ny")?;
89        let nz = self.attributes.get("nz")?;
90        Some([*nx, *ny, *nz])
91    }
92
93    pub fn set_normal(&mut self, nx: f32, ny: f32, nz: f32) {
94        self.attributes.insert("nx".to_string(), nx);
95        self.attributes.insert("ny".to_string(), ny);
96        self.attributes.insert("nz".to_string(), nz);
97    }
98}
99
100impl Default for Mesh {
101    fn default() -> Self {
102        Self::new()
103    }
104}
105
106impl Mesh {
107    /// Creates a new empty halfedge mesh
108    pub fn new() -> Self {
109        let mut default_vertex_attributes = HashMap::new();
110        default_vertex_attributes.insert("x".to_string(), 0.0);
111        default_vertex_attributes.insert("y".to_string(), 0.0);
112        default_vertex_attributes.insert("z".to_string(), 0.0);
113
114        Mesh {
115            halfedge: HashMap::new(),
116            vertex: HashMap::new(),
117            face: HashMap::new(),
118            facedata: HashMap::new(),
119            edgedata: HashMap::new(),
120            default_vertex_attributes,
121            default_face_attributes: HashMap::new(),
122            default_edge_attributes: HashMap::new(),
123            triangulation: HashMap::new(),
124            max_vertex: 0,
125            max_face: 0,
126            guid: uuid::Uuid::new_v4().to_string(),
127            name: "my_mesh".to_string(),
128            pointcolors: Vec::new(),
129            facecolors: Vec::new(),
130            linecolors: Vec::new(),
131            widths: Vec::new(),
132            xform: Xform::identity(),
133        }
134    }
135
136    pub fn is_empty(&self) -> bool {
137        self.vertex.is_empty() && self.face.is_empty()
138    }
139
140    pub fn clear(&mut self) {
141        self.halfedge.clear();
142        self.vertex.clear();
143        self.face.clear();
144        self.facedata.clear();
145        self.edgedata.clear();
146        self.triangulation.clear();
147        self.max_vertex = 0;
148        self.max_face = 0;
149        self.pointcolors.clear();
150        self.facecolors.clear();
151        self.linecolors.clear();
152        self.widths.clear();
153    }
154
155    pub fn number_of_vertices(&self) -> usize {
156        self.vertex.len()
157    }
158
159    pub fn number_of_faces(&self) -> usize {
160        self.face.len()
161    }
162
163    pub fn number_of_edges(&self) -> usize {
164        let mut seen = HashSet::new();
165        let mut count = 0;
166
167        for u in self.halfedge.keys() {
168            if let Some(neighbors) = self.halfedge.get(u) {
169                for v in neighbors.keys() {
170                    let edge = if u < v { (*u, *v) } else { (*v, *u) };
171                    if seen.insert(edge) {
172                        count += 1;
173                    }
174                }
175            }
176        }
177
178        count
179    }
180
181    pub fn euler(&self) -> i32 {
182        let v = self.number_of_vertices() as i32;
183        let e = self.number_of_edges() as i32;
184        let f = self.number_of_faces() as i32;
185        v - e + f
186    }
187
188    pub fn add_vertex(&mut self, position: Point, key: Option<usize>) -> usize {
189        let vertex_key = key.unwrap_or_else(|| {
190            self.max_vertex += 1;
191            self.max_vertex
192        });
193
194        if vertex_key >= self.max_vertex {
195            self.max_vertex = vertex_key + 1;
196        }
197
198        let vertex_data = VertexData::new(position);
199        self.vertex.insert(vertex_key, vertex_data);
200        self.halfedge.entry(vertex_key).or_default();
201        self.pointcolors.push(Color::white());
202
203        vertex_key
204    }
205
206    pub fn add_face(&mut self, vertices: Vec<usize>, fkey: Option<usize>) -> Option<usize> {
207        if vertices.len() < 3 {
208            return None;
209        }
210
211        if !vertices.iter().all(|v| self.vertex.contains_key(v)) {
212            return None;
213        }
214
215        let mut unique_vertices = HashSet::new();
216        for vertex in &vertices {
217            if !unique_vertices.insert(*vertex) {
218                return None;
219            }
220        }
221
222        let face_key = fkey.unwrap_or_else(|| {
223            self.max_face += 1;
224            self.max_face
225        });
226
227        if face_key >= self.max_face {
228            self.max_face = face_key + 1;
229        }
230
231        self.face.insert(face_key, vertices.clone());
232        self.triangulation.remove(&face_key);
233        self.facecolors.push(Color::white());
234
235        for i in 0..vertices.len() {
236            let u = vertices[i];
237            let v = vertices[(i + 1) % vertices.len()];
238
239            self.halfedge.entry(u).or_default();
240            self.halfedge.entry(v).or_default();
241
242            let is_new_edge = !self.halfedge.get(&v).unwrap().contains_key(&u);
243
244            self.halfedge.get_mut(&u).unwrap().insert(v, Some(face_key));
245
246            if is_new_edge {
247                self.halfedge.get_mut(&v).unwrap().insert(u, None);
248                self.linecolors.push(Color::white());
249                self.widths.push(1.0);
250            }
251        }
252
253        Some(face_key)
254    }
255
256    pub fn vertex_position(&self, vertex_key: usize) -> Option<Point> {
257        self.vertex.get(&vertex_key).map(|v| v.position())
258    }
259
260    pub fn face_vertices(&self, face_key: usize) -> Option<&Vec<usize>> {
261        self.face.get(&face_key)
262    }
263
264    pub fn vertex_neighbors(&self, vertex_key: usize) -> Vec<usize> {
265        self.halfedge
266            .get(&vertex_key)
267            .map(|neighbors| neighbors.keys().copied().collect())
268            .unwrap_or_default()
269    }
270
271    pub fn vertex_faces(&self, vertex_key: usize) -> Vec<usize> {
272        let mut faces = Vec::new();
273        for (face_key, face_vertices) in &self.face {
274            if face_vertices.contains(&vertex_key) {
275                faces.push(*face_key);
276            }
277        }
278        faces
279    }
280
281    pub fn is_vertex_on_boundary(&self, vertex_key: usize) -> bool {
282        if let Some(neigh) = self.halfedge.get(&vertex_key) {
283            for (_v, face_opt) in neigh.iter() {
284                if face_opt.is_none() {
285                    return true;
286                }
287            }
288        }
289
290        for (_u, neigh) in self.halfedge.iter() {
291            if let Some(face_opt) = neigh.get(&vertex_key) {
292                if face_opt.is_none() {
293                    return true;
294                }
295            }
296        }
297        false
298    }
299
300    pub fn face_normal(&self, face_key: usize) -> Option<Vector> {
301        let vertices = self.face.get(&face_key)?;
302        if vertices.len() < 3 {
303            return None;
304        }
305
306        let p0 = self.vertex_position(vertices[0])?;
307        let p1 = self.vertex_position(vertices[1])?;
308        let p2 = self.vertex_position(vertices[2])?;
309
310        let u = Vector::new(p1.x() - p0.x(), p1.y() - p0.y(), p1.z() - p0.z());
311        let v = Vector::new(p2.x() - p0.x(), p2.y() - p0.y(), p2.z() - p0.z());
312
313        let mut normal = u.cross(&v);
314        let len = normal.magnitude();
315        if len > Tolerance::ZERO_TOLERANCE as f32 {
316            Some(Vector::new(
317                normal.x() / len,
318                normal.y() / len,
319                normal.z() / len,
320            ))
321        } else {
322            None
323        }
324    }
325
326    pub fn vertex_normal(&self, vertex_key: usize) -> Option<Vector> {
327        self.vertex_normal_weighted(vertex_key, NormalWeighting::Area)
328    }
329
330    pub fn vertex_normal_weighted(
331        &self,
332        vertex_key: usize,
333        weighting: NormalWeighting,
334    ) -> Option<Vector> {
335        let faces = self.vertex_faces(vertex_key);
336        if faces.is_empty() {
337            return None;
338        }
339
340        let mut normal_acc = Vector::new(0.0, 0.0, 0.0);
341
342        for face_key in faces {
343            if let Some(face_normal) = self.face_normal(face_key) {
344                let weight = match weighting {
345                    NormalWeighting::Area => self.face_area(face_key).unwrap_or(1.0),
346                    NormalWeighting::Angle => self
347                        .vertex_angle_in_face(vertex_key, face_key)
348                        .unwrap_or(1.0),
349                    NormalWeighting::Uniform => 1.0,
350                };
351
352                normal_acc.set_x(normal_acc.x() + face_normal.x() * weight);
353                normal_acc.set_y(normal_acc.y() + face_normal.y() * weight);
354                normal_acc.set_z(normal_acc.z() + face_normal.z() * weight);
355            }
356        }
357
358        let len = normal_acc.magnitude();
359        if len > Tolerance::ZERO_TOLERANCE as f32 {
360            Some(Vector::new(
361                normal_acc.x() / len,
362                normal_acc.y() / len,
363                normal_acc.z() / len,
364            ))
365        } else {
366            None
367        }
368    }
369
370    pub fn face_area(&self, face_key: usize) -> Option<f32> {
371        let vertices = self.face.get(&face_key)?;
372        if vertices.len() < 3 {
373            return Some(0.0);
374        }
375
376        let mut area = 0.0;
377        let p0 = self.vertex_position(vertices[0])?;
378
379        for i in 1..(vertices.len() - 1) {
380            let p1 = self.vertex_position(vertices[i])?;
381            let p2 = self.vertex_position(vertices[i + 1])?;
382
383            let u = Vector::new(p1.x() - p0.x(), p1.y() - p0.y(), p1.z() - p0.z());
384            let v = Vector::new(p2.x() - p0.x(), p2.y() - p0.y(), p2.z() - p0.z());
385
386            area += u.cross(&v).magnitude() * 0.5;
387        }
388
389        Some(area)
390    }
391
392    pub fn vertex_angle_in_face(&self, vertex_key: usize, face_key: usize) -> Option<f32> {
393        let vertices = self.face.get(&face_key)?;
394        let vertex_index = vertices.iter().position(|&v| v == vertex_key)?;
395
396        let n = vertices.len();
397        let prev_vertex = vertices[(vertex_index + n - 1) % n];
398        let next_vertex = vertices[(vertex_index + 1) % n];
399
400        let center = self.vertex_position(vertex_key)?;
401        let prev_pos = self.vertex_position(prev_vertex)?;
402        let next_pos = self.vertex_position(next_vertex)?;
403
404        let mut u = Vector::new(
405            prev_pos.x() - center.x(),
406            prev_pos.y() - center.y(),
407            prev_pos.z() - center.z(),
408        );
409        let mut v = Vector::new(
410            next_pos.x() - center.x(),
411            next_pos.y() - center.y(),
412            next_pos.z() - center.z(),
413        );
414
415        let u_len = u.magnitude();
416        let v_len = v.magnitude();
417
418        if u_len < Tolerance::ZERO_TOLERANCE as f32 || v_len < Tolerance::ZERO_TOLERANCE as f32 {
419            return Some(0.0);
420        }
421
422        let cos_angle = u.dot(&v) / (u_len * v_len);
423        let cos_angle = cos_angle.clamp(-1.0, 1.0);
424        Some(cos_angle.acos())
425    }
426
427    pub fn face_normals(&self) -> HashMap<usize, Vector> {
428        let mut normals = HashMap::new();
429        for face_key in self.face.keys() {
430            if let Some(normal) = self.face_normal(*face_key) {
431                normals.insert(*face_key, normal);
432            }
433        }
434        normals
435    }
436
437    pub fn vertex_normals(&self) -> HashMap<usize, Vector> {
438        self.vertex_normals_weighted(NormalWeighting::Area)
439    }
440
441    pub fn vertex_normals_weighted(&self, weighting: NormalWeighting) -> HashMap<usize, Vector> {
442        let mut normals = HashMap::new();
443        for vertex_key in self.vertex.keys() {
444            if let Some(normal) = self.vertex_normal_weighted(*vertex_key, weighting) {
445                normals.insert(*vertex_key, normal);
446            }
447        }
448        normals
449    }
450
451    pub fn vertex_index(&self) -> HashMap<usize, usize> {
452        let mut keys: Vec<usize> = self.vertex.keys().copied().collect();
453        keys.sort();
454        keys.iter()
455            .enumerate()
456            .map(|(index, &key)| (key, index))
457            .collect()
458    }
459
460    pub fn to_vertices_and_faces(&self) -> (Vec<Point>, Vec<Vec<usize>>) {
461        let vertex_index = self.vertex_index();
462        let mut vertices: Vec<Point> = vec![Point::default(); self.vertex.len()];
463
464        for (&key, data) in &self.vertex {
465            let idx = vertex_index[&key];
466            vertices[idx] = data.position();
467        }
468
469        // Sort face keys to ensure consistent ordering
470        let mut face_keys: Vec<usize> = self.face.keys().copied().collect();
471        face_keys.sort();
472
473        let mut faces = Vec::new();
474        for face_key in face_keys {
475            let face_vertices = &self.face[&face_key];
476            let remapped: Vec<usize> = face_vertices.iter().map(|v| vertex_index[v]).collect();
477            faces.push(remapped);
478        }
479
480        (vertices, faces)
481    }
482
483    pub fn from_polygons(polygons: Vec<Vec<Point>>, precision: Option<f32>) -> Self {
484        let mut mesh = Mesh::new();
485        let mut map_eps: HashMap<(i64, i64, i64), usize> = HashMap::new();
486        let mut map_exact: HashMap<(u64, u64, u64), usize> = HashMap::new();
487        let eps = precision.unwrap_or(0.0);
488        let use_eps = eps > 0.0;
489
490        let mut get_vkey = |p: &Point, mesh: &mut Mesh| -> usize {
491            if use_eps {
492                let kx = (p.x() / eps).round() as i64;
493                let ky = (p.y() / eps).round() as i64;
494                let kz = (p.z() / eps).round() as i64;
495                let key = (kx, ky, kz);
496                if let Some(&vk) = map_eps.get(&key) {
497                    return vk;
498                }
499                let vk = mesh.add_vertex(p.clone(), None);
500                map_eps.insert(key, vk);
501                vk
502            } else {
503                let key = (
504                    p.x().to_bits() as u64,
505                    p.y().to_bits() as u64,
506                    p.z().to_bits() as u64,
507                );
508                if let Some(&vk) = map_exact.get(&key) {
509                    return vk;
510                }
511                let vk = mesh.add_vertex(p.clone(), None);
512                map_exact.insert(key, vk);
513                vk
514            }
515        };
516
517        for poly in polygons.into_iter() {
518            if poly.len() < 3 {
519                continue;
520            }
521            let mut vkeys: Vec<usize> = Vec::with_capacity(poly.len());
522            for p in &poly {
523                let vk = get_vkey(p, &mut mesh);
524                vkeys.push(vk);
525            }
526            let _ = mesh.add_face(vkeys, None);
527        }
528
529        mesh
530    }
531
532    ///////////////////////////////////////////////////////////////////////////////////////////
533    // Color and Width Management
534    ///////////////////////////////////////////////////////////////////////////////////////////
535
536    pub fn set_vertex_color(&mut self, index: usize, color: Color) {
537        if index < self.pointcolors.len() {
538            self.pointcolors[index] = color;
539        }
540    }
541
542    pub fn set_face_color(&mut self, index: usize, color: Color) {
543        if index < self.facecolors.len() {
544            self.facecolors[index] = color;
545        }
546    }
547
548    pub fn set_edge_color(&mut self, index: usize, color: Color) {
549        if index < self.linecolors.len() {
550            self.linecolors[index] = color;
551        }
552    }
553
554    pub fn set_edge_width(&mut self, index: usize, width: f32) {
555        if index < self.widths.len() {
556            self.widths[index] = width;
557        }
558    }
559
560    ///////////////////////////////////////////////////////////////////////////////////////////
561    // JSON
562    ///////////////////////////////////////////////////////////////////////////////////////////
563
564    /// Serializes the Mesh to JSON data
565    pub fn jsondump(&self) -> serde_json::Value {
566        let pointcolors_flat: Vec<u8> = self
567            .pointcolors
568            .iter()
569            .flat_map(|c| vec![c.r, c.g, c.b])
570            .collect();
571
572        let facecolors_flat: Vec<u8> = self
573            .facecolors
574            .iter()
575            .flat_map(|c| vec![c.r, c.g, c.b])
576            .collect();
577
578        let linecolors_flat: Vec<u8> = self
579            .linecolors
580            .iter()
581            .flat_map(|c| vec![c.r, c.g, c.b])
582            .collect();
583
584        serde_json::json!({
585            "type": "Mesh",
586            "guid": self.guid,
587            "name": self.name,
588            "vertex": self.vertex,
589            "face": self.face,
590            "halfedge": self.halfedge,
591            "facedata": self.facedata,
592            "edgedata": self.edgedata,
593            "default_vertex_attributes": self.default_vertex_attributes,
594            "default_face_attributes": self.default_face_attributes,
595            "default_edge_attributes": self.default_edge_attributes,
596            "max_vertex": self.max_vertex,
597            "max_face": self.max_face,
598            "pointcolors": pointcolors_flat,
599            "facecolors": facecolors_flat,
600            "linecolors": linecolors_flat,
601            "widths": self.widths
602        })
603    }
604
605    pub fn jsonload(data: &serde_json::Value) -> Option<Self> {
606        let mut mesh = Mesh::new();
607
608        if let Some(guid) = data.get("guid").and_then(|v| v.as_str()) {
609            mesh.guid = guid.to_string();
610        }
611        if let Some(name) = data.get("name").and_then(|v| v.as_str()) {
612            mesh.name = name.to_string();
613        }
614
615        if let Some(vertex_data) = data.get("vertex") {
616            mesh.vertex = serde_json::from_value(vertex_data.clone()).ok()?;
617        }
618        if let Some(face_data) = data.get("face") {
619            mesh.face = serde_json::from_value(face_data.clone()).ok()?;
620        }
621        if let Some(halfedge_data) = data.get("halfedge") {
622            mesh.halfedge = serde_json::from_value(halfedge_data.clone()).ok()?;
623        }
624        if let Some(facedata) = data.get("facedata") {
625            mesh.facedata = serde_json::from_value(facedata.clone()).ok()?;
626        }
627        if let Some(edgedata) = data.get("edgedata") {
628            mesh.edgedata = serde_json::from_value(edgedata.clone()).ok()?;
629        }
630        if let Some(max_vertex) = data.get("max_vertex").and_then(|v| v.as_u64()) {
631            mesh.max_vertex = max_vertex as usize;
632        }
633        if let Some(max_face) = data.get("max_face").and_then(|v| v.as_u64()) {
634            mesh.max_face = max_face as usize;
635        }
636
637        // Deserialize flat color arrays
638        if let Some(pointcolors_flat) = data.get("pointcolors").and_then(|v| v.as_array()) {
639            let rgb_values: Vec<u8> = pointcolors_flat
640                .iter()
641                .filter_map(|v| v.as_u64().map(|n| n as u8))
642                .collect();
643            mesh.pointcolors = rgb_values
644                .chunks(3)
645                .map(|chunk| {
646                    if chunk.len() == 3 {
647                        Color::new(chunk[0], chunk[1], chunk[2], 255)
648                    } else {
649                        Color::white()
650                    }
651                })
652                .collect();
653        }
654
655        if let Some(facecolors_flat) = data.get("facecolors").and_then(|v| v.as_array()) {
656            let rgb_values: Vec<u8> = facecolors_flat
657                .iter()
658                .filter_map(|v| v.as_u64().map(|n| n as u8))
659                .collect();
660            mesh.facecolors = rgb_values
661                .chunks(3)
662                .map(|chunk| {
663                    if chunk.len() == 3 {
664                        Color::new(chunk[0], chunk[1], chunk[2], 255)
665                    } else {
666                        Color::white()
667                    }
668                })
669                .collect();
670        }
671
672        if let Some(linecolors_flat) = data.get("linecolors").and_then(|v| v.as_array()) {
673            let rgb_values: Vec<u8> = linecolors_flat
674                .iter()
675                .filter_map(|v| v.as_u64().map(|n| n as u8))
676                .collect();
677            mesh.linecolors = rgb_values
678                .chunks(3)
679                .map(|chunk| {
680                    if chunk.len() == 3 {
681                        Color::new(chunk[0], chunk[1], chunk[2], 255)
682                    } else {
683                        Color::white()
684                    }
685                })
686                .collect();
687        }
688
689        if let Some(widths) = data.get("widths").and_then(|v| v.as_array()) {
690            mesh.widths = widths
691                .iter()
692                .filter_map(|v| v.as_f64().map(|n| n as f32))
693                .collect();
694        }
695
696        Some(mesh)
697    }
698
699    pub fn to_json(&self, filename: &str) -> std::io::Result<()> {
700        let data = self.jsondump();
701        std::fs::write(filename, serde_json::to_string_pretty(&data)?)
702    }
703
704    pub fn from_json(filename: &str) -> std::io::Result<Self> {
705        let content = std::fs::read_to_string(filename)?;
706        let data: serde_json::Value = serde_json::from_str(&content)?;
707        Self::jsonload(&data).ok_or_else(|| {
708            std::io::Error::new(std::io::ErrorKind::InvalidData, "Invalid mesh data")
709        })
710    }
711}
712
713#[cfg(test)]
714#[path = "mesh_test.rs"]
715mod mesh_test;