use crate::geom::{Real, edge_sign, vert_eq, vert_leq};
use crate::mesh::{EdgeIdx, INVALID};
use crate::dict::{DICT_HEAD, Dict, NodeIdx};
use crate::sweep::ActiveRegion;
use super::{Tessellator, WindingRule, RegionIdx};
impl Tessellator {
pub(super) fn add_sentinel(&mut self, smin: Real, smax: Real, t: Real) -> bool {
let e = match self.mesh.as_mut().unwrap().make_edge() {
Some(e) => e,
None => return false,
};
{
let mesh = self.mesh.as_mut().unwrap();
let org = mesh.edges[e as usize].org;
let dst = mesh.dst(e);
mesh.verts[org as usize].s = smax;
mesh.verts[org as usize].t = t;
mesh.verts[dst as usize].s = smin;
mesh.verts[dst as usize].t = t;
}
let dst = self.mesh.as_ref().unwrap().dst(e);
let (dst_s, dst_t) = {
let m = self.mesh.as_ref().unwrap();
(m.verts[dst as usize].s, m.verts[dst as usize].t)
};
self.event = dst;
self.event_s = dst_s;
self.event_t = dst_t;
let reg = self.alloc_region();
{
let r = self.region_mut(reg);
r.e_up = e;
r.winding_number = 0;
r.inside = false;
r.sentinel = true;
r.dirty = false;
r.fix_upper_edge = false;
}
let node = self.dict_insert_region(reg);
if node == INVALID {
return false;
}
self.region_mut(reg).node_up = node;
self.mesh.as_mut().unwrap().edges[e as usize].active_region = reg;
true
}
pub(super) fn dict_insert_region(&mut self, reg: RegionIdx) -> NodeIdx {
self.dict_insert_before(reg, DICT_HEAD)
}
pub(super) fn dict_insert_before(&mut self, reg: RegionIdx, start_node: NodeIdx) -> NodeIdx {
let max_dict_iters = self.dict.nodes.len() + 2;
let mut node = start_node;
let mut dict_iter = 0usize;
loop {
node = self.dict.nodes[node as usize].prev;
let key = self.dict.nodes[node as usize].key;
if key == INVALID {
break; }
if self.edge_leq(key, reg) {
break;
}
dict_iter += 1;
if dict_iter > max_dict_iters {
break; }
}
let after = node;
let before = self.dict.nodes[after as usize].next;
let new_node = self.dict.nodes.len() as NodeIdx;
use crate::dict::DictNode;
let new_dict_node = DictNode {
key: reg,
next: before,
prev: after,
};
self.dict.nodes.push(new_dict_node);
self.dict.nodes[after as usize].next = new_node;
self.dict.nodes[before as usize].prev = new_node;
new_node
}
pub(super) fn init_edge_dict(&mut self) -> bool {
self.dict = Dict::new();
let w = (self.bmax[0] - self.bmin[0]) + 0.01;
let h = (self.bmax[1] - self.bmin[1]) + 0.01;
let smin = self.bmin[0] - w;
let smax = self.bmax[0] + w;
let tmin = self.bmin[1] - h;
let tmax = self.bmax[1] + h;
if !self.add_sentinel(smin, smax, tmin) {
return false;
}
if !self.add_sentinel(smin, smax, tmax) {
return false;
}
true
}
pub(super) fn done_edge_dict(&mut self) {
let mut node = self.dict.min();
while node != DICT_HEAD {
let key = self.dict.key(node);
let next = self.dict.succ(node);
if key != INVALID {
let is_sentinel = self.region(key).sentinel;
if is_sentinel {
self.dict.delete(node);
self.free_region(key);
}
}
node = next;
}
}
pub(super) fn alloc_region(&mut self) -> RegionIdx {
if let Some(idx) = self.region_free.pop() {
self.regions[idx as usize] = Some(ActiveRegion::default());
idx
} else {
let idx = self.regions.len() as RegionIdx;
self.regions.push(Some(ActiveRegion::default()));
idx
}
}
pub(super) fn free_region(&mut self, idx: RegionIdx) {
if idx != INVALID {
self.regions[idx as usize] = None;
self.region_free.push(idx);
}
}
pub(super) fn region(&self, idx: RegionIdx) -> &ActiveRegion {
self.regions[idx as usize].as_ref().unwrap()
}
pub(super) fn region_mut(&mut self, idx: RegionIdx) -> &mut ActiveRegion {
self.regions[idx as usize].as_mut().unwrap()
}
pub(super) fn region_above(&self, reg: RegionIdx) -> RegionIdx {
let node = self.region(reg).node_up;
self.dict.key(self.dict.succ(node))
}
pub(super) fn region_below(&self, reg: RegionIdx) -> RegionIdx {
let node = self.region(reg).node_up;
self.dict.key(self.dict.pred(node))
}
pub(super) fn edge_leq(&self, reg1: RegionIdx, reg2: RegionIdx) -> bool {
let e1 = self.region(reg1).e_up;
let e2 = self.region(reg2).e_up;
if e1 == INVALID {
return true;
}
if e2 == INVALID {
return false;
}
let mesh = self.mesh.as_ref().unwrap();
let e1_dst = mesh.dst(e1);
let e2_dst = mesh.dst(e2);
let e1_org = mesh.edges[e1 as usize].org;
let e2_org = mesh.edges[e2 as usize].org;
let ev_s = self.event_s;
let ev_t = self.event_t;
let (e1ds, e1dt) = (mesh.verts[e1_dst as usize].s, mesh.verts[e1_dst as usize].t);
let (e2ds, e2dt) = (mesh.verts[e2_dst as usize].s, mesh.verts[e2_dst as usize].t);
let (e1os, e1ot) = (mesh.verts[e1_org as usize].s, mesh.verts[e1_org as usize].t);
let (e2os, e2ot) = (mesh.verts[e2_org as usize].s, mesh.verts[e2_org as usize].t);
if vert_eq(e1ds, e1dt, ev_s, ev_t) {
if vert_eq(e2ds, e2dt, ev_s, ev_t) {
if vert_leq(e1os, e1ot, e2os, e2ot) {
return edge_sign(e2ds, e2dt, e1os, e1ot, e2os, e2ot) <= 0.0;
}
return edge_sign(e1ds, e1dt, e2os, e2ot, e1os, e1ot) >= 0.0;
}
return edge_sign(e2ds, e2dt, ev_s, ev_t, e2os, e2ot) <= 0.0;
}
if vert_eq(e2ds, e2dt, ev_s, ev_t) {
return edge_sign(e1ds, e1dt, ev_s, ev_t, e1os, e1ot) >= 0.0;
}
let t1 = crate::geom::edge_eval(e1ds, e1dt, ev_s, ev_t, e1os, e1ot);
let t2 = crate::geom::edge_eval(e2ds, e2dt, ev_s, ev_t, e2os, e2ot);
t1 >= t2
}
pub(super) fn add_region_below(&mut self, _reg_above: RegionIdx, e_new_up: EdgeIdx) -> RegionIdx {
let reg_new = self.alloc_region();
{
let r = self.region_mut(reg_new);
r.e_up = e_new_up;
r.fix_upper_edge = false;
r.sentinel = false;
r.dirty = false;
}
let new_node_idx = self.dict_insert_region(reg_new);
if new_node_idx == INVALID {
self.free_region(reg_new);
return INVALID;
}
self.region_mut(reg_new).node_up = new_node_idx;
debug_assert_eq!(
self.mesh.as_ref().unwrap().edges[(e_new_up ^ 1) as usize].active_region,
INVALID,
"add_region_below({}): sym {} already bound to active region {}",
e_new_up,
e_new_up ^ 1,
self.mesh.as_ref().unwrap().edges[(e_new_up ^ 1) as usize].active_region,
);
self.mesh.as_mut().unwrap().edges[e_new_up as usize].active_region = reg_new;
self.compute_winding(reg_new);
reg_new
}
pub(super) fn delete_region(&mut self, reg: RegionIdx) {
if self.region(reg).fix_upper_edge {
}
let e_up = self.region(reg).e_up;
if e_up != INVALID {
self.mesh.as_mut().unwrap().edges[e_up as usize].active_region = INVALID;
}
let node = self.region(reg).node_up;
self.dict.delete(node);
self.free_region(reg);
}
pub(super) fn fix_upper_edge(&mut self, reg: RegionIdx, new_edge: EdgeIdx) -> bool {
let old_edge = self.region(reg).e_up;
if old_edge != INVALID {
let mesh = self.mesh.as_mut().unwrap();
mesh.edges[old_edge as usize].active_region = INVALID;
mesh.edges[(old_edge ^ 1) as usize].active_region = INVALID;
if !mesh.delete_edge(old_edge) {
return false;
}
}
self.region_mut(reg).fix_upper_edge = false;
self.region_mut(reg).e_up = new_edge;
self.mesh.as_mut().unwrap().edges[new_edge as usize].active_region = reg;
true
}
pub(super) fn is_winding_inside(&self, n: i32) -> bool {
match self.winding_rule {
WindingRule::Odd => n & 1 != 0,
WindingRule::NonZero => n != 0,
WindingRule::Positive => n > 0,
WindingRule::Negative => n < 0,
WindingRule::AbsGeqTwo => n >= 2 || n <= -2,
}
}
pub(super) fn compute_winding(&mut self, reg: RegionIdx) {
let above = self.region_above(reg);
let above_winding = if above != INVALID {
self.region(above).winding_number
} else {
0
};
let e_up = self.region(reg).e_up;
let e_winding = if e_up != INVALID {
self.mesh.as_ref().unwrap().edges[e_up as usize].winding
} else {
0
};
let new_winding = above_winding + e_winding;
let inside = self.is_winding_inside(new_winding);
if self.trace_enabled {
eprintln!(
"R COMPUTE_WINDING winding={} inside={} edge_winding={}",
new_winding, inside as i32, e_winding
);
}
self.region_mut(reg).winding_number = new_winding;
self.region_mut(reg).inside = inside;
}
pub(super) fn finish_region(&mut self, reg: RegionIdx) {
let e = self.region(reg).e_up;
if e != INVALID {
let lface = self.mesh.as_ref().unwrap().edges[e as usize].lface;
if lface != INVALID {
let inside = self.region(reg).inside;
if self.trace_enabled {
let mesh = self.mesh.as_ref().unwrap();
let mut edge_count = 0u32;
let an = mesh.faces[lface as usize].an_edge;
if an != INVALID {
let mut iter = an;
loop {
edge_count += 1;
iter = mesh.edges[iter as usize].lnext;
if iter == an || edge_count > 10000 { break; }
}
}
let org = mesh.edges[e as usize].org;
let (os, ot) = if org != INVALID {
(mesh.verts[org as usize].s, mesh.verts[org as usize].t)
} else {
(0.0, 0.0)
};
eprintln!(
"R FINISH_REGION inside={} winding={} face_edges={} eUp_org=({:.2},{:.2})",
inside as i32,
self.region(reg).winding_number,
edge_count,
os, ot
);
}
self.mesh.as_mut().unwrap().faces[lface as usize].inside = inside;
self.mesh.as_mut().unwrap().faces[lface as usize].an_edge = e;
}
}
self.delete_region(reg);
}
pub(super) fn top_left_region(&mut self, reg: RegionIdx) -> RegionIdx {
let org = {
let e = self.region(reg).e_up;
if e == INVALID {
return INVALID;
}
self.mesh.as_ref().unwrap().edges[e as usize].org
};
let max_region_iters = self.regions.len() + 2;
let mut r = reg;
let mut region_iter = 0usize;
loop {
r = self.region_above(r);
if r == INVALID {
return INVALID;
}
let e = self.region(r).e_up;
if e == INVALID {
return INVALID;
}
let e_org = self.mesh.as_ref().unwrap().edges[e as usize].org;
if e_org != org {
break;
}
region_iter += 1;
if region_iter > max_region_iters {
return INVALID; }
}
if self.region(r).fix_upper_edge {
let below = self.region_below(r);
let below_e = self.region(below).e_up;
let below_e_sym = below_e ^ 1;
let r_e = self.region(r).e_up;
let r_e_lnext = self.mesh.as_ref().unwrap().edges[r_e as usize].lnext;
let new_e = match self.mesh.as_mut().unwrap().connect(below_e_sym, r_e_lnext) {
Some(e) => e,
None => return INVALID,
};
if !self.fix_upper_edge(r, new_e) {
return INVALID;
}
r = self.region_above(r);
}
r
}
pub(super) fn top_right_region(&self, reg: RegionIdx) -> RegionIdx {
let dst = {
let e = self.region(reg).e_up;
if e == INVALID {
return INVALID;
}
self.mesh.as_ref().unwrap().dst(e)
};
let max_region_iters = self.regions.len() + 2;
let mut r = reg;
let mut region_iter = 0usize;
loop {
r = self.region_above(r);
if r == INVALID {
return INVALID;
}
let e = self.region(r).e_up;
if e == INVALID {
return INVALID;
}
let e_dst = self.mesh.as_ref().unwrap().dst(e);
if e_dst != dst {
break;
}
region_iter += 1;
if region_iter > max_region_iters {
return INVALID; }
}
r
}
}