1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
use crate::mesh::*;
use std::collections::HashMap;

impl Mesh {
    /// Appends the `other` mesh to this mesh without creating a connection between them.
    /// Use `merge_with` if merging of overlapping primitives is desired, thereby creating a connection.
    /// All the primitives of the `other` mesh are copied to the current mesh and the `other` mesh is therefore not changed.
    pub fn append(&mut self, other: &Self) {
        let mut mapping: HashMap<VertexID, VertexID> = HashMap::new();
        let mut get_or_create_vertex = |mesh: &mut Mesh, vertex_id| -> VertexID {
            if let Some(vid) = mapping.get(&vertex_id) {
                return *vid;
            }
            let p = other.vertex_position(vertex_id);
            let vid = mesh.add_vertex(p.clone());
            mapping.insert(vertex_id, vid);
            vid
        };

        let mut face_mapping: HashMap<FaceID, FaceID> = HashMap::new();
        for other_face_id in other.face_iter() {
            let vertex_ids = other.face_vertices(other_face_id);

            let vertex_id0 = get_or_create_vertex(self, vertex_ids.0);
            let vertex_id1 = get_or_create_vertex(self, vertex_ids.1);
            let vertex_id2 = get_or_create_vertex(self, vertex_ids.2);
            let new_face_id = self
                .connectivity_info
                .create_face(vertex_id0, vertex_id1, vertex_id2);

            for halfedge_id in other.face_halfedge_iter(other_face_id) {
                if let Some(fid) = other.walker_from_halfedge(halfedge_id).as_twin().face_id() {
                    if let Some(self_face_id) = face_mapping.get(&fid) {
                        for halfedge_id1 in self.face_halfedge_iter(*self_face_id) {
                            let mut walker1 = self.walker_from_halfedge(halfedge_id1);
                            let source_vertex_id = walker1.vertex_id().unwrap();
                            let sink_vertex_id = walker1.as_next().vertex_id().unwrap();

                            for halfedge_id2 in self.face_halfedge_iter(new_face_id) {
                                let mut walker2 = self.walker_from_halfedge(halfedge_id2);
                                if sink_vertex_id == walker2.vertex_id().unwrap()
                                    && source_vertex_id == walker2.as_next().vertex_id().unwrap()
                                {
                                    self.connectivity_info.set_halfedge_twin(
                                        walker1.halfedge_id().unwrap(),
                                        walker2.halfedge_id().unwrap(),
                                    );
                                }
                            }
                        }
                    }
                }
            }

            face_mapping.insert(other_face_id, new_face_id);
        }

        self.create_boundary_edges();
    }

    fn create_boundary_edges(&mut self) {
        let mut walker = self.walker();
        for halfedge_id in self.halfedge_iter() {
            walker.as_halfedge_walker(halfedge_id);
            if walker.twin_id().is_none() {
                let boundary_halfedge_id = self.connectivity_info.new_halfedge(
                    walker.as_previous().vertex_id(),
                    None,
                    None,
                );
                self.connectivity_info
                    .set_halfedge_twin(halfedge_id, boundary_halfedge_id);
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use three_d_asset::TriMesh;

    #[test]
    fn test_sphere_sphere_append() {
        let mut mesh1: Mesh = TriMesh::sphere(4).into();
        let mut mesh2: Mesh = TriMesh::sphere(3).into();
        mesh2.translate(vec3(0.5, 0.5, 0.5));

        let prev_no_vertices = mesh1.no_vertices();
        let prev_no_halfedges = mesh1.no_halfedges();
        let prev_no_faces = mesh1.no_faces();

        mesh1.append(&mesh2);

        mesh1.is_valid().unwrap();
        mesh2.is_valid().unwrap();

        assert_eq!(mesh1.no_vertices(), mesh2.no_vertices() + prev_no_vertices);
        assert_eq!(
            mesh1.no_halfedges(),
            mesh2.no_halfedges() + prev_no_halfedges
        );
        assert_eq!(mesh1.no_faces(), mesh2.no_faces() + prev_no_faces);

        for pos in mesh2.vertex_iter().map(|v| mesh2.vertex_position(v)) {
            assert!(mesh1
                .vertex_iter()
                .find(|v| mesh1.vertex_position(*v) == pos)
                .is_some());
        }
    }
}