// 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 "propagate_winding_numbers.h" #include "../../extract_manifold_patches.h" #include "../../extract_non_manifold_edge_curves.h" #include "../../facet_components.h" #include "../../unique_edge_map.h" #include "../../piecewise_constant_winding_number.h" #include "../../writeOBJ.h" #include "../../writePLY.h" #include "../../get_seconds.h" #include "../../LinSpaced.h" #include "order_facets_around_edge.h" #include "outer_facet.h" #include "closest_facet.h" #include "assign.h" #include "extract_cells.h" #include "cell_adjacency.h" #include #include #include #include #include //#define PROPAGATE_WINDING_NUMBER_TIMING template< typename DerivedV, typename DerivedF, typename DerivedL, typename DerivedW> IGL_INLINE bool igl::copyleft::cgal::propagate_winding_numbers( const Eigen::PlainObjectBase& V, const Eigen::PlainObjectBase& F, const Eigen::PlainObjectBase& labels, Eigen::PlainObjectBase& W) { #ifdef PROPAGATE_WINDING_NUMBER_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 { std::cout << "propagate_winding_num." << label << ": " << tictoc() << std::endl; }; tictoc(); #endif 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); DerivedW per_patch_cells; const size_t num_cells = igl::copyleft::cgal::extract_cells( V, F, P, E, uE, uE2E, EMAP, per_patch_cells); #ifdef PROPAGATE_WINDING_NUMBER_TIMING log_time("cell_extraction"); #endif return propagate_winding_numbers(V, F, uE, uE2E, num_patches, P, num_cells, per_patch_cells, labels, W); } template< typename DerivedV, typename DerivedF, typename DeriveduE, typename uE2EType, typename DerivedP, typename DerivedC, typename DerivedL, typename DerivedW> IGL_INLINE bool igl::copyleft::cgal::propagate_winding_numbers( const Eigen::PlainObjectBase& V, const Eigen::PlainObjectBase& F, const Eigen::PlainObjectBase& uE, const std::vector >& uE2E, const size_t num_patches, const Eigen::PlainObjectBase& P, const size_t num_cells, const Eigen::PlainObjectBase& C, const Eigen::PlainObjectBase& labels, Eigen::PlainObjectBase& W) { #ifdef PROPAGATE_WINDING_NUMBER_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 { std::cout << "propagate_winding_num." << label << ": " << tictoc() << std::endl; }; tictoc(); #endif bool valid = true; // https://github.com/libigl/libigl/issues/674 if (!igl::piecewise_constant_winding_number(F, uE, uE2E)) { assert(false && "Input mesh is not PWN"); std::cerr << "Input mesh is not PWN!" << std::endl; valid = false; } const size_t num_faces = F.rows(); typedef std::tuple CellConnection; std::vector > cell_adj; igl::copyleft::cgal::cell_adjacency(C, num_cells, cell_adj); #ifdef PROPAGATE_WINDING_NUMBER_TIMING log_time("cell_connectivity"); #endif auto save_cell = [&](const std::string& filename, size_t cell_id) -> void{ std::vector faces; for (size_t i=0; i std::list { std::list path; path.push_back(idx); while ((size_t)parents[path.back()] != path.back()) { path.push_back(parents[path.back()]); } return path; }; for (size_t i=0; i Q; Q.push(i); parents[i] = i; while (!Q.empty()) { size_t curr_idx = Q.front(); Q.pop(); int curr_label = cell_labels[curr_idx]; for (const auto& neighbor : cell_adj[curr_idx]) { if (cell_labels[std::get<0>(neighbor)] == 0) { cell_labels[std::get<0>(neighbor)] = curr_label * -1; Q.push(std::get<0>(neighbor)); parents[std::get<0>(neighbor)] = curr_idx; } else { if (cell_labels[std::get<0>(neighbor)] != curr_label * -1) { std::cerr << "Odd cell cycle detected!" << std::endl; auto path = trace_parents(curr_idx); path.reverse(); auto path2 = trace_parents(std::get<0>(neighbor)); path.insert(path.end(), path2.begin(), path2.end()); for (auto cell_id : path) { std::cout << cell_id << " "; std::stringstream filename; filename << "cell_" << cell_id << ".ply"; save_cell(filename.str(), cell_id); } std::cout << std::endl; valid = false; } // Do not fail when odd cycle is detected because the resulting // integer winding number field, although inconsistent, may still // be used if the problem region is local and embedded within a // valid volume. //assert(cell_labels[std::get<0>(neighbor)] == curr_label * -1); } } } } } #ifdef PROPAGATE_WINDING_NUMBER_TIMING log_time("odd_cycle_check"); #endif } #endif size_t outer_facet; bool flipped; Eigen::VectorXi I = igl::LinSpaced(num_faces, 0, num_faces-1); igl::copyleft::cgal::outer_facet(V, F, I, outer_facet, flipped); #ifdef PROPAGATE_WINDING_NUMBER_TIMING log_time("outer_facet"); #endif const size_t outer_patch = P[outer_facet]; const size_t infinity_cell = C(outer_patch, flipped?1:0); Eigen::VectorXi patch_labels(num_patches); const int INVALID = std::numeric_limits::max(); patch_labels.setConstant(INVALID); for (size_t i=0; i Q; Q.push(infinity_cell); while (!Q.empty()) { size_t curr_cell = Q.front(); Q.pop(); for (const auto& neighbor : cell_adj[curr_cell]) { size_t neighbor_cell, patch_idx; bool direction; std::tie(neighbor_cell, direction, patch_idx) = neighbor; if ((per_cell_W.row(neighbor_cell).array() == INVALID).any()) { per_cell_W.row(neighbor_cell) = per_cell_W.row(curr_cell); for (size_t i=0; i, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, unsigned long, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, std::vector >, std::allocator > > > const&, unsigned long, Eigen::PlainObjectBase > const&, unsigned long, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); // generated by autoexplicit.sh template bool igl::copyleft::cgal::propagate_winding_numbers, -1, -1, 1, -1, -1>, Eigen::Matrix, Eigen::Matrix, unsigned long, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, std::vector >, std::allocator > > > const&, unsigned long, Eigen::PlainObjectBase > const&, unsigned long, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); template bool igl::copyleft::cgal::propagate_winding_numbers, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); #ifdef WIN32 template bool igl::copyleft::cgal::propagate_winding_numbers, -1, -1, 1, -1, -1>, class Eigen::Matrix, class Eigen::Matrix, unsigned __int64, class Eigen::Matrix, class Eigen::Matrix, class Eigen::Matrix, class Eigen::Matrix>(class Eigen::PlainObjectBase, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> const &, class std::vector>, class std::allocator>>> const &, unsigned __int64, class Eigen::PlainObjectBase> const &, unsigned __int64, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> &); template bool igl::copyleft::cgal::propagate_winding_numbers, -1, -1, 1, -1, -1>, class Eigen::Matrix, class Eigen::Matrix, unsigned __int64, class Eigen::Matrix, class Eigen::Matrix, class Eigen::Matrix, class Eigen::Matrix>(class Eigen::PlainObjectBase, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> const &, class std::vector>, class std::allocator>>> const &, unsigned __int64, class Eigen::PlainObjectBase> const &, unsigned __int64, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> const &, class Eigen::PlainObjectBase> &); #endif #endif