use crate::math::{Isometry, Point, Real, Vector};
use crate::na::ComplexField;
#[cfg(feature = "dim3")]
use {crate::math::DIM, num::Zero};
pub fn transform(points: &mut [Point<Real>], m: Isometry<Real>) {
points.iter_mut().for_each(|p| *p = m * *p);
}
pub fn transformed(mut points: Vec<Point<Real>>, m: Isometry<Real>) -> Vec<Point<Real>> {
transform(&mut points, m);
points
}
pub fn scaled(mut points: Vec<Point<Real>>, scale: Vector<Real>) -> Vec<Point<Real>> {
points
.iter_mut()
.for_each(|p| p.coords.component_mul_assign(&scale));
points
}
#[cfg(feature = "dim3")]
#[inline]
pub fn push_circle(radius: Real, nsubdiv: u32, dtheta: Real, y: Real, out: &mut Vec<Point<Real>>) {
let mut curr_theta = Real::zero();
for _ in 0..nsubdiv {
out.push(Point::new(
ComplexField::cos(curr_theta) * radius,
y,
ComplexField::sin(curr_theta) * radius,
));
curr_theta += dtheta;
}
}
#[inline]
#[cfg(feature = "dim2")]
pub fn push_xy_arc(radius: Real, nsubdiv: u32, dtheta: Real, out: &mut Vec<Point<Real>>) {
let mut curr_theta: Real = 0.0;
for _ in 0..nsubdiv {
let mut pt_coords = Vector::zeros();
pt_coords[0] = ComplexField::cos(curr_theta) * radius;
pt_coords[1] = ComplexField::sin(curr_theta) * radius;
out.push(Point::from(pt_coords));
curr_theta += dtheta;
}
}
#[cfg(feature = "dim3")]
#[inline]
pub fn push_ring_indices(
base_lower_circle: u32,
base_upper_circle: u32,
nsubdiv: u32,
out: &mut Vec<[u32; DIM]>,
) {
push_open_ring_indices(base_lower_circle, base_upper_circle, nsubdiv, out);
push_rectangle_indices(
base_upper_circle,
base_upper_circle + nsubdiv - 1,
base_lower_circle,
base_lower_circle + nsubdiv - 1,
out,
);
}
#[cfg(feature = "dim3")]
#[inline]
pub fn push_open_ring_indices(
base_lower_circle: u32,
base_upper_circle: u32,
nsubdiv: u32,
out: &mut Vec<[u32; DIM]>,
) {
assert!(nsubdiv > 0);
for i in 0..nsubdiv - 1 {
let bli = base_lower_circle + i;
let bui = base_upper_circle + i;
push_rectangle_indices(bui + 1, bui, bli + 1, bli, out);
}
}
#[cfg(feature = "dim3")]
#[inline]
pub fn push_degenerate_top_ring_indices(
base_circle: u32,
point: u32,
nsubdiv: u32,
out: &mut Vec<[u32; DIM]>,
) {
push_degenerate_open_top_ring_indices(base_circle, point, nsubdiv, out);
out.push([base_circle + nsubdiv - 1, point, base_circle]);
}
#[cfg(feature = "dim3")]
#[inline]
pub fn push_degenerate_open_top_ring_indices(
base_circle: u32,
point: u32,
nsubdiv: u32,
out: &mut Vec<[u32; DIM]>,
) {
assert!(nsubdiv > 0);
for i in 0..nsubdiv - 1 {
out.push([base_circle + i, point, base_circle + i + 1]);
}
}
#[cfg(feature = "dim3")]
#[inline]
pub fn push_filled_circle_indices(base_circle: u32, nsubdiv: u32, out: &mut Vec<[u32; DIM]>) {
for i in base_circle + 1..base_circle + nsubdiv - 1 {
out.push([base_circle, i, i + 1]);
}
}
#[cfg(feature = "dim3")]
#[inline]
pub fn push_rectangle_indices(ul: u32, ur: u32, dl: u32, dr: u32, out: &mut Vec<[u32; DIM]>) {
out.push([ul, dl, dr]);
out.push([dr, ur, ul]);
}
#[cfg(feature = "dim3")]
#[inline]
pub fn reverse_clockwising(indices: &mut [[u32; DIM]]) {
indices.iter_mut().for_each(|idx| idx.swap(0, 1));
}
#[cfg(feature = "dim3")]
#[inline]
pub fn push_circle_outline_indices(indices: &mut Vec<[u32; 2]>, range: std::ops::Range<u32>) {
indices.extend((range.start..range.end - 1).map(|i| [i, i + 1]));
indices.push([range.end - 1, range.start]);
}
#[cfg(feature = "dim3")]
#[inline]
pub fn push_open_circle_outline_indices(indices: &mut Vec<[u32; 2]>, range: std::ops::Range<u32>) {
indices.extend((range.start..range.end - 1).map(|i| [i, i + 1]));
}
#[cfg(feature = "dim3")]
pub fn push_arc_and_idx(
center: Point<Real>,
start: u32,
end: u32,
nsubdivs: u32,
out_vtx: &mut Vec<Point<Real>>,
out_idx: &mut Vec<[u32; 2]>,
) {
let base = out_vtx.len() as u32;
push_arc(
center,
out_vtx[start as usize],
out_vtx[end as usize],
nsubdivs,
out_vtx,
);
push_arc_idx(start, base..base + nsubdivs - 1, end, out_idx);
}
pub fn push_arc(
center: Point<Real>,
start: Point<Real>,
end: Point<Real>,
nsubdivs: u32,
out: &mut Vec<Point<Real>>,
) {
assert!(nsubdivs > 0);
if let (Some((start_dir, start_len)), Some((end_dir, end_len))) = (
na::Unit::try_new_and_get(start - center, 0.0),
na::Unit::try_new_and_get(end - center, 0.0),
) {
let len_inc = (end_len - start_len) / nsubdivs as Real;
#[cfg(feature = "dim2")]
let rot = Some(na::UnitComplex::scaled_rotation_between_axis(
&start_dir,
&end_dir,
1.0 / nsubdivs as Real,
));
#[cfg(feature = "dim3")]
let rot = na::UnitQuaternion::scaled_rotation_between_axis(
&start_dir,
&end_dir,
1.0 / nsubdivs as Real,
);
if let Some(rot) = rot {
let mut curr_dir = start_dir;
let mut curr_len = start_len;
for _ in 0..nsubdivs - 1 {
curr_dir = rot * curr_dir;
curr_len += len_inc;
out.push(center + *curr_dir * curr_len);
}
}
}
}
#[cfg(feature = "dim3")]
pub fn push_arc_idx(start: u32, arc: std::ops::Range<u32>, end: u32, out: &mut Vec<[u32; 2]>) {
if arc.is_empty() {
out.push([start, end]);
} else {
out.push([start, arc.start]);
for i in arc.start..arc.end - 1 {
out.push([i, i + 1])
}
out.push([arc.end - 1, end])
}
}
#[cfg(feature = "dim3")]
pub fn apply_revolution(
collapse_bottom: bool,
collapse_top: bool,
circle_ranges: &[std::ops::Range<u32>],
nsubdivs: u32,
out_vtx: &mut Vec<Point<Real>>, out_idx: &mut Vec<[u32; 2]>,
) {
use na::RealField;
let ang_increment = Real::two_pi() / (nsubdivs as Real);
let angles = [
ang_increment * (nsubdivs / 4) as Real,
ang_increment * (nsubdivs / 2) as Real,
ang_increment * ((3 * nsubdivs) / 4) as Real,
];
let half_profile_len = out_vtx.len();
for k in 0..half_profile_len as u32 - 1 {
out_idx.push([k, k + 1]);
}
let mut range = 0..half_profile_len;
if collapse_bottom {
range.start += 1;
}
if collapse_top {
range.end -= 1;
}
for angle in angles {
let base = out_vtx.len() as u32;
let rot = na::UnitQuaternion::new(Vector::y() * angle);
if collapse_bottom {
out_idx.push([0, base]);
}
for k in range.clone() {
out_vtx.push(rot * out_vtx[k]);
}
for k in 0..range.len() as u32 - 1 {
out_idx.push([base + k, base + k + 1]);
}
if collapse_top {
out_idx.push([base + range.len() as u32 - 1, half_profile_len as u32 - 1]);
}
}
for circle_range in circle_ranges {
for i in circle_range.clone() {
let pt = out_vtx[i as usize];
let base = out_vtx.len() as u32;
push_circle(
pt.coords.xz().norm(),
nsubdivs,
ang_increment,
pt.y,
out_vtx,
);
push_circle_outline_indices(out_idx, base..base + nsubdivs)
}
}
}