extern crate cgmath;
extern crate genmesh;
use std::collections::HashSet;
use cgmath::InnerSpace;
use genmesh::{generators, EmitLines, Line, Lines, MapToVertices, Vertex};
#[derive(Debug)]
struct Edge {
dir: cgmath::Vector3<f32>,
mid: cgmath::Vector3<f32>,
nor: cgmath::Vector3<f32>,
}
impl Edge {
fn new(line: Line<Vertex>) -> Self {
let Line {
x: Vertex { pos: x, normal: nx },
y: Vertex { pos: y, normal: ny },
} = line;
Edge {
dir: cgmath::vec3(y.x - x.x, y.y - x.y, y.z - x.z),
mid: cgmath::vec3(y.x + x.x, y.y + x.y, y.z + x.z) * 0.5,
nor: cgmath::vec3(nx.x + ny.x, nx.y + ny.y, nx.z + ny.z),
}
}
fn check_to(&self, e: &Edge) {
let normal = self.dir.cross(e.dir);
let mid = (self.mid + e.mid) * 0.5;
assert!(normal.dot(mid) > 0.0 && e.nor.dot(mid) > 0.0);
}
}
fn test_outward<P, I>(poly_iter: I)
where
P: EmitLines<Vertex = Vertex> + ::std::fmt::Debug,
I: Iterator<Item = P>,
{
let mut edges = Vec::new();
for poly in poly_iter {
edges.clear();
poly.emit_lines(|l| edges.push(Edge::new(l)));
edges.last().unwrap().check_to(&edges[0]);
for (a, b) in edges.iter().zip(edges[1..].iter()) {
a.check_to(b);
}
}
}
fn test_closed<P, I>(poly_iter: I)
where
P: EmitLines<Vertex = Vertex> + ::std::fmt::Debug,
I: Iterator<Item = P>,
{
fn to_checkable(vertex: Vertex) -> [i32; 3] {
[
(vertex.pos.x * 1000000.) as i32,
(vertex.pos.y * 1000000.) as i32,
(vertex.pos.z * 1000000.) as i32,
]
}
let mut lines = HashSet::new();
for line in poly_iter.lines().vertex(to_checkable) {
if !lines.remove(&line) {
lines.insert(Line {
x: line.y,
y: line.x,
});
}
}
assert!(lines.len() == 0);
}
#[test]
fn wind_plane() {
test_outward(generators::Plane::new().vertex(|mut v| {
v.pos.z = 1.;
v
}));
test_outward(generators::Plane::subdivide(3, 4).vertex(|mut v| {
v.pos.z = 1.;
v
}));
}
#[test]
fn gen_cube() {
test_outward(generators::Cube::new());
test_closed(generators::Cube::new());
}
#[test]
fn gen_cylinder() {
test_outward(generators::Cylinder::new(5));
test_closed(generators::Cylinder::new(5));
test_outward(generators::Cylinder::subdivide(3, 4));
test_closed(generators::Cylinder::subdivide(3, 4));
}
#[test]
fn gen_sphere_uv() {
test_outward(generators::SphereUv::new(4, 3));
test_closed(generators::SphereUv::new(4, 3));
}
#[test]
fn gen_ico_sphere() {
test_outward(generators::IcoSphere::new());
test_closed(generators::IcoSphere::new());
test_outward(generators::IcoSphere::subdivide(3));
test_closed(generators::IcoSphere::subdivide(3));
}
#[test]
fn gen_cone() {
test_outward(generators::Cone::new(8));
test_closed(generators::Cone::new(8));
}
#[test]
fn gen_torus() {
test_closed(generators::Torus::new(10.0, 5.0, 8, 8));
}