Lagrange
compute_bordered_components.h
1/*
2 * Copyright 2019 Adobe. All rights reserved.
3 * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License. You may obtain a copy
5 * of the License at http://www.apache.org/licenses/LICENSE-2.0
6 *
7 * Unless required by applicable law or agreed to in writing, software distributed under
8 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9 * OF ANY KIND, either express or implied. See the License for the specific language
10 * governing permissions and limitations under the License.
11 */
12#pragma once
13
14#include <cassert>
15#include <deque>
16#include <vector>
17
18#include <lagrange/MeshTrait.h>
19#include <lagrange/common.h>
20#include <lagrange/legacy/inline.h>
21#include <lagrange/utils/range.h>
22
23namespace lagrange {
24LAGRANGE_LEGACY_INLINE
25namespace legacy {
26
27template <typename Index>
29{
30 // maps the facet index to the component
31 std::vector<Index> facet_to_component;
32 // maps the component to its involved facets
33 std::vector<std::vector<Index>> component_to_facets;
34};
35
36// Given a mesh and a binary list of whether certain edges are passable or blockers,
37// Divides the mesh into different components enclosed by these non-passable edges
38// (and of course the boundaries). There is no requirement on being manifold, but
39// the edge data must be initialized (otherwise, how did you compute is_edge_passable
40// in the first place).
41//
42// INPUT:
43// mesh
44// is_edge_passable (index -> bool)
45//
46// RETURNS:
47// ComputeBorderedComponentsOutput
48//
49// NOTE: Unlike Components.h that uses connectivity, this version uses the edge data
50// I am not sure if we can consolidate this two parts of the code (TODO: or can we?)
51template <typename MeshType>
53 const MeshType& mesh,
54 const std::vector<bool>& is_edge_passable)
55{
56 static_assert(MeshTrait<MeshType>::is_mesh(), "First argument must be Lagrange::Mesh<>.");
57 using Index = typename MeshType::Index;
58
59 // We just check it, since the use must have called it in order to populate is_edge_passable.
60 la_runtime_assert(mesh.is_edge_data_initialized(), "Edge data is not initialized");
61 la_runtime_assert(safe_cast<Index>(is_edge_passable.size()) == mesh.get_num_edges());
62
63 std::vector<Index> facet_component_ids(mesh.get_num_facets(), invalid<Index>());
64
65 auto perform_bfs = [&](const Index seed_id, const Index component_id) {
66 assert(facet_component_ids[seed_id] == invalid<Index>());
67 std::deque<Index> search_queue;
68 search_queue.push_back(seed_id);
69 while (!search_queue.empty()) {
70 const auto candidate_id = search_queue.back();
71 search_queue.pop_back();
72 if (facet_component_ids[candidate_id] == invalid<Index>()) {
73 facet_component_ids[candidate_id] = component_id;
74 for (Index ci : range(mesh.get_vertex_per_facet())) {
75 const auto edge_id = mesh.get_edge(candidate_id, ci);
76 const bool is_passable = is_edge_passable[edge_id];
77 if (is_passable) {
78 mesh.foreach_facets_around_edge(edge_id, [&](Index f) {
79 if (f != candidate_id) { // Not a mandatory check.
80 search_queue.push_back(f);
81 }
82 });
83 } // passable
84 } // edges
85 } // have not been visited
86 } // loop over queue
87 }; // perform_bfs()
88
89
90 Index num_components = 0;
91 for (auto i : range(mesh.get_num_facets())) {
92 if (facet_component_ids[i] == invalid<Index>()) {
93 perform_bfs(i, num_components);
94 ++num_components;
95 }
96 }
98 num_components > 0 || mesh.get_num_facets() == 0,
99 "Extracted " + std::to_string(num_components) + " comps out of " +
100 std::to_string(mesh.get_num_facets()) + " facets");
101
102 std::vector<std::vector<Index>> component_to_facets(num_components);
103 std::vector<Index> num_component_facets(num_components, 0);
104 for (auto i : range(mesh.get_num_facets())) {
105 const auto component_id = facet_component_ids[i];
106 ++num_component_facets[component_id];
107 }
108 for (auto i : range(num_components)) {
109 component_to_facets[i].reserve(num_component_facets[i]);
110 }
111 for (auto i : range(mesh.get_num_facets())) {
112 const auto component_id = facet_component_ids[i];
113 component_to_facets[component_id].push_back(i);
114 }
115
116
117 ComputeBorderedComponentsOutput<Index> output;
118 output.facet_to_component.swap(facet_component_ids);
119 output.component_to_facets.swap(component_to_facets);
120
121 return output;
122}
123
124} // namespace legacy
125} // namespace lagrange
Definition: Mesh.h:48
#define la_runtime_assert(...)
Runtime assertion check.
Definition: assert.h:169
internal::Range< Index > range(Index end)
Returns an iterable object representing the range [0, end).
Definition: range.h:176
Main namespace for Lagrange.
Definition: AABBIGL.h:30
MeshTrait class provide compiler check for different mesh types.
Definition: MeshTrait.h:108
Definition: compute_bordered_components.h:29