// 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_cells_single_component.h" #include "closest_facet.h" #include "outer_facet.h" #include "submesh_aabb_tree.h" #include "../../extract_manifold_patches.h" #include "../../facet_components.h" #include "../../IGL_ASSERT.h" #include "../../parallel_for.h" #include "../../get_seconds.h" #include "../../triangle_triangle_adjacency.h" #include "../../unique_edge_map.h" #include "../../C_STR.h" #include "../../vertex_triangle_adjacency.h" #include #include #include #include #include #include #include #include #include #include //#define EXTRACT_CELLS_TIMING template< typename DerivedV, typename DerivedF, typename DerivedC > 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(); // Construct edge adjacency Eigen::MatrixXi E, uE; Eigen::VectorXi EMAP; Eigen::VectorXi uEC,uEE; igl::unique_edge_map(F, E, uE, EMAP, uEC, uEE); // Cluster into manifold patches Eigen::VectorXi P; igl::extract_manifold_patches(F, EMAP, uEC, uEE, P); // Extract cells DerivedC per_patch_cells; const size_t ncells = extract_cells(V,F,P,uE,EMAP,uEC,uEE,per_patch_cells); // Distribute per-patch cell information to each face cells.resize(num_faces, 2); 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& uE, const Eigen::PlainObjectBase& EMAP, const Eigen::PlainObjectBase& uEC, const Eigen::PlainObjectBase& uEE, Eigen::PlainObjectBase& cells) { // Trivial base case if(P.size() == 0) { assert(F.size() == 0); cells.resize(0,2); return 0; } typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; #ifdef EXTRACT_CELLS_TIMING const auto & tictoc = []() -> double { static double t_start = igl::get_seconds(); double diff = igl::get_seconds()-t_start; t_start += diff; return diff; }; const auto log_time = [&](const std::string& label) -> void { printf("%50s: %0.5lf\n", C_STR("extract_cells." << label),tictoc()); }; tictoc(); #else // no-op const auto log_time = [](const std::string){}; #endif const size_t num_faces = F.rows(); typedef typename DerivedF::Scalar Index; assert(P.size() > 0); const size_t num_patches = P.maxCoeff()+1; // Extract all cells... DerivedC raw_cells; const int num_raw_cells = extract_cells_single_component(V,F,P,uE,uEC,uEE,raw_cells); log_time("extract_cells_single_component"); // Compute triangle-triangle adjacency data-structure std::vector > > TT,_1; igl::triangle_triangle_adjacency(EMAP, uEC, uEE, false, TT, _1); log_time("compute_face_adjacency"); // Compute connected components of the mesh Eigen::VectorXi C, counts; igl::facet_components(TT, C, counts); log_time("form_components"); const size_t num_components = counts.size(); // components[c] --> list of face indices into F of faces in component c std::vector > components(num_components); // Loop over all faces for (size_t i=0; i > VF,VFi; igl::vertex_triangle_adjacency(V.rows(), F, VF, VFi); std::vector Is(num_components); std::vector< CGAL::AABB_tree< CGAL::AABB_traits< Kernel, CGAL::AABB_triangle_primitive< Kernel, std::vector< Kernel::Triangle_3 >::iterator > > > > trees(num_components); std::vector< std::vector > triangle_lists(num_components); // O(num_components * num_faces) // In general, extract_cells appears to have O(num_components * num_faces) // performance. This could be painfully tested by a processing a cloud of // tetrahedra. std::vector > in_Is(num_components); // Find outer facets, their orientations and cells for each component Eigen::VectorXi outer_facets(num_components); Eigen::VectorXi outer_facet_orientation(num_components); Eigen::VectorXi outer_cells(num_components); igl::parallel_for(num_components,[&](size_t i) { Is[i].resize(components[i].size()); std::copy(components[i].begin(), components[i].end(),Is[i].data()); bool flipped; igl::copyleft::cgal::outer_facet(V, F, Is[i], outer_facets[i], flipped); outer_facet_orientation[i] = flipped?1:0; outer_cells[i] = raw_cells(P[outer_facets[i]], outer_facet_orientation[i]); },1000); #ifdef EXTRACT_CELLS_TIMING log_time("outer_facet_per_component"); #endif // Compute barycenter of a triangle in mesh (V,F) // // Inputs: // fid index into F // Returns row-vector of barycenter coordinates const auto get_triangle_center = [&V,&F](const size_t fid) { return ((V.row(F(fid,0))+V.row(F(fid,1))+V.row(F(fid,2)))/3.0).eval(); }; std::vector > nested_cells(num_raw_cells); std::vector > ambient_cells(num_raw_cells); std::vector > ambient_comps(num_components); // Only bother if there's more than one component if(num_components > 1) { // construct bounding boxes for each component DerivedV bbox_min(num_components, 3); DerivedV bbox_max(num_components, 3); // Assuming our mesh (in exact numbers) fits in the range of double. bbox_min.setConstant(std::numeric_limits::max()); bbox_max.setConstant(std::numeric_limits::lowest()); // Loop over faces for (size_t i=0; i candidate_comps; candidate_comps.reserve(num_components); // Loop over components for (size_t j=0; j component index inside component i, because the cell of the // closest facet on i to component index is **not** the same as the // "outer cell" of component i: component index is **not** outside of // component i (therefore it's inside). nested_cells[ambient_cell].push_back(outer_cells[index]); ambient_cells[outer_cells[index]].push_back(ambient_cell); ambient_comps[index].push_back(i); } } } } #ifdef EXTRACT_CELLS_TIMING log_time("nested_relationship"); #endif const size_t INVALID = std::numeric_limits::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); // Always map infinite cell to index 0. mapped_indices[INFINITE_CELL] = count; count++; for (size_t i=0; i // Explicit template instantiation // generated by autoexplicit.sh template size_t igl::copyleft::cgal::extract_cells, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); template size_t igl::copyleft::cgal::extract_cells, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); template size_t igl::copyleft::cgal::extract_cells, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); #ifdef WIN32 #endif #endif