// 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 "exterior_element.h" #include "vertex_triangle_adjacency.h" #include template < typename DerivedV, typename DerivedF, typename DerivedI, typename IndexType, typename DerivedA > IGL_INLINE void igl::exterior_vertex( const Eigen::PlainObjectBase & V, const Eigen::PlainObjectBase & F, const Eigen::PlainObjectBase & I, IndexType & v_index, Eigen::PlainObjectBase & A) { // Algorithm: // Find an exterior vertex (i.e. vertex reachable from infinity) // Return the vertex with the largest X value. // If there is a tie, pick the one with largest Y value. // If there is still a tie, pick the one with the largest Z value. // If there is still a tie, then there are duplicated vertices within the // mesh, which violates the precondition. const size_t INVALID = std::numeric_limits::max(); const size_t num_selected_faces = I.rows(); std::vector candidate_faces; size_t exterior_vid = INVALID; typename DerivedV::Scalar exterior_val = 0; for (size_t i=0; i exterior_val) { exterior_val = vx; exterior_vid = v; candidate_faces = {f}; } else if (v == exterior_vid) { candidate_faces.push_back(f); } else if (vx == exterior_val) { // Break tie. auto vy = V(v,1); auto vz = V(v, 2); auto exterior_y = V(exterior_vid, 1); auto exterior_z = V(exterior_vid, 2); assert(!(vy == exterior_y && vz == exterior_z)); bool replace = (vy > exterior_y) || ((vy == exterior_y) && (vz > exterior_z)); if (replace) { exterior_val = vx; exterior_vid = v; candidate_faces = {f}; } } } } assert(exterior_vid != INVALID); assert(candidate_faces.size() > 0); v_index = exterior_vid; A.resize(candidate_faces.size()); std::copy(candidate_faces.begin(), candidate_faces.end(), A.data()); } template< typename DerivedV, typename DerivedF, typename DerivedI, typename IndexType, typename DerivedA > IGL_INLINE void igl::exterior_edge( const Eigen::PlainObjectBase & V, const Eigen::PlainObjectBase & F, const Eigen::PlainObjectBase & I, IndexType & v1, IndexType & v2, Eigen::PlainObjectBase & A) { // Algorithm: // Find an exterior vertex first. // Find the incident edge with largest slope when projected onto XY plane. // If there is still a tie, break it using the projected splot onto ZX plane. // If there is still a tie, then there are multiple overlapping edges, // which violates the precondition. typedef typename DerivedV::Scalar Scalar; typedef typename DerivedV::Index Index; typedef typename Eigen::Matrix ScalarArray3; typedef typename Eigen::Matrix IndexArray3; const size_t INVALID = std::numeric_limits::max(); Index exterior_vid; DerivedI candidate_faces; exterior_vertex(V, F, I, exterior_vid, candidate_faces); const ScalarArray3& exterior_v = V.row(exterior_vid); assert(candidate_faces.size() > 0); auto get_vertex_index = [&](const IndexArray3& f, Index vid) { if (f[0] == vid) return 0; if (f[1] == vid) return 1; if (f[2] == vid) return 2; assert(false); }; Scalar exterior_slope_YX = 0; Scalar exterior_slope_ZX = 0; size_t exterior_opp_vid = INVALID; bool infinite_slope_detected = false; std::vector incident_faces; auto check_and_update_exterior_edge = [&](Index opp_vid, Index fid) { if (opp_vid == exterior_opp_vid) { incident_faces.push_back(fid); return; } const ScalarArray3 opp_v = V.row(opp_vid); if (!infinite_slope_detected && exterior_v[0] != opp_v[0]) { // Finite slope const ScalarArray3 diff = opp_v - exterior_v; const Scalar slope_YX = diff[1] / diff[0]; const Scalar slope_ZX = diff[2] / diff[0]; if (exterior_opp_vid == INVALID || slope_YX > exterior_slope_YX || (slope_YX == exterior_slope_YX && slope_ZX > exterior_slope_ZX)) { exterior_opp_vid = opp_vid; exterior_slope_YX = slope_YX; exterior_slope_ZX = slope_ZX; incident_faces = {fid}; } } else if (!infinite_slope_detected) { // Infinite slope exterior_opp_vid = opp_vid; infinite_slope_detected = true; incident_faces = {fid}; } }; const auto num_candidate_faces = candidate_faces.size(); for (size_t i=0; i IGL_INLINE void igl::exterior_facet( const Eigen::PlainObjectBase & V, const Eigen::PlainObjectBase & F, const Eigen::PlainObjectBase & N, const Eigen::PlainObjectBase & I, IndexType & f, bool & flipped) { // Algorithm: // Compute the exterior edge. // Find the facet with the largest absolute X normal component. // If there is a tie, keep the one with positive X component. // If there is still a tie, just pick first candidate. typedef typename DerivedV::Scalar Scalar; typedef typename DerivedV::Index Index; const size_t INVALID = std::numeric_limits::max(); Index v1,v2; DerivedI incident_faces; exterior_edge(V, F, I, v1, v2, incident_faces); assert(incident_faces.size() > 0); auto generic_fabs = [&](const Scalar& val) -> const Scalar { if (val >= 0) return val; else return -val; }; Scalar max_nx = 0; size_t exterior_fid = INVALID; const size_t num_incident_faces = incident_faces.size(); for (size_t i=0; i generic_fabs(max_nx)) { max_nx = nx; exterior_fid = fid; } else if (nx == -max_nx && nx > 0) { max_nx = nx; exterior_fid = fid; } } } assert(exterior_fid != INVALID); f = exterior_fid; flipped = max_nx < 0; } #ifdef IGL_STATIC_LIBRARY // Explicit template specialization template void igl::exterior_facet, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, int>(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, int&, bool&); template void igl::exterior_facet, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, unsigned long>(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, unsigned long&, bool&); template void igl::exterior_facet, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, int>(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, int&, bool&); template void igl::exterior_facet, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix, int>(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, int&, bool&); #endif