#![allow(dead_code)]
use tess2_rust::{ElementType, Tessellator, WindingRule};
pub fn parse_contours(data: &str) -> Vec<Vec<f64>> {
let mut contours: Vec<Vec<f64>> = Vec::new();
let mut current: Vec<f64> = Vec::new();
for line in data.lines() {
let trimmed = line.trim();
if trimmed.is_empty() {
if !current.is_empty() {
contours.push(std::mem::take(&mut current));
}
continue;
}
let floats: Vec<f64> = trimmed
.split(|c: char| c == ',' || c.is_whitespace())
.filter(|s| !s.is_empty())
.filter_map(|s| s.parse::<f64>().ok())
.collect();
current.extend(floats);
}
if !current.is_empty() {
contours.push(current);
}
contours
}
pub fn triangle_area(x0: f64, y0: f64, x1: f64, y1: f64, x2: f64, y2: f64) -> f64 {
0.5 * ((x1 - x0) * (y2 - y0) - (x2 - x0) * (y1 - y0))
}
pub fn total_tessellation_area(tess: &Tessellator) -> f64 {
let verts = tess.vertices();
let elems = tess.elements();
let mut total = 0.0f64;
for tri in elems.chunks(3) {
if tri.len() < 3 {
break;
}
let (i0, i1, i2) = (tri[0] as usize, tri[1] as usize, tri[2] as usize);
let x0 = verts[i0 * 2];
let y0 = verts[i0 * 2 + 1];
let x1 = verts[i1 * 2];
let y1 = verts[i1 * 2 + 1];
let x2 = verts[i2 * 2];
let y2 = verts[i2 * 2 + 1];
total += triangle_area(x0, y0, x1, y1, x2, y2).abs();
}
total
}
pub fn total_tessellation_signed_area(tess: &Tessellator) -> f64 {
let verts = tess.vertices();
let elems = tess.elements();
let mut total = 0.0f64;
for tri in elems.chunks(3) {
if tri.len() < 3 {
break;
}
let (i0, i1, i2) = (tri[0] as usize, tri[1] as usize, tri[2] as usize);
let x0 = verts[i0 * 2];
let y0 = verts[i0 * 2 + 1];
let x1 = verts[i1 * 2];
let y1 = verts[i1 * 2 + 1];
let x2 = verts[i2 * 2];
let y2 = verts[i2 * 2 + 1];
total += triangle_area(x0, y0, x1, y1, x2, y2);
}
total
}
pub fn verify_valid_output(tess: &Tessellator) {
let verts = tess.vertices();
let elems = tess.elements();
let vert_count = tess.vertex_count();
for (i, &v) in verts.iter().enumerate() {
assert!(
v.is_finite(),
"vertex component [{}] = {} is not finite",
i,
v
);
}
for (i, &idx) in elems.iter().enumerate() {
if idx == u32::MAX {
continue; }
assert!(
(idx as usize) < vert_count,
"element[{}] = {} out of range (vertex_count={})",
i,
idx,
vert_count
);
}
}
pub fn verify_no_degenerate_triangles(tess: &Tessellator, epsilon: f64) {
let verts = tess.vertices();
let elems = tess.elements();
for (i, tri) in elems.chunks(3).enumerate() {
if tri.len() < 3 {
break;
}
let (i0, i1, i2) = (tri[0] as usize, tri[1] as usize, tri[2] as usize);
let area = triangle_area(
verts[i0 * 2],
verts[i0 * 2 + 1],
verts[i1 * 2],
verts[i1 * 2 + 1],
verts[i2 * 2],
verts[i2 * 2 + 1],
)
.abs();
assert!(
area > epsilon,
"triangle {} is degenerate (area={}, vertices=({},{}) ({},{}) ({},{}))",
i,
area,
verts[i0 * 2],
verts[i0 * 2 + 1],
verts[i1 * 2],
verts[i1 * 2 + 1],
verts[i2 * 2],
verts[i2 * 2 + 1],
);
}
}
pub fn tessellate_contours(contours: &[Vec<f64>], winding_rule: WindingRule) -> Tessellator {
let mut tess = Tessellator::new();
for contour in contours {
tess.add_contour(2, contour);
}
let ok = tess.tessellate(winding_rule, ElementType::Polygons, 3, 2, None);
assert!(
ok,
"tessellation failed for winding rule {:?}",
winding_rule
);
tess
}
pub fn polygon_signed_area(verts: &[f64]) -> f64 {
let n = verts.len() / 2;
if n < 3 {
return 0.0;
}
let mut area = 0.0f64;
for i in 0..n {
let j = (i + 1) % n;
area += verts[i * 2] * verts[j * 2 + 1];
area -= verts[j * 2] * verts[i * 2 + 1];
}
area * 0.5
}