is_inside.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. #include "is_inside.h"
  2. #include <cassert>
  3. #include <list>
  4. #include <limits>
  5. #include <vector>
  6. #include <CGAL/AABB_tree.h>
  7. #include <CGAL/AABB_traits.h>
  8. #include <CGAL/AABB_triangle_primitive.h>
  9. #include <CGAL/Exact_predicates_exact_constructions_kernel.h>
  10. #include "order_facets_around_edge.h"
  11. #include "assign_scalar.h"
  12. namespace igl {
  13. namespace cgal {
  14. namespace is_inside_helper {
  15. typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
  16. typedef Kernel::Ray_3 Ray_3;
  17. typedef Kernel::Point_3 Point_3;
  18. typedef Kernel::Vector_3 Vector_3;
  19. typedef Kernel::Triangle_3 Triangle;
  20. typedef Kernel::Plane_3 Plane_3;
  21. typedef std::vector<Triangle>::iterator Iterator;
  22. typedef CGAL::AABB_triangle_primitive<Kernel, Iterator> Primitive;
  23. typedef CGAL::AABB_traits<Kernel, Primitive> AABB_triangle_traits;
  24. typedef CGAL::AABB_tree<AABB_triangle_traits> Tree;
  25. enum ElementType { VERTEX, EDGE, FACE };
  26. template<typename DerivedV, typename DerivedF, typename DerivedI>
  27. ElementType determine_element_type(
  28. const Eigen::PlainObjectBase<DerivedV>& V,
  29. const Eigen::PlainObjectBase<DerivedF>& F,
  30. const Eigen::PlainObjectBase<DerivedI>& I,
  31. const size_t fid, const Point_3& p,
  32. size_t& element_index) {
  33. const Eigen::Vector3i f = F.row(I(fid, 0));
  34. const Point_3 p0(V(f[0], 0), V(f[0], 1), V(f[0], 2));
  35. const Point_3 p1(V(f[1], 0), V(f[1], 1), V(f[1], 2));
  36. const Point_3 p2(V(f[2], 0), V(f[2], 1), V(f[2], 2));
  37. if (p == p0) { element_index = 0; return VERTEX; }
  38. if (p == p1) { element_index = 1; return VERTEX; }
  39. if (p == p2) { element_index = 2; return VERTEX; }
  40. if (CGAL::collinear(p0, p1, p)) { element_index = 2; return EDGE; }
  41. if (CGAL::collinear(p1, p2, p)) { element_index = 0; return EDGE; }
  42. if (CGAL::collinear(p2, p0, p)) { element_index = 1; return EDGE; }
  43. element_index = 0;
  44. return FACE;
  45. }
  46. template<typename DerivedV, typename DerivedF, typename DerivedI>
  47. void extract_adj_faces(
  48. const Eigen::PlainObjectBase<DerivedV>& V,
  49. const Eigen::PlainObjectBase<DerivedF>& F,
  50. const Eigen::PlainObjectBase<DerivedI>& I,
  51. const size_t s, const size_t d,
  52. std::vector<int>& adj_faces) {
  53. const size_t num_faces = I.rows();
  54. for (size_t i=0; i<num_faces; i++) {
  55. Eigen::Vector3i f = F.row(I(i, 0));
  56. if ((f[0] == s && f[1] == d) ||
  57. (f[1] == s && f[2] == d) ||
  58. (f[2] == s && f[0] == d)) {
  59. adj_faces.push_back((I(i, 0)+1) * -1);
  60. continue;
  61. }
  62. if ((f[0] == d && f[1] == s) ||
  63. (f[1] == d && f[2] == s) ||
  64. (f[2] == d && f[0] == s)) {
  65. adj_faces.push_back(I(i, 0)+1);
  66. continue;
  67. }
  68. }
  69. }
  70. template<typename DerivedV, typename DerivedF, typename DerivedI>
  71. void extract_adj_vertices(
  72. const Eigen::PlainObjectBase<DerivedV>& V,
  73. const Eigen::PlainObjectBase<DerivedF>& F,
  74. const Eigen::PlainObjectBase<DerivedI>& I,
  75. const size_t v, std::vector<int>& adj_vertices) {
  76. std::set<size_t> unique_adj_vertices;
  77. const size_t num_faces = I.rows();
  78. for (size_t i=0; i<num_faces; i++) {
  79. Eigen::Vector3i f = F.row(I(i, 0));
  80. assert((f.array() < V.rows()).all());
  81. if (f[0] == v) {
  82. unique_adj_vertices.insert(f[1]);
  83. unique_adj_vertices.insert(f[2]);
  84. } else if (f[1] == v) {
  85. unique_adj_vertices.insert(f[0]);
  86. unique_adj_vertices.insert(f[2]);
  87. } else if (f[2] == v) {
  88. unique_adj_vertices.insert(f[0]);
  89. unique_adj_vertices.insert(f[1]);
  90. }
  91. }
  92. adj_vertices.resize(unique_adj_vertices.size());
  93. std::copy(unique_adj_vertices.begin(),
  94. unique_adj_vertices.end(),
  95. adj_vertices.begin());
  96. }
  97. template<typename DerivedV, typename DerivedF, typename DerivedI>
  98. bool determine_point_edge_orientation(
  99. const Eigen::PlainObjectBase<DerivedV>& V,
  100. const Eigen::PlainObjectBase<DerivedF>& F,
  101. const Eigen::PlainObjectBase<DerivedI>& I,
  102. const Point_3& query, size_t s, size_t d) {
  103. // Algorithm:
  104. //
  105. // Order the adj faces around the edge (s,d) clockwise using
  106. // query point as pivot. (i.e. The first face of the ordering
  107. // is directly after the pivot point, and the last face is
  108. // directly before the pivot.)
  109. //
  110. // The point is outside if the first and last faces of the
  111. // ordering forms a convex angle. This check can be done
  112. // without any construction by looking at the orientation of the
  113. // faces. The angle is convex iff the first face contains (s,d)
  114. // as an edge and the last face contains (d,s) as an edge.
  115. //
  116. // The point is inside if the first and last faces of the
  117. // ordering forms a concave angle. That is the first face
  118. // contains (d,s) as an edge and the last face contains (s,d) as
  119. // an edge.
  120. //
  121. // In the special case of duplicated faces. I.e. multiple faces
  122. // sharing the same 3 corners, but not necessarily the same
  123. // orientation. The ordering will always rank faces containing
  124. // edge (s,d) before faces containing edge (d,s).
  125. //
  126. // Therefore, if there are any duplicates of the first faces,
  127. // the ordering will always choose the one with edge (s,d) if
  128. // possible. The same for the last face.
  129. //
  130. // In the very degenerated case where the first and last face
  131. // are duplicates, but with different orientations, it is
  132. // equally valid to think the angle formed by them is either 0
  133. // or 360 degrees. By default, 0 degree is used, and thus the
  134. // query point is outside.
  135. std::vector<int> adj_faces;
  136. extract_adj_faces(V, F, I, s, d, adj_faces);
  137. const size_t num_adj_faces = adj_faces.size();
  138. assert(num_adj_faces > 0);
  139. DerivedV pivot_point(1, 3);
  140. igl::cgal::assign_scalar(query.x(), pivot_point(0, 0));
  141. igl::cgal::assign_scalar(query.y(), pivot_point(0, 1));
  142. igl::cgal::assign_scalar(query.z(), pivot_point(0, 2));
  143. Eigen::VectorXi order;
  144. order_facets_around_edge(V, F, s, d,
  145. adj_faces, pivot_point, order);
  146. assert(order.size() == num_adj_faces);
  147. if (adj_faces[order[0]] > 0 &&
  148. adj_faces[order[num_adj_faces-1] < 0]) {
  149. return true;
  150. } else if (adj_faces[order[0]] < 0 &&
  151. adj_faces[order[num_adj_faces-1] > 0]) {
  152. return false;
  153. } else {
  154. throw "The input mesh does not represent a valid volume";
  155. }
  156. assert(false);
  157. return false;
  158. }
  159. template<typename DerivedV, typename DerivedF, typename DerivedI>
  160. bool determine_point_vertex_orientation(
  161. const Eigen::PlainObjectBase<DerivedV>& V,
  162. const Eigen::PlainObjectBase<DerivedF>& F,
  163. const Eigen::PlainObjectBase<DerivedI>& I,
  164. const Point_3& query, size_t s) {
  165. std::vector<int> adj_vertices;
  166. extract_adj_vertices(V, F, I, s, adj_vertices);
  167. const size_t num_adj_vertices = adj_vertices.size();
  168. std::vector<Point_3> adj_points;
  169. for (size_t i=0; i<num_adj_vertices; i++) {
  170. const size_t vi = adj_vertices[i];
  171. adj_points.emplace_back(V(vi,0), V(vi,1), V(vi,2));
  172. }
  173. // A plane is on the exterior if all adj_points lies on or to
  174. // one side of the plane.
  175. auto is_on_exterior = [&](const Plane_3& separator) {
  176. size_t positive=0;
  177. size_t negative=0;
  178. size_t coplanar=0;
  179. for (const auto& point : adj_points) {
  180. switch(separator.oriented_side(point)) {
  181. case CGAL::ON_POSITIVE_SIDE:
  182. positive++;
  183. break;
  184. case CGAL::ON_NEGATIVE_SIDE:
  185. negative++;
  186. break;
  187. case CGAL::ON_ORIENTED_BOUNDARY:
  188. coplanar++;
  189. break;
  190. default:
  191. assert(false);
  192. }
  193. }
  194. auto query_orientation = separator.oriented_side(query);
  195. bool r =
  196. (positive == 0 && query_orientation == CGAL::POSITIVE)
  197. ||
  198. (negative == 0 && query_orientation == CGAL::NEGATIVE);
  199. return r;
  200. };
  201. size_t d = std::numeric_limits<size_t>::max();
  202. Point_3 p(V(s,0), V(s,1), V(s,2));
  203. for (size_t i=0; i<num_adj_vertices; i++) {
  204. const size_t vi = adj_vertices[i];
  205. for (size_t j=i+1; j<num_adj_vertices; j++) {
  206. const size_t vj = adj_vertices[j];
  207. Plane_3 separator(p, adj_points[i], adj_points[j]);
  208. assert(!separator.is_degenerate());
  209. if (is_on_exterior(separator)) {
  210. d = vi;
  211. assert(!CGAL::collinear(p, adj_points[i], query));
  212. break;
  213. }
  214. }
  215. if (d < V.rows()) break;
  216. }
  217. if (d > V.rows()) {
  218. // All adj faces are coplanar, use the first edge.
  219. d = adj_vertices[0];
  220. }
  221. return determine_point_edge_orientation(V, F, I, query, s, d);
  222. }
  223. template<typename DerivedV, typename DerivedF, typename DerivedI>
  224. bool determine_point_face_orientation(
  225. const Eigen::PlainObjectBase<DerivedV>& V,
  226. const Eigen::PlainObjectBase<DerivedF>& F,
  227. const Eigen::PlainObjectBase<DerivedI>& I,
  228. const Point_3& query, size_t fid) {
  229. // Algorithm: A point is on the inside of a face if the
  230. // tetrahedron formed by them is negatively oriented.
  231. Eigen::Vector3i f = F.row(I(fid, 0));
  232. const Point_3 v0(V(f[0], 0), V(f[0], 1), V(f[0], 2));
  233. const Point_3 v1(V(f[1], 0), V(f[1], 1), V(f[1], 2));
  234. const Point_3 v2(V(f[2], 0), V(f[2], 1), V(f[2], 2));
  235. auto result = CGAL::orientation(v0, v1, v2, query);
  236. assert(result != CGAL::COPLANAR);
  237. return result == CGAL::NEGATIVE;
  238. }
  239. }
  240. }
  241. }
  242. template <typename DerivedV, typename DerivedF, typename DerivedI>
  243. IGL_INLINE bool igl::cgal::is_inside(
  244. const Eigen::PlainObjectBase<DerivedV>& V1,
  245. const Eigen::PlainObjectBase<DerivedF>& F1,
  246. const Eigen::PlainObjectBase<DerivedI>& I1,
  247. const Eigen::PlainObjectBase<DerivedV>& V2,
  248. const Eigen::PlainObjectBase<DerivedF>& F2,
  249. const Eigen::PlainObjectBase<DerivedI>& I2) {
  250. assert(F1.rows() > 0);
  251. assert(I1.rows() > 0);
  252. assert(F2.rows() > 0);
  253. assert(I2.rows() > 0);
  254. const Eigen::Vector3i& f = F1.row(I1(0, 0));
  255. const Eigen::Matrix<typename DerivedV::Scalar, 1, 3> query(
  256. (V1(f[0],0) + V1(f[1],0) + V1(f[2],0))/3.0,
  257. (V1(f[0],1) + V1(f[1],1) + V1(f[2],1))/3.0,
  258. (V1(f[0],2) + V1(f[1],2) + V1(f[2],2))/3.0);
  259. Eigen::VectorXi inside;
  260. igl::cgal::is_inside(V2, F2, I2, query, inside);
  261. assert(inside.size() == 1);
  262. return inside[0];
  263. }
  264. template<typename DerivedV, typename DerivedF>
  265. IGL_INLINE bool igl::cgal::is_inside(
  266. const Eigen::PlainObjectBase<DerivedV>& V1,
  267. const Eigen::PlainObjectBase<DerivedF>& F1,
  268. const Eigen::PlainObjectBase<DerivedV>& V2,
  269. const Eigen::PlainObjectBase<DerivedF>& F2) {
  270. Eigen::VectorXi I1(F1.rows()), I2(F2.rows());
  271. I1.setLinSpaced(F1.rows(), 0, F1.rows()-1);
  272. I2.setLinSpaced(F2.rows(), 0, F2.rows()-1);
  273. return igl::cgal::is_inside(V1, F1, I1, V2, F2, I2);
  274. }
  275. template<typename DerivedV, typename DerivedF, typename DerivedI,
  276. typename DerivedP, typename DerivedB>
  277. IGL_INLINE void igl::cgal::is_inside(
  278. const Eigen::PlainObjectBase<DerivedV>& V,
  279. const Eigen::PlainObjectBase<DerivedF>& F,
  280. const Eigen::PlainObjectBase<DerivedI>& I,
  281. const Eigen::PlainObjectBase<DerivedP>& P,
  282. Eigen::PlainObjectBase<DerivedB>& inside) {
  283. using namespace igl::cgal::is_inside_helper;
  284. assert(F.rows() > 0);
  285. assert(I.rows() > 0);
  286. const size_t num_faces = I.rows();
  287. std::vector<Triangle> triangles;
  288. for (size_t i=0; i<num_faces; i++) {
  289. const Eigen::Vector3i f = F.row(I(i, 0));
  290. triangles.emplace_back(
  291. Point_3(V(f[0], 0), V(f[0], 1), V(f[0], 2)),
  292. Point_3(V(f[1], 0), V(f[1], 1), V(f[1], 2)),
  293. Point_3(V(f[2], 0), V(f[2], 1), V(f[2], 2)));
  294. assert(!triangles.back().is_degenerate());
  295. }
  296. Tree tree(triangles.begin(), triangles.end());
  297. tree.accelerate_distance_queries();
  298. const size_t num_queries = P.rows();
  299. inside.resize(num_queries);
  300. for (size_t i=0; i<num_queries; i++) {
  301. const Point_3 query(P(i,0), P(i,1), P(i,2));
  302. auto projection = tree.closest_point_and_primitive(query);
  303. auto closest_point = projection.first;
  304. size_t fid = projection.second - triangles.begin();
  305. size_t element_index;
  306. switch (determine_element_type(
  307. V, F, I, fid, closest_point, element_index)) {
  308. case VERTEX:
  309. {
  310. const size_t s = F(I(fid, 0), element_index);
  311. inside[i] = determine_point_vertex_orientation(
  312. V, F, I, query, s);
  313. }
  314. break;
  315. case EDGE:
  316. {
  317. const size_t s = F(I(fid, 0), (element_index+1)%3);
  318. const size_t d = F(I(fid, 0), (element_index+2)%3);
  319. inside[i] = determine_point_edge_orientation(
  320. V, F, I, query, s, d);
  321. }
  322. break;
  323. case FACE:
  324. inside[i] = determine_point_face_orientation(V, F, I, query, fid);
  325. break;
  326. default:
  327. assert(false);
  328. }
  329. }
  330. }
  331. template<typename DerivedV, typename DerivedF, typename DerivedP,
  332. typename DerivedB>
  333. IGL_INLINE void igl::cgal::is_inside(
  334. const Eigen::PlainObjectBase<DerivedV>& V,
  335. const Eigen::PlainObjectBase<DerivedF>& F,
  336. const Eigen::PlainObjectBase<DerivedP>& P,
  337. Eigen::PlainObjectBase<DerivedB>& inside) {
  338. Eigen::VectorXi I(F.rows());
  339. I.setLinSpaced(F.rows(), 0, F.rows()-1);
  340. igl::cgal::is_inside(V, F, I, P, inside);
  341. }
  342. #ifdef IGL_STATIC_LIBRARY
  343. // Explicit template specialization
  344. template void igl::cgal::is_inside<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
  345. template void igl::cgal::is_inside<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
  346. template void igl::cgal::is_inside<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
  347. #endif