use glam::vec2;
use super::EPS;
use crate::{
Aabb,
math_curve::are_very_close_points,
math_segment::{Segment, SegmentColor},
segment::cycle_color,
};
pub(super) enum RecolorVisit {
Start {
index: usize,
},
Continue {
index: usize,
previous_angle: i16,
previous_color: SegmentColor,
},
}
pub(super) fn recolor(segments: &mut [Segment], state: &mut super::IntersectRemoveState) {
state.stack.clear();
state.stack.push(RecolorVisit::Start { index: 0 });
state.visited.clear();
state.visited.resize(segments.len(), false);
fn push_next_segments(segments: &mut [Segment], i: usize, stack: &mut Vec<RecolorVisit>) {
let seg = segments[i];
let mut seg_aabb = Aabb::from_segment(seg);
seg_aabb.min -= vec2(EPS, EPS);
seg_aabb.max += vec2(EPS, EPS);
let mut is_first = true;
super::visit_bvh(segments, &|aabb| aabb.overlap(&seg_aabb), &mut |i| {
if are_very_close_points(seg.to, segments[i].from) {
if is_first {
stack.push(RecolorVisit::Continue {
index: i,
previous_angle: seg.angle(),
previous_color: seg.color,
});
is_first = false;
} else {
stack.push(RecolorVisit::Start { index: i });
}
}
});
}
while let Some(visit) = state.stack.pop() {
match visit {
RecolorVisit::Start { index } => {
if state.visited[index] {
continue;
}
state.visited[index] = true;
segments[index].color = SegmentColor::BlueRed;
push_next_segments(segments, index, &mut state.stack);
}
RecolorVisit::Continue {
index,
previous_angle,
previous_color,
} => {
if state.visited[index] {
continue;
}
state.visited[index] = true;
let angle = segments[index].angle();
let is_corner = if let Some(seg_prev_angle) = segments[index].prev_angle {
segments[index].prev_angle = None;
seg_prev_angle != previous_angle
} else {
segments[index].prev_angle = Some(previous_angle);
angle != previous_angle
};
let mut color = previous_color;
if is_corner {
cycle_color(&mut color);
}
segments[index].color = color;
push_next_segments(segments, index, &mut state.stack);
}
}
}
}