closest_facet.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
  4. //
  5. // This Source Code Form is subject to the terms of the Mozilla Public License
  6. // v. 2.0. If a copy of the MPL was not distributed with this file, You can
  7. // obtain one at http://mozilla.org/MPL/2.0/.
  8. //
  9. #include "closest_facet.h"
  10. #include <vector>
  11. #include <stdexcept>
  12. #include <unordered_map>
  13. #include <CGAL/AABB_tree.h>
  14. #include <CGAL/AABB_traits.h>
  15. #include <CGAL/AABB_triangle_primitive.h>
  16. #include <CGAL/intersections.h>
  17. #include <CGAL/Exact_predicates_exact_constructions_kernel.h>
  18. #include "order_facets_around_edge.h"
  19. #include "../../vertex_triangle_adjacency.h"
  20. #include "../../writePLY.h"
  21. template<
  22. typename DerivedV,
  23. typename DerivedF,
  24. typename DerivedI,
  25. typename DerivedP,
  26. typename uE2EType,
  27. typename DerivedEMAP,
  28. typename DerivedR,
  29. typename DerivedS >
  30. IGL_INLINE void igl::copyleft::cgal::closest_facet(
  31. const Eigen::PlainObjectBase<DerivedV>& V,
  32. const Eigen::PlainObjectBase<DerivedF>& F,
  33. const Eigen::PlainObjectBase<DerivedI>& I,
  34. const Eigen::PlainObjectBase<DerivedP>& P,
  35. const std::vector<std::vector<uE2EType> >& uE2E,
  36. const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
  37. Eigen::PlainObjectBase<DerivedR>& R,
  38. Eigen::PlainObjectBase<DerivedS>& S) {
  39. typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
  40. typedef Kernel::Point_3 Point_3;
  41. typedef Kernel::Plane_3 Plane_3;
  42. typedef Kernel::Segment_3 Segment_3;
  43. typedef Kernel::Triangle_3 Triangle;
  44. typedef std::vector<Triangle>::iterator Iterator;
  45. typedef CGAL::AABB_triangle_primitive<Kernel, Iterator> Primitive;
  46. typedef CGAL::AABB_traits<Kernel, Primitive> AABB_triangle_traits;
  47. typedef CGAL::AABB_tree<AABB_triangle_traits> Tree;
  48. if (F.rows() <= 0 || I.rows() <= 0) {
  49. throw std::runtime_error(
  50. "Closest facet cannot be computed on empty mesh.");
  51. }
  52. std::vector<std::vector<size_t> > VF;
  53. std::vector<std::vector<size_t> > VFi;
  54. igl::vertex_triangle_adjacency(V.rows(), F, VF, VFi);
  55. std::vector<bool> in_I(F.rows(), false);
  56. const size_t num_faces = I.rows();
  57. std::vector<Triangle> triangles;
  58. for (size_t i=0; i<num_faces; i++) {
  59. const Eigen::Vector3i f = F.row(I(i, 0));
  60. in_I[I(i,0)] = true;
  61. triangles.emplace_back(
  62. Point_3(V(f[0], 0), V(f[0], 1), V(f[0], 2)),
  63. Point_3(V(f[1], 0), V(f[1], 1), V(f[1], 2)),
  64. Point_3(V(f[2], 0), V(f[2], 1), V(f[2], 2)));
  65. if (triangles.back().is_degenerate()) {
  66. throw std::runtime_error(
  67. "Input facet components contains degenerated triangles");
  68. }
  69. }
  70. Tree tree(triangles.begin(), triangles.end());
  71. tree.accelerate_distance_queries();
  72. auto on_the_positive_side = [&](size_t fid, const Point_3& p) {
  73. const auto& f = F.row(fid).eval();
  74. Point_3 v0(V(f[0], 0), V(f[0], 1), V(f[0], 2));
  75. Point_3 v1(V(f[1], 0), V(f[1], 1), V(f[1], 2));
  76. Point_3 v2(V(f[2], 0), V(f[2], 1), V(f[2], 2));
  77. auto ori = CGAL::orientation(v0, v1, v2, p);
  78. switch (ori) {
  79. case CGAL::POSITIVE:
  80. return true;
  81. case CGAL::NEGATIVE:
  82. return false;
  83. case CGAL::COPLANAR:
  84. // Warning:
  85. // This can only happen if fid contains a boundary edge.
  86. // Catergorized this ambiguous case as negative side.
  87. return false;
  88. default:
  89. throw std::runtime_error("Unknown CGAL state.");
  90. }
  91. return false;
  92. };
  93. auto get_orientation = [&](size_t fid, size_t s, size_t d) -> bool {
  94. const auto& f = F.row(fid);
  95. if ((size_t)f[0] == s && (size_t)f[1] == d) return false;
  96. else if ((size_t)f[1] == s && (size_t)f[2] == d) return false;
  97. else if ((size_t)f[2] == s && (size_t)f[0] == d) return false;
  98. else if ((size_t)f[0] == d && (size_t)f[1] == s) return true;
  99. else if ((size_t)f[1] == d && (size_t)f[2] == s) return true;
  100. else if ((size_t)f[2] == d && (size_t)f[0] == s) return true;
  101. else {
  102. throw std::runtime_error(
  103. "Cannot compute orientation due to incorrect connectivity");
  104. return false;
  105. }
  106. };
  107. auto index_to_signed_index = [&](size_t index, bool ori) -> int{
  108. return (index+1) * (ori? 1:-1);
  109. };
  110. //auto signed_index_to_index = [&](int signed_index) -> size_t {
  111. // return abs(signed_index) - 1;
  112. //};
  113. enum ElementType { VERTEX, EDGE, FACE };
  114. auto determine_element_type = [&](const Point_3& p, const size_t fid,
  115. size_t& element_index) {
  116. const auto& tri = triangles[fid];
  117. const Point_3 p0 = tri[0];
  118. const Point_3 p1 = tri[1];
  119. const Point_3 p2 = tri[2];
  120. if (p == p0) { element_index = 0; return VERTEX; }
  121. if (p == p1) { element_index = 1; return VERTEX; }
  122. if (p == p2) { element_index = 2; return VERTEX; }
  123. if (CGAL::collinear(p0, p1, p)) { element_index = 2; return EDGE; }
  124. if (CGAL::collinear(p1, p2, p)) { element_index = 0; return EDGE; }
  125. if (CGAL::collinear(p2, p0, p)) { element_index = 1; return EDGE; }
  126. element_index = 0;
  127. return FACE;
  128. };
  129. auto process_edge_case = [&](
  130. size_t query_idx,
  131. const size_t s, const size_t d,
  132. size_t preferred_facet,
  133. bool& orientation) {
  134. Point_3 query_point(
  135. P(query_idx, 0),
  136. P(query_idx, 1),
  137. P(query_idx, 2));
  138. size_t corner_idx = std::numeric_limits<size_t>::max();
  139. if ((s == F(preferred_facet, 0) && d == F(preferred_facet, 1)) ||
  140. (s == F(preferred_facet, 1) && d == F(preferred_facet, 0))) {
  141. corner_idx = 2;
  142. } else if ((s == F(preferred_facet, 0) && d == F(preferred_facet, 2)) ||
  143. (s == F(preferred_facet, 2) && d == F(preferred_facet, 0))) {
  144. corner_idx = 1;
  145. } else if ((s == F(preferred_facet, 1) && d == F(preferred_facet, 2)) ||
  146. (s == F(preferred_facet, 2) && d == F(preferred_facet, 1))) {
  147. corner_idx = 0;
  148. } else {
  149. std::cerr << "s: " << s << "\t d:" << d << std::endl;
  150. std::cerr << F.row(preferred_facet) << std::endl;
  151. throw std::runtime_error(
  152. "Invalid connectivity, edge does not belong to facet");
  153. }
  154. auto ueid = EMAP(preferred_facet + corner_idx * F.rows());
  155. auto eids = uE2E[ueid];
  156. std::vector<size_t> intersected_face_indices;
  157. for (auto eid : eids) {
  158. const size_t fid = eid % F.rows();
  159. if (in_I[fid]) {
  160. intersected_face_indices.push_back(fid);
  161. }
  162. }
  163. const size_t num_intersected_faces = intersected_face_indices.size();
  164. std::vector<int> intersected_face_signed_indices(num_intersected_faces);
  165. std::transform(
  166. intersected_face_indices.begin(),
  167. intersected_face_indices.end(),
  168. intersected_face_signed_indices.begin(),
  169. [&](size_t index) {
  170. return index_to_signed_index(
  171. index, get_orientation(index, s,d));
  172. });
  173. assert(num_intersected_faces >= 1);
  174. if (num_intersected_faces == 1) {
  175. // The edge must be a boundary edge. Thus, the orientation can be
  176. // simply determined by checking if the query point is on the
  177. // positive side of the facet.
  178. const size_t fid = intersected_face_indices[0];
  179. orientation = on_the_positive_side(fid, query_point);
  180. return fid;
  181. }
  182. Eigen::VectorXi order;
  183. DerivedP pivot = P.row(query_idx).eval();
  184. igl::copyleft::cgal::order_facets_around_edge(V, F, s, d,
  185. intersected_face_signed_indices,
  186. pivot, order);
  187. // Although first and last are equivalent, make the choice based on
  188. // preferred_facet.
  189. const size_t first = order[0];
  190. const size_t last = order[num_intersected_faces-1];
  191. if (intersected_face_indices[first] == preferred_facet) {
  192. orientation = intersected_face_signed_indices[first] < 0;
  193. return intersected_face_indices[first];
  194. } else if (intersected_face_indices[last] == preferred_facet) {
  195. orientation = intersected_face_signed_indices[last] > 0;
  196. return intersected_face_indices[last];
  197. } else {
  198. orientation = intersected_face_signed_indices[order[0]] < 0;
  199. return intersected_face_indices[order[0]];
  200. }
  201. };
  202. auto process_face_case = [&](
  203. const size_t query_idx, const Point_3& closest_point,
  204. const size_t fid, bool& orientation) {
  205. const auto& f = F.row(I(fid, 0));
  206. return process_edge_case(query_idx, f[0], f[1], I(fid, 0), orientation);
  207. };
  208. auto process_vertex_case = [&](const size_t query_idx, size_t s,
  209. size_t preferred_facet, bool& orientation) {
  210. const Point_3 query_point(
  211. P(query_idx, 0), P(query_idx, 1), P(query_idx, 2));
  212. const Point_3 closest_point(V(s, 0), V(s, 1), V(s, 2));
  213. std::vector<size_t> adj_faces;
  214. std::vector<size_t> adj_face_corners;
  215. {
  216. // Gether adj faces to s within I.
  217. const auto& all_adj_faces = VF[s];
  218. const auto& all_adj_face_corners = VFi[s];
  219. const size_t num_all_adj_faces = all_adj_faces.size();
  220. for (size_t i=0; i<num_all_adj_faces; i++) {
  221. const size_t fid = all_adj_faces[i];
  222. if (in_I[fid]) {
  223. adj_faces.push_back(fid);
  224. adj_face_corners.push_back(all_adj_face_corners[i]);
  225. }
  226. }
  227. }
  228. const size_t num_adj_faces = adj_faces.size();
  229. assert(num_adj_faces > 0);
  230. std::set<size_t> adj_vertices_set;
  231. std::unordered_multimap<size_t, size_t> v2f;
  232. for (size_t i=0; i<num_adj_faces; i++) {
  233. const size_t fid = adj_faces[i];
  234. const size_t cid = adj_face_corners[i];
  235. const auto& f = F.row(adj_faces[i]);
  236. const size_t next = f[(cid+1)%3];
  237. const size_t prev = f[(cid+2)%3];
  238. adj_vertices_set.insert(next);
  239. adj_vertices_set.insert(prev);
  240. v2f.insert({{next, fid}, {prev, fid}});
  241. }
  242. const size_t num_adj_vertices = adj_vertices_set.size();
  243. std::vector<size_t> adj_vertices(num_adj_vertices);
  244. std::copy(adj_vertices_set.begin(), adj_vertices_set.end(),
  245. adj_vertices.begin());
  246. std::vector<Point_3> adj_points;
  247. for (size_t vid : adj_vertices) {
  248. adj_points.emplace_back(V(vid,0), V(vid,1), V(vid,2));
  249. }
  250. // A plane is on the exterior if all adj_points lies on or to
  251. // one side of the plane.
  252. auto is_on_exterior = [&](const Plane_3& separator) {
  253. size_t positive=0;
  254. size_t negative=0;
  255. size_t coplanar=0;
  256. for (const auto& point : adj_points) {
  257. switch(separator.oriented_side(point)) {
  258. case CGAL::ON_POSITIVE_SIDE:
  259. positive++;
  260. break;
  261. case CGAL::ON_NEGATIVE_SIDE:
  262. negative++;
  263. break;
  264. case CGAL::ON_ORIENTED_BOUNDARY:
  265. coplanar++;
  266. break;
  267. default:
  268. throw "Unknown plane-point orientation";
  269. }
  270. }
  271. auto query_orientation = separator.oriented_side(query_point);
  272. if (query_orientation == CGAL::ON_ORIENTED_BOUNDARY &&
  273. (positive == 0 && negative == 0)) {
  274. // All adj vertices and query point are coplanar.
  275. // In this case, all separators are equally valid.
  276. return true;
  277. } else {
  278. bool r = (positive == 0 && query_orientation == CGAL::POSITIVE)
  279. || (negative == 0 && query_orientation == CGAL::NEGATIVE);
  280. return r;
  281. }
  282. };
  283. size_t d = std::numeric_limits<size_t>::max();
  284. for (size_t i=0; i<num_adj_vertices; i++) {
  285. const size_t vi = adj_vertices[i];
  286. for (size_t j=i+1; j<num_adj_vertices; j++) {
  287. Plane_3 separator(closest_point, adj_points[i], adj_points[j]);
  288. if (separator.is_degenerate()) {
  289. continue;
  290. }
  291. if (is_on_exterior(separator)) {
  292. if (!CGAL::collinear(
  293. query_point, adj_points[i], closest_point)) {
  294. d = vi;
  295. break;
  296. } else {
  297. d = adj_vertices[j];
  298. assert(!CGAL::collinear(
  299. query_point, adj_points[j], closest_point));
  300. break;
  301. }
  302. }
  303. }
  304. }
  305. if (d == std::numeric_limits<size_t>::max()) {
  306. Eigen::MatrixXd tmp_vertices(V.rows(), V.cols());
  307. for (size_t i=0; i<V.rows(); i++) {
  308. for (size_t j=0; j<V.cols(); j++) {
  309. tmp_vertices(i,j) = CGAL::to_double(V(i,j));
  310. }
  311. }
  312. Eigen::MatrixXi tmp_faces(adj_faces.size(), 3);
  313. for (size_t i=0; i<adj_faces.size(); i++) {
  314. tmp_faces.row(i) = F.row(adj_faces[i]);
  315. }
  316. igl::writePLY("debug.ply", tmp_vertices, tmp_faces, false);
  317. throw std::runtime_error("Invalid vertex neighborhood");
  318. }
  319. const auto itr = v2f.equal_range(d);
  320. assert(itr.first != itr.second);
  321. return process_edge_case(query_idx, s, d, itr.first->second, orientation);
  322. };
  323. const size_t num_queries = P.rows();
  324. R.resize(num_queries, 1);
  325. S.resize(num_queries, 1);
  326. for (size_t i=0; i<num_queries; i++) {
  327. const Point_3 query(P(i,0), P(i,1), P(i,2));
  328. auto projection = tree.closest_point_and_primitive(query);
  329. const Point_3 closest_point = projection.first;
  330. size_t fid = projection.second - triangles.begin();
  331. bool fid_ori = false;
  332. // Gether all facets sharing the closest point.
  333. std::vector<Tree::Primitive_id> intersected_faces;
  334. tree.all_intersected_primitives(Segment_3(closest_point, query),
  335. std::back_inserter(intersected_faces));
  336. const size_t num_intersected_faces = intersected_faces.size();
  337. std::vector<size_t> intersected_face_indices(num_intersected_faces);
  338. std::transform(intersected_faces.begin(),
  339. intersected_faces.end(),
  340. intersected_face_indices.begin(),
  341. [&](const Tree::Primitive_id& itr) -> size_t
  342. { return I(itr-triangles.begin(), 0); });
  343. size_t element_index;
  344. auto element_type = determine_element_type(closest_point, fid,
  345. element_index);
  346. switch(element_type) {
  347. case VERTEX:
  348. {
  349. const auto& f = F.row(I(fid, 0));
  350. const size_t s = f[element_index];
  351. fid = process_vertex_case(i, s, I(fid, 0), fid_ori);
  352. }
  353. break;
  354. case EDGE:
  355. {
  356. const auto& f = F.row(I(fid, 0));
  357. const size_t s = f[(element_index+1)%3];
  358. const size_t d = f[(element_index+2)%3];
  359. fid = process_edge_case(i, s, d, I(fid, 0), fid_ori);
  360. }
  361. break;
  362. case FACE:
  363. {
  364. fid = process_face_case(i, closest_point, fid, fid_ori);
  365. }
  366. break;
  367. default:
  368. throw std::runtime_error("Unknown element type.");
  369. }
  370. R(i,0) = fid;
  371. S(i,0) = fid_ori;
  372. }
  373. }
  374. template<
  375. typename DerivedV,
  376. typename DerivedF,
  377. typename DerivedP,
  378. typename uE2EType,
  379. typename DerivedEMAP,
  380. typename DerivedR,
  381. typename DerivedS >
  382. IGL_INLINE void igl::copyleft::cgal::closest_facet(
  383. const Eigen::PlainObjectBase<DerivedV>& V,
  384. const Eigen::PlainObjectBase<DerivedF>& F,
  385. const Eigen::PlainObjectBase<DerivedP>& P,
  386. const std::vector<std::vector<uE2EType> >& uE2E,
  387. const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
  388. Eigen::PlainObjectBase<DerivedR>& R,
  389. Eigen::PlainObjectBase<DerivedS>& S) {
  390. const size_t num_faces = F.rows();
  391. Eigen::VectorXi I(num_faces);
  392. I.setLinSpaced(num_faces, 0, num_faces-1);
  393. igl::copyleft::cgal::closest_facet(V, F, I, P, uE2E, EMAP, R, S);
  394. }
  395. #ifdef IGL_STATIC_LIBRARY
  396. template void igl::copyleft::cgal::closest_facet<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, unsigned long, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, std::__1::vector<std::__1::vector<unsigned long, std::__1::allocator<unsigned long> >, std::__1::allocator<std::__1::vector<unsigned long, std::__1::allocator<unsigned long> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
  397. #endif