use crate::geometry::*;
use crate::{Face, Polyhedron, VertexGraph, VertexHandle};
use petgraph::algo::all_simple_paths;
use petgraph::graph::NodeIndex;
use std::f32::consts::{FRAC_1_SQRT_2, PI};
pub fn make_tetrahedron() -> Polyhedron {
let mut graph: VertexGraph = VertexGraph::default();
let mut faces = Vec::new();
let mut nodes = Vec::new();
let vertex_positions = [
Point::new(1.0, 0.0, -FRAC_1_SQRT_2),
Point::new(-1.0, 0.0, -FRAC_1_SQRT_2),
Point::new(0.0, 1.0, FRAC_1_SQRT_2),
Point::new(0.0, -1.0, FRAC_1_SQRT_2),
];
for point in &vertex_positions {
nodes.push(graph.add_node(*point));
}
graph.update_edge(nodes[0], nodes[1], ());
graph.update_edge(nodes[0], nodes[2], ());
graph.update_edge(nodes[0], nodes[3], ());
graph.update_edge(nodes[1], nodes[2], ());
graph.update_edge(nodes[1], nodes[3], ());
graph.update_edge(nodes[2], nodes[3], ());
{
let mut create_face = |a, b, c| {
faces.push(Face::new_triangle(&[
VertexHandle::new(nodes[a]),
VertexHandle::new(nodes[b]),
VertexHandle::new(nodes[c]),
]));
};
create_face(0, 2, 3);
create_face(1, 3, 2);
create_face(2, 0, 1);
create_face(3, 1, 0);
}
let poly = Polyhedron { graph, faces };
debug_assert_eq!(poly.faces.len(), 4);
debug_assert_eq!(poly.assert_consistency(), Ok(()));
poly
}
pub fn make_cube() -> Polyhedron {
let mut graph: VertexGraph = VertexGraph::default();
let mut faces = Vec::new();
let mut nodes = Vec::new();
let vertex_positions = [
Point::new(1.0, 1.0, 1.0),
Point::new(1.0, -1.0, 1.0),
Point::new(-1.0, -1.0, 1.0),
Point::new(-1.0, 1.0, 1.0),
Point::new(1.0, 1.0, -1.0),
Point::new(1.0, -1.0, -1.0),
Point::new(-1.0, -1.0, -1.0),
Point::new(-1.0, 1.0, -1.0),
];
for point in &vertex_positions {
nodes.push(graph.add_node(*point));
}
graph.update_edge(nodes[0], nodes[1], ());
graph.update_edge(nodes[1], nodes[2], ());
graph.update_edge(nodes[2], nodes[3], ());
graph.update_edge(nodes[3], nodes[0], ());
graph.update_edge(nodes[4], nodes[5], ());
graph.update_edge(nodes[5], nodes[6], ());
graph.update_edge(nodes[6], nodes[7], ());
graph.update_edge(nodes[7], nodes[4], ());
graph.update_edge(nodes[0], nodes[4], ());
graph.update_edge(nodes[1], nodes[5], ());
graph.update_edge(nodes[2], nodes[6], ());
graph.update_edge(nodes[3], nodes[7], ());
{
let mut create_face = |a, b, c, d| {
faces.push(Face::new(&[
VertexHandle::new(nodes[a]),
VertexHandle::new(nodes[b]),
VertexHandle::new(nodes[c]),
VertexHandle::new(nodes[d]),
]));
};
create_face(0, 1, 2, 3);
create_face(0, 1, 5, 4);
create_face(1, 2, 6, 5);
create_face(2, 3, 7, 6);
create_face(3, 0, 4, 7);
create_face(4, 5, 6, 7);
}
let poly = Polyhedron { graph, faces };
debug_assert_eq!(poly.faces.len(), 6);
debug_assert_eq!(poly.assert_consistency(), Ok(()));
poly
}
pub fn make_octahedron() -> Polyhedron {
let mut graph: VertexGraph = VertexGraph::default();
let mut faces = Vec::new();
let mut nodes = Vec::new();
let vertex_positions = [
Point::new(1.0, 0.0, 0.0),
Point::new(0.0, -1.0, 0.0),
Point::new(-1.0, 0.0, 0.0),
Point::new(0.0, 1.0, 0.0),
Point::new(0.0, 0.0, 1.0),
Point::new(0.0, 0.0, -1.0),
];
for point in &vertex_positions {
nodes.push(graph.add_node(*point));
}
graph.update_edge(nodes[4], nodes[0], ());
graph.update_edge(nodes[4], nodes[1], ());
graph.update_edge(nodes[4], nodes[2], ());
graph.update_edge(nodes[4], nodes[3], ());
graph.update_edge(nodes[5], nodes[0], ());
graph.update_edge(nodes[5], nodes[1], ());
graph.update_edge(nodes[5], nodes[2], ());
graph.update_edge(nodes[5], nodes[3], ());
graph.update_edge(nodes[0], nodes[1], ());
graph.update_edge(nodes[1], nodes[2], ());
graph.update_edge(nodes[2], nodes[3], ());
graph.update_edge(nodes[3], nodes[0], ());
{
let mut create_face = |a, b, c| {
faces.push(Face::new_triangle(&[
VertexHandle::new(nodes[a]),
VertexHandle::new(nodes[b]),
VertexHandle::new(nodes[c]),
]));
};
create_face(4, 0, 1);
create_face(4, 1, 2);
create_face(4, 2, 3);
create_face(4, 3, 0);
create_face(5, 1, 0);
create_face(5, 2, 1);
create_face(5, 3, 2);
create_face(5, 0, 3);
}
let poly = Polyhedron { graph, faces };
debug_assert_eq!(poly.faces.len(), 8);
debug_assert_eq!(poly.assert_consistency(), Ok(()));
poly
}
pub fn make_dodecahedron() -> Polyhedron {
let mut graph: VertexGraph = VertexGraph::default();
let mut faces = Vec::new();
let mut nodes = Vec::new();
let h = (-1.0 + 5.0_f32.sqrt()) * 0.5;
let h2 = h * h;
let vertex_positions = [
Point::new(1.0, 1.0, 1.0),
Point::new(1.0, -1.0, 1.0),
Point::new(-1.0, -1.0, 1.0),
Point::new(-1.0, 1.0, 1.0),
Point::new(1.0, 1.0, -1.0),
Point::new(1.0, -1.0, -1.0),
Point::new(-1.0, -1.0, -1.0),
Point::new(-1.0, 1.0, -1.0),
Point::new(0.0, 1.0 + h, 1.0 - h2),
Point::new(0.0, -(1.0 + h), 1.0 - h2),
Point::new(0.0, 1.0 + h, -(1.0 - h2)),
Point::new(0.0, -(1.0 + h), -(1.0 - h2)),
Point::new(1.0 + h, 1.0 - h2, 0.0),
Point::new(-(1.0 + h), 1.0 - h2, 0.0),
Point::new(1.0 + h, -(1.0 - h2), 0.0),
Point::new(-(1.0 + h), -(1.0 - h2), 0.0),
Point::new(1.0 - h2, 0.0, 1.0 + h),
Point::new(1.0 - h2, 0.0, -(1.0 + h)),
Point::new(-(1.0 - h2), 0.0, 1.0 + h),
Point::new(-(1.0 - h2), 0.0, -(1.0 + h)),
];
for point in &vertex_positions {
nodes.push(graph.add_node(*point));
}
graph.update_edge(nodes[0], nodes[12], ());
graph.update_edge(nodes[0], nodes[16], ());
graph.update_edge(nodes[0], nodes[8], ());
graph.update_edge(nodes[1], nodes[14], ());
graph.update_edge(nodes[1], nodes[16], ());
graph.update_edge(nodes[1], nodes[9], ());
graph.update_edge(nodes[2], nodes[15], ());
graph.update_edge(nodes[2], nodes[18], ());
graph.update_edge(nodes[2], nodes[9], ());
graph.update_edge(nodes[3], nodes[13], ());
graph.update_edge(nodes[3], nodes[18], ());
graph.update_edge(nodes[3], nodes[8], ());
graph.update_edge(nodes[4], nodes[10], ());
graph.update_edge(nodes[4], nodes[12], ());
graph.update_edge(nodes[4], nodes[17], ());
graph.update_edge(nodes[5], nodes[11], ());
graph.update_edge(nodes[5], nodes[14], ());
graph.update_edge(nodes[5], nodes[17], ());
graph.update_edge(nodes[6], nodes[11], ());
graph.update_edge(nodes[6], nodes[15], ());
graph.update_edge(nodes[6], nodes[19], ());
graph.update_edge(nodes[7], nodes[10], ());
graph.update_edge(nodes[7], nodes[13], ());
graph.update_edge(nodes[7], nodes[19], ());
graph.update_edge(nodes[8], nodes[10], ());
graph.update_edge(nodes[9], nodes[11], ());
graph.update_edge(nodes[12], nodes[14], ());
graph.update_edge(nodes[13], nodes[15], ());
graph.update_edge(nodes[16], nodes[18], ());
graph.update_edge(nodes[17], nodes[19], ());
{
let mut create_face = |a, b, c, d, e| {
faces.push(Face::new(&[
VertexHandle::new(nodes[a]),
VertexHandle::new(nodes[b]),
VertexHandle::new(nodes[c]),
VertexHandle::new(nodes[d]),
VertexHandle::new(nodes[e]),
]));
};
create_face(0, 8, 10, 4, 12);
create_face(0, 8, 3, 18, 16);
create_face(0, 12, 14, 1, 16);
create_face(1, 9, 11, 5, 14);
create_face(1, 9, 2, 18, 16);
create_face(2, 9, 11, 6, 15);
create_face(2, 18, 3, 13, 15);
create_face(3, 8, 10, 7, 13);
create_face(4, 17, 19, 7, 10);
create_face(4, 17, 5, 14, 12);
create_face(5, 17, 19, 6, 11);
create_face(6, 19, 7, 13, 15);
}
for node in nodes {
let face_path: Vec<Vec<NodeIndex>> =
all_simple_paths(&graph, node, node, 4, Some(4)).collect();
for face in &face_path {
println!("{:?}", face);
}
}
let poly = Polyhedron { graph, faces };
debug_assert_eq!(poly.faces.len(), 12);
debug_assert_eq!(poly.assert_consistency(), Ok(()));
poly
}
pub fn make_icosahedron() -> Polyhedron {
let mut graph: VertexGraph = VertexGraph::default();
let mut faces = Vec::new();
let c1 = (2.0_f32 * PI / 5.0).cos();
let c2 = (1.0_f32 * PI / 5.0).cos();
let s1 = (2.0_f32 * PI / 5.0).sin();
let s2 = (4.0_f32 * PI / 5.0).sin();
let h = 0.5_f32.atan().sin();
let vertex_positions = [
Point::new(0.0, 0.0, 1.0),
Point::new(0.0, 0.0, -1.0),
Point::new(0.0, -1.0, h),
Point::new(s1, -c1, h),
Point::new(s2, c2, h),
Point::new(-s2, c2, h),
Point::new(-s1, -c1, h),
Point::new(s2, -c2, -h),
Point::new(s1, c1, -h),
Point::new(0.0, 1.0, -h),
Point::new(-s1, c1, -h),
Point::new(-s2, -c2, -h),
];
let mut nodes = Vec::new();
for point in &vertex_positions {
nodes.push(graph.add_node(*point));
}
{
let vertex_top = &nodes[0];
let vertex_bottom = &nodes[1];
let pentagon_top = &nodes[2..(2 + 5)];
let pentagon_bottom = &nodes[7..(7 + 5)];
{
let mut connect_poles = |pentagon: &[NodeIndex], pole_vertex: &NodeIndex| {
for (i, vertex) in pentagon.iter().enumerate() {
let neighbor_l_index = (5 + i - 1) % 5;
let neighbor_l = pentagon[neighbor_l_index];
graph.update_edge(*vertex, neighbor_l, ());
graph.update_edge(*vertex, *pole_vertex, ());
let face = Face::new_triangle(&[
VertexHandle::new(*vertex),
VertexHandle::new(neighbor_l),
VertexHandle::new(*pole_vertex),
]);
faces.push(face);
}
};
connect_poles(pentagon_top, vertex_top);
connect_poles(pentagon_bottom, vertex_bottom);
}
for (i, vertex) in pentagon_bottom.iter().enumerate() {
let neighbor_bottom = pentagon_bottom[(5 + i - 1) % 5];
let neighbor_top = pentagon_top[i];
graph.update_edge(*vertex, neighbor_top, ());
faces.push(Face::new_triangle(&[
VertexHandle::new(*vertex),
VertexHandle::new(neighbor_top),
VertexHandle::new(neighbor_bottom),
]));
}
for (i, vertex) in pentagon_top.iter().enumerate() {
let neighbor_top = pentagon_top[(5 + i - 1) % 5];
let neighbor_bottom = pentagon_bottom[(5 + i - 1) % 5];
graph.update_edge(*vertex, neighbor_bottom, ());
faces.push(Face::new_triangle(&[
VertexHandle::new(*vertex),
VertexHandle::new(neighbor_top),
VertexHandle::new(neighbor_bottom),
]));
}
}
let poly = Polyhedron { graph, faces };
debug_assert_eq!(poly.faces.len(), 20);
debug_assert_eq!(poly.assert_consistency(), Ok(()));
poly
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_icosahedron_face_edge_consistency() {
for _i in 0..5 {
let poly = make_icosahedron();
for face in poly.faces.iter() {
for (v1, v2) in face.edges().iter() {
assert_ne!(
poly.graph.find_edge_undirected(v1.ix, v2.ix),
None,
"Found invalid edge: ({:?}, {:?}) in face",
v1,
v2
);
}
}
}
}
#[test]
fn test_icosahedron_creation() {
let ico = make_icosahedron();
assert!(
ico.assert_consistency().is_ok(),
"{:?}",
ico.assert_consistency()
);
}
}