// 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 "points_inside_component.h" #include "../../LinSpaced.h" #include "order_facets_around_edge.h" #include "assign_scalar.h" #include #include #include #include #include #include #include #include namespace igl { namespace copyleft { namespace cgal { namespace points_inside_component_helper { typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; typedef Kernel::Ray_3 Ray_3; typedef Kernel::Point_3 Point_3; typedef Kernel::Vector_3 Vector_3; typedef Kernel::Triangle_3 Triangle; typedef Kernel::Plane_3 Plane_3; typedef std::vector::iterator Iterator; typedef CGAL::AABB_triangle_primitive Primitive; typedef CGAL::AABB_traits AABB_triangle_traits; typedef CGAL::AABB_tree Tree; template void extract_adj_faces( const Eigen::PlainObjectBase& F, const Eigen::PlainObjectBase& I, const size_t s, const size_t d, std::vector& adj_faces) { const size_t num_faces = I.rows(); for (size_t i=0; i void extract_adj_vertices( const Eigen::PlainObjectBase& F, const Eigen::PlainObjectBase& I, const size_t v, std::vector& adj_vertices) { std::set unique_adj_vertices; const size_t num_faces = I.rows(); for (size_t i=0; i bool determine_point_edge_orientation( const Eigen::PlainObjectBase& V, const Eigen::PlainObjectBase& F, const Eigen::PlainObjectBase& I, const Point_3& query, size_t s, size_t d) { // Algorithm: // // Order the adj faces around the edge (s,d) clockwise using // query point as pivot. (i.e. The first face of the ordering // is directly after the pivot point, and the last face is // directly before the pivot.) // // The point is outside if the first and last faces of the // ordering forms a convex angle. This check can be done // without any construction by looking at the orientation of the // faces. The angle is convex iff the first face contains (s,d) // as an edge and the last face contains (d,s) as an edge. // // The point is inside if the first and last faces of the // ordering forms a concave angle. That is the first face // contains (d,s) as an edge and the last face contains (s,d) as // an edge. // // In the special case of duplicated faces. I.e. multiple faces // sharing the same 3 corners, but not necessarily the same // orientation. The ordering will always rank faces containing // edge (s,d) before faces containing edge (d,s). // // Therefore, if there are any duplicates of the first faces, // the ordering will always choose the one with edge (s,d) if // possible. The same for the last face. // // In the very degenerated case where the first and last face // are duplicates, but with different orientations, it is // equally valid to think the angle formed by them is either 0 // or 360 degrees. By default, 0 degree is used, and thus the // query point is outside. std::vector adj_faces; extract_adj_faces(F, I, s, d, adj_faces); const size_t num_adj_faces = adj_faces.size(); assert(num_adj_faces > 0); DerivedV pivot_point(1, 3); igl::copyleft::cgal::assign_scalar(query.x(), pivot_point(0, 0)); igl::copyleft::cgal::assign_scalar(query.y(), pivot_point(0, 1)); igl::copyleft::cgal::assign_scalar(query.z(), pivot_point(0, 2)); Eigen::VectorXi order; order_facets_around_edge(V, F, s, d, adj_faces, pivot_point, order); assert((size_t)order.size() == num_adj_faces); if (adj_faces[order[0]] > 0 && adj_faces[order[num_adj_faces-1] < 0]) { return true; } else if (adj_faces[order[0]] < 0 && adj_faces[order[num_adj_faces-1] > 0]) { return false; } else { throw "The input mesh does not represent a valid volume"; } throw "The input mesh does not represent a valid volume"; return false; } template bool determine_point_vertex_orientation( const Eigen::PlainObjectBase& V, const Eigen::PlainObjectBase& F, const Eigen::PlainObjectBase& I, const Point_3& query, size_t s) { std::vector adj_vertices; extract_adj_vertices(F, I, s, adj_vertices); const size_t num_adj_vertices = adj_vertices.size(); std::vector adj_points; for (size_t i=0; i bool{ size_t positive=0; size_t negative=0; size_t coplanar=0; for (const auto& point : adj_points) { switch(separator.oriented_side(point)) { case CGAL::ON_POSITIVE_SIDE: positive++; break; case CGAL::ON_NEGATIVE_SIDE: negative++; break; case CGAL::ON_ORIENTED_BOUNDARY: coplanar++; break; default: throw "Unknown plane-point orientation"; } } auto query_orientation = separator.oriented_side(query); bool r = (positive == 0 && query_orientation == CGAL::POSITIVE) || (negative == 0 && query_orientation == CGAL::NEGATIVE); return r; }; size_t d = std::numeric_limits::max(); Point_3 p(V(s,0), V(s,1), V(s,2)); for (size_t i=0; i (size_t)V.rows()) { // All adj faces are coplanar, use the first edge. d = adj_vertices[0]; } return determine_point_edge_orientation(V, F, I, query, s, d); } template bool determine_point_face_orientation( const Eigen::PlainObjectBase& V, const Eigen::PlainObjectBase& F, const Eigen::PlainObjectBase& I, const Point_3& query, size_t fid) { // Algorithm: A point is on the inside of a face if the // tetrahedron formed by them is negatively oriented. Eigen::Vector3i f = F.row(I(fid, 0)); const Point_3 v0(V(f[0], 0), V(f[0], 1), V(f[0], 2)); const Point_3 v1(V(f[1], 0), V(f[1], 1), V(f[1], 2)); const Point_3 v2(V(f[2], 0), V(f[2], 1), V(f[2], 2)); auto result = CGAL::orientation(v0, v1, v2, query); if (result == CGAL::COPLANAR) { throw "Cannot determine inside/outside because query point lies exactly on the input surface."; } return result == CGAL::NEGATIVE; } } } } } template IGL_INLINE void igl::copyleft::cgal::points_inside_component( const Eigen::PlainObjectBase& V, const Eigen::PlainObjectBase& F, const Eigen::PlainObjectBase& I, const Eigen::PlainObjectBase& P, Eigen::PlainObjectBase& inside) { using namespace igl::copyleft::cgal::points_inside_component_helper; if (F.rows() <= 0 || I.rows() <= 0) { throw "Inside check cannot be done on empty facet component."; } const size_t num_faces = I.rows(); std::vector triangles; for (size_t i=0; i ElementType{ const Eigen::Vector3i f = F.row(I(fid, 0)); const Point_3 p0(V(f[0], 0), V(f[0], 1), V(f[0], 2)); const Point_3 p1(V(f[1], 0), V(f[1], 1), V(f[1], 2)); const Point_3 p2(V(f[2], 0), V(f[2], 1), V(f[2], 2)); if (p == p0) { element_index = 0; return VERTEX; } if (p == p1) { element_index = 1; return VERTEX; } if (p == p2) { element_index = 2; return VERTEX; } if (CGAL::collinear(p0, p1, p)) { element_index = 2; return EDGE; } if (CGAL::collinear(p1, p2, p)) { element_index = 0; return EDGE; } if (CGAL::collinear(p2, p0, p)) { element_index = 1; return EDGE; } element_index = 0; return FACE; }; const size_t num_queries = P.rows(); inside.resize(num_queries, 1); for (size_t i=0; i IGL_INLINE void igl::copyleft::cgal::points_inside_component( const Eigen::PlainObjectBase& V, const Eigen::PlainObjectBase& F, const Eigen::PlainObjectBase& P, Eigen::PlainObjectBase& inside) { Eigen::VectorXi I = igl::LinSpaced(F.rows(), 0, F.rows()-1); igl::copyleft::cgal::points_inside_component(V, F, I, P, inside); } #ifdef IGL_STATIC_LIBRARY // Explicit template instantiation // generated by autoexplicit.sh template void igl::copyleft::cgal::points_inside_component, Eigen::Matrix, Eigen::Matrix, -1, 3, 0, -1, 3>, Eigen::Array >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase >&); template void igl::copyleft::cgal::points_inside_component< Eigen::Matrix, Eigen::Matrix< int, -1, -1, 0, -1, -1>, Eigen::Matrix< int, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix< int, -1, -1, 0, -1, -1> > ( Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); template void igl::copyleft::cgal::points_inside_component< Eigen::Matrix, Eigen::Matrix< int, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix< int, -1, -1, 0, -1, -1> > ( Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); template void igl::copyleft::cgal::points_inside_component, -1, 3, 0, -1, 3>, Eigen::Matrix, Eigen::Matrix, -1, 3, 0, -1, 3>, Eigen::Matrix >(Eigen::PlainObjectBase, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase >&); template void igl::copyleft::cgal::points_inside_component, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); template void igl::copyleft::cgal::points_inside_component, Eigen::Matrix, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase >&); template void igl::copyleft::cgal::points_inside_component, -1, -1, 0, -1, -1>, Eigen::Matrix, Eigen::Matrix, -1, -1, 0, -1, -1>, Eigen::Matrix >(Eigen::PlainObjectBase, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase >&); #endif