veloren_world/site/settlement/building/
skeleton.rs

1use crate::site::BlockMask;
2use vek::*;
3
4#[derive(Copy, Clone, PartialEq, Eq)]
5pub enum Ori {
6    East,
7    North,
8}
9
10impl Ori {
11    #[must_use]
12    pub fn flip(self) -> Self {
13        match self {
14            Ori::East => Ori::North,
15            Ori::North => Ori::East,
16        }
17    }
18
19    pub fn dir(self) -> Vec2<i32> {
20        match self {
21            Ori::East => Vec2::unit_x(),
22            Ori::North => Vec2::unit_y(),
23        }
24    }
25}
26
27pub struct Branch<T> {
28    pub len: i32,
29    pub attr: T,
30    pub locus: i32,
31    pub border: i32,
32    pub children: Vec<(i32, Branch<T>)>,
33}
34
35impl<T> Branch<T> {
36    fn for_each<'a>(
37        &'a self,
38        node: Vec2<i32>,
39        ori: Ori,
40        is_child: bool,
41        parent_locus: i32,
42        f: &mut impl FnMut(Vec2<i32>, Ori, &'a Branch<T>, bool, i32),
43    ) {
44        f(node, ori, self, is_child, parent_locus);
45        for (offset, child) in &self.children {
46            child.for_each(node + ori.dir() * *offset, ori.flip(), true, self.locus, f);
47        }
48    }
49}
50
51pub struct Skeleton<T> {
52    pub offset: i32,
53    pub ori: Ori,
54    pub root: Branch<T>,
55}
56
57impl<T> Skeleton<T> {
58    pub fn for_each<'a>(&'a self, mut f: impl FnMut(Vec2<i32>, Ori, &'a Branch<T>, bool, i32)) {
59        self.root
60            .for_each(self.ori.dir() * self.offset, self.ori, false, 0, &mut f);
61    }
62
63    pub fn bounds(&self) -> Aabr<i32> {
64        let mut bounds = Aabr::new_empty(self.ori.dir() * self.offset);
65        self.for_each(|node, ori, branch, _, _| {
66            let node2 = node + ori.dir() * branch.len;
67
68            let a = node.map2(node2, |a, b| a.min(b)) - (branch.locus + branch.border);
69            let b = node.map2(node2, |a, b| a.max(b)) + (branch.locus + branch.border);
70            bounds.expand_to_contain_point(a);
71            bounds.expand_to_contain_point(b);
72        });
73        bounds
74    }
75
76    pub fn sample_closest(
77        &self,
78        pos: Vec3<i32>,
79        mut f: impl FnMut(Vec3<i32>, i32, Vec2<i32>, Vec2<i32>, Ori, &Branch<T>) -> BlockMask,
80    ) -> BlockMask {
81        let mut min = None::<(_, BlockMask)>;
82        self.for_each(|node, ori, branch, is_child, parent_locus| {
83            let node2 = node + ori.dir() * branch.len;
84            let node = node
85                + if is_child {
86                    ori.dir()
87                        * branch.len.signum()
88                        * (branch.locus - parent_locus).clamped(0, branch.len.abs())
89                } else {
90                    Vec2::zero()
91                };
92            let bounds = Aabr::new_empty(node).expanded_to_contain_point(node2);
93            let bound_offset = if ori == Ori::East {
94                Vec2::new(
95                    node.y - pos.y,
96                    pos.x - pos.x.clamped(bounds.min.x, bounds.max.x),
97                )
98            } else {
99                Vec2::new(
100                    node.x - pos.x,
101                    pos.y - pos.y.clamped(bounds.min.y, bounds.max.y),
102                )
103            }
104            .map(|e| e.abs());
105            let center_offset = if ori == Ori::East {
106                Vec2::new(pos.y - bounds.center().y, pos.x - bounds.center().x)
107            } else {
108                Vec2::new(pos.x - bounds.center().x, pos.y - bounds.center().y)
109            };
110            let dist = bound_offset.reduce_max();
111            let dist_locus = dist - branch.locus;
112            let new_bm = f(pos, dist, bound_offset, center_offset, ori, branch);
113            min = min
114                .map(|(_, bm)| (dist_locus, bm.resolve_with(new_bm)))
115                .or(Some((dist_locus, new_bm)));
116        });
117        min.map(|(_, bm)| bm).unwrap_or_else(BlockMask::nothing)
118    }
119}