use crate::{GlyphItem, PolylineItem};
pub fn polyline_node_vectors_to_glyphs(item: &PolylineItem) -> GlyphItem {
let n = item.positions.len().min(item.node_vectors.len());
GlyphItem {
positions: item.positions[..n].to_vec(),
vectors: item.node_vectors[..n].to_vec(),
scale: item.vector_scale,
..Default::default()
}
}
pub fn polyline_edge_vectors_to_glyphs(item: &PolylineItem) -> GlyphItem {
let positions = &item.positions;
let npos = positions.len();
let strip_ranges: Vec<(usize, usize)> = if item.strip_lengths.is_empty() {
vec![(0, npos)]
} else {
let mut ranges = Vec::with_capacity(item.strip_lengths.len());
let mut off = 0usize;
for &l in &item.strip_lengths {
ranges.push((off, off + l as usize));
off += l as usize;
}
ranges
};
let total_segs: usize = strip_ranges
.iter()
.map(|&(s, e): &(usize, usize)| e.min(npos).saturating_sub(s).saturating_sub(1))
.sum();
let n = total_segs.min(item.edge_vectors.len());
let mut glyph_positions: Vec<[f32; 3]> = Vec::with_capacity(n);
let mut glyph_vectors: Vec<[f32; 3]> = Vec::with_capacity(n);
let mut seg_idx = 0usize;
'outer: for &(strip_start, strip_end) in &strip_ranges {
let end = strip_end.min(npos);
for i in strip_start..end.saturating_sub(1) {
if seg_idx >= n {
break 'outer;
}
let j = i + 1;
let mid = [
(positions[i][0] + positions[j][0]) * 0.5,
(positions[i][1] + positions[j][1]) * 0.5,
(positions[i][2] + positions[j][2]) * 0.5,
];
glyph_positions.push(mid);
glyph_vectors.push(item.edge_vectors[seg_idx]);
seg_idx += 1;
}
}
GlyphItem {
positions: glyph_positions,
vectors: glyph_vectors,
scale: item.vector_scale,
..Default::default()
}
}
#[cfg(test)]
mod tests {
use super::*;
fn make_polyline(
positions: Vec<[f32; 3]>,
node_vectors: Vec<[f32; 3]>,
edge_vectors: Vec<[f32; 3]>,
strip_lengths: Vec<u32>,
) -> PolylineItem {
PolylineItem {
positions,
node_vectors,
edge_vectors,
strip_lengths,
vector_scale: 2.0,
..Default::default()
}
}
#[test]
fn node_vectors_positions_match_input() {
let pl = make_polyline(
vec![[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]],
vec![[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]],
vec![],
vec![],
);
let item = polyline_node_vectors_to_glyphs(&pl);
assert_eq!(item.positions, pl.positions);
assert_eq!(item.vectors, pl.node_vectors);
assert!((item.scale - 2.0).abs() < 1e-6);
}
#[test]
fn node_vectors_empty_returns_empty() {
let pl = make_polyline(vec![[0.0; 3]; 3], vec![], vec![], vec![]);
let item = polyline_node_vectors_to_glyphs(&pl);
assert!(item.positions.is_empty());
}
#[test]
fn edge_vectors_midpoints_correct() {
let pl = make_polyline(
vec![[0.0, 0.0, 0.0], [2.0, 0.0, 0.0], [2.0, 4.0, 0.0]],
vec![],
vec![[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]],
vec![], );
let item = polyline_edge_vectors_to_glyphs(&pl);
assert_eq!(item.positions.len(), 2);
assert!((item.positions[0][0] - 1.0).abs() < 1e-5);
assert!((item.positions[1][0] - 2.0).abs() < 1e-5);
assert!((item.positions[1][1] - 2.0).abs() < 1e-5);
}
#[test]
fn edge_vectors_with_strip_lengths() {
let pl = make_polyline(
vec![
[0.0, 0.0, 0.0],
[1.0, 0.0, 0.0],
[2.0, 0.0, 0.0],
[3.0, 0.0, 0.0],
],
vec![],
vec![[1.0, 0.0, 0.0]; 2], vec![2, 2], );
let item = polyline_edge_vectors_to_glyphs(&pl);
assert_eq!(item.positions.len(), 2);
assert!((item.positions[0][0] - 0.5).abs() < 1e-5);
assert!((item.positions[1][0] - 2.5).abs() < 1e-5);
}
#[test]
fn edge_vectors_empty_returns_empty() {
let pl = make_polyline(vec![[0.0; 3]; 3], vec![], vec![], vec![]);
let item = polyline_edge_vectors_to_glyphs(&pl);
assert!(item.positions.is_empty());
}
}