honeycomb_render/capture/
mod.rs

1pub mod ecs_data;
2pub mod system;
3
4use bevy::prelude::*;
5use bevy::utils::HashMap;
6use honeycomb_core::cmap::{CMap2, DartIdType, FaceIdType, Orbit2, OrbitPolicy, VertexIdType};
7use honeycomb_core::geometry::CoordsFloat;
8
9use crate::bundles::{DartBodyBundle, DartHeadBundle, EdgeBundle, FaceBundle, VertexBundle};
10use crate::capture::ecs_data::CaptureId;
11use crate::capture::system::{populate_darts, populate_edges, populate_vertices};
12
13/// Plugin handling capture data & entity generation from it.
14pub struct CapturePlugin;
15
16impl Plugin for CapturePlugin {
17    fn build(&self, app: &mut App) {
18        // resource
19        app.insert_resource(FocusedCapture::default())
20            .insert_resource(CaptureList::default());
21        // systems
22        app.add_systems(Startup, populate_darts)
23            .add_systems(Startup, populate_vertices)
24            .add_systems(Startup, populate_edges);
25        //.add_systems(Startup, populate_faces);
26    }
27}
28
29#[derive(Resource)]
30pub struct FocusedCapture(pub CaptureId);
31
32impl Default for FocusedCapture {
33    fn default() -> Self {
34        Self(CaptureId(0))
35    }
36}
37
38#[derive(Resource, Default)]
39pub struct CaptureList(pub Vec<Capture>);
40
41pub struct Capture {
42    pub metadata: CaptureMD,
43    pub vertex_vals: Vec<Vec3>,
44    pub normals: HashMap<FaceIdType, Vec<Vec3>>,
45    pub darts: Vec<(DartHeadBundle, DartBodyBundle)>,
46    pub vertices: Vec<VertexBundle>,
47    pub edges: Vec<EdgeBundle>,
48    pub faces: Vec<FaceBundle>,
49}
50
51impl Capture {
52    #[allow(clippy::too_many_lines)]
53    pub fn new<T: CoordsFloat>(cap_id: usize, cmap: &CMap2<T>) -> Self {
54        let map_vertices: Vec<_> = cmap.iter_vertices().collect();
55        let map_edges: Vec<_> = cmap.iter_edges().collect();
56        let map_faces: Vec<_> = cmap.iter_faces().collect();
57        let metadata = CaptureMD {
58            capture_id: cap_id,
59            n_darts: cmap.n_darts() - cmap.n_unused_darts(),
60            n_vertices: cmap.n_vertices(),
61            n_edges: map_edges.len(),
62            n_faces: map_faces.len(),
63            n_volumes: 0,
64        };
65
66        let mut index_map: HashMap<VertexIdType, usize> = HashMap::with_capacity(cmap.n_vertices());
67
68        let vertex_vals: Vec<Vec3> = map_vertices
69            .iter()
70            .enumerate()
71            .map(|(idx, vid)| {
72                index_map.insert(*vid, idx);
73                let v = cmap
74                    .force_read_vertex(*vid)
75                    .expect("E: found a topological vertex with no associated coordinates");
76                // sane unwraps; will crash if the coordinates cannot be converted to f32
77                Vec3::from((v.0.to_f32().unwrap(), v.1.to_f32().unwrap(), 0.0))
78            })
79            .collect();
80
81        let vertices: Vec<VertexBundle> = map_vertices
82            .iter()
83            .map(|id| VertexBundle::new(cap_id, *id, index_map[id]))
84            .collect();
85
86        let edges: Vec<EdgeBundle> = map_edges
87            .iter()
88            .map(|id| {
89                let v1id = cmap.vertex_id(*id as DartIdType);
90                let v2id = if cmap.is_i_free::<2>(*id as DartIdType) {
91                    cmap.vertex_id(cmap.beta::<1>(*id as DartIdType))
92                } else {
93                    cmap.vertex_id(cmap.beta::<2>(*id as DartIdType))
94                };
95                EdgeBundle::new(cap_id, *id, (index_map[&v1id], index_map[&v2id]))
96            })
97            .collect();
98
99        let mut normals = HashMap::new();
100        let mut darts: Vec<(DartHeadBundle, DartBodyBundle)> = Vec::new();
101
102        let faces: Vec<FaceBundle> = map_faces
103            .iter()
104            .map(|id| {
105                let vertex_ids: Vec<usize> =
106                    Orbit2::new(cmap, OrbitPolicy::Custom(&[1]), *id as DartIdType)
107                        .map(|dart_id| index_map[&cmap.vertex_id(dart_id)])
108                        .collect();
109                let n_v = vertex_ids.len();
110                let mut loc_normals = vec![{
111                    let (ver_in, ver, ver_out) =
112                        (&vertex_ids[n_v - 1], &vertex_ids[0], &vertex_ids[1]);
113                    let (vec_in, vec_out) = (
114                        vertex_vals[*ver] - vertex_vals[*ver_in],
115                        vertex_vals[*ver_out] - vertex_vals[*ver],
116                    );
117                    // vec_in/out belong to X/Y plane => .cross(Z) == normal in the plane
118                    // a firts normalization is required because both edges should weight equally
119                    (vec_in.cross(Vec3::Z).normalize() + vec_out.cross(Vec3::Z).normalize())
120                        .normalize()
121                }];
122                loc_normals.extend(vertex_ids.windows(3).map(|wdw| {
123                    let [ver_in, ver, ver_out] = wdw else {
124                        unreachable!("i kneel");
125                    };
126                    let (vec_in, vec_out) = (
127                        vertex_vals[*ver] - vertex_vals[*ver_in],
128                        vertex_vals[*ver_out] - vertex_vals[*ver],
129                    );
130                    (vec_in.cross(Vec3::Z).normalize() + vec_out.cross(Vec3::Z).normalize())
131                        .normalize()
132                }));
133                loc_normals.push({
134                    let (ver_in, ver, ver_out) =
135                        (&vertex_ids[n_v - 2], &vertex_ids[n_v - 1], &vertex_ids[0]);
136                    let (vec_in, vec_out) = (
137                        vertex_vals[*ver] - vertex_vals[*ver_in],
138                        vertex_vals[*ver_out] - vertex_vals[*ver],
139                    );
140                    (vec_in.cross(Vec3::Z).normalize() + vec_out.cross(Vec3::Z).normalize())
141                        .normalize()
142                });
143
144                assert_eq!(loc_normals.len(), n_v);
145
146                normals.insert(*id, loc_normals);
147
148                // common dart iterator
149                let mut tmp = Orbit2::new(cmap, OrbitPolicy::Custom(&[1]), *id as DartIdType)
150                    .enumerate()
151                    .map(|(idx, dart_id)| (dart_id, index_map[&cmap.vertex_id(dart_id)], idx))
152                    .collect::<Vec<_>>();
153                tmp.push(tmp[0]); // trick for the `.windows` call
154
155                // dart bodies
156                let bodies = tmp.windows(2).map(|wd| {
157                    let [(dart_id, v1_id, v1n_id), (_, v2_id, v2n_id)] = wd else {
158                        unreachable!("i kneel");
159                    };
160                    DartBodyBundle::new(
161                        cap_id,
162                        *dart_id,
163                        cmap.vertex_id(*dart_id),
164                        cmap.edge_id(*dart_id),
165                        *id,
166                        (*v1_id, *v2_id),
167                        (*v1n_id, *v2n_id),
168                    )
169                });
170
171                let heads = tmp.windows(2).map(|wd| {
172                    let [(dart_id, v1_id, v1n_id), (_, v2_id, v2n_id)] = wd else {
173                        unreachable!("i kneel");
174                    };
175                    DartHeadBundle::new(
176                        cap_id,
177                        *dart_id,
178                        cmap.vertex_id(*dart_id),
179                        cmap.edge_id(*dart_id),
180                        *id,
181                        (*v1_id, *v2_id),
182                        (*v1n_id, *v2n_id),
183                    )
184                });
185
186                darts.extend(heads.zip(bodies));
187
188                FaceBundle::new(cap_id, *id, vertex_ids)
189            })
190            .collect();
191
192        Self {
193            metadata,
194            vertex_vals,
195            normals,
196            darts,
197            vertices,
198            edges,
199            faces,
200        }
201    }
202}
203
204pub struct CaptureMD {
205    pub capture_id: usize,
206    pub n_darts: usize,
207    pub n_vertices: usize,
208    pub n_edges: usize,
209    pub n_faces: usize,
210    pub n_volumes: usize,
211}