use super::path::*;
use crate::bezier::curve::*;
use crate::geo::*;
use crate::consts::*;
use smallvec::*;
use std::fmt;
use std::cell::*;
mod edge;
mod edge_ref;
mod ray_collision;
mod path_collision;
#[cfg(test)] pub (crate) mod test;
pub use self::edge::*;
pub use self::edge_ref::*;
pub use self::ray_collision::*;
pub use self::path_collision::*;
const MAX_HEAL_DEPTH: usize = 3;
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum GraphPathEdgeKind {
Uncategorised,
Visited,
Exterior,
Interior
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct GraphEdgeRef {
pub (crate) start_idx: usize,
pub (crate) edge_idx: usize,
pub (crate) reverse: bool
}
#[derive(Clone, Debug)]
struct GraphPathEdge<Point, Label> {
label: Label,
following_edge_idx: usize,
kind: GraphPathEdgeKind,
cp1: Point,
cp2: Point,
end_idx: usize,
bbox: RefCell<Option<(Point, Point)>>
}
#[derive(Clone, Debug)]
struct GraphPathPoint<Point, Label> {
position: Point,
forward_edges: SmallVec<[GraphPathEdge<Point, Label>; 2]>,
connected_from: SmallVec<[usize; 2]>
}
impl<Point, Label> GraphPathPoint<Point, Label> {
fn new(position: Point, forward_edges: SmallVec<[GraphPathEdge<Point, Label>; 2]>, connected_from: SmallVec<[usize; 2]>) -> GraphPathPoint<Point, Label> {
GraphPathPoint { position, forward_edges, connected_from }
}
}
#[derive(Clone)]
pub struct GraphPath<Point, Label> {
points: Vec<GraphPathPoint<Point, Label>>,
next_path_index: usize
}
#[derive(Clone)]
pub enum CollidedGraphPath<Point, Label> {
Collided(GraphPath<Point, Label>),
Merged(GraphPath<Point, Label>)
}
impl<Point: Coordinate, Label> Geo for GraphPath<Point, Label> {
type Point = Point;
}
impl<Point: Coordinate+Coordinate2D, Label: Copy> GraphPath<Point, Label> {
pub fn new() -> GraphPath<Point, Label> {
GraphPath {
points: vec![],
next_path_index: 0
}
}
pub fn from_path<P: BezierPath<Point=Point>>(path: &P, label: Label) -> GraphPath<Point, Label> {
let mut points = vec![];
let start_point = path.start_point();
points.push(GraphPathPoint::new(start_point, smallvec![], smallvec![]));
let mut last_point_pos = start_point;
let mut last_point_idx = 0;
let mut next_point_idx = 1;
for (cp1, cp2, end_point) in path.points() {
if end_point.is_near_to(&last_point_pos, CLOSE_DISTANCE) {
if cp1.is_near_to(&last_point_pos, CLOSE_DISTANCE) && cp2.is_near_to(&cp1, CLOSE_DISTANCE) {
continue;
}
}
points.push(GraphPathPoint::new(end_point, smallvec![], smallvec![]));
points[last_point_idx].forward_edges.push(GraphPathEdge::new(GraphPathEdgeKind::Uncategorised, (cp1, cp2), next_point_idx, label, 0));
last_point_idx += 1;
next_point_idx += 1;
last_point_pos = end_point;
}
if last_point_idx > 0 {
if start_point.distance_to(&points[last_point_idx].position) < CLOSE_DISTANCE {
points.pop();
last_point_idx -= 1;
points[last_point_idx].forward_edges[0].end_idx = 0;
} else {
let close_vector = points[last_point_idx].position - start_point;
let cp1 = close_vector * 0.33 + start_point;
let cp2 = close_vector * 0.66 + start_point;
points[last_point_idx].forward_edges.push(GraphPathEdge::new(GraphPathEdgeKind::Uncategorised, (cp1, cp2), 0, label, 0));
}
} else {
points.pop();
}
let mut path = GraphPath {
points: points,
next_path_index: 1
};
path.recalculate_reverse_connections();
path
}
pub fn from_merged_paths<'a, P: 'a+BezierPath<Point=Point>, PathIter: IntoIterator<Item=(&'a P, Label)>>(paths: PathIter) -> GraphPath<Point, Label> {
let mut merged_path = GraphPath::new();
for (path, label) in paths {
let path = GraphPath::from_path(path, label);
merged_path = merged_path.merge(path);
}
merged_path
}
fn recalculate_reverse_connections(&mut self) {
for point_idx in 0..(self.points.len()) {
self.points[point_idx].connected_from.clear();
}
for point_idx in 0..(self.points.len()) {
for edge_idx in 0..(self.points[point_idx].forward_edges.len()) {
let end_idx = self.points[point_idx].forward_edges[edge_idx].end_idx;
self.points[end_idx].connected_from.push(point_idx);
}
}
for point_idx in 0..(self.points.len()) {
self.points[point_idx].connected_from.sort();
self.points[point_idx].connected_from.dedup();
}
}
#[inline]
pub fn num_points(&self) -> usize {
self.points.len()
}
#[inline]
pub fn all_edges<'a>(&'a self) -> impl 'a+Iterator<Item=GraphEdge<'a, Point, Label>> {
(0..(self.points.len()))
.into_iter()
.flat_map(move |point_num| self.edges_for_point(point_num))
}
#[inline]
pub fn all_edge_refs<'a>(&'a self) -> impl 'a+Iterator<Item=GraphEdgeRef> {
(0..(self.points.len()))
.into_iter()
.flat_map(move |point_idx| (0..(self.points[point_idx].forward_edges.len()))
.into_iter()
.map(move |edge_idx| GraphEdgeRef {
start_idx: point_idx,
edge_idx: edge_idx,
reverse: false
}))
}
#[inline]
pub fn edges_for_point<'a>(&'a self, point_num: usize) -> impl 'a+Iterator<Item=GraphEdge<'a, Point, Label>> {
(0..(self.points[point_num].forward_edges.len()))
.into_iter()
.map(move |edge_idx| GraphEdge::new(self, GraphEdgeRef { start_idx: point_num, edge_idx: edge_idx, reverse: false }))
}
pub fn edge_refs_for_point(&self, point_num: usize) -> impl Iterator<Item=GraphEdgeRef> {
(0..(self.points[point_num].forward_edges.len()))
.into_iter()
.map(move |edge_idx| GraphEdgeRef { start_idx: point_num, edge_idx: edge_idx, reverse: false })
}
#[inline]
pub fn point_position(&self, point_num: usize) -> Point {
self.points[point_num].position.clone()
}
pub fn reverse_edges_for_point<'a>(&'a self, point_num: usize) -> impl 'a+Iterator<Item=GraphEdge<'a, Point, Label>> {
self.points[point_num].connected_from
.iter()
.flat_map(move |connected_from| {
let connected_from = *connected_from;
(0..(self.points[connected_from].forward_edges.len()))
.into_iter()
.filter_map(move |edge_idx| {
if self.points[connected_from].forward_edges[edge_idx].end_idx == point_num {
Some(GraphEdgeRef { start_idx: connected_from, edge_idx: edge_idx, reverse: true })
} else {
None
}
})
})
.map(move |edge_ref| GraphEdge::new(self, edge_ref))
}
pub fn merge(self, merge_path: GraphPath<Point, Label>) -> GraphPath<Point, Label> {
let mut new_points = self.points;
let next_path_idx = self.next_path_index;
let offset = new_points.len();
new_points.extend(merge_path.points.into_iter()
.map(|mut point| {
for mut edge in &mut point.forward_edges {
edge.end_idx += offset;
}
for previous_point in &mut point.connected_from {
*previous_point += offset;
}
point
}));
GraphPath {
points: new_points,
next_path_index: next_path_idx + merge_path.next_path_index
}
}
fn edge_is_very_short(&self, edge_ref: GraphEdgeRef) -> bool {
let edge = &self.points[edge_ref.start_idx].forward_edges[edge_ref.edge_idx];
if edge_ref.start_idx == edge.end_idx {
let start_point = &self.points[edge_ref.start_idx].position;
let cp1 = &edge.cp1;
let cp2 = &edge.cp2;
let end_point = &self.points[edge.end_idx].position;
start_point.is_near_to(end_point, CLOSE_DISTANCE)
&& start_point.is_near_to(cp1, CLOSE_DISTANCE)
&& cp1.is_near_to(cp2, CLOSE_DISTANCE)
&& cp2.is_near_to(end_point, CLOSE_DISTANCE)
} else {
false
}
}
fn remove_edge(&mut self, edge_ref: GraphEdgeRef) {
self.check_following_edge_consistency();
let next_point_idx = self.points[edge_ref.start_idx].forward_edges[edge_ref.edge_idx].end_idx;
let next_edge_idx = self.points[edge_ref.start_idx].forward_edges[edge_ref.edge_idx].following_edge_idx;
test_assert!(next_point_idx != edge_ref.start_idx || next_edge_idx != edge_ref.edge_idx);
let previous_edge_ref = self.points[edge_ref.start_idx].connected_from
.iter()
.map(|point_idx| { let point_idx = *point_idx; self.points[point_idx].forward_edges.iter().enumerate().map(move |(edge_idx, edge)| (point_idx, edge_idx, edge)) })
.flatten()
.filter_map(|(point_idx, edge_idx, edge)| {
if edge.end_idx == edge_ref.start_idx && edge.following_edge_idx == edge_ref.edge_idx {
Some(GraphEdgeRef { start_idx: point_idx, edge_idx: edge_idx, reverse: false })
} else {
None
}
})
.nth(0);
test_assert!(previous_edge_ref.is_some());
if let Some(previous_edge_ref) = previous_edge_ref {
test_assert!(self.points[previous_edge_ref.start_idx].forward_edges[previous_edge_ref.edge_idx].end_idx == edge_ref.start_idx);
test_assert!(self.points[previous_edge_ref.start_idx].forward_edges[previous_edge_ref.edge_idx].following_edge_idx == edge_ref.edge_idx);
self.points[previous_edge_ref.start_idx].forward_edges[previous_edge_ref.edge_idx].end_idx = next_point_idx;
self.points[previous_edge_ref.start_idx].forward_edges[previous_edge_ref.edge_idx].following_edge_idx = next_edge_idx;
self.points[edge_ref.start_idx].forward_edges.remove(edge_ref.edge_idx);
let mut still_connected = false;
self.points[edge_ref.start_idx].connected_from.sort();
self.points[edge_ref.start_idx].connected_from.dedup();
for connected_point_idx in self.points[edge_ref.start_idx].connected_from.clone() {
for edge_idx in 0..(self.points[connected_point_idx].forward_edges.len()) {
let connected_edge = &mut self.points[connected_point_idx].forward_edges[edge_idx];
if connected_edge.end_idx != edge_ref.start_idx {
continue;
}
test_assert!(connected_edge.following_edge_idx != edge_ref.edge_idx);
if connected_edge.following_edge_idx > edge_ref.edge_idx {
connected_edge.following_edge_idx -= 1;
}
if connected_edge.end_idx == edge_ref.start_idx {
still_connected = true;
}
}
}
if !still_connected {
self.points[edge_ref.start_idx].connected_from.retain(|point_idx| *point_idx != edge_ref.start_idx);
}
self.check_following_edge_consistency();
}
}
fn remove_all_very_short_edges(&mut self) {
for point_idx in 0..(self.points.len()) {
let mut edge_idx = 0;
while edge_idx < self.points[point_idx].forward_edges.len() {
let edge_ref = GraphEdgeRef { start_idx: point_idx, edge_idx: edge_idx, reverse: false };
if self.edge_is_very_short(edge_ref) {
self.remove_edge(edge_ref);
} else {
edge_idx += 1;
}
}
}
}
pub fn collide_or_merge(mut self, collide_path: GraphPath<Point, Label>, accuracy: f64) -> CollidedGraphPath<Point, Label> {
let collision_offset = self.points.len();
self = self.merge(collide_path);
let total_points = self.points.len();
if self.detect_collisions(0..collision_offset, collision_offset..total_points, accuracy) {
CollidedGraphPath::Collided(self)
} else {
CollidedGraphPath::Merged(self)
}
}
pub fn collide(mut self, collide_path: GraphPath<Point, Label>, accuracy: f64) -> GraphPath<Point, Label> {
let collision_offset = self.points.len();
self = self.merge(collide_path);
let total_points = self.points.len();
self.detect_collisions(0..collision_offset, collision_offset..total_points, accuracy);
self
}
pub fn round(&mut self, accuracy: f64) {
for point_idx in 0..(self.num_points()) {
self.points[point_idx].position.round(accuracy);
for edge_idx in 0..(self.points[point_idx].forward_edges.len()) {
self.points[point_idx].forward_edges[edge_idx].cp1.round(accuracy);
self.points[point_idx].forward_edges[edge_idx].cp2.round(accuracy);
}
}
}
pub fn self_collide(&mut self, accuracy: f64) {
let total_points = self.points.len();
self.detect_collisions(0..total_points, 0..total_points, accuracy);
}
#[inline]
pub fn get_edge<'a>(&'a self, edge: GraphEdgeRef) -> GraphEdge<'a, Point, Label> {
GraphEdge::new(self, edge)
}
#[inline]
pub fn set_edge_kind(&mut self, edge: GraphEdgeRef, new_type: GraphPathEdgeKind) {
self.points[edge.start_idx].forward_edges[edge.edge_idx].kind = new_type;
}
#[inline]
pub fn set_edge_label(&mut self, edge: GraphEdgeRef, new_label: Label) {
self.points[edge.start_idx].forward_edges[edge.edge_idx].label = new_label;
}
#[inline]
pub fn edge_kind(&self, edge: GraphEdgeRef) -> GraphPathEdgeKind {
self.points[edge.start_idx].forward_edges[edge.edge_idx].kind
}
#[inline]
pub fn edge_label(&self, edge: GraphEdgeRef) -> Label {
self.points[edge.start_idx].forward_edges[edge.edge_idx].label
}
pub fn reset_edge_kinds(&mut self) {
for point in self.points.iter_mut() {
for edge in point.forward_edges.iter_mut() {
edge.kind = GraphPathEdgeKind::Uncategorised;
}
}
}
pub fn set_edge_kind_connected(&mut self, edge: GraphEdgeRef, kind: GraphPathEdgeKind) {
let mut current_edge = edge;
let mut visited = vec![false; self.points.len()];
loop {
self.set_edge_kind(current_edge, kind);
visited[current_edge.start_idx] = true;
let end_idx = self.points[current_edge.start_idx].forward_edges[current_edge.edge_idx].end_idx;
let edges = &self.points[end_idx].forward_edges;
if edges.len() != 1 {
break;
} else {
current_edge = GraphEdgeRef {
start_idx: end_idx,
edge_idx: 0,
reverse: false
}
}
if visited[current_edge.start_idx] {
break;
}
}
current_edge = edge;
loop {
visited[current_edge.start_idx] = true;
if self.points[current_edge.start_idx].connected_from.len() != 1 {
break;
} else {
let current_point_idx = current_edge.start_idx;
let previous_point_idx = self.points[current_edge.start_idx].connected_from[0];
let mut previous_edges = (0..(self.points[previous_point_idx].forward_edges.len()))
.into_iter()
.filter(|edge_idx| self.points[previous_point_idx].forward_edges[*edge_idx].end_idx == current_point_idx);
let previous_edge_idx = previous_edges.next().expect("Previous edge");
if previous_edges.next().is_some() {
break;
}
current_edge = GraphEdgeRef {
start_idx: previous_point_idx,
edge_idx: previous_edge_idx,
reverse: false
};
self.set_edge_kind(current_edge, kind);
}
if visited[current_edge.start_idx] {
break;
}
}
}
fn has_single_exterior_edge(&self, point_idx: usize) -> bool {
self.edges_for_point(point_idx)
.chain(self.reverse_edges_for_point(point_idx))
.filter(|edge| edge.kind() == GraphPathEdgeKind::Exterior)
.count() == 1
}
fn edge_has_gap(&self, edge: GraphEdgeRef) -> bool {
if self.points[edge.start_idx].forward_edges[edge.edge_idx].kind != GraphPathEdgeKind::Exterior {
false
} else {
let (start_idx, end_idx) = if edge.reverse {
(self.points[edge.start_idx].forward_edges[edge.edge_idx].end_idx, edge.start_idx)
} else {
(edge.start_idx, self.points[edge.start_idx].forward_edges[edge.edge_idx].end_idx)
};
!self.edges_for_point(end_idx)
.chain(self.reverse_edges_for_point(end_idx))
.filter(|following_edge| following_edge.end_point_index() != start_idx)
.any(|following_edge| following_edge.kind() == GraphPathEdgeKind::Exterior)
}
}
fn heal_edge_with_gap(&mut self, point_idx: usize, edge_idx: usize, max_depth: usize) -> bool {
let end_point_idx = self.points[point_idx].forward_edges[edge_idx].end_idx;
let mut preceding_edge = vec![None; self.points.len()];
let mut points_to_process = vec![(point_idx, end_point_idx)];
let mut current_depth = 0;
let mut target_point_idx = None;
while current_depth < max_depth && target_point_idx.is_none() {
let mut next_points_to_process = vec![];
for (from_point_idx, next_point_idx) in points_to_process {
if target_point_idx.is_some() { break; }
for next_edge in self.edges_for_point(next_point_idx) {
let edge_end_point_idx = next_edge.end_point_index();
let next_edge_ref = GraphEdgeRef::from(&next_edge);
let edge_start_idx = next_edge.start_point_index();
if edge_end_point_idx == from_point_idx { continue; }
if preceding_edge[edge_end_point_idx].is_some() { continue; }
let mut reversed_edge_ref = next_edge_ref;
reversed_edge_ref.reverse = !reversed_edge_ref.reverse;
if next_edge.kind() == GraphPathEdgeKind::Exterior && !self.edge_has_gap(reversed_edge_ref) { continue; }
preceding_edge[edge_end_point_idx] = Some(next_edge_ref);
if next_edge.kind() == GraphPathEdgeKind::Exterior {
target_point_idx = Some(edge_end_point_idx);
break;
}
next_points_to_process.push((edge_start_idx, edge_end_point_idx));
}
}
points_to_process = next_points_to_process;
current_depth += 1;
}
if let Some(target_point_idx) = target_point_idx {
let mut current_point_idx = target_point_idx;
while current_point_idx != end_point_idx {
let previous_edge_ref = preceding_edge[current_point_idx].expect("Previous point during gap healing");
self.points[previous_edge_ref.start_idx].forward_edges[previous_edge_ref.edge_idx].kind = GraphPathEdgeKind::Exterior;
let previous_edge = self.get_edge(previous_edge_ref);
current_point_idx = previous_edge.start_point_index();
}
true
} else {
false
}
}
pub fn heal_exterior_gaps(&mut self) -> bool {
let mut all_healed = true;
for point_idx in 0..(self.points.len()) {
for edge_idx in 0..(self.points[point_idx].forward_edges.len()) {
if self.edge_has_gap(GraphEdgeRef { start_idx: point_idx, edge_idx: edge_idx, reverse: false }) {
if !self.heal_edge_with_gap(point_idx, edge_idx, MAX_HEAL_DEPTH) {
all_healed = false;
}
}
}
}
all_healed
}
pub fn exterior_paths<POut: BezierPathFactory<Point=Point>>(&self) -> Vec<POut> {
let mut exterior_paths = vec![];
let mut visited = vec![false; self.points.len()];
let mut previous_point = vec![None; self.points.len()];
let mut points_to_check: SmallVec<[_; 16]> = smallvec![];
for point_idx in 0..(self.points.len()) {
if visited[point_idx] {
continue;
}
for p in previous_point.iter_mut() {
*p = None;
}
points_to_check.clear();
points_to_check.push((point_idx, point_idx));
while previous_point[point_idx].is_none() {
if points_to_check.len() == 0 {
break;
}
let mut next_points_to_check: SmallVec<[_; 16]> = smallvec![];
for (previous_point_idx, current_point_idx) in points_to_check {
let mut edges = if current_point_idx == point_idx {
self.reverse_edges_for_point(current_point_idx).collect::<SmallVec<[_; 8]>>()
} else {
self.edges_for_point(current_point_idx)
.chain(self.reverse_edges_for_point(current_point_idx))
.collect::<SmallVec<[_; 8]>>()
};
if current_point_idx == point_idx || edges.iter().any(|edge| edge.kind() == GraphPathEdgeKind::Exterior && edge.end_point_index() != previous_point_idx) {
edges.retain(|edge| edge.kind() == GraphPathEdgeKind::Exterior);
} else {
edges.retain(|edge| self.has_single_exterior_edge(edge.end_point_index()));
}
for edge in edges {
let next_point_idx = edge.end_point_index();
if previous_point[next_point_idx].is_some() {
continue;
}
if next_point_idx == previous_point_idx {
continue;
}
previous_point[next_point_idx] = Some((current_point_idx, edge));
next_points_to_check.push((current_point_idx, next_point_idx));
}
}
points_to_check = next_points_to_check;
}
if previous_point[point_idx].is_some() {
let mut path_points = vec![];
let mut cur_point_idx = point_idx;
while let Some((last_point_idx, ref edge)) = previous_point[cur_point_idx] {
let (cp1, cp2) = edge.control_points();
let start_point = edge.start_point();
path_points.push((cp2, cp1, start_point));
visited[last_point_idx] = true;
cur_point_idx = last_point_idx;
if cur_point_idx == point_idx {
break;
}
}
let start_point = self.points[point_idx].position.clone();
let new_path = POut::from_points(start_point, path_points);
exterior_paths.push(new_path);
}
}
exterior_paths
}
}
#[derive(Clone)]
pub struct GraphEdge<'a, Point: 'a, Label: 'a> {
graph: &'a GraphPath<Point, Label>,
edge: GraphEdgeRef
}
impl<Point: Coordinate2D+Coordinate+fmt::Debug, Label: Copy> fmt::Debug for GraphPath<Point, Label> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for point_idx in 0..(self.points.len()) {
write!(f, "\nPoint {:?}:", point_idx)?;
for edge in self.edges_for_point(point_idx) {
write!(f, "\n {:?}", edge)?;
}
}
Ok(())
}
}