use na;
use na::{Pnt3, Vec3, Pnt2, BaseFloat};
use super::{Polyline, TriMesh, IndexBuffer};
use super::utils;
use math::{Scalar, Point, Vect};
pub fn sphere<N>(diameter: N,
ntheta_subdiv: u32,
nphi_subdiv: u32,
generate_uvs: bool)
-> TriMesh<Pnt3<N>>
where N: Scalar {
let mut sphere = unit_sphere(ntheta_subdiv, nphi_subdiv, generate_uvs);
sphere.scale_by_scalar(diameter);
sphere
}
pub fn unit_sphere<N>(ntheta_subdiv: u32,
nphi_subdiv: u32,
generate_uvs: bool)
-> TriMesh<Pnt3<N>>
where N: Scalar {
if generate_uvs {
unit_sphere_with_uvs(ntheta_subdiv, nphi_subdiv)
}
else {
unit_sphere_without_uvs(ntheta_subdiv, nphi_subdiv)
}
}
fn unit_sphere_without_uvs<N>(ntheta_subdiv: u32, nphi_subdiv: u32) -> TriMesh<Pnt3<N>>
where N: Scalar {
let pi: N = BaseFloat::pi();
let two_pi: N = BaseFloat::two_pi();
let pi_two: N = BaseFloat::frac_pi_2();
let dtheta = two_pi / na::cast(ntheta_subdiv as f64);
let dphi = pi / na::cast(nphi_subdiv as f64);
let mut coords = Vec::new();
let mut curr_phi = -pi_two + dphi;
coords.push(Pnt3::new(na::zero(), -na::one::<N>(), na::zero()));
for _ in 0 .. nphi_subdiv - 1 {
utils::push_circle(curr_phi.cos(), ntheta_subdiv, dtheta, curr_phi.sin(), &mut coords);
curr_phi = curr_phi + dphi;
}
coords.push(Pnt3::new(na::zero(), na::one(), na::zero()));
let normals: Vec<Vec3<N>> = coords.iter().map(|p| p.as_vec().clone()).collect();
let mut idx = Vec::new();
utils::push_degenerate_top_ring_indices(1, 0, ntheta_subdiv, &mut idx);
utils::reverse_clockwising(&mut idx[..]);
for i in 0 .. nphi_subdiv - 2 {
let bottom = 1 + i * ntheta_subdiv;
let up = bottom + ntheta_subdiv;
utils::push_ring_indices(bottom, up, ntheta_subdiv, &mut idx);
}
utils::push_degenerate_top_ring_indices(1 + (nphi_subdiv - 2) * ntheta_subdiv,
coords.len() as u32 - 1,
ntheta_subdiv,
&mut idx);
let mut res = TriMesh::new(coords, Some(normals), None, Some(IndexBuffer::Unified(idx)));
let _0_5: N = na::cast(0.5);
res.scale_by_scalar(_0_5);
res
}
fn unit_sphere_with_uvs<N>(ntheta_subdiv: u32, nphi_subdiv: u32) -> TriMesh<Pnt3<N>>
where N: Scalar {
let pi: N = BaseFloat::pi();
let two_pi: N = BaseFloat::two_pi();
let pi_two: N = BaseFloat::frac_pi_2();
let duvtheta = na::one::<N>() / na::cast(ntheta_subdiv as f64); let duvphi = na::one::<N>() / na::cast(nphi_subdiv as f64); let dtheta = two_pi * duvtheta;
let dphi = pi * duvphi;
let mut coords = Vec::new();
let mut curr_phi = -pi_two;
for _ in 0 .. nphi_subdiv + 1 {
utils::push_circle(curr_phi.cos(), ntheta_subdiv + 1, dtheta, curr_phi.sin(), &mut coords);
curr_phi = curr_phi + dphi;
}
let normals: Vec<Vec3<N>> = coords.iter().map(|p| p.as_vec().clone()).collect();
let mut idx = Vec::new();
for i in 0 .. nphi_subdiv {
let bottom = i * (ntheta_subdiv + 1);
let up = bottom + (ntheta_subdiv + 1);
utils::push_open_ring_indices(bottom, up, ntheta_subdiv + 1, &mut idx);
}
let mut uvs = Vec::new();
let mut curr_uvphi = na::zero::<N>();
for _ in 0 .. nphi_subdiv + 1 {
let mut curr_uvtheta = na::zero::<N>();
for _ in 0 .. ntheta_subdiv + 1 {
uvs.push(Pnt2::new(curr_uvtheta, curr_uvphi));
curr_uvtheta = curr_uvtheta + duvtheta;
}
curr_uvphi = curr_uvphi + duvphi;
}
let mut res = TriMesh::new(coords, Some(normals), Some(uvs), Some(IndexBuffer::Unified(idx)));
let _0_5: N = na::cast(0.5);
res.scale_by_scalar(_0_5);
res
}
pub fn unit_hemisphere<N>(ntheta_subdiv: u32, nphi_subdiv: u32) -> TriMesh<Pnt3<N>>
where N: Scalar {
let two_pi: N = BaseFloat::two_pi();
let pi_two: N = BaseFloat::frac_pi_2();
let dtheta = two_pi / na::cast(ntheta_subdiv as f64);
let dphi = pi_two / na::cast(nphi_subdiv as f64);
let mut coords = Vec::new();
let mut curr_phi = na::zero::<N>();
for _ in 0 .. nphi_subdiv - 1 {
utils::push_circle(curr_phi.cos(), ntheta_subdiv, dtheta, curr_phi.sin(), &mut coords);
curr_phi = curr_phi + dphi;
}
coords.push(Pnt3::new(na::zero(), na::one(), na::zero()));
let mut idx = Vec::new();
for i in 0 .. nphi_subdiv - 2 {
utils::push_ring_indices(i * ntheta_subdiv, (i + 1) * ntheta_subdiv, ntheta_subdiv, &mut idx);
}
utils::push_degenerate_top_ring_indices((nphi_subdiv - 2) * ntheta_subdiv,
coords.len() as u32 - 1,
ntheta_subdiv,
&mut idx);
let normals: Vec<Vec3<N>> = coords.iter().map(|p| p.as_vec().clone()).collect();
let mut out = TriMesh::new(coords, Some(normals), None, Some(IndexBuffer::Unified(idx)));
let _0_5: N = na::cast(0.5);
out.scale_by_scalar(_0_5);
out
}
pub fn circle<P>(diameter: &<P::Vect as Vect>::Scalar, nsubdivs: u32) -> Polyline<P>
where P: Point {
let two_pi: <P::Vect as Vect>::Scalar = BaseFloat::two_pi();
let dtheta = two_pi / na::cast(nsubdivs as f64);
let mut pts = Vec::with_capacity(nsubdivs as usize);
utils::push_xy_arc(*diameter / na::cast(2.0), nsubdivs, dtheta, &mut pts);
Polyline::new(pts, None)
}
pub fn unit_circle<P>(nsubdivs: u32) -> Polyline<P>
where P: Point {
circle::<P>(&na::cast(1.0), nsubdivs)
}