use axiolid_core::{Point2, Tolerance};
use crate::arc::{arc_ring_area, reverse_arc_ring, validate_arc_ring, ArcRing};
use crate::exact_arc::arrangement::{self, Raw};
use crate::OverlayError;
#[derive(Debug, Clone, PartialEq)]
pub struct ArrangementEdge {
pub from: usize,
pub to: usize,
pub bulge: f64,
pub sources: Vec<EdgeSource>,
left: Vec<bool>,
right: Vec<bool>,
}
impl ArrangementEdge {
pub fn inside_left(&self, ring: usize) -> bool {
self.left.get(ring).copied().unwrap_or(false)
}
pub fn inside_right(&self, ring: usize) -> bool {
self.right.get(ring).copied().unwrap_or(false)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct EdgeSource {
pub ring: usize,
pub edge: usize,
pub forward: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct EdgeUse {
pub edge: usize,
pub reversed: bool,
}
#[derive(Debug, Clone, PartialEq)]
pub struct ArrangementRegion {
pub outer: Vec<EdgeUse>,
pub holes: Vec<Vec<EdgeUse>>,
}
pub struct ArcArrangement {
raw: Raw,
vertices: Vec<Point2>,
edges: Vec<ArrangementEdge>,
counts: Vec<usize>,
}
impl std::fmt::Debug for ArcArrangement {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ArcArrangement")
.field("vertices", &self.vertices)
.field("edges", &self.edges)
.finish_non_exhaustive()
}
}
impl ArcArrangement {
pub fn new(rings: &[ArcRing], tolerance: Tolerance) -> Result<Self, OverlayError> {
let mut oriented = Vec::with_capacity(rings.len());
let mut reversed = Vec::with_capacity(rings.len());
for ring in rings {
validate_arc_ring(ring, tolerance)?;
let flip = arc_ring_area(ring) < 0.0;
oriented.push(if flip {
reverse_arc_ring(ring)
} else {
ring.clone()
});
reversed.push(flip);
}
let raw = arrangement::build(&oriented);
let counts: Vec<usize> = rings.iter().map(|ring| ring.vertices.len()).collect();
let edges = raw
.edges
.iter()
.map(|edge| ArrangementEdge {
from: edge.from,
to: edge.to,
bulge: edge.bulge,
sources: edge
.sources
.iter()
.map(|&(ring, index, forward)| {
let n = counts[ring];
if reversed[ring] {
EdgeSource {
ring,
edge: (2 * n - 2 - index) % n,
forward: !forward,
}
} else {
EdgeSource {
ring,
edge: index,
forward,
}
}
})
.collect(),
left: edge.sides(counts.len(), true),
right: edge.sides(counts.len(), false),
})
.collect();
Ok(Self {
vertices: raw.vertex_positions(),
raw,
edges,
counts,
})
}
pub fn vertices(&self) -> &[Point2] {
&self.vertices
}
pub fn edges(&self) -> &[ArrangementEdge] {
&self.edges
}
pub fn ring_count(&self) -> usize {
self.counts.len()
}
pub fn regions(
&self,
inside: impl Fn(&[bool]) -> bool,
) -> Result<Vec<ArrangementRegion>, OverlayError> {
let keep: Vec<Option<bool>> = self
.edges
.iter()
.map(|edge| match (inside(&edge.left), inside(&edge.right)) {
(true, false) => Some(false),
(false, true) => Some(true),
_ => None,
})
.collect();
let uses = |ring: Vec<(usize, bool)>| -> Vec<EdgeUse> {
ring.into_iter()
.map(|(edge, reversed)| EdgeUse { edge, reversed })
.collect()
};
Ok(self
.raw
.regions(&keep)?
.into_iter()
.map(|(outer, holes)| ArrangementRegion {
outer: uses(outer),
holes: holes.into_iter().map(uses).collect(),
})
.collect())
}
pub fn ring(&self, uses: &[EdgeUse]) -> ArcRing {
ArcRing::new(
uses.iter()
.map(|u| {
let edge = &self.edges[u.edge];
let (from, bulge) = if u.reversed {
(edge.to, -edge.bulge)
} else {
(edge.from, edge.bulge)
};
crate::arc::ArcVertex::bulged(self.vertices[from], bulge)
})
.collect(),
)
}
}