use std::collections::{BTreeMap, HashMap};
use crate::disjoint_sets::DisjointSets;
use super::classify::{Classification, Tag};
use super::intersection_graph::{edge_key, EdgeKey, IntersectionGraph};
pub struct Propagation {
pub tags: Vec<Option<Tag>>,
pub untagged: Vec<(usize, usize)>,
pub component: Vec<usize>,
}
pub fn propagate(graph: &IntersectionGraph, cls: &Classification) -> Propagation {
let n = graph.pieces.len();
let ds = DisjointSets::new(n as u32);
let mut edge_owner: HashMap<(u8, EdgeKey), Vec<usize>> = HashMap::new();
for (pi, piece) in graph.pieces.iter().enumerate() {
if cls.discarded[pi] {
continue;
}
for e in 0..3 {
let key = edge_key(piece.vi[e], piece.vi[(e + 1) % 3]);
if graph.isect_edges.contains(&key) {
continue; }
edge_owner.entry((piece.mesh, key)).or_default().push(pi);
}
}
for owners in edge_owner.values() {
for w in owners.windows(2) {
ds.unite(w[0] as u32, w[1] as u32);
}
}
let mut comp_tag: BTreeMap<usize, Tag> = BTreeMap::new();
for pi in 0..n {
if cls.discarded[pi] {
continue;
}
if let Some(tag) = cls.tags[pi] {
let root = ds.find(pi as u32) as usize;
let prev = comp_tag.insert(root, tag);
debug_assert!(
prev.is_none() || prev == Some(tag),
"conflicting tags within one surface component"
);
}
}
let mut tags: Vec<Option<Tag>> = vec![None; n];
let mut component = vec![0usize; n];
let mut untagged_roots: BTreeMap<usize, usize> = BTreeMap::new();
for pi in 0..n {
if cls.discarded[pi] {
continue;
}
let root = ds.find(pi as u32) as usize;
component[pi] = root;
match comp_tag.get(&root) {
Some(tag) => tags[pi] = Some(*tag),
None => {
untagged_roots.entry(root).or_insert(pi);
}
}
}
Propagation {
tags,
untagged: untagged_roots.into_iter().collect(),
component,
}
}