closest_facet.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. #include "closest_facet.h"
  2. #include <vector>
  3. #include <stdexcept>
  4. #include <CGAL/AABB_tree.h>
  5. #include <CGAL/AABB_traits.h>
  6. #include <CGAL/AABB_triangle_primitive.h>
  7. #include <CGAL/intersections.h>
  8. #include <CGAL/Exact_predicates_exact_constructions_kernel.h>
  9. #include "order_facets_around_edge.h"
  10. template<
  11. typename DerivedV,
  12. typename DerivedF,
  13. typename DerivedI,
  14. typename DerivedP,
  15. typename DerivedR,
  16. typename DerivedS >
  17. IGL_INLINE void igl::cgal::closest_facet(
  18. const Eigen::PlainObjectBase<DerivedV>& V,
  19. const Eigen::PlainObjectBase<DerivedF>& F,
  20. const Eigen::PlainObjectBase<DerivedI>& I,
  21. const Eigen::PlainObjectBase<DerivedP>& P,
  22. Eigen::PlainObjectBase<DerivedR>& R,
  23. Eigen::PlainObjectBase<DerivedS>& S) {
  24. typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
  25. typedef Kernel::Point_3 Point_3;
  26. typedef Kernel::Plane_3 Plane_3;
  27. typedef Kernel::Segment_3 Segment_3;
  28. typedef Kernel::Triangle_3 Triangle;
  29. typedef std::vector<Triangle>::iterator Iterator;
  30. typedef CGAL::AABB_triangle_primitive<Kernel, Iterator> Primitive;
  31. typedef CGAL::AABB_traits<Kernel, Primitive> AABB_triangle_traits;
  32. typedef CGAL::AABB_tree<AABB_triangle_traits> Tree;
  33. if (F.rows() <= 0 || I.rows() <= 0) {
  34. throw std::runtime_error(
  35. "Closest facet cannot be computed on empty mesh.");
  36. }
  37. const size_t num_faces = I.rows();
  38. std::vector<Triangle> triangles;
  39. for (size_t i=0; i<num_faces; i++) {
  40. const Eigen::Vector3i f = F.row(I(i, 0));
  41. triangles.emplace_back(
  42. Point_3(V(f[0], 0), V(f[0], 1), V(f[0], 2)),
  43. Point_3(V(f[1], 0), V(f[1], 1), V(f[1], 2)),
  44. Point_3(V(f[2], 0), V(f[2], 1), V(f[2], 2)));
  45. if (triangles.back().is_degenerate()) {
  46. throw std::runtime_error(
  47. "Input facet components contains degenerated triangles");
  48. }
  49. }
  50. Tree tree(triangles.begin(), triangles.end());
  51. tree.accelerate_distance_queries();
  52. auto on_the_positive_side = [&](size_t fid, const Point_3& p) {
  53. const auto& f = F.row(fid).eval();
  54. Point_3 v0(V(f[0], 0), V(f[0], 1), V(f[0], 2));
  55. Point_3 v1(V(f[1], 0), V(f[1], 1), V(f[1], 2));
  56. Point_3 v2(V(f[2], 0), V(f[2], 1), V(f[2], 2));
  57. auto ori = CGAL::orientation(v0, v1, v2, p);
  58. switch (ori) {
  59. case CGAL::POSITIVE:
  60. return true;
  61. case CGAL::NEGATIVE:
  62. return false;
  63. case CGAL::COPLANAR:
  64. throw std::runtime_error(
  65. "It seems input mesh contains self intersection");
  66. default:
  67. throw std::runtime_error("Unknown CGAL state.");
  68. }
  69. return false;
  70. };
  71. auto get_orientation = [&](size_t fid, size_t s, size_t d) -> bool {
  72. const auto& f = F.row(fid);
  73. if (f[0] == s && f[1] == d) return false;
  74. else if (f[1] == s && f[2] == d) return false;
  75. else if (f[2] == s && f[0] == d) return false;
  76. else if (f[0] == d && f[1] == s) return true;
  77. else if (f[1] == d && f[2] == s) return true;
  78. else if (f[2] == d && f[0] == s) return true;
  79. else {
  80. throw std::runtime_error(
  81. "Cannot compute orientation due to incorrect connectivity");
  82. return false;
  83. }
  84. };
  85. auto index_to_signed_index = [&](size_t index, bool ori) -> int{
  86. return (index+1) * (ori? 1:-1);
  87. };
  88. auto signed_index_to_index = [&](int signed_index) -> size_t {
  89. return abs(signed_index) - 1;
  90. };
  91. enum ElementType { VERTEX, EDGE, FACE };
  92. auto determine_element_type = [&](const Point_3& p, const size_t fid,
  93. size_t& element_index) {
  94. const auto& tri = triangles[fid];
  95. const Point_3 p0 = tri[0];
  96. const Point_3 p1 = tri[1];
  97. const Point_3 p2 = tri[2];
  98. if (p == p0) { element_index = 0; return VERTEX; }
  99. if (p == p1) { element_index = 1; return VERTEX; }
  100. if (p == p2) { element_index = 2; return VERTEX; }
  101. if (CGAL::collinear(p0, p1, p)) { element_index = 2; return EDGE; }
  102. if (CGAL::collinear(p1, p2, p)) { element_index = 0; return EDGE; }
  103. if (CGAL::collinear(p2, p0, p)) { element_index = 1; return EDGE; }
  104. element_index = 0;
  105. return FACE;
  106. };
  107. auto process_edge_case = [&](
  108. size_t query_idx,
  109. const size_t s, const size_t d,
  110. size_t preferred_facet,
  111. bool& orientation) {
  112. Point_3 mid_edge_point(
  113. (V(s,0) + V(d,0)) * 0.5,
  114. (V(s,1) + V(d,1)) * 0.5,
  115. (V(s,2) + V(d,2)) * 0.5);
  116. Point_3 query_point(
  117. P(query_idx, 0),
  118. P(query_idx, 1),
  119. P(query_idx, 2));
  120. std::vector<Tree::Primitive_id> intersected_faces;
  121. tree.all_intersected_primitives(Segment_3(mid_edge_point, query_point),
  122. std::back_inserter(intersected_faces));
  123. const size_t num_intersected_faces = intersected_faces.size();
  124. std::vector<size_t> intersected_face_indices(num_intersected_faces);
  125. std::vector<int> intersected_face_signed_indices(num_intersected_faces);
  126. std::transform(intersected_faces.begin(),
  127. intersected_faces.end(),
  128. intersected_face_indices.begin(),
  129. [&](const Tree::Primitive_id& itr) -> size_t
  130. { return I(itr-triangles.begin(), 0); });
  131. std::transform(
  132. intersected_face_indices.begin(),
  133. intersected_face_indices.end(),
  134. intersected_face_signed_indices.begin(),
  135. [&](size_t index) {
  136. return index_to_signed_index(
  137. index, get_orientation(index, s,d));
  138. });
  139. assert(num_intersected_faces >= 1);
  140. if (num_intersected_faces == 1) {
  141. // The edge must be a boundary edge. Thus, the orientation can be
  142. // simply determined by checking if the query point is on the
  143. // positive side of the facet.
  144. const size_t fid = intersected_face_indices[0];
  145. orientation = on_the_positive_side(fid, query_point);
  146. return fid;
  147. }
  148. Eigen::VectorXi order;
  149. DerivedP pivot = P.row(query_idx).eval();
  150. igl::cgal::order_facets_around_edge(V, F, s, d,
  151. intersected_face_signed_indices,
  152. pivot, order);
  153. // Although first and last are equivalent, make the choice based on
  154. // preferred_facet.
  155. const size_t first = order[0];
  156. const size_t last = order[num_intersected_faces-1];
  157. if (intersected_face_indices[first] == preferred_facet) {
  158. orientation = intersected_face_signed_indices[first] < 0;
  159. return intersected_face_indices[first];
  160. } else if (intersected_face_indices[last] == preferred_facet) {
  161. orientation = intersected_face_signed_indices[last] > 0;
  162. return intersected_face_indices[last];
  163. } else {
  164. orientation = intersected_face_signed_indices[order[0]] < 0;
  165. return intersected_face_indices[order[0]];
  166. }
  167. };
  168. auto process_face_case = [&](
  169. const size_t query_idx, const size_t fid, bool& orientation) {
  170. const auto& f = F.row(I(fid, 0));
  171. return process_edge_case(query_idx, f[0], f[1], I(fid, 0), orientation);
  172. };
  173. auto process_vertex_case = [&](const size_t query_idx, size_t s,
  174. size_t preferred_facet, bool& orientation) {
  175. Point_3 closest_point(V(s, 0), V(s, 1), V(s, 2));
  176. Point_3 query_point(P(query_idx, 0), P(query_idx, 1), P(query_idx, 2));
  177. std::vector<Tree::Primitive_id> intersected_faces;
  178. tree.all_intersected_primitives(Segment_3(closest_point, query_point),
  179. std::back_inserter(intersected_faces));
  180. const size_t num_intersected_faces = intersected_faces.size();
  181. std::vector<size_t> intersected_face_indices(num_intersected_faces);
  182. std::transform(intersected_faces.begin(),
  183. intersected_faces.end(),
  184. intersected_face_indices.begin(),
  185. [&](const Tree::Primitive_id& itr) -> size_t
  186. { return I(itr-triangles.begin(), 0); });
  187. std::set<size_t> adj_vertices_set;
  188. for (auto fid : intersected_face_indices) {
  189. const auto& f = F.row(fid);
  190. if (f[0] != s) adj_vertices_set.insert(f[0]);
  191. if (f[1] != s) adj_vertices_set.insert(f[1]);
  192. if (f[2] != s) adj_vertices_set.insert(f[2]);
  193. }
  194. const size_t num_adj_vertices = adj_vertices_set.size();
  195. std::vector<size_t> adj_vertices(num_adj_vertices);
  196. std::copy(adj_vertices_set.begin(), adj_vertices_set.end(),
  197. adj_vertices.begin());
  198. std::vector<Point_3> adj_points;
  199. for (size_t vid : adj_vertices) {
  200. adj_points.emplace_back(V(vid,0), V(vid,1), V(vid,2));
  201. }
  202. // A plane is on the exterior if all adj_points lies on or to
  203. // one side of the plane.
  204. auto is_on_exterior = [&](const Plane_3& separator) {
  205. size_t positive=0;
  206. size_t negative=0;
  207. size_t coplanar=0;
  208. for (const auto& point : adj_points) {
  209. switch(separator.oriented_side(point)) {
  210. case CGAL::ON_POSITIVE_SIDE:
  211. positive++;
  212. break;
  213. case CGAL::ON_NEGATIVE_SIDE:
  214. negative++;
  215. break;
  216. case CGAL::ON_ORIENTED_BOUNDARY:
  217. coplanar++;
  218. break;
  219. default:
  220. throw "Unknown plane-point orientation";
  221. }
  222. }
  223. auto query_orientation = separator.oriented_side(query_point);
  224. bool r = (positive == 0 && query_orientation == CGAL::POSITIVE)
  225. || (negative == 0 && query_orientation == CGAL::NEGATIVE);
  226. return r;
  227. };
  228. size_t d = std::numeric_limits<size_t>::max();
  229. for (size_t i=0; i<num_adj_vertices; i++) {
  230. const size_t vi = adj_vertices[i];
  231. for (size_t j=i+1; j<num_adj_vertices; j++) {
  232. Plane_3 separator(closest_point, adj_points[i], adj_points[j]);
  233. if (separator.is_degenerate()) {
  234. throw std::runtime_error(
  235. "Input mesh contains degenerated faces");
  236. }
  237. if (is_on_exterior(separator)) {
  238. d = vi;
  239. assert(!CGAL::collinear(
  240. query_point, adj_points[i], closest_point));
  241. break;
  242. }
  243. }
  244. }
  245. assert(d != std::numeric_limits<size_t>::max());
  246. return process_edge_case(query_idx, s, d, preferred_facet, orientation);
  247. };
  248. const size_t num_queries = P.rows();
  249. R.resize(num_queries, 1);
  250. S.resize(num_queries, 1);
  251. for (size_t i=0; i<num_queries; i++) {
  252. const Point_3 query(P(i,0), P(i,1), P(i,2));
  253. auto projection = tree.closest_point_and_primitive(query);
  254. const Point_3 closest_point = projection.first;
  255. size_t fid = projection.second - triangles.begin();
  256. bool fid_ori = false;
  257. // Gether all facets sharing the closest point.
  258. std::vector<Tree::Primitive_id> intersected_faces;
  259. tree.all_intersected_primitives(Segment_3(closest_point, query),
  260. std::back_inserter(intersected_faces));
  261. const size_t num_intersected_faces = intersected_faces.size();
  262. std::vector<size_t> intersected_face_indices(num_intersected_faces);
  263. std::transform(intersected_faces.begin(),
  264. intersected_faces.end(),
  265. intersected_face_indices.begin(),
  266. [&](const Tree::Primitive_id& itr) -> size_t
  267. { return I(itr-triangles.begin(), 0); });
  268. size_t element_index;
  269. auto element_type = determine_element_type(closest_point, fid,
  270. element_index);
  271. switch(element_type) {
  272. case VERTEX:
  273. {
  274. const auto& f = F.row(I(fid, 0));
  275. const size_t s = f[element_index];
  276. fid = process_vertex_case(i, s, I(fid, 0), fid_ori);
  277. }
  278. break;
  279. case EDGE:
  280. {
  281. const auto& f = F.row(I(fid, 0));
  282. const size_t s = f[(element_index+1)%3];
  283. const size_t d = f[(element_index+2)%3];
  284. fid = process_edge_case(i, s, d, I(fid, 0), fid_ori);
  285. }
  286. break;
  287. case FACE:
  288. {
  289. fid = process_face_case(i, fid, fid_ori);
  290. }
  291. break;
  292. default:
  293. throw std::runtime_error("Unknown element type.");
  294. }
  295. R(i,0) = fid;
  296. S(i,0) = fid_ori;
  297. }
  298. }
  299. template<
  300. typename DerivedV,
  301. typename DerivedF,
  302. typename DerivedP,
  303. typename DerivedR,
  304. typename DerivedS >
  305. IGL_INLINE void igl::cgal::closest_facet(
  306. const Eigen::PlainObjectBase<DerivedV>& V,
  307. const Eigen::PlainObjectBase<DerivedF>& F,
  308. const Eigen::PlainObjectBase<DerivedP>& P,
  309. Eigen::PlainObjectBase<DerivedR>& R,
  310. Eigen::PlainObjectBase<DerivedS>& S) {
  311. const size_t num_faces = F.rows();
  312. Eigen::VectorXi I(num_faces);
  313. I.setLinSpaced(num_faces, 0, num_faces-1);
  314. igl::cgal::closest_facet(V, F, I, P, R, S);
  315. }