use std::ops::{Deref, DerefMut};
use glam::Vec3;
use itertools::Itertools;
use crate::prelude::Interpolatable;
use crate::prelude::Partial;
use crate::utils::bezier::trim_quad_bezier;
use crate::utils::math::interpolate_usize;
use super::ComponentVec;
#[derive(Default, Debug, Clone, Copy, PartialEq)]
pub struct VPoint(pub Vec3);
impl From<Vec3> for VPoint {
fn from(value: Vec3) -> Self {
Self(value)
}
}
impl Deref for VPoint {
type Target = Vec3;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for VPoint {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl Interpolatable for VPoint {
fn lerp(&self, target: &Self, t: f32) -> Self {
Self(self.0.lerp(target.0, t))
}
}
impl Partial for ComponentVec<VPoint> {
fn get_partial(&self, range: std::ops::Range<f32>) -> Self {
let max_anchor_idx = self.len() / 2;
let (start_index, start_residue) = interpolate_usize(0, max_anchor_idx, range.start);
let (end_index, end_residue) = interpolate_usize(0, max_anchor_idx, range.end);
if end_index - start_index == 0 {
let seg = self.get_seg(start_index).unwrap().map(|p| p.0);
let quad = trim_quad_bezier(&seg, start_residue, end_residue);
quad.into()
} else {
let mut partial = Vec::with_capacity((end_index - start_index + 1 + 2) * 2 + 1);
let seg = self.get_seg(start_index).unwrap().map(|p| p.0);
let start_part = trim_quad_bezier(&seg, start_residue, 1.0);
partial.extend_from_slice(&start_part);
if end_index - start_index > 1 {
let mid = self
.get((start_index + 1) * 2 + 1..=end_index * 2)
.unwrap()
.iter()
.map(|p| p.0);
partial.extend(mid);
}
if end_residue != 0.0 {
let seg = self.get_seg(end_index).unwrap().map(|p| p.0);
let end_part = trim_quad_bezier(&seg, 0.0, end_residue);
partial.extend_from_slice(&end_part[1..]);
}
partial.into()
}
}
}
impl ComponentVec<VPoint> {
pub fn get_seg(&self, idx: usize) -> Option<&[VPoint; 3]> {
self.get(idx * 2..idx * 2 + 3)
.and_then(|seg| seg.try_into().ok())
}
pub fn get_closepath_flags(&self) -> Vec<bool> {
let len = self.len();
let mut flags = vec![false; len];
let mut i = 0;
for mut chunk in &self.0.iter().enumerate().skip(2).chunks(2) {
let (a, b) = (chunk.next(), chunk.next());
if let Some((ia, a)) = match (a, b) {
(Some((ia, a)), Some((_ib, b))) => {
if a == b { Some((ia, a)) } else { None }
}
(Some((ia, a)), None) => Some((ia, a)),
_ => unreachable!(),
} {
if (a.0 - self.get(i).unwrap().0).length_squared() <= 0.0001 {
flags[i..=ia].fill(true);
}
i = ia + 2;
}
}
flags
}
}
#[cfg(test)]
mod test {
use glam::vec3;
use crate::{components::ComponentVec, prelude::Partial};
use super::VPoint;
#[test]
fn test_get_partial() {
let points: ComponentVec<VPoint> = vec![
vec3(0.0, 0.0, 0.0),
vec3(1.0, 1.0, 1.0),
vec3(2.0, 2.0, 2.0),
vec3(2.0, 2.0, 2.0),
vec3(3.0, 3.0, 3.0),
vec3(4.0, 4.0, 4.0),
vec3(5.0, 5.0, 5.0),
]
.into();
let partial = points.get_partial(0.0..1.0);
assert_eq!(partial, points);
let partial = points.get_partial(0.0..0.5);
println!("{:?}", partial);
}
}