ifc_lite_geometry/
union_find.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
5//! Minimal union-find with path halving, shared by mesh cavity removal and
6//! scan plane merging (`ifc_lite_processing::scan_segmentation`).
7//!
8//! `union(a, b)` always re-parents `b`'s root under `a`'s root, so the root of
9//! a set depends only on the sequence of unions, never on hashing or memory
10//! layout: callers that union in a deterministic order get deterministic roots.
11
12/// Disjoint sets over `0..n`.
13pub struct UnionFind {
14    parent: Vec<u32>,
15}
16
17impl UnionFind {
18    /// `n` singleton sets.
19    pub fn new(n: usize) -> Self {
20        Self {
21            parent: (0..n as u32).collect(),
22        }
23    }
24
25    /// Representative of `x`'s set (halves the path as it walks; the walk is
26    /// iterative and bounded by the set size).
27    pub fn find(&mut self, mut x: u32) -> u32 {
28        while self.parent[x as usize] != x {
29            let grand = self.parent[self.parent[x as usize] as usize];
30            self.parent[x as usize] = grand;
31            x = grand;
32        }
33        x
34    }
35
36    /// Merge the sets of `a` and `b`; `b`'s root is re-parented under `a`'s.
37    /// Returns whether two distinct sets were joined.
38    pub fn union(&mut self, a: u32, b: u32) -> bool {
39        let (ra, rb) = (self.find(a), self.find(b));
40        if ra != rb {
41            self.parent[rb as usize] = ra;
42        }
43        ra != rb
44    }
45}