use bevy::math::Mat2;
use bevy::prelude::*;
use serde::{Deserialize, Serialize};
use super::{Transform2D, SAT};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Triangle {
verts: [Vec2; 3],
normals: [Vec2; 3],
}
impl Triangle {
pub fn new(v1: Vec2, v2: Vec2, v3: Vec2) -> Triangle {
let mut t = Triangle {
verts: [v1, v2, v3],
normals: [
(v2 - v1).perp().normalize(),
(v3 - v2).perp().normalize(),
(v1 - v2).perp().normalize()
],
};
t.validate_normals();
t
}
pub fn validate_normals(&mut self) {
let v = &self.verts;
let center = (v[0] + v[1] + v[2]) / 3.0;
let c = [
(v[1] - v[0]) * 0.5 + v[0] - center,
(v[2] - v[1]) * 0.5 + v[1] - center,
(v[0] - v[2]) * 0.5 + v[2] - center,
];
let n = &mut self.normals;
for i in 0..3 {
if n[i].dot(c[i]) < 0.0 {
n[i] = -n[i];
}
}
}
pub fn update_vert(&mut self, i: usize, nv: Vec2) {
if i > 2 {
panic!("Cannot update_vert with i = {}(as it is over 2", i);
}
self.verts[i] = nv;
self.normals[i] = (self.verts[i + 1 % 3] - self.verts[i]).perp().normalize();
self.normals[i - 1 % 3] = (self.verts[i] - self.verts[i - 1 % 3]).perp().normalize();
}
pub fn update_v1(&mut self, nv: Vec2) {
self.update_vert(0, nv);
self.validate_normals();
}
pub fn update_v2(&mut self, nv: Vec2) {
self.update_vert(1, nv);
self.validate_normals();
}
pub fn update_v3(&mut self, nv: Vec2) {
self.update_vert(2, nv);
self.validate_normals();
}
}
impl SAT for Triangle {
fn get_normals(&self, trans: &Transform2D) -> Box<dyn Iterator<Item = bevy::prelude::Vec2> + '_> {
let rot = Mat2::from_angle(trans.rotation());
Box::new(self.normals.iter().map(move |n| rot * *n))
}
fn project(&self, trans: &Transform2D, normal: Vec2) -> (f32,f32) {
let rot = Mat2::from_angle(trans.rotation());
let mut min = f32::INFINITY;
let mut max = f32::NEG_INFINITY;
for v in self.verts {
let v = rot * v + trans.translation();
let proj = v.dot(normal);
min = min.min(proj);
max = max.max(proj);
}
(min, max)
}
fn get_closest_vertex(&self, trans: &Transform2D, vertex: Vec2) -> Vec2 {
let rot = Mat2::from_angle(trans.rotation());
let mut cv = Vec2::ZERO;
let mut cls = f32::INFINITY;
for v in self.verts {
let v = rot * v + trans.translation();
let ls = (v - vertex).length_squared();
if ls < cls {
cls = ls;
cv = v;
}
}
cv
}
fn ray(&self, trans: &Transform2D, ray_origin: Vec2, ray_cast: Vec2) -> Option<f32> {
let n = ray_cast.normalize();
let p = n.perp();
let r_len = ray_cast.dot(n);
let rot = Mat2::from_angle(trans.rotation());
let mut coll = None;
for i in 0..3 {
let es = rot * self.verts[i] + trans.translation();
let ee = rot * self.verts[i + 1 % 3] + trans.translation();
let es_p = es.dot(p);
let ee_p = ee.dot(p);
let ep_min = es_p.min(ee_p);
let ep_max = es_p.max(ee_p);
let rp = ray_origin.dot(p);
if ep_min < rp && ep_max > rp {
let en_min = ee.dot(n).min(es.dot(n));
let en_max = ee.dot(n).max(es.dot(n));
let r_min = ray_origin.dot(n);
let r_max = (ray_origin + ray_cast).dot(n);
if (en_min > r_min && en_min < r_max) || (en_max > r_min && en_max < r_max) {
let t = (rp - es_p) / (ee_p - es_p);
let y = (1.0 - t) * n.dot(es) + t * n.dot(ee);
let y = y - n.dot(ray_origin);
if y <= r_len && y >= 0.0 && y < coll.unwrap_or(f32::INFINITY) {
coll = Some(y)
}
}
}
}
coll
}
}