Skip to main content

oxihuman_export/
brep_export.rs

1// Copyright (C) 2026 COOLJAPAN OU (Team KitaSan)
2// SPDX-License-Identifier: Apache-2.0
3#![allow(dead_code)]
4
5//! B-Rep topology export stub.
6
7/// A B-Rep vertex.
8#[derive(Debug, Clone)]
9pub struct BRepVertex {
10    pub id: u32,
11    pub position: [f64; 3],
12}
13
14/// A B-Rep edge (connects two vertex ids).
15#[derive(Debug, Clone)]
16pub struct BRepEdge {
17    pub id: u32,
18    pub v0: u32,
19    pub v1: u32,
20}
21
22/// A B-Rep face (a list of edge ids forming the boundary loop).
23#[derive(Debug, Clone)]
24pub struct BRepFace {
25    pub id: u32,
26    pub edges: Vec<u32>,
27    pub normal: [f64; 3],
28}
29
30/// B-Rep topology export.
31#[derive(Debug, Clone, Default)]
32pub struct BRepExport {
33    pub vertices: Vec<BRepVertex>,
34    pub edges: Vec<BRepEdge>,
35    pub faces: Vec<BRepFace>,
36}
37
38/// Create an empty B-Rep export.
39pub fn new_brep_export() -> BRepExport {
40    BRepExport::default()
41}
42
43/// Add a vertex; returns its id.
44pub fn add_brep_vertex(export: &mut BRepExport, position: [f64; 3]) -> u32 {
45    let id = export.vertices.len() as u32;
46    export.vertices.push(BRepVertex { id, position });
47    id
48}
49
50/// Add an edge; returns its id.
51pub fn add_brep_edge(export: &mut BRepExport, v0: u32, v1: u32) -> u32 {
52    let id = export.edges.len() as u32;
53    export.edges.push(BRepEdge { id, v0, v1 });
54    id
55}
56
57/// Add a face; returns its id.
58pub fn add_brep_face(export: &mut BRepExport, edges: Vec<u32>, normal: [f64; 3]) -> u32 {
59    let id = export.faces.len() as u32;
60    export.faces.push(BRepFace { id, edges, normal });
61    id
62}
63
64/// Validate that all edge vertex references exist.
65pub fn validate_brep(export: &BRepExport) -> bool {
66    let nv = export.vertices.len() as u32;
67    export.edges.iter().all(|e| e.v0 < nv && e.v1 < nv)
68        && export.faces.iter().all(|f| {
69            let ne = export.edges.len() as u32;
70            f.edges.iter().all(|&eid| eid < ne)
71        })
72}
73
74/// Compute the Euler characteristic V - E + F.
75pub fn euler_characteristic(export: &BRepExport) -> i32 {
76    export.vertices.len() as i32 - export.edges.len() as i32 + export.faces.len() as i32
77}
78
79#[cfg(test)]
80mod tests {
81    use super::*;
82
83    fn simple_quad() -> BRepExport {
84        let mut exp = new_brep_export();
85        let v0 = add_brep_vertex(&mut exp, [0.0, 0.0, 0.0]);
86        let v1 = add_brep_vertex(&mut exp, [1.0, 0.0, 0.0]);
87        let v2 = add_brep_vertex(&mut exp, [1.0, 1.0, 0.0]);
88        let v3 = add_brep_vertex(&mut exp, [0.0, 1.0, 0.0]);
89        let e0 = add_brep_edge(&mut exp, v0, v1);
90        let e1 = add_brep_edge(&mut exp, v1, v2);
91        let e2 = add_brep_edge(&mut exp, v2, v3);
92        let e3 = add_brep_edge(&mut exp, v3, v0);
93        add_brep_face(&mut exp, vec![e0, e1, e2, e3], [0.0, 0.0, 1.0]);
94        exp
95    }
96
97    #[test]
98    fn test_vertex_count() {
99        let exp = simple_quad();
100        assert_eq!(exp.vertices.len(), 4);
101    }
102
103    #[test]
104    fn test_edge_count() {
105        let exp = simple_quad();
106        assert_eq!(exp.edges.len(), 4);
107    }
108
109    #[test]
110    fn test_face_count() {
111        let exp = simple_quad();
112        assert_eq!(exp.faces.len(), 1);
113    }
114
115    #[test]
116    fn test_validate_simple_quad() {
117        assert!(validate_brep(&simple_quad()));
118    }
119
120    #[test]
121    fn test_euler_characteristic_quad() {
122        /* V=4, E=4, F=1 → χ = 1 */
123        let exp = simple_quad();
124        assert_eq!(euler_characteristic(&exp), 1);
125    }
126
127    #[test]
128    fn test_add_vertex_ids_sequential() {
129        let mut exp = new_brep_export();
130        let a = add_brep_vertex(&mut exp, [0.0; 3]);
131        let b = add_brep_vertex(&mut exp, [1.0; 3]);
132        assert_eq!(a, 0);
133        assert_eq!(b, 1);
134    }
135
136    #[test]
137    fn test_validate_empty() {
138        assert!(validate_brep(&new_brep_export()));
139    }
140
141    #[test]
142    fn test_add_edge_ids_sequential() {
143        let mut exp = new_brep_export();
144        add_brep_vertex(&mut exp, [0.0; 3]);
145        add_brep_vertex(&mut exp, [1.0; 3]);
146        let e0 = add_brep_edge(&mut exp, 0, 1);
147        let e1 = add_brep_edge(&mut exp, 1, 0);
148        assert_eq!(e0, 0);
149        assert_eq!(e1, 1);
150    }
151
152    #[test]
153    fn test_face_normal_stored() {
154        let mut exp = new_brep_export();
155        let v0 = add_brep_vertex(&mut exp, [0.0; 3]);
156        let v1 = add_brep_vertex(&mut exp, [1.0; 3]);
157        let e0 = add_brep_edge(&mut exp, v0, v1);
158        let normal = [0.0, 1.0, 0.0];
159        add_brep_face(&mut exp, vec![e0], normal);
160        assert_eq!(exp.faces[0].normal, normal);
161    }
162}