Skip to content

Instantly share code, notes, and snippets.

@swiftcoder
Last active May 11, 2019 18:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save swiftcoder/f2d7086d7ad565b59f4c130cddf555ca to your computer and use it in GitHub Desktop.
Save swiftcoder/f2d7086d7ad565b59f4c130cddf555ca to your computer and use it in GitHub Desktop.
Recursive Icosphere subdivision in rust
extern crate cgmath;
use std::collections::BTreeMap;
use cgmath::Vector3;
struct Face {
pub indices: [usize; 3],
}
impl Face {
pub fn new(indices: [usize; 3]) -> Face {
Face { indices }
}
}
struct Primitive {
vertices: Vec<Vector3<f32>>,
faces: Vec<Face>,
}
impl Primitive {
pub fn new_icosahedron() -> Primitive {
let phi = (1.0 + 5.0_f32.sqrt()) / 2.0;
let du = 1.0 / (phi * phi + 1.0).sqrt();
let dv = phi * du;
let vertices = vec![
Vector3::new(0.0, dv, du),
Vector3::new(0.0, dv, -du),
Vector3::new(0.0, -dv, du),
Vector3::new(0.0, -dv, -du),
Vector3::new(du, 0.0, dv),
Vector3::new(-du, 0.0, dv),
Vector3::new(du, 0.0, -dv),
Vector3::new(-du, 0.0, -dv),
Vector3::new(dv, du, 0.0),
Vector3::new(dv, -du, 0.0),
Vector3::new(-dv, du, 0.0),
Vector3::new(-dv, -du, 0.0),
];
let faces = vec![
Face::new([0, 1, 8]),
Face::new([0, 4, 5]),
Face::new([0, 5, 10]),
Face::new([0, 8, 4]),
Face::new([0, 10, 1]),
Face::new([1, 6, 8]),
Face::new([1, 7, 6]),
Face::new([1, 10, 7]),
Face::new([2, 3, 11]),
Face::new([2, 4, 9]),
Face::new([2, 5, 4]),
Face::new([2, 9, 3]),
Face::new([2, 11, 5]),
Face::new([3, 6, 7]),
Face::new([3, 7, 11]),
Face::new([3, 9, 6]),
Face::new([4, 8, 9]),
Face::new([5, 11, 10]),
Face::new([6, 9, 8]),
Face::new([7, 10, 11]),
];
Primitive {
vertices,
faces,
}
}
pub fn subdivide(&mut self) {
let mut edge_to_vert_mapping = BTreeMap::new();
let mut old_faces = vec![];
std::mem::swap(&mut self.faces, &mut old_faces);
for face in old_faces.iter() {
let n = face.indices.clone();
let a = self.ensure_edge_is_split(&mut edge_to_vert_mapping, n[0], n[1]);
let b = self.ensure_edge_is_split(&mut edge_to_vert_mapping, n[1], n[2]);
let c = self.ensure_edge_is_split(&mut edge_to_vert_mapping, n[2], n[0]);
self.faces.push(Face::new([n[0], a, c]));
self.faces.push(Face::new([a, n[1], b]));
self.faces.push(Face::new([c, b, n[2]]));
self.faces.push(Face::new([c, a, b]));
}
}
// splits the edge into two (creating a new vertex at the center), or returns the existing vertex if this edge was already split
fn ensure_edge_is_split(
&mut self,
edge_to_vert_mapping: &mut BTreeMap<(usize, usize), usize>,
a: usize,
b: usize,
) -> usize {
let key = ascending_order(a, b);
if !edge_to_vert_mapping.contains_key(&key) {
let n = self.vertices.len();
let p = self.vertices[a].lerp(self.vertices[b], 0.5).normalize();
self.vertices.push(p);
edge_to_vert_mapping.insert(key, n);
}
return edge_to_vert_mapping[&key];
}
}
// given a pair of numbers, returns them in ascending order
fn ascending_order(a: usize, b: usize) -> (usize, usize) {
if a < b {
return (a, b);
}
return (b, a);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment