honeycomb_render/capture/
mod.rs1pub 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
13pub struct CapturePlugin;
15
16impl Plugin for CapturePlugin {
17 fn build(&self, app: &mut App) {
18 app.insert_resource(FocusedCapture::default())
20 .insert_resource(CaptureList::default());
21 app.add_systems(Startup, populate_darts)
23 .add_systems(Startup, populate_vertices)
24 .add_systems(Startup, populate_edges);
25 }
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 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.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 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]); 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}