// This file is part of libigl, a simple c++ geometry processing library. // // Copyright (C) 2015 Alec Jacobson // // 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 "order_facets_around_edges.h" #include "../sort_angles.h" #include #include template< typename DerivedV, typename DerivedF, typename DerivedN, typename DerivedE, typename DeriveduE, typename DerivedEMAP, typename uE2EType, typename uE2oEType, typename uE2CType > IGL_INLINE typename std::enable_if::value, void>::type igl::cgal::order_facets_around_edges( const Eigen::PlainObjectBase& V, const Eigen::PlainObjectBase& F, const Eigen::PlainObjectBase& N, const Eigen::PlainObjectBase& E, const Eigen::PlainObjectBase& uE, const Eigen::PlainObjectBase& EMAP, const std::vector >& uE2E, std::vector >& uE2oE, std::vector >& uE2C ) { typedef Eigen::Matrix Vector3F; const typename DerivedV::Scalar EPS = 1e-12; const size_t num_faces = F.rows(); const size_t num_undirected_edges = uE.rows(); auto edge_index_to_face_index = [&](size_t ei) { return ei % num_faces; }; auto edge_index_to_corner_index = [&](size_t ei) { return ei / num_faces; }; uE2oE.resize(num_undirected_edges); uE2C.resize(num_undirected_edges); for(size_t ui = 0;ui 0); const auto ref_edge = adj_edges[0]; const auto ref_face = edge_index_to_face_index(ref_edge); Vector3F ref_normal = N.row(ref_face); const auto ref_corner_o = edge_index_to_corner_index(ref_edge); const auto ref_corner_s = (ref_corner_o+1)%3; const auto ref_corner_d = (ref_corner_o+2)%3; const typename DerivedF::Scalar o = F(ref_face, ref_corner_o); const typename DerivedF::Scalar s = F(ref_face, ref_corner_s); const typename DerivedF::Scalar d = F(ref_face, ref_corner_d); Vector3F edge = V.row(d) - V.row(s); auto edge_len = edge.norm(); bool degenerated = edge_len < EPS; if (degenerated) { if (edge_valance <= 2) { // There is only one way to order 2 or less faces. edge.setZero(); } else { edge.setZero(); Eigen::Matrix normals(edge_valance, 3); for (size_t fei=0; fei= EPS) { edge.normalize(); break; } } // Ensure edge direction are consistent with reference face. Vector3F in_face_vec = V.row(o) - V.row(s); if (edge.cross(in_face_vec).dot(ref_normal) < 0) { edge *= -1; } if (edge.norm() < EPS) { std::cerr << "=====================================" << std::endl; std::cerr << " ui: " << ui << std::endl; std::cerr << "edge: " << ref_edge << std::endl; std::cerr << "face: " << ref_face << std::endl; std::cerr << " vs: " << V.row(s) << std::endl; std::cerr << " vd: " << V.row(d) << std::endl; std::cerr << "adj face normals: " << std::endl; std::cerr << normals << std::endl; std::cerr << "Very degenerated case detected:" << std::endl; std::cerr << "Near zero edge surrounded by " << edge_valance << " neearly colinear faces" << std::endl; std::cerr << "=====================================" << std::endl; } } } else { edge.normalize(); } Eigen::MatrixXd angle_data(edge_valance, 3); std::vector cons(edge_valance); for (size_t fei=0; fei IGL_INLINE typename std::enable_if::value, void>::type igl::cgal::order_facets_around_edges( const Eigen::PlainObjectBase& V, const Eigen::PlainObjectBase& F, const Eigen::PlainObjectBase& N, const Eigen::PlainObjectBase& E, const Eigen::PlainObjectBase& uE, const Eigen::PlainObjectBase& EMAP, const std::vector >& uE2E, std::vector >& uE2oE, std::vector >& uE2C ) { typedef Eigen::Matrix Vector3F; typedef Eigen::Matrix Vector3E; const typename DerivedV::Scalar EPS = 1e-12; const size_t num_faces = F.rows(); const size_t num_undirected_edges = uE.rows(); auto edge_index_to_face_index = [&](size_t ei) { return ei % num_faces; }; auto edge_index_to_corner_index = [&](size_t ei) { return ei / num_faces; }; uE2oE.resize(num_undirected_edges); uE2C.resize(num_undirected_edges); for(size_t ui = 0;ui 0); const auto ref_edge = adj_edges[0]; const auto ref_face = edge_index_to_face_index(ref_edge); Vector3F ref_normal = N.row(ref_face); const auto ref_corner_o = edge_index_to_corner_index(ref_edge); const auto ref_corner_s = (ref_corner_o+1)%3; const auto ref_corner_d = (ref_corner_o+2)%3; const typename DerivedF::Scalar o = F(ref_face, ref_corner_o); const typename DerivedF::Scalar s = F(ref_face, ref_corner_s); const typename DerivedF::Scalar d = F(ref_face, ref_corner_d); Vector3E exact_edge = V.row(d) - V.row(s); exact_edge.array() /= exact_edge.squaredNorm(); Vector3F edge( CGAL::to_double(exact_edge[0]), CGAL::to_double(exact_edge[1]), CGAL::to_double(exact_edge[2])); edge.normalize(); Eigen::MatrixXd angle_data(edge_valance, 3); std::vector cons(edge_valance); for (size_t fei=0; fei std::vector index_sort(const std::vector& data) { const size_t len = data.size(); std::vector order(len); for (size_t i=0; i void order_facets_around_edge( const Eigen::PlainObjectBase& V, const Eigen::PlainObjectBase& F, size_t s, size_t d, const std::vector& adj_faces, Eigen::PlainObjectBase& order) { // Although we only need exact predicates in the algorithm, // exact constructions are needed to avoid degeneracies due to // casting to double. typedef CGAL::Exact_predicates_exact_constructions_kernel K; typedef K::Point_3 Point_3; typedef K::Plane_3 Plane_3; auto get_face_index = [&](int adj_f)->size_t{ return abs(adj_f) - 1; }; auto get_opposite_vertex = [&](size_t fid)->size_t { if (F(fid, 0) != s && F(fid, 0) != d) return F(fid, 0); if (F(fid, 1) != s && F(fid, 1) != d) return F(fid, 1); if (F(fid, 2) != s && F(fid, 2) != d) return F(fid, 2); assert(false); return -1; }; // Handle base cases if (adj_faces.size() == 0) { order.resize(0); return; } else if (adj_faces.size() == 1) { order.resize(1); order[0] = 0; return; } else if (adj_faces.size() == 2) { const size_t o1 = get_opposite_vertex(get_face_index(adj_faces[0])); const size_t o2 = get_opposite_vertex(get_face_index(adj_faces[1])); const Point_3 ps(V(s, 0), V(s, 1), V(s, 2)); const Point_3 pd(V(d, 0), V(d, 1), V(d, 2)); const Point_3 p1(V(o1, 0), V(o1, 1), V(o1, 2)); const Point_3 p2(V(o2, 0), V(o2, 1), V(o2, 2)); order.resize(2); switch (CGAL::orientation(ps, pd, p1, p2)) { case CGAL::POSITIVE: order[0] = 1; order[1] = 0; break; case CGAL::NEGATIVE: order[0] = 0; order[1] = 1; break; case CGAL::COPLANAR: order[0] = adj_faces[0] < adj_faces[1] ? 0:1; order[1] = adj_faces[0] < adj_faces[1] ? 1:0; break; default: assert(false); } return; } const size_t num_adj_faces = adj_faces.size(); const size_t o = get_opposite_vertex( get_face_index(adj_faces[0])); const Point_3 p_s(V(s, 0), V(s, 1), V(s, 2)); const Point_3 p_d(V(d, 0), V(d, 1), V(d, 2)); const Point_3 p_o(V(o, 0), V(o, 1), V(o, 2)); const Plane_3 separator(p_s, p_d, p_o); assert(!separator.is_degenerate()); std::vector opposite_vertices; for (size_t i=0; i positive_side; std::vector negative_side; std::vector tie_positive_oriented; std::vector tie_negative_oriented; std::vector positive_side_index; std::vector negative_side_index; std::vector tie_positive_oriented_index; std::vector tie_negative_oriented_index; for (size_t i=0; i positive_order, negative_order; igl::cgal::order_facets_around_edges_helper::order_facets_around_edge( V, F, s, d, positive_side, positive_order); igl::cgal::order_facets_around_edges_helper::order_facets_around_edge( V, F, s, d, negative_side, negative_order); std::vector tie_positive_order = index_sort(tie_positive_oriented); std::vector tie_negative_order = index_sort(tie_negative_oriented); // Copy results into order vector. const size_t tie_positive_size = tie_positive_oriented.size(); const size_t tie_negative_size = tie_negative_oriented.size(); const size_t positive_size = positive_order.size(); const size_t negative_size = negative_order.size(); order.resize(tie_positive_size + positive_size + tie_negative_size + negative_size); size_t count=0; for (size_t i=0; i IGL_INLINE void igl::cgal::order_facets_around_edges( const Eigen::PlainObjectBase& V, const Eigen::PlainObjectBase& F, const Eigen::PlainObjectBase& E, const Eigen::PlainObjectBase& uE, const Eigen::PlainObjectBase& EMAP, const std::vector >& uE2E, std::vector >& uE2oE, std::vector >& uE2C ) { typedef Eigen::Matrix Vector3E; const size_t num_faces = F.rows(); const size_t num_undirected_edges = uE.rows(); auto edge_index_to_face_index = [&](size_t ei) { return ei % num_faces; }; auto edge_index_to_corner_index = [&](size_t ei) { return ei / num_faces; }; uE2oE.resize(num_undirected_edges); uE2C.resize(num_undirected_edges); for(size_t ui = 0;ui 0); const auto ref_edge = adj_edges[0]; const auto ref_face = edge_index_to_face_index(ref_edge); const auto ref_corner_o = edge_index_to_corner_index(ref_edge); const auto ref_corner_s = (ref_corner_o+1)%3; const auto ref_corner_d = (ref_corner_o+2)%3; const typename DerivedF::Scalar o = F(ref_face, ref_corner_o); const typename DerivedF::Scalar s = F(ref_face, ref_corner_s); const typename DerivedF::Scalar d = F(ref_face, ref_corner_d); std::vector cons(edge_valance); std::vector adj_faces(edge_valance); for (size_t fei=0; fei