is_inside.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  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. #include "intersect_other.h"
  13. #include "RemeshSelfIntersectionsParam.h"
  14. namespace igl {
  15. namespace cgal {
  16. namespace is_inside_helper {
  17. typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
  18. typedef Kernel::Ray_3 Ray_3;
  19. typedef Kernel::Point_3 Point_3;
  20. typedef Kernel::Vector_3 Vector_3;
  21. typedef Kernel::Triangle_3 Triangle;
  22. typedef Kernel::Plane_3 Plane_3;
  23. typedef std::vector<Triangle>::iterator Iterator;
  24. typedef CGAL::AABB_triangle_primitive<Kernel, Iterator> Primitive;
  25. typedef CGAL::AABB_traits<Kernel, Primitive> AABB_triangle_traits;
  26. typedef CGAL::AABB_tree<AABB_triangle_traits> Tree;
  27. template<typename DerivedV, typename DerivedF, typename DerivedI>
  28. bool intersect_each_other(
  29. const Eigen::PlainObjectBase<DerivedV>& V1,
  30. const Eigen::PlainObjectBase<DerivedF>& F1,
  31. const Eigen::PlainObjectBase<DerivedI>& I1,
  32. const Eigen::PlainObjectBase<DerivedV>& V2,
  33. const Eigen::PlainObjectBase<DerivedF>& F2,
  34. const Eigen::PlainObjectBase<DerivedI>& I2) {
  35. const size_t num_faces_1 = I1.rows();
  36. DerivedF F1_selected(num_faces_1, F1.cols());
  37. for (size_t i=0; i<num_faces_1; i++) {
  38. F1_selected.row(i) = F1.row(I1(i,0));
  39. }
  40. const size_t num_faces_2 = I2.rows();
  41. DerivedF F2_selected(num_faces_2, F2.cols());
  42. for (size_t i=0; i<num_faces_2; i++) {
  43. F2_selected.row(i) = F2.row(I2(i,0));
  44. }
  45. DerivedV VVA, VVB;
  46. DerivedF IF, FFA, FFB;
  47. Eigen::VectorXi JA, IMA, JB, IMB;
  48. RemeshSelfIntersectionsParam param;
  49. param.detect_only = true;
  50. param.first_only = true;
  51. return igl::cgal::intersect_other(
  52. V1, F1_selected,
  53. V2, F2_selected,
  54. param, IF,
  55. VVA, FFA, JA, IMA,
  56. VVB, FFB, JB, IMB);
  57. }
  58. enum ElementType { VERTEX, EDGE, FACE };
  59. template<typename DerivedV, typename DerivedF, typename DerivedI>
  60. ElementType determine_element_type(
  61. const Eigen::PlainObjectBase<DerivedV>& V,
  62. const Eigen::PlainObjectBase<DerivedF>& F,
  63. const Eigen::PlainObjectBase<DerivedI>& I,
  64. const size_t fid, const Point_3& p,
  65. size_t& element_index) {
  66. const Eigen::Vector3i f = F.row(I(fid, 0));
  67. const Point_3 p0(V(f[0], 0), V(f[0], 1), V(f[0], 2));
  68. const Point_3 p1(V(f[1], 0), V(f[1], 1), V(f[1], 2));
  69. const Point_3 p2(V(f[2], 0), V(f[2], 1), V(f[2], 2));
  70. if (p == p0) { element_index = 0; return VERTEX; }
  71. if (p == p1) { element_index = 1; return VERTEX; }
  72. if (p == p2) { element_index = 2; return VERTEX; }
  73. if (CGAL::collinear(p0, p1, p)) { element_index = 2; return EDGE; }
  74. if (CGAL::collinear(p1, p2, p)) { element_index = 0; return EDGE; }
  75. if (CGAL::collinear(p2, p0, p)) { element_index = 1; return EDGE; }
  76. element_index = 0;
  77. return FACE;
  78. }
  79. template<typename DerivedV, typename DerivedF, typename DerivedI>
  80. void extract_adj_faces(
  81. const Eigen::PlainObjectBase<DerivedV>& V,
  82. const Eigen::PlainObjectBase<DerivedF>& F,
  83. const Eigen::PlainObjectBase<DerivedI>& I,
  84. const size_t s, const size_t d,
  85. std::vector<int>& adj_faces) {
  86. const size_t num_faces = I.rows();
  87. for (size_t i=0; i<num_faces; i++) {
  88. Eigen::Vector3i f = F.row(I(i, 0));
  89. if ((f[0] == s && f[1] == d) ||
  90. (f[1] == s && f[2] == d) ||
  91. (f[2] == s && f[0] == d)) {
  92. adj_faces.push_back((I(i, 0)+1) * -1);
  93. continue;
  94. }
  95. if ((f[0] == d && f[1] == s) ||
  96. (f[1] == d && f[2] == s) ||
  97. (f[2] == d && f[0] == s)) {
  98. adj_faces.push_back(I(i, 0)+1);
  99. continue;
  100. }
  101. }
  102. }
  103. template<typename DerivedV, typename DerivedF, typename DerivedI>
  104. void extract_adj_vertices(
  105. const Eigen::PlainObjectBase<DerivedV>& V,
  106. const Eigen::PlainObjectBase<DerivedF>& F,
  107. const Eigen::PlainObjectBase<DerivedI>& I,
  108. const size_t v, std::vector<int>& adj_vertices) {
  109. std::set<size_t> unique_adj_vertices;
  110. const size_t num_faces = I.rows();
  111. for (size_t i=0; i<num_faces; i++) {
  112. Eigen::Vector3i f = F.row(I(i, 0));
  113. assert((f.array() < V.rows()).all());
  114. if (f[0] == v) {
  115. unique_adj_vertices.insert(f[1]);
  116. unique_adj_vertices.insert(f[2]);
  117. } else if (f[1] == v) {
  118. unique_adj_vertices.insert(f[0]);
  119. unique_adj_vertices.insert(f[2]);
  120. } else if (f[2] == v) {
  121. unique_adj_vertices.insert(f[0]);
  122. unique_adj_vertices.insert(f[1]);
  123. }
  124. }
  125. adj_vertices.resize(unique_adj_vertices.size());
  126. std::copy(unique_adj_vertices.begin(),
  127. unique_adj_vertices.end(),
  128. adj_vertices.begin());
  129. }
  130. template<typename DerivedV, typename DerivedF, typename DerivedI>
  131. bool determine_point_edge_orientation(
  132. const Eigen::PlainObjectBase<DerivedV>& V,
  133. const Eigen::PlainObjectBase<DerivedF>& F,
  134. const Eigen::PlainObjectBase<DerivedI>& I,
  135. const Point_3& query, size_t s, size_t d) {
  136. // Algorithm:
  137. //
  138. // If the query point is projected onto an edge, all adjacent
  139. // faces of that edge must be on or belong to a single half
  140. // space (i.e. there exists a plane passing through the edge and
  141. // all adjacent faces are either on the plane or on the same
  142. // side of that plane).
  143. //
  144. // If these adjacent faces are not coplanar, query is inside iff
  145. // the edge is concave.
  146. //
  147. // If two or more faces are coplanar, the query point is
  148. // definitely outside of the
  149. std::vector<int> adj_faces;
  150. extract_adj_faces(V, F, I, s, d, adj_faces);
  151. const size_t num_adj_faces = adj_faces.size();
  152. assert(num_adj_faces > 0);
  153. //std::cout << "adj faces: ";
  154. //for (size_t i=0; i<num_adj_faces; i++) {
  155. // std::cout << adj_faces[i] << " ";
  156. //}
  157. //std::cout << std::endl;
  158. DerivedV pivot_point(1, 3);
  159. igl::cgal::assign_scalar(query.x(), pivot_point(0, 0));
  160. igl::cgal::assign_scalar(query.y(), pivot_point(0, 1));
  161. igl::cgal::assign_scalar(query.z(), pivot_point(0, 2));
  162. //{
  163. // auto get_opposite_vertex = [&](int fid) -> size_t{
  164. // Eigen::Vector3i f = F.row(abs(fid)-1);
  165. // if (f[0] != s && f[0] != d) return f[0];
  166. // if (f[1] != s && f[1] != d) return f[1];
  167. // if (f[2] != s && f[2] != d) return f[2];
  168. // return -1;
  169. // };
  170. // Point_3 p_s(V(s,0), V(s,1), V(s,2));
  171. // Point_3 p_d(V(d,0), V(d,1), V(d,2));
  172. // //std::cout << "s: "
  173. // // << CGAL::to_double(V(s,0)) << " "
  174. // // << CGAL::to_double(V(s,1)) << " "
  175. // // << CGAL::to_double(V(s,2)) << std::endl;
  176. // //std::cout << "d: "
  177. // // << CGAL::to_double(V(d,0)) << " "
  178. // // << CGAL::to_double(V(d,1)) << " "
  179. // // << CGAL::to_double(V(d,2)) << std::endl;
  180. // for (size_t i=0; i<num_adj_faces; i++) {
  181. // size_t o = get_opposite_vertex(adj_faces[i]);
  182. // Point_3 p_o(V(o,0), V(o,1), V(o,2));
  183. // std::cout << "o" << i << ": "
  184. // << CGAL::to_double(V(o,0)) << " "
  185. // << CGAL::to_double(V(o,1)) << " "
  186. // << CGAL::to_double(V(o,2)) << std::endl;
  187. // switch (CGAL::orientation(p_s, p_d, p_o, query)) {
  188. // case CGAL::POSITIVE:
  189. // std::cout << adj_faces[i] << " positive" <<
  190. // std::endl;
  191. // break;
  192. // case CGAL::NEGATIVE:
  193. // std::cout << adj_faces[i] << " negative" <<
  194. // std::endl;
  195. // break;
  196. // case CGAL::COPLANAR:
  197. // std::cout << adj_faces[i] << " coplanar" <<
  198. // std::endl;
  199. // break;
  200. // default:
  201. // break;
  202. // }
  203. // //assert(!CGAL::coplanar(p_s, p_d, p_o, query));
  204. // }
  205. //}
  206. Eigen::VectorXi order;
  207. order_facets_around_edge(V, F, s, d,
  208. adj_faces, pivot_point, order);
  209. //std::cout << "order: " << order.transpose() << std::endl;
  210. assert(order.size() == num_adj_faces);
  211. if (adj_faces[order[0]] > 0 &&
  212. adj_faces[order[num_adj_faces-1] < 0]) {
  213. return true;
  214. } else if (adj_faces[order[0]] < 0 &&
  215. adj_faces[order[num_adj_faces-1] > 0]) {
  216. return false;
  217. } else {
  218. assert(false);
  219. }
  220. assert(false);
  221. return false;
  222. }
  223. template<typename DerivedV, typename DerivedF, typename DerivedI>
  224. bool determine_point_vertex_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 s) {
  229. std::vector<int> adj_vertices;
  230. extract_adj_vertices(V, F, I, s, adj_vertices);
  231. const size_t num_adj_vertices = adj_vertices.size();
  232. //std::cout << "Q: "
  233. // << CGAL::to_double(query.x()) << " "
  234. // << CGAL::to_double(query.y()) << " "
  235. // << CGAL::to_double(query.z()) << " "
  236. // << std::endl;
  237. std::vector<Point_3> adj_points;
  238. for (size_t i=0; i<num_adj_vertices; i++) {
  239. const size_t vi = adj_vertices[i];
  240. //std::cout << "P: "
  241. // << CGAL::to_double(V(vi,0)) << " "
  242. // << CGAL::to_double(V(vi,1)) << " "
  243. // << CGAL::to_double(V(vi,2)) << " "
  244. // << std::endl;
  245. adj_points.emplace_back(V(vi,0), V(vi,1), V(vi,2));
  246. }
  247. // A plane is on the exterior if all adj_points lies on or to
  248. // one side of the plane.
  249. auto is_on_exterior = [&](const Plane_3& separator) {
  250. size_t positive=0;
  251. size_t negative=0;
  252. size_t coplanar=0;
  253. for (const auto& point : adj_points) {
  254. switch(separator.oriented_side(point)) {
  255. case CGAL::ON_POSITIVE_SIDE:
  256. positive++;
  257. break;
  258. case CGAL::ON_NEGATIVE_SIDE:
  259. negative++;
  260. break;
  261. case CGAL::ON_ORIENTED_BOUNDARY:
  262. coplanar++;
  263. break;
  264. default:
  265. assert(false);
  266. }
  267. }
  268. auto query_orientation = separator.oriented_side(query);
  269. bool r =
  270. (positive == 0 && query_orientation == CGAL::POSITIVE)
  271. ||
  272. (negative == 0 && query_orientation == CGAL::NEGATIVE);
  273. return r;
  274. };
  275. size_t d = std::numeric_limits<size_t>::max();
  276. //std::cout << "P: "
  277. // << CGAL::to_double(V(s,0)) << " "
  278. // << CGAL::to_double(V(s,1)) << " "
  279. // << CGAL::to_double(V(s,2)) << " "
  280. // << std::endl;
  281. Point_3 p(V(s,0), V(s,1), V(s,2));
  282. for (size_t i=0; i<num_adj_vertices; i++) {
  283. const size_t vi = adj_vertices[i];
  284. for (size_t j=i+1; j<num_adj_vertices; j++) {
  285. const size_t vj = adj_vertices[j];
  286. Plane_3 separator(p, adj_points[i], adj_points[j]);
  287. assert(!separator.is_degenerate());
  288. if (is_on_exterior(separator)) {
  289. d = vi;
  290. assert(!CGAL::collinear(p, adj_points[i], query));
  291. break;
  292. }
  293. }
  294. if (d < V.rows()) break;
  295. }
  296. if (d > V.rows()) {
  297. // All adj faces are coplanar, use the first edge.
  298. d = adj_vertices[0];
  299. //std::cout << "all adj faces are coplanar" << std::endl;
  300. //return false;
  301. }
  302. //std::cout << "s: " << s << " d: " << d << std::endl;
  303. return determine_point_edge_orientation(V, F, I, query, s, d);
  304. }
  305. template<typename DerivedV, typename DerivedF, typename DerivedI>
  306. bool determine_point_face_orientation(
  307. const Eigen::PlainObjectBase<DerivedV>& V,
  308. const Eigen::PlainObjectBase<DerivedF>& F,
  309. const Eigen::PlainObjectBase<DerivedI>& I,
  310. const Point_3& query, size_t fid) {
  311. // Algorithm: A point is on the inside of a face if the
  312. // tetrahedron formed by them is negatively oriented.
  313. Eigen::Vector3i f = F.row(I(fid, 0));
  314. const Point_3 v0(V(f[0], 0), V(f[0], 1), V(f[0], 2));
  315. const Point_3 v1(V(f[1], 0), V(f[1], 1), V(f[1], 2));
  316. const Point_3 v2(V(f[2], 0), V(f[2], 1), V(f[2], 2));
  317. auto result = CGAL::orientation(v0, v1, v2, query);
  318. assert(result != CGAL::COPLANAR);
  319. return result == CGAL::NEGATIVE;
  320. }
  321. }
  322. }
  323. }
  324. template <typename DerivedV, typename DerivedF, typename DerivedI>
  325. IGL_INLINE bool igl::cgal::is_inside(
  326. const Eigen::PlainObjectBase<DerivedV>& V1,
  327. const Eigen::PlainObjectBase<DerivedF>& F1,
  328. const Eigen::PlainObjectBase<DerivedI>& I1,
  329. const Eigen::PlainObjectBase<DerivedV>& V2,
  330. const Eigen::PlainObjectBase<DerivedF>& F2,
  331. const Eigen::PlainObjectBase<DerivedI>& I2) {
  332. using namespace igl::cgal::is_inside_helper;
  333. assert(F1.rows() > 0);
  334. assert(I1.rows() > 0);
  335. assert(F2.rows() > 0);
  336. assert(I2.rows() > 0);
  337. //assert(!intersect_each_other(V1, F1, I1, V2, F2, I2));
  338. const size_t num_faces = I2.rows();
  339. std::vector<Triangle> triangles;
  340. for (size_t i=0; i<num_faces; i++) {
  341. const Eigen::Vector3i f = F2.row(I2(i, 0));
  342. triangles.emplace_back(
  343. Point_3(V2(f[0], 0), V2(f[0], 1), V2(f[0], 2)),
  344. Point_3(V2(f[1], 0), V2(f[1], 1), V2(f[1], 2)),
  345. Point_3(V2(f[2], 0), V2(f[2], 1), V2(f[2], 2)));
  346. assert(!triangles.back().is_degenerate());
  347. }
  348. Tree tree(triangles.begin(), triangles.end());
  349. tree.accelerate_distance_queries();
  350. const Eigen::Vector3i& f = F1.row(I1(0, 0));
  351. const Point_3 query(
  352. (V1(f[0],0) + V1(f[1],0) + V1(f[2],0))/3.0,
  353. (V1(f[0],1) + V1(f[1],1) + V1(f[2],1))/3.0,
  354. (V1(f[0],2) + V1(f[1],2) + V1(f[2],2))/3.0);
  355. // Computing the closest point to mesh2 is the only exact construction
  356. // needed in the algorithm.
  357. auto projection = tree.closest_point_and_primitive(query);
  358. auto closest_point = projection.first;
  359. size_t fid = projection.second - triangles.begin();
  360. size_t element_index;
  361. switch (determine_element_type(
  362. V2, F2, I2, fid, closest_point, element_index)) {
  363. case VERTEX:
  364. {
  365. //std::cout << "vertex case" << std::endl;
  366. const size_t s = F2(I2(fid, 0), element_index);
  367. return determine_point_vertex_orientation(
  368. V2, F2, I2, query, s);
  369. }
  370. break;
  371. case EDGE:
  372. {
  373. //std::cout << "edge case" << std::endl;
  374. const size_t s = F2(I2(fid, 0), (element_index+1)%3);
  375. const size_t d = F2(I2(fid, 0), (element_index+2)%3);
  376. return determine_point_edge_orientation(
  377. V2, F2, I2, query, s, d);
  378. }
  379. break;
  380. case FACE:
  381. //std::cout << "face case" << std::endl;
  382. return determine_point_face_orientation(V2, F2, I2, query, fid);
  383. break;
  384. default:
  385. assert(false);
  386. }
  387. assert(false);
  388. return false;
  389. }
  390. template<typename DerivedV, typename DerivedF>
  391. IGL_INLINE bool igl::cgal::is_inside(
  392. const Eigen::PlainObjectBase<DerivedV>& V1,
  393. const Eigen::PlainObjectBase<DerivedF>& F1,
  394. const Eigen::PlainObjectBase<DerivedV>& V2,
  395. const Eigen::PlainObjectBase<DerivedF>& F2) {
  396. Eigen::VectorXi I1(F1.rows()), I2(F2.rows());
  397. I1.setLinSpaced(F1.rows(), 0, F1.rows()-1);
  398. I2.setLinSpaced(F2.rows(), 0, F2.rows()-1);
  399. return igl::cgal::is_inside(V1, F1, I1, V2, F2, I2);
  400. }