use crate::fixed::F26Dot6;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Edge {
pub x: F26Dot6,
pub x_increment: F26Dot6,
pub direction: i8,
pub y_max: i32,
pub y_min: i32,
}
impl Edge {
pub fn new(x1: F26Dot6, y1: F26Dot6, x2: F26Dot6, y2: F26Dot6) -> Option<Self> {
let dy = y2 - y1;
if dy == F26Dot6::ZERO {
return None;
}
let (x_start, y_start, x_end, y_end, direction) = if dy > F26Dot6::ZERO {
(x1, y1, x2, y2, 1i8)
} else {
(x2, y2, x1, y1, -1i8)
};
let dy_abs = y_end - y_start;
let dx = x_end - x_start;
let x_increment = dx.div(dy_abs);
let y_min = y_start.ceil().to_int();
let y_max = y_end.ceil().to_int() - 1;
if y_min > y_max {
return None;
}
let delta_y = F26Dot6::from_int(y_min) - y_start;
let x = x_start + delta_y.mul(x_increment);
Some(Edge {
x,
x_increment,
direction,
y_max,
y_min,
})
}
#[inline]
pub fn step(&mut self) {
self.x = self.x + self.x_increment;
}
#[inline]
pub fn is_active(&self, y: i32) -> bool {
y <= self.y_max
}
}
#[derive(Debug, Clone, Default)]
pub struct EdgeList {
edges: Vec<Edge>,
}
impl EdgeList {
pub fn new() -> Self {
Self { edges: Vec::new() }
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
edges: Vec::with_capacity(capacity),
}
}
pub fn insert_sorted(&mut self, edge: Edge) {
let pos = self
.edges
.binary_search_by(|e| e.x.cmp(&edge.x))
.unwrap_or_else(|e| e);
self.edges.insert(pos, edge);
}
pub fn sort_by_x(&mut self) {
self.edges.sort_by(|a, b| a.x.cmp(&b.x));
}
pub fn remove_inactive(&mut self, y: i32) {
self.edges.retain(|edge| edge.is_active(y));
}
pub fn step_all(&mut self) {
for edge in &mut self.edges {
edge.step();
}
}
pub fn clear(&mut self) {
self.edges.clear();
}
#[inline]
pub fn len(&self) -> usize {
self.edges.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.edges.is_empty()
}
#[inline]
pub fn as_slice(&self) -> &[Edge] {
&self.edges
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [Edge] {
&mut self.edges
}
pub fn push(&mut self, edge: Edge) {
self.edges.push(edge);
}
pub fn extend(&mut self, other: &EdgeList) {
self.edges.extend_from_slice(&other.edges);
}
pub fn iter(&self) -> std::slice::Iter<'_, Edge> {
self.edges.iter()
}
pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, Edge> {
self.edges.iter_mut()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_edge_new_vertical() {
let e = Edge::new(
F26Dot6::from_int(10),
F26Dot6::from_int(5),
F26Dot6::from_int(10),
F26Dot6::from_int(15),
)
.unwrap();
assert_eq!(e.x, F26Dot6::from_int(10));
assert_eq!(e.x_increment, F26Dot6::ZERO);
assert_eq!(e.direction, 1);
assert_eq!(e.y_min, 5);
assert_eq!(e.y_max, 14); }
#[test]
fn test_edge_new_horizontal_returns_none() {
let e = Edge::new(
F26Dot6::from_int(10),
F26Dot6::from_int(5),
F26Dot6::from_int(20),
F26Dot6::from_int(5),
);
assert!(e.is_none());
}
#[test]
fn test_edge_new_diagonal() {
let e = Edge::new(
F26Dot6::from_int(0),
F26Dot6::from_int(0),
F26Dot6::from_int(10),
F26Dot6::from_int(10),
)
.unwrap();
assert_eq!(e.x, F26Dot6::from_int(0));
assert_eq!(e.direction, 1);
assert_eq!(e.y_min, 0);
assert_eq!(e.y_max, 9); assert_eq!(e.x_increment.raw(), 64);
}
#[test]
fn test_edge_new_swaps_if_downward() {
let e = Edge::new(
F26Dot6::from_int(20),
F26Dot6::from_int(15),
F26Dot6::from_int(10),
F26Dot6::from_int(5),
)
.unwrap();
assert_eq!(e.x, F26Dot6::from_int(10));
assert_eq!(e.y_min, 5);
assert_eq!(e.y_max, 14); assert_eq!(e.direction, -1);
}
#[test]
fn test_edge_step() {
let mut e = Edge::new(
F26Dot6::from_int(0),
F26Dot6::from_int(0),
F26Dot6::from_int(10),
F26Dot6::from_int(10),
)
.unwrap();
assert_eq!(e.x.to_int(), 0);
e.step();
assert_eq!(e.x.to_int(), 1);
e.step();
assert_eq!(e.x.to_int(), 2);
}
#[test]
fn test_edge_is_active() {
let e = Edge::new(
F26Dot6::from_int(0),
F26Dot6::from_int(5),
F26Dot6::from_int(10),
F26Dot6::from_int(15),
)
.unwrap();
assert!(e.is_active(5));
assert!(e.is_active(10));
assert!(e.is_active(14));
assert!(!e.is_active(15));
}
#[test]
fn test_edgelist_new() {
let list = EdgeList::new();
assert!(list.is_empty());
assert_eq!(list.len(), 0);
}
#[test]
fn test_edgelist_push() {
let mut list = EdgeList::new();
let e = Edge::new(
F26Dot6::from_int(10),
F26Dot6::from_int(0),
F26Dot6::from_int(10),
F26Dot6::from_int(10),
)
.unwrap();
list.push(e);
assert_eq!(list.len(), 1);
assert!(!list.is_empty());
}
#[test]
fn test_edgelist_insert_sorted() {
let mut list = EdgeList::new();
list.insert_sorted(
Edge::new(
F26Dot6::from_int(20),
F26Dot6::ZERO,
F26Dot6::from_int(20),
F26Dot6::from_int(10),
)
.unwrap(),
);
list.insert_sorted(
Edge::new(
F26Dot6::from_int(10),
F26Dot6::ZERO,
F26Dot6::from_int(10),
F26Dot6::from_int(10),
)
.unwrap(),
);
list.insert_sorted(
Edge::new(
F26Dot6::from_int(15),
F26Dot6::ZERO,
F26Dot6::from_int(15),
F26Dot6::from_int(10),
)
.unwrap(),
);
assert_eq!(list.len(), 3);
assert_eq!(list.as_slice()[0].x.to_int(), 10);
assert_eq!(list.as_slice()[1].x.to_int(), 15);
assert_eq!(list.as_slice()[2].x.to_int(), 20);
}
#[test]
fn test_edgelist_sort_by_x() {
let mut list = EdgeList::new();
list.push(
Edge::new(
F26Dot6::from_int(20),
F26Dot6::ZERO,
F26Dot6::from_int(20),
F26Dot6::from_int(10),
)
.unwrap(),
);
list.push(
Edge::new(
F26Dot6::from_int(10),
F26Dot6::ZERO,
F26Dot6::from_int(10),
F26Dot6::from_int(10),
)
.unwrap(),
);
list.sort_by_x();
assert_eq!(list.as_slice()[0].x.to_int(), 10);
assert_eq!(list.as_slice()[1].x.to_int(), 20);
}
#[test]
fn test_edgelist_remove_inactive() {
let mut list = EdgeList::new();
list.push(
Edge::new(
F26Dot6::from_int(10),
F26Dot6::ZERO,
F26Dot6::from_int(10),
F26Dot6::from_int(5),
)
.unwrap(),
);
list.push(
Edge::new(
F26Dot6::from_int(20),
F26Dot6::ZERO,
F26Dot6::from_int(20),
F26Dot6::from_int(10),
)
.unwrap(),
);
assert_eq!(list.len(), 2);
list.remove_inactive(6);
assert_eq!(list.len(), 1);
assert_eq!(list.as_slice()[0].x.to_int(), 20);
}
#[test]
fn test_edgelist_step_all() {
let mut list = EdgeList::new();
list.push(
Edge::new(
F26Dot6::from_int(0),
F26Dot6::from_int(0),
F26Dot6::from_int(10),
F26Dot6::from_int(10),
)
.unwrap(),
);
list.push(
Edge::new(
F26Dot6::from_int(0),
F26Dot6::from_int(0),
F26Dot6::from_int(20),
F26Dot6::from_int(10),
)
.unwrap(),
);
assert_eq!(list.as_slice()[0].x.to_int(), 0);
assert_eq!(list.as_slice()[1].x.to_int(), 0);
list.step_all();
assert_eq!(list.as_slice()[0].x.to_int(), 1);
assert_eq!(list.as_slice()[1].x.to_int(), 2);
}
#[test]
fn test_edgelist_clear() {
let mut list = EdgeList::new();
list.push(
Edge::new(
F26Dot6::from_int(10),
F26Dot6::ZERO,
F26Dot6::from_int(10),
F26Dot6::from_int(10),
)
.unwrap(),
);
assert!(!list.is_empty());
list.clear();
assert!(list.is_empty());
}
#[test]
fn test_edgelist_extend() {
let mut list1 = EdgeList::new();
let mut list2 = EdgeList::new();
list1.push(
Edge::new(
F26Dot6::from_int(10),
F26Dot6::ZERO,
F26Dot6::from_int(10),
F26Dot6::from_int(10),
)
.unwrap(),
);
list2.push(
Edge::new(
F26Dot6::from_int(20),
F26Dot6::ZERO,
F26Dot6::from_int(20),
F26Dot6::from_int(10),
)
.unwrap(),
);
list1.extend(&list2);
assert_eq!(list1.len(), 2);
}
#[test]
fn test_edge_fractional_slope() {
let e = Edge::new(
F26Dot6::from_int(0),
F26Dot6::from_int(0),
F26Dot6::from_int(5),
F26Dot6::from_int(10),
)
.unwrap();
assert_eq!(e.x_increment.raw(), 32);
let mut x = e.x;
x = x + e.x_increment;
x = x + e.x_increment;
assert_eq!(x.to_int(), 1);
}
#[test]
fn test_edge_negative_slope() {
let e = Edge::new(
F26Dot6::from_int(10),
F26Dot6::from_int(0),
F26Dot6::from_int(0),
F26Dot6::from_int(10),
)
.unwrap();
assert_eq!(e.x_increment.raw(), -64);
let mut test_e = e;
assert_eq!(test_e.x.to_int(), 10);
test_e.step();
assert_eq!(test_e.x.to_int(), 9);
}
#[test]
fn test_edgelist_with_capacity() {
let list = EdgeList::with_capacity(100);
assert_eq!(list.len(), 0);
assert!(list.edges.capacity() >= 100);
}
#[test]
fn test_edge_winding_direction() {
let e_up = Edge::new(
F26Dot6::from_int(0),
F26Dot6::from_int(0),
F26Dot6::from_int(10),
F26Dot6::from_int(10),
)
.unwrap();
assert_eq!(e_up.direction, 1);
let e_down = Edge::new(
F26Dot6::from_int(10),
F26Dot6::from_int(10),
F26Dot6::from_int(0),
F26Dot6::from_int(0),
)
.unwrap();
assert_eq!(e_down.direction, -1);
}
#[test]
fn test_edgelist_iter() {
let mut list = EdgeList::new();
list.push(
Edge::new(
F26Dot6::from_int(10),
F26Dot6::ZERO,
F26Dot6::from_int(10),
F26Dot6::from_int(10),
)
.unwrap(),
);
let count = list.iter().count();
assert_eq!(count, 1);
}
#[test]
fn test_edgelist_iter_mut() {
let mut list = EdgeList::new();
list.push(
Edge::new(
F26Dot6::from_int(10),
F26Dot6::ZERO,
F26Dot6::from_int(10),
F26Dot6::from_int(10),
)
.unwrap(),
);
for edge in list.iter_mut() {
edge.step();
}
assert_eq!(list.as_slice()[0].x.to_int(), 10);
}
}