use crate::math_segment::distance_point_to_line;
use glam::Vec2;
const CORNER_THRESHOLD: f32 = 0.0871557;
pub(crate) fn is_corner(v1: Vec2, v2: Vec2) -> bool {
v1.dot(v2) <= 0. || cross(v1.normalize(), v2.normalize()).abs() > CORNER_THRESHOLD
}
pub(crate) fn are_very_close_points(a: Vec2, b: Vec2) -> bool {
a.distance_squared(b) <= 1e-6
}
pub fn flatten_quad(
p: [Vec2; 3],
split_at_deviation: f32,
to_seg: &mut impl FnMut(Vec2, Vec2, Vec2),
) {
let [p0, p1, p2] = p;
let p01 = p0.midpoint(p1);
let p12 = p1.midpoint(p2);
let mid = p01.midpoint(p12);
if !flat_enough_quad(p0, p01, mid, split_at_deviation) {
flatten_quad([p0, p01, mid], split_at_deviation, to_seg);
} else {
to_seg(p0, p01, mid);
}
if !flat_enough_quad(mid, p12, p2, split_at_deviation) {
flatten_quad([mid, p12, p2], split_at_deviation, to_seg);
} else {
to_seg(mid, p12, p2);
}
}
pub fn flatten_cube(
p: [Vec2; 4],
split_at_deviation: f32,
to_seg: &mut impl FnMut(Vec2, Vec2, Vec2),
) {
let [p0, p1, p2, p3] = p;
if flat_enough_cube(p0, p1, p2, p3, split_at_deviation) {
let (q0, q1, q2) = approx_cubic_as_quad(p0, p1, p2, p3);
to_seg(q0, q1, q2);
return;
}
let (p01, p012, mid, p123, p23) = split_cube(p0, p1, p2, p3);
flatten_cube([p0, p01, p012, mid], split_at_deviation, to_seg);
flatten_cube([mid, p123, p23, p3], split_at_deviation, to_seg);
}
fn approx_cubic_as_quad(p0: Vec2, p1: Vec2, p2: Vec2, p3: Vec2) -> (Vec2, Vec2, Vec2) {
let q0 = p0;
let q2 = p3;
let q1 = (-p0 + 3. * p1 + 3. * p2 - p3) / 4.;
(q0, q1, q2)
}
fn flat_enough_quad(p0: Vec2, p1: Vec2, p2: Vec2, split_at_deviation: f32) -> bool {
let d = distance_point_to_line(p1, p0, p2);
d <= split_at_deviation
}
fn flat_enough_cube(p0: Vec2, p1: Vec2, p2: Vec2, p3: Vec2, split_at_deviation: f32) -> bool {
let q1 = (-p0 + 3.0 * p1 + 3.0 * p2 - p3) * 0.25;
let d_q1 = distance_point_to_line(q1, p0, p3);
let d_p1 = distance_point_to_line(p1, p0, p3);
let d_p2 = distance_point_to_line(p2, p0, p3);
let delta3 = p3 - 3.0 * p2 + 3.0 * p1 - p0;
let approx_error = delta3.length() * (1.0 / 20.8);
let chord_threshold = split_at_deviation * 0.0625;
d_q1.max(d_p1).max(d_p2) <= chord_threshold && approx_error <= split_at_deviation
}
pub(crate) fn split_cube(p0: Vec2, p1: Vec2, p2: Vec2, p3: Vec2) -> (Vec2, Vec2, Vec2, Vec2, Vec2) {
let p01 = p0.midpoint(p1);
let p12 = p1.midpoint(p2);
let p23 = p2.midpoint(p3);
let p012 = p01.midpoint(p12);
let p123 = p12.midpoint(p23);
let mid = p012.midpoint(p123);
(p01, p012, mid, p123, p23)
}
pub(crate) fn cross(v1: Vec2, v2: Vec2) -> f32 {
v1.x * v2.y - v1.y * v2.x
}