use bevy::prelude::{Bundle, Commands, Component, Res, Resource, Vec3};
use bevy::utils::HashMap;
use honeycomb_core::cmap::NULL_DART_ID;
use honeycomb_core::{
cmap::{
CMap2, CMap3, DartIdType, EdgeIdType, FaceIdType, OrbitPolicy, VertexIdType, VolumeIdType,
},
geometry::CoordsFloat,
};
use itertools::Itertools;
#[derive(Resource)]
pub struct Map<T: CoordsFloat>(pub CMap2<T>);
#[derive(Resource)]
pub struct Map3<T: CoordsFloat>(pub CMap3<T>);
#[derive(Resource)]
pub struct MapVertices(pub Vec<Vec3>);
#[derive(Resource)]
pub struct FaceNormals(pub HashMap<(FaceIdType, usize), Vec3>);
#[derive(Resource)]
pub struct VolumeNormals(pub HashMap<(VolumeIdType, usize), Vec3>);
#[derive(Bundle, Clone)]
pub struct DartBundle {
pub(crate) id: DartId,
pub(crate) vertex_id: VertexId,
pub(crate) edge_id: EdgeId,
pub(crate) face_id: FaceId,
pub(crate) volume_id: VolumeId,
pub(crate) dart: Dart,
}
#[derive(Bundle, Clone)]
pub struct VertexBundle {
pub(crate) id: VertexId,
pub(crate) vertex: Vertex,
}
#[derive(Bundle, Clone)]
pub struct EdgeBundle {
pub(crate) id: EdgeId,
pub(crate) edge: Edge,
}
#[derive(Bundle, Clone)]
pub struct FaceBundle {
pub(crate) id: FaceId,
pub(crate) face: Face,
}
#[derive(Component, Clone)]
pub struct DartId(pub DartIdType);
#[derive(Component, Clone)]
pub struct VertexId(pub VertexIdType);
#[derive(Component, Clone)]
pub struct EdgeId(pub EdgeIdType);
#[derive(Component, Clone)]
pub struct FaceId(pub FaceIdType);
#[derive(Component, Clone)]
pub struct VolumeId(pub VolumeIdType);
#[derive(Component, Clone)]
pub struct Dart {
pub(crate) start: usize,
pub(crate) end: usize,
}
#[derive(Component, Clone)]
pub struct Beta(pub u8, pub usize, pub usize);
#[derive(Component, Clone)]
pub struct Vertex(pub usize);
#[derive(Component, Clone)]
pub struct Edge(pub usize, pub usize);
#[derive(Component, Clone)]
pub struct Face(pub Vec<usize>);
#[derive(Component, Clone)]
pub struct Volume;
#[allow(clippy::too_many_lines)]
pub fn extract_data_from_map<T: CoordsFloat>(mut commands: Commands, cmap: Res<Map<T>>) {
let cmap = &cmap.0;
let map_vertices: Vec<_> = cmap.iter_vertices().collect();
let map_edges: Vec<_> = cmap.iter_edges().collect();
let map_faces: Vec<_> = cmap.iter_faces().collect();
let mut index_map: HashMap<VertexIdType, usize> = HashMap::with_capacity(cmap.n_vertices());
let vertex_vals: Vec<Vec3> = map_vertices
.iter()
.enumerate()
.map(|(idx, vid)| {
index_map.insert(*vid, idx);
let v = cmap
.read_vertex(*vid)
.expect("E: found a topological vertex with no associated coordinates");
Vec3::from((v.0.to_f32().unwrap(), v.1.to_f32().unwrap(), 0.0))
})
.collect();
let vertices: Vec<VertexBundle> = map_vertices
.iter()
.map(|id| VertexBundle {
id: VertexId(*id),
vertex: Vertex(index_map[id]),
})
.collect();
let edges: Vec<EdgeBundle> = map_edges
.iter()
.map(|id| {
let v1id = cmap.vertex_id(*id as DartIdType);
let v2id = if cmap.is_i_free::<2>(*id as DartIdType) {
cmap.vertex_id(cmap.beta::<1>(*id as DartIdType))
} else {
cmap.vertex_id(cmap.beta::<2>(*id as DartIdType))
};
EdgeBundle {
id: EdgeId(*id),
edge: Edge(index_map[&v1id], index_map[&v2id]),
}
})
.collect();
let mut face_normals = HashMap::new();
let mut darts: Vec<DartBundle> = Vec::new();
let faces: Vec<FaceBundle> = map_faces
.iter()
.map(|id| {
let vertex_ids: Vec<usize> = cmap
.orbit(OrbitPolicy::Custom(&[1]), *id as DartIdType)
.map(|dart_id| index_map[&cmap.vertex_id(dart_id)])
.collect();
let n_v = vertex_ids.len();
{
let (ver_in, ver, ver_out) = (&vertex_ids[n_v - 1], &vertex_ids[0], &vertex_ids[1]);
let (vec_in, vec_out) = (
vertex_vals[*ver] - vertex_vals[*ver_in],
vertex_vals[*ver_out] - vertex_vals[*ver],
);
let normal = (vec_in.cross(Vec3::Z).normalize()
+ vec_out.cross(Vec3::Z).normalize())
.normalize();
face_normals.insert((*id, *ver), normal);
}
vertex_ids.windows(3).for_each(|wdw| {
let [ver_in, ver, ver_out] = wdw else {
unreachable!("i kneel");
};
let (vec_in, vec_out) = (
vertex_vals[*ver] - vertex_vals[*ver_in],
vertex_vals[*ver_out] - vertex_vals[*ver],
);
let normal = (vec_in.cross(Vec3::Z).normalize()
+ vec_out.cross(Vec3::Z).normalize())
.normalize();
face_normals.insert((*id, *ver), normal);
});
{
let (ver_in, ver, ver_out) =
(&vertex_ids[n_v - 2], &vertex_ids[n_v - 1], &vertex_ids[0]);
let (vec_in, vec_out) = (
vertex_vals[*ver] - vertex_vals[*ver_in],
vertex_vals[*ver_out] - vertex_vals[*ver],
);
let normal = (vec_in.cross(Vec3::Z).normalize()
+ vec_out.cross(Vec3::Z).normalize())
.normalize();
face_normals.insert((*id, *ver), normal);
}
let mut tmp = cmap
.orbit(OrbitPolicy::Custom(&[1]), *id as DartIdType)
.map(|dart_id| (dart_id, index_map[&cmap.vertex_id(dart_id)]))
.collect::<Vec<_>>();
tmp.push(tmp[0]);
let bodies = tmp.windows(2).map(|wd| {
let [(dart_id, v1_id), (_, v2_id)] = wd else {
unreachable!("i kneel");
};
DartBundle {
id: DartId(*dart_id),
vertex_id: VertexId(cmap.vertex_id(*dart_id)),
edge_id: EdgeId(cmap.edge_id(*dart_id)),
face_id: FaceId(*id),
volume_id: VolumeId(1),
dart: Dart {
start: *v1_id,
end: *v2_id,
},
}
});
darts.extend(bodies);
FaceBundle {
id: FaceId(*id),
face: Face(vertex_ids),
}
})
.collect();
commands.insert_resource(MapVertices(vertex_vals));
commands.insert_resource(FaceNormals(face_normals));
for bundle in darts {
commands.spawn(bundle);
}
for bundle in vertices {
commands.spawn(bundle);
}
for bundle in edges {
commands.spawn(bundle);
}
for bundle in faces {
commands.spawn(bundle);
}
}
#[allow(clippy::too_many_lines)]
pub fn extract_data_from_3d_map<T: CoordsFloat>(mut commands: Commands, cmap: Res<Map3<T>>) {
let cmap = &cmap.0;
let map_vertices: Vec<_> = cmap.iter_vertices().collect();
let map_edges: Vec<_> = cmap.iter_edges().collect();
let map_faces: Vec<_> = cmap.iter_faces().collect();
let map_volumes: Vec<_> = cmap.iter_volumes().collect();
let mut index_map: HashMap<VertexIdType, usize> = HashMap::with_capacity(cmap.n_vertices());
let vertex_vals: Vec<Vec3> = map_vertices
.iter()
.enumerate()
.map(|(idx, vid)| {
index_map.insert(*vid, idx);
let v = cmap
.read_vertex(*vid)
.expect("E: found a topological vertex with no associated coordinates");
Vec3::from((
v.0.to_f32().unwrap(),
v.1.to_f32().unwrap(),
v.2.to_f32().unwrap(),
))
})
.collect();
let vertices: Vec<VertexBundle> = map_vertices
.iter()
.map(|id| VertexBundle {
id: VertexId(*id),
vertex: Vertex(index_map[id]),
})
.collect();
let edges: Vec<EdgeBundle> = map_edges
.iter()
.map(|id| {
let v1id = cmap.vertex_id(*id as DartIdType);
let v2id = if cmap.is_i_free::<3>(*id as DartIdType) {
if cmap.is_i_free::<2>(*id as DartIdType) {
cmap.vertex_id(cmap.beta::<1>(*id as DartIdType))
} else {
cmap.vertex_id(cmap.beta::<2>(*id as DartIdType))
}
} else {
cmap.vertex_id(cmap.beta::<3>(*id as DartIdType))
};
EdgeBundle {
id: EdgeId(*id),
edge: Edge(index_map[&v1id], index_map[&v2id]),
}
})
.collect();
let mut face_normals = HashMap::new();
let mut darts: Vec<DartBundle> = Vec::new();
let faces: Vec<FaceBundle> = map_faces
.iter()
.map(|id| {
let vertex_ids: Vec<usize> = cmap
.orbit(OrbitPolicy::Custom(&[1]), *id as DartIdType) .map(|dart_id| index_map[&cmap.vertex_id(dart_id)])
.collect();
let n_v = vertex_ids.len();
{
let (ver_in, ver, ver_out) = (&vertex_ids[n_v - 1], &vertex_ids[0], &vertex_ids[1]);
let (vec_in, vec_out) = (
vertex_vals[*ver] - vertex_vals[*ver_in],
vertex_vals[*ver_out] - vertex_vals[*ver],
);
let plane_normal = vec_in.cross(vec_out).normalize();
let normal = (vec_in.cross(plane_normal).normalize()
+ vec_out.cross(plane_normal).normalize())
.normalize();
face_normals.insert((*id, *ver), normal);
}
vertex_ids.windows(3).for_each(|wdw| {
let [ver_in, ver, ver_out] = wdw else {
unreachable!("i kneel");
};
let (vec_in, vec_out) = (
vertex_vals[*ver] - vertex_vals[*ver_in],
vertex_vals[*ver_out] - vertex_vals[*ver],
);
let plane_normal = vec_in.cross(vec_out).normalize();
let normal = (vec_in.cross(plane_normal).normalize()
+ vec_out.cross(plane_normal).normalize())
.normalize();
face_normals.insert((*id, *ver), normal);
});
{
let (ver_in, ver, ver_out) =
(&vertex_ids[n_v - 2], &vertex_ids[n_v - 1], &vertex_ids[0]);
let (vec_in, vec_out) = (
vertex_vals[*ver] - vertex_vals[*ver_in],
vertex_vals[*ver_out] - vertex_vals[*ver],
);
let plane_normal = vec_in.cross(vec_out).normalize();
let normal = (vec_in.cross(plane_normal).normalize()
+ vec_out.cross(plane_normal).normalize())
.normalize();
face_normals.insert((*id, *ver), normal);
}
let mut tmp = cmap
.orbit(OrbitPolicy::Custom(&[1]), *id as DartIdType)
.map(|dart_id| (dart_id, index_map[&cmap.vertex_id(dart_id)]))
.collect::<Vec<_>>();
tmp.push(tmp[0]);
let bodies = tmp.windows(2).map(|wd| {
let [(dart_id, v1_id), (_, v2_id)] = wd else {
unreachable!("i kneel");
};
DartBundle {
id: DartId(*dart_id),
vertex_id: VertexId(cmap.vertex_id(*dart_id)),
edge_id: EdgeId(cmap.edge_id(*dart_id)),
face_id: FaceId(*id),
volume_id: VolumeId(cmap.volume_id(*dart_id)),
dart: Dart {
start: *v1_id,
end: *v2_id,
},
}
});
darts.extend(bodies);
let mut tmp2 = cmap
.orbit(OrbitPolicy::Custom(&[1]), cmap.beta::<3>(*id as DartIdType))
.filter_map(|dart_id| {
if dart_id == NULL_DART_ID {
return None;
}
Some((dart_id, index_map[&cmap.vertex_id(dart_id)]))
})
.collect::<Vec<_>>();
if !tmp2.is_empty() {
tmp2.push(tmp2[0]); }
let bodies2 = tmp2.windows(2).map(|wd| {
let [(dart_id, v1_id), (_, v2_id)] = wd else {
unreachable!("i kneel");
};
DartBundle {
id: DartId(*dart_id),
vertex_id: VertexId(cmap.vertex_id(*dart_id)),
edge_id: EdgeId(cmap.edge_id(*dart_id)),
face_id: FaceId(*id),
volume_id: VolumeId(cmap.volume_id(*dart_id)),
dart: Dart {
start: *v1_id,
end: *v2_id,
},
}
});
darts.extend(bodies2);
FaceBundle {
id: FaceId(*id),
face: Face(vertex_ids),
}
})
.collect();
let mut volume_normals = HashMap::new();
for vol in map_volumes {
let darts: Vec<_> = cmap.orbit(OrbitPolicy::Volume, vol as DartIdType).collect();
let norms: HashMap<_, _> = darts
.iter()
.unique_by(|&d| cmap.face_id(*d))
.map(|d| {
let mut base = Vec3::default();
let tmp: Vec<_> = cmap
.orbit(OrbitPolicy::Custom(&[1]), *d as DartIdType)
.chain([*d])
.collect();
tmp.windows(2).for_each(|sl| {
let [d1, d2] = sl else { unreachable!() };
let (vid1, vid2) = (
index_map[&cmap.vertex_id(*d1)],
index_map[&cmap.vertex_id(*d2)],
);
let (v1, v2) = (vertex_vals[vid1], vertex_vals[vid2]);
base.x += (v1.y - v2.y) * (v1.z + v2.z);
base.y += (v1.z - v2.z) * (v1.x + v2.x);
base.z += (v1.x - v2.x) * (v1.y + v2.y);
});
(cmap.face_id(*d), base.normalize())
})
.collect();
for d in darts {
let fid = cmap.face_id(d);
let vid = index_map[&cmap.vertex_id(d)];
if let Some(val) = volume_normals.get_mut(&(vol, vid)) {
*val += norms[&fid];
} else {
volume_normals.insert((vol, vid), norms[&fid]);
}
}
}
for val in volume_normals.values_mut() {
*val = val.normalize();
}
commands.insert_resource(MapVertices(vertex_vals));
commands.insert_resource(FaceNormals(face_normals));
commands.insert_resource(VolumeNormals(volume_normals));
for bundle in darts {
commands.spawn(bundle);
}
for bundle in vertices {
commands.spawn(bundle);
}
for bundle in edges {
commands.spawn(bundle);
}
for bundle in faces {
commands.spawn(bundle);
}
}