use smallvec::*;
use std::ops::*;
pub trait Coordinate : Sized+Copy+Add<Self, Output=Self>+Mul<f64, Output=Self>+Sub<Self, Output=Self>+PartialEq {
fn from_components(components: &[f64]) -> Self;
fn origin() -> Self;
fn len() -> usize;
fn get(&self, index: usize) -> f64;
fn from_biggest_components(p1: Self, p2: Self) -> Self;
fn from_smallest_components(p1: Self, p2: Self) -> Self;
#[inline]
fn distance_to(&self, target: &Self) -> f64 {
let offset = *self - *target;
let squared_distance = offset.dot(&offset);
f64::sqrt(squared_distance)
}
#[inline]
fn dot(&self, target: &Self) -> f64 {
let mut dot_product = 0.0;
for component_index in 0..Self::len() {
dot_product += self.get(component_index) * target.get(component_index);
}
dot_product
}
#[inline]
fn magnitude(&self) -> f64 {
f64::sqrt(self.dot(self))
}
#[inline]
fn to_unit_vector(&self) -> Self {
let magnitude = self.magnitude();
if magnitude == 0.0 {
Self::origin()
} else {
*self * (1.0/magnitude)
}
}
#[inline]
fn is_nan(&self) -> bool {
for component in 0..Self::len() {
if self.get(component).is_nan() {
return true;
}
}
false
}
#[inline]
fn round(self, accuracy: f64) -> Self {
let mut new_components: SmallVec<[_; 4]> = smallvec![];
for component in 0..Self::len() {
let unrounded_value = self.get(component);
let rounded_value = (unrounded_value/accuracy).round() * accuracy;
new_components.push(rounded_value);
}
Self::from_components(&new_components)
}
#[inline]
fn is_near_to(&self, other: &Self, max_distance: f64) -> bool {
let offset = *self - *other;
let squared_distance = offset.dot(&offset);
squared_distance <= (max_distance*max_distance)
}
fn smooth(points: &[Self], weights: &[f64]) -> Vec<Self> {
let mut smoothed = vec![];
let points_len = points.len() as i32;
let weight_len = weights.len() as i32;
let weight_offset = weight_len/2;
for index in 0..points_len {
let mut res = Self::origin();
let initial_pos = index - weight_offset;
for weight_pos in 0..weight_len {
let weight = weights[weight_pos as usize];
let source_pos = initial_pos + weight_pos;
let source_val = if source_pos < 0 {
&points[0]
} else if source_pos >= points_len {
&points[(points_len-1) as usize]
} else {
&points[source_pos as usize]
};
res = res + (*source_val * weight);
}
smoothed.push(res);
}
smoothed
}
}
pub trait Coordinate2D {
fn x(&self) -> f64;
fn y(&self) -> f64;
#[inline]
fn coords(&self) -> (f64, f64) { (self.x(), self.y()) }
}
pub trait Coordinate3D {
fn x(&self) -> f64;
fn y(&self) -> f64;
fn z(&self) -> f64;
}