#![allow(dead_code)]
pub struct EdgeFlowField {
pub flow_vectors: Vec<[f32; 3]>,
pub vertex_count: usize,
}
pub fn new_edge_flow_field(n: usize) -> EdgeFlowField {
EdgeFlowField {
flow_vectors: vec![[0.0; 3]; n],
vertex_count: n,
}
}
pub fn edge_flow_field_set(f: &mut EdgeFlowField, i: usize, v: [f32; 3]) {
f.flow_vectors[i] = v;
}
pub fn edge_flow_field_get(f: &EdgeFlowField, i: usize) -> [f32; 3] {
f.flow_vectors[i]
}
pub fn edge_flow_field_divergence(f: &EdgeFlowField, i: usize, neighbors: &[usize]) -> f32 {
let fi = f.flow_vectors[i];
let mut div = 0.0_f32;
for &j in neighbors {
let fj = f.flow_vectors[j];
div += fi[0] - fj[0] + fi[1] - fj[1] + fi[2] - fj[2];
}
div
}
pub fn edge_flow_field_curl_magnitude(
f: &EdgeFlowField,
center: [f32; 3],
ring: &[(usize, [f32; 3])],
) -> f32 {
let _ = center; let k = ring.len();
if k < 3 {
return 0.0;
}
let mut nx = 0.0f32;
let mut ny = 0.0f32;
let mut nz = 0.0f32;
#[allow(clippy::needless_range_loop)]
for i in 0..k {
let a = ring[i].1;
let b = ring[(i + 1) % k].1;
nx += (a[1] - b[1]) * (a[2] + b[2]);
ny += (a[2] - b[2]) * (a[0] + b[0]);
nz += (a[0] - b[0]) * (a[1] + b[1]);
}
let area = 0.5 * (nx * nx + ny * ny + nz * nz).sqrt();
if area < 1e-12 {
return 0.0;
}
let mut circ = 0.0f32;
for i in 0..k {
let (idx_i, p_i) = ring[i];
let (idx_j, p_j) = ring[(i + 1) % k];
let fi = f.flow_vectors.get(idx_i).copied().unwrap_or([0.0; 3]);
let fj = f.flow_vectors.get(idx_j).copied().unwrap_or([0.0; 3]);
let favg = [
0.5 * (fi[0] + fj[0]),
0.5 * (fi[1] + fj[1]),
0.5 * (fi[2] + fj[2]),
];
let edge = [p_j[0] - p_i[0], p_j[1] - p_i[1], p_j[2] - p_i[2]];
circ += favg[0] * edge[0] + favg[1] * edge[1] + favg[2] * edge[2];
}
(circ / area).abs()
}
pub fn edge_flow_field_mean_speed(f: &EdgeFlowField) -> f32 {
if f.flow_vectors.is_empty() {
return 0.0;
}
let total: f32 = f
.flow_vectors
.iter()
.map(|v| (v[0] * v[0] + v[1] * v[1] + v[2] * v[2]).sqrt())
.sum();
total / f.flow_vectors.len() as f32
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_edge_flow_field() {
let f = new_edge_flow_field(4);
assert_eq!(f.vertex_count, 4);
assert_eq!(edge_flow_field_get(&f, 0), [0.0, 0.0, 0.0]);
}
#[test]
fn test_set_get() {
let mut f = new_edge_flow_field(3);
edge_flow_field_set(&mut f, 1, [1.0, 0.0, 0.0]);
assert_eq!(edge_flow_field_get(&f, 1), [1.0, 0.0, 0.0]);
}
#[test]
fn test_mean_speed_uniform() {
let mut f = new_edge_flow_field(3);
for i in 0..3 {
edge_flow_field_set(&mut f, i, [1.0, 0.0, 0.0]);
}
assert!((edge_flow_field_mean_speed(&f) - 1.0).abs() < 1e-5);
}
#[test]
fn test_curl_empty_ring() {
let f = new_edge_flow_field(2);
assert!((edge_flow_field_curl_magnitude(&f, [0.0; 3], &[])).abs() < 1e-6);
}
#[test]
fn test_curl_rotational_field() {
let corners = [
[1.0f32, -1.0, 0.0],
[1.0, 1.0, 0.0],
[-1.0, 1.0, 0.0],
[-1.0, -1.0, 0.0],
];
let mut f = new_edge_flow_field(4);
for (i, c) in corners.iter().enumerate() {
edge_flow_field_set(&mut f, i, [-c[1], c[0], 0.0]);
}
let ring: Vec<(usize, [f32; 3])> =
corners.iter().enumerate().map(|(i, &p)| (i, p)).collect();
let curl = edge_flow_field_curl_magnitude(&f, [0.0; 3], &ring);
assert!((curl - 2.0).abs() < 1e-4, "expected curl 2.0, got {curl}");
}
#[test]
fn test_divergence_no_neighbors() {
let f = new_edge_flow_field(3);
assert!((edge_flow_field_divergence(&f, 0, &[])).abs() < 1e-6);
}
#[test]
fn test_mean_speed_empty() {
let f = new_edge_flow_field(0);
assert!((edge_flow_field_mean_speed(&f)).abs() < 1e-6);
}
}