// This file is part of libigl, a simple c++ geometry processing library. // // Copyright (C) 2015 Qingnan Zhou // // This Source Code Form is subject to the terms of the Mozilla Public License // v. 2.0. If a copy of the MPL was not distributed with this file, You can // obtain one at http://mozilla.org/MPL/2.0/. // #include "extract_cells.h" #include "../../extract_manifold_patches.h" #include "../../facet_components.h" #include "../../triangle_triangle_adjacency.h" #include "../../unique_edge_map.h" #include "../../get_seconds.h" #include "closest_facet.h" #include "order_facets_around_edge.h" #include "outer_facet.h" #include #include //#define EXTRACT_CELLS_DEBUG template< typename DerivedV, typename DerivedF, typename DerivedP, typename DeriveduE, typename uE2EType, typename DerivedEMAP, typename DerivedC > IGL_INLINE size_t igl::copyleft::cgal::extract_cells_single_component( const Eigen::PlainObjectBase& V, const Eigen::PlainObjectBase& F, const Eigen::PlainObjectBase& P, const Eigen::PlainObjectBase& uE, const std::vector >& uE2E, const Eigen::PlainObjectBase& EMAP, Eigen::PlainObjectBase& cells) { //typedef typename DerivedF::Scalar Index; const size_t num_faces = F.rows(); auto edge_index_to_face_index = [&](size_t index) { return index % num_faces; }; auto is_consistent = [&](const size_t fid, const size_t s, const size_t d) { if ((size_t)F(fid, 0) == s && (size_t)F(fid, 1) == d) return false; if ((size_t)F(fid, 1) == s && (size_t)F(fid, 2) == d) return false; if ((size_t)F(fid, 2) == s && (size_t)F(fid, 0) == d) return false; if ((size_t)F(fid, 0) == d && (size_t)F(fid, 1) == s) return true; if ((size_t)F(fid, 1) == d && (size_t)F(fid, 2) == s) return true; if ((size_t)F(fid, 2) == d && (size_t)F(fid, 0) == s) return true; throw "Invalid face!"; return false; }; const size_t num_unique_edges = uE.rows(); const size_t num_patches = P.maxCoeff() + 1; std::vector > patch_edge_adj(num_patches); std::vector orders(num_unique_edges); std::vector > orientations(num_unique_edges); for (size_t i=0; i 2) { std::vector signed_adj_faces; for (auto ei : adj_faces) { const size_t fid = edge_index_to_face_index(ei); bool cons = is_consistent(fid, s, d); signed_adj_faces.push_back((fid+1)*(cons ? 1:-1)); } auto& order = orders[i]; igl::copyleft::cgal::order_facets_around_edge( V, F, s, d, signed_adj_faces, order); auto& orientation = orientations[i]; orientation.resize(order.size()); std::transform(order.data(), order.data() + order.size(), orientation.begin(), [&](int index) { return signed_adj_faces[index] > 0; }); std::transform(order.data(), order.data() + order.size(), order.data(), [&](int index) { return adj_faces[index]; }); for (auto ei : adj_faces) { const size_t fid = edge_index_to_face_index(ei); patch_edge_adj[P[fid]].push_back(ei); } } } const int INVALID = std::numeric_limits::max(); cells.resize(num_patches, 2); cells.setConstant(INVALID); auto peel_cell_bd = [&]( size_t seed_patch_id, short seed_patch_side, size_t cell_idx) { typedef std::pair PatchSide; std::queue Q; Q.emplace(seed_patch_id, seed_patch_side); cells(seed_patch_id, seed_patch_side) = cell_idx; while (!Q.empty()) { auto entry = Q.front(); Q.pop(); const size_t patch_id = entry.first; const short side = entry.second; const auto& adj_edges = patch_edge_adj[patch_id]; for (const auto& ei : adj_edges) { const size_t uei = EMAP[ei]; const auto& order = orders[uei]; const auto& orientation = orientations[uei]; const size_t edge_valance = order.size(); size_t curr_i = 0; for (curr_i=0; curr_i < edge_valance; curr_i++) { if ((size_t)order[curr_i] == ei) break; } assert(curr_i < edge_valance); const bool cons = orientation[curr_i]; size_t next; if (side == 0) { next = (cons ? (curr_i + 1) : (curr_i + edge_valance - 1)) % edge_valance; } else { next = (cons ? (curr_i + edge_valance - 1) : (curr_i + 1)) % edge_valance; } const size_t next_ei = order[next]; const bool next_cons = orientation[next]; const size_t next_patch_id = P[next_ei % num_faces]; const short next_patch_side = (next_cons != cons) ? side:abs(side-1); if (cells(next_patch_id, next_patch_side) == INVALID) { Q.emplace(next_patch_id, next_patch_side); cells(next_patch_id, next_patch_side) = cell_idx; } else { assert( (size_t)cells(next_patch_id, next_patch_side) == cell_idx); } } } }; size_t count=0; for (size_t i=0; i IGL_INLINE size_t igl::copyleft::cgal::extract_cells( const Eigen::PlainObjectBase& V, const Eigen::PlainObjectBase& F, const Eigen::PlainObjectBase& P, const Eigen::PlainObjectBase& E, const Eigen::PlainObjectBase& uE, const std::vector >& uE2E, const Eigen::PlainObjectBase& EMAP, Eigen::PlainObjectBase& cells) { #ifdef EXTRACT_CELLS_DEBUG const auto & tictoc = []() { static double t_start = igl::get_seconds(); double diff = igl::get_seconds()-t_start; t_start += diff; return diff; }; tictoc(); #endif const size_t num_faces = F.rows(); typedef typename DerivedF::Scalar Index; const size_t num_patches = P.maxCoeff()+1; DerivedC raw_cells; const size_t num_raw_cells = igl::copyleft::cgal::extract_cells_single_component( V, F, P, uE, uE2E, EMAP, raw_cells); #ifdef EXTRACT_CELLS_DEBUG std::cout << "Extract single component cells: " << tictoc() << std::endl; #endif std::vector > > TT,_1; igl::triangle_triangle_adjacency(E, EMAP, uE2E, false, TT, _1); #ifdef EXTRACT_CELLS_DEBUG std::cout << "face adj: " << tictoc() << std::endl; #endif Eigen::VectorXi C, counts; igl::facet_components(TT, C, counts); #ifdef EXTRACT_CELLS_DEBUG std::cout << "face comp: " << tictoc() << std::endl; #endif const size_t num_components = counts.size(); std::vector > components(num_components); for (size_t i=0; i Is(num_components); for (size_t i=0; i > nested_cells(num_raw_cells); std::vector > ambient_cells(num_raw_cells); std::vector > ambient_comps(num_components); if (num_components > 1) { DerivedV bbox_min(num_components, 3); DerivedV bbox_max(num_components, 3); bbox_min.rowwise() = V.colwise().maxCoeff().eval(); bbox_max.rowwise() = V.colwise().minCoeff().eval(); for (size_t i=0; i candidate_comps; candidate_comps.reserve(num_components); for (size_t j=0; j::max(); const size_t INFINITE_CELL = num_raw_cells; std::vector embedded_cells(num_raw_cells, INVALID); for (size_t i=0; i 0) { size_t embedded_comp = INVALID; size_t embedded_cell = INVALID; for (size_t j=0; j mapped_indices(num_raw_cells+1, INVALID); for (size_t i=0; i IGL_INLINE size_t igl::copyleft::cgal::extract_cells( const Eigen::PlainObjectBase& V, const Eigen::PlainObjectBase& F, Eigen::PlainObjectBase& cells) { const size_t num_faces = F.rows(); //typedef typename DerivedF::Scalar Index; Eigen::MatrixXi E, uE; Eigen::VectorXi EMAP; std::vector > uE2E; igl::unique_edge_map(F, E, uE, EMAP, uE2E); Eigen::VectorXi P; //const size_t num_patches = igl::extract_manifold_patches(F, EMAP, uE2E, P); DerivedC per_patch_cells; const size_t num_cells = igl::copyleft::cgal::extract_cells(V, F, P, E, uE, uE2E, EMAP, per_patch_cells); cells.resize(num_faces, 2); for (size_t i=0; i template unsigned long igl::copyleft::cgal::extract_cells, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, unsigned long, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, std::vector >, std::allocator > > > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); #endif