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 
11 #include <vector>
12 #include <stdexcept>
13 #include <unordered_map>
14 
15 #include "order_facets_around_edge.h"
16 #include "submesh_aabb_tree.h"
17 #include "../../vertex_triangle_adjacency.h"
18 #include "../../LinSpaced.h"
19 //#include "../../writePLY.h"
20 
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 >
closest_facet(const Eigen::PlainObjectBase<DerivedV> & V,const Eigen::PlainObjectBase<DerivedF> & F,const Eigen::PlainObjectBase<DerivedI> & I,const Eigen::PlainObjectBase<DerivedP> & P,const std::vector<std::vector<uE2EType>> & uE2E,const Eigen::PlainObjectBase<DerivedEMAP> & EMAP,Eigen::PlainObjectBase<DerivedR> & R,Eigen::PlainObjectBase<DerivedS> & S)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 {
40 
41   typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
42   typedef Kernel::Point_3 Point_3;
43   typedef Kernel::Plane_3 Plane_3;
44   typedef Kernel::Segment_3 Segment_3;
45   typedef Kernel::Triangle_3 Triangle;
46   typedef std::vector<Triangle>::iterator Iterator;
47   typedef CGAL::AABB_triangle_primitive<Kernel, Iterator> Primitive;
48   typedef CGAL::AABB_traits<Kernel, Primitive> AABB_triangle_traits;
49   typedef CGAL::AABB_tree<AABB_triangle_traits> Tree;
50 
51   if (F.rows() <= 0 || I.rows() <= 0) {
52     throw std::runtime_error(
53         "Closest facet cannot be computed on empty mesh.");
54   }
55 
56   std::vector<std::vector<size_t> > VF, VFi;
57   igl::vertex_triangle_adjacency(V.rows(), F, VF, VFi);
58   std::vector<bool> in_I;
59   std::vector<Triangle> triangles;
60   Tree tree;
61   submesh_aabb_tree(V,F,I,tree,triangles,in_I);
62 
63   return closest_facet(
64     V,F,I,P,uE2E,EMAP,VF,VFi,tree,triangles,in_I,R,S);
65 }
66 
67 template<
68   typename DerivedV,
69   typename DerivedF,
70   typename DerivedI,
71   typename DerivedP,
72   typename uE2EType,
73   typename DerivedEMAP,
74   typename Kernel,
75   typename DerivedR,
76   typename DerivedS >
closest_facet(const Eigen::PlainObjectBase<DerivedV> & V,const Eigen::PlainObjectBase<DerivedF> & F,const Eigen::PlainObjectBase<DerivedI> & I,const Eigen::PlainObjectBase<DerivedP> & P,const std::vector<std::vector<uE2EType>> & uE2E,const Eigen::PlainObjectBase<DerivedEMAP> & EMAP,const std::vector<std::vector<size_t>> & VF,const std::vector<std::vector<size_t>> & VFi,const CGAL::AABB_tree<CGAL::AABB_traits<Kernel,CGAL::AABB_triangle_primitive<Kernel,typename std::vector<typename Kernel::Triangle_3>::iterator>>> & tree,const std::vector<typename Kernel::Triangle_3> & triangles,const std::vector<bool> & in_I,Eigen::PlainObjectBase<DerivedR> & R,Eigen::PlainObjectBase<DerivedS> & S)77 IGL_INLINE void igl::copyleft::cgal::closest_facet(
78     const Eigen::PlainObjectBase<DerivedV>& V,
79     const Eigen::PlainObjectBase<DerivedF>& F,
80     const Eigen::PlainObjectBase<DerivedI>& I,
81     const Eigen::PlainObjectBase<DerivedP>& P,
82     const std::vector<std::vector<uE2EType> >& uE2E,
83     const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
84     const std::vector<std::vector<size_t> > & VF,
85     const std::vector<std::vector<size_t> > & VFi,
86     const CGAL::AABB_tree<
87       CGAL::AABB_traits<
88         Kernel,
89         CGAL::AABB_triangle_primitive<
90           Kernel, typename std::vector<
91             typename Kernel::Triangle_3 >::iterator > > > & tree,
92     const std::vector<typename Kernel::Triangle_3 > & triangles,
93     const std::vector<bool> & in_I,
94     Eigen::PlainObjectBase<DerivedR>& R,
95     Eigen::PlainObjectBase<DerivedS>& S)
96 {
97   typedef typename Kernel::Point_3 Point_3;
98   typedef typename Kernel::Plane_3 Plane_3;
99   typedef typename Kernel::Segment_3 Segment_3;
100   typedef typename Kernel::Triangle_3 Triangle;
101   typedef typename std::vector<Triangle>::iterator Iterator;
102   typedef typename CGAL::AABB_triangle_primitive<Kernel, Iterator> Primitive;
103   typedef typename CGAL::AABB_traits<Kernel, Primitive> AABB_triangle_traits;
104   typedef typename CGAL::AABB_tree<AABB_triangle_traits> Tree;
105 
106   const size_t num_faces = I.rows();
107   if (F.rows() <= 0 || I.rows() <= 0) {
108     throw std::runtime_error(
109         "Closest facet cannot be computed on empty mesh.");
110   }
111 
112   auto on_the_positive_side = [&](size_t fid, const Point_3& p) -> bool
113   {
114     const auto& f = F.row(fid).eval();
115     Point_3 v0(V(f[0], 0), V(f[0], 1), V(f[0], 2));
116     Point_3 v1(V(f[1], 0), V(f[1], 1), V(f[1], 2));
117     Point_3 v2(V(f[2], 0), V(f[2], 1), V(f[2], 2));
118     auto ori = CGAL::orientation(v0, v1, v2, p);
119     switch (ori) {
120       case CGAL::POSITIVE:
121         return true;
122       case CGAL::NEGATIVE:
123         return false;
124       case CGAL::COPLANAR:
125         // Warning:
126         // This can only happen if fid contains a boundary edge.
127         // Categorized this ambiguous case as negative side.
128         return false;
129       default:
130         throw std::runtime_error("Unknown CGAL state.");
131     }
132     return false;
133   };
134 
135   auto get_orientation = [&](size_t fid, size_t s, size_t d) -> bool
136   {
137     const auto& f = F.row(fid);
138     if      ((size_t)f[0] == s && (size_t)f[1] == d) return false;
139     else if ((size_t)f[1] == s && (size_t)f[2] == d) return false;
140     else if ((size_t)f[2] == s && (size_t)f[0] == d) return false;
141     else if ((size_t)f[0] == d && (size_t)f[1] == s) return true;
142     else if ((size_t)f[1] == d && (size_t)f[2] == s) return true;
143     else if ((size_t)f[2] == d && (size_t)f[0] == s) return true;
144     else {
145       throw std::runtime_error(
146           "Cannot compute orientation due to incorrect connectivity");
147       return false;
148     }
149   };
150   auto index_to_signed_index = [&](size_t index, bool ori) -> int{
151     return (index+1) * (ori? 1:-1);
152   };
153   //auto signed_index_to_index = [&](int signed_index) -> size_t {
154   //    return abs(signed_index) - 1;
155   //};
156 
157   enum ElementType { VERTEX, EDGE, FACE };
158   auto determine_element_type = [&](const Point_3& p, const size_t fid,
159       size_t& element_index) -> ElementType {
160     const auto& tri = triangles[fid];
161     const Point_3 p0 = tri[0];
162     const Point_3 p1 = tri[1];
163     const Point_3 p2 = tri[2];
164 
165     if (p == p0) { element_index = 0; return VERTEX; }
166     if (p == p1) { element_index = 1; return VERTEX; }
167     if (p == p2) { element_index = 2; return VERTEX; }
168     if (CGAL::collinear(p0, p1, p)) { element_index = 2; return EDGE; }
169     if (CGAL::collinear(p1, p2, p)) { element_index = 0; return EDGE; }
170     if (CGAL::collinear(p2, p0, p)) { element_index = 1; return EDGE; }
171 
172     element_index = 0;
173     return FACE;
174   };
175 
176   auto process_edge_case = [&](
177       size_t query_idx,
178       const size_t s, const size_t d,
179       size_t preferred_facet,
180       bool& orientation) -> size_t
181   {
182     Point_3 query_point(
183       P(query_idx, 0),
184       P(query_idx, 1),
185       P(query_idx, 2));
186 
187     size_t corner_idx = std::numeric_limits<size_t>::max();
188     if ((s == F(preferred_facet, 0) && d == F(preferred_facet, 1)) ||
189         (s == F(preferred_facet, 1) && d == F(preferred_facet, 0)))
190     {
191       corner_idx = 2;
192     } else if ((s == F(preferred_facet, 0) && d == F(preferred_facet, 2)) ||
193         (s == F(preferred_facet, 2) && d == F(preferred_facet, 0)))
194     {
195       corner_idx = 1;
196     } else if ((s == F(preferred_facet, 1) && d == F(preferred_facet, 2)) ||
197         (s == F(preferred_facet, 2) && d == F(preferred_facet, 1)))
198     {
199       corner_idx = 0;
200     } else
201     {
202       std::cerr << "s: " << s << "\t d:" << d << std::endl;
203       std::cerr << F.row(preferred_facet) << std::endl;
204       throw std::runtime_error(
205           "Invalid connectivity, edge does not belong to facet");
206     }
207 
208     auto ueid = EMAP(preferred_facet + corner_idx * F.rows());
209     auto eids = uE2E[ueid];
210     std::vector<size_t> intersected_face_indices;
211     for (auto eid : eids)
212     {
213       const size_t fid = eid % F.rows();
214       if (in_I[fid])
215       {
216         intersected_face_indices.push_back(fid);
217       }
218     }
219 
220     const size_t num_intersected_faces = intersected_face_indices.size();
221     std::vector<int> intersected_face_signed_indices(num_intersected_faces);
222     std::transform(
223         intersected_face_indices.begin(),
224         intersected_face_indices.end(),
225         intersected_face_signed_indices.begin(),
226         [&](size_t index) {
227         return index_to_signed_index(
228           index, get_orientation(index, s,d));
229         });
230 
231     assert(num_intersected_faces >= 1);
232     if (num_intersected_faces == 1)
233     {
234       // The edge must be a boundary edge.  Thus, the orientation can be
235       // simply determined by checking if the query point is on the
236       // positive side of the facet.
237       const size_t fid = intersected_face_indices[0];
238       orientation = on_the_positive_side(fid, query_point);
239       return fid;
240     }
241 
242     Eigen::VectorXi order;
243     DerivedP pivot = P.row(query_idx).eval();
244     igl::copyleft::cgal::order_facets_around_edge(V, F, s, d,
245       intersected_face_signed_indices,
246       pivot, order);
247 
248     // Although first and last are equivalent, make the choice based on
249     // preferred_facet.
250     const size_t first = order[0];
251     const size_t last = order[num_intersected_faces-1];
252     if (intersected_face_indices[first] == preferred_facet) {
253       orientation = intersected_face_signed_indices[first] < 0;
254       return intersected_face_indices[first];
255     } else if (intersected_face_indices[last] == preferred_facet) {
256       orientation = intersected_face_signed_indices[last] > 0;
257       return intersected_face_indices[last];
258     } else {
259       orientation = intersected_face_signed_indices[order[0]] < 0;
260       return intersected_face_indices[order[0]];
261     }
262   };
263 
264   auto process_face_case = [&](
265       const size_t query_idx, const Point_3& closest_point,
266       const size_t fid, bool& orientation) -> size_t {
267     const auto& f = F.row(I(fid, 0));
268     return process_edge_case(query_idx, f[0], f[1], I(fid, 0), orientation);
269   };
270 
271   // Given that the closest point to query point P(query_idx,:) on (V,F(I,:))
272   // is the vertex at V(s,:) which is incident at least on triangle
273   // F(preferred_facet,:), determine a facet incident on V(s,:) that is
274   // _exposed_ to the query point and determine whether that facet is facing
275   // _toward_ or _away_ from the query point.
276   //
277   // Inputs:
278   //   query_idx  index into P of query point
279   //   s  index into V of closest point at vertex
280   //   preferred_facet  facet incident on s
281   // Outputs:
282   //   orientation  whether returned face is facing toward or away from
283   //     query (parity unclear)
284   // Returns face guaranteed to be "exposed" to P(query_idx,:)
285   auto process_vertex_case = [&](
286     const size_t query_idx,
287     size_t s,
288     size_t preferred_facet,
289     bool& orientation) -> size_t
290   {
291     const Point_3 query_point(
292         P(query_idx, 0), P(query_idx, 1), P(query_idx, 2));
293     const Point_3 closest_point(V(s, 0), V(s, 1), V(s, 2));
294     std::vector<size_t> adj_faces;
295     std::vector<size_t> adj_face_corners;
296     {
297       // Gather adj faces to s within I.
298       const auto& all_adj_faces = VF[s];
299       const auto& all_adj_face_corners = VFi[s];
300       const size_t num_all_adj_faces = all_adj_faces.size();
301       for (size_t i=0; i<num_all_adj_faces; i++)
302       {
303         const size_t fid = all_adj_faces[i];
304         // Shouldn't this always be true if I is a full connected component?
305         if (in_I[fid])
306         {
307           adj_faces.push_back(fid);
308           adj_face_corners.push_back(all_adj_face_corners[i]);
309         }
310       }
311     }
312     const size_t num_adj_faces = adj_faces.size();
313     assert(num_adj_faces > 0);
314 
315     std::set<size_t> adj_vertices_set;
316     std::unordered_multimap<size_t, size_t> v2f;
317     for (size_t i=0; i<num_adj_faces; i++)
318     {
319       const size_t fid = adj_faces[i];
320       const size_t cid = adj_face_corners[i];
321       const auto& f = F.row(adj_faces[i]);
322       const size_t next = f[(cid+1)%3];
323       const size_t prev = f[(cid+2)%3];
324       adj_vertices_set.insert(next);
325       adj_vertices_set.insert(prev);
326       v2f.insert({{next, fid}, {prev, fid}});
327     }
328     const size_t num_adj_vertices = adj_vertices_set.size();
329     std::vector<size_t> adj_vertices(num_adj_vertices);
330     std::copy(adj_vertices_set.begin(), adj_vertices_set.end(),
331         adj_vertices.begin());
332 
333     std::vector<Point_3> adj_points;
334     for (size_t vid : adj_vertices)
335     {
336       adj_points.emplace_back(V(vid,0), V(vid,1), V(vid,2));
337     }
338 
339     // A plane is on the exterior if all adj_points lies on or to
340     // one side of the plane.
341     auto is_on_exterior = [&](const Plane_3& separator) -> bool{
342       size_t positive=0;
343       size_t negative=0;
344       size_t coplanar=0;
345       for (const auto& point : adj_points) {
346         switch(separator.oriented_side(point)) {
347           case CGAL::ON_POSITIVE_SIDE:
348             positive++;
349             break;
350           case CGAL::ON_NEGATIVE_SIDE:
351             negative++;
352             break;
353           case CGAL::ON_ORIENTED_BOUNDARY:
354             coplanar++;
355             break;
356           default:
357             throw "Unknown plane-point orientation";
358         }
359       }
360       auto query_orientation = separator.oriented_side(query_point);
361       if (query_orientation == CGAL::ON_ORIENTED_BOUNDARY &&
362           (positive == 0 && negative == 0)) {
363         // All adj vertices and query point are coplanar.
364         // In this case, all separators are equally valid.
365         return true;
366       } else {
367         bool r = (positive == 0 && query_orientation == CGAL::POSITIVE)
368           || (negative == 0 && query_orientation == CGAL::NEGATIVE);
369         return r;
370       }
371     };
372 
373     size_t d = std::numeric_limits<size_t>::max();
374     for (size_t i=0; i<num_adj_vertices; i++) {
375       const size_t vi = adj_vertices[i];
376       for (size_t j=i+1; j<num_adj_vertices; j++) {
377         Plane_3 separator(closest_point, adj_points[i], adj_points[j]);
378         if (separator.is_degenerate()) {
379           continue;
380         }
381         if (is_on_exterior(separator)) {
382           if (!CGAL::collinear(
383                 query_point, adj_points[i], closest_point)) {
384             d = vi;
385             break;
386           } else {
387             d = adj_vertices[j];
388             assert(!CGAL::collinear(
389                   query_point, adj_points[j], closest_point));
390             break;
391           }
392         }
393       }
394     }
395     if (d == std::numeric_limits<size_t>::max()) {
396       Eigen::MatrixXd tmp_vertices(V.rows(), V.cols());
397       for (size_t i=0; i<V.rows(); i++) {
398         for (size_t j=0; j<V.cols(); j++) {
399           tmp_vertices(i,j) = CGAL::to_double(V(i,j));
400         }
401       }
402       Eigen::MatrixXi tmp_faces(adj_faces.size(), 3);
403       for (size_t i=0; i<adj_faces.size(); i++) {
404         tmp_faces.row(i) = F.row(adj_faces[i]);
405       }
406       //igl::writePLY("debug.ply", tmp_vertices, tmp_faces, false);
407       throw std::runtime_error("Invalid vertex neighborhood");
408     }
409     const auto itr = v2f.equal_range(d);
410     assert(itr.first != itr.second);
411 
412     return process_edge_case(query_idx, s, d, itr.first->second, orientation);
413   };
414 
415   const size_t num_queries = P.rows();
416   R.resize(num_queries, 1);
417   S.resize(num_queries, 1);
418   for (size_t i=0; i<num_queries; i++) {
419     const Point_3 query(P(i,0), P(i,1), P(i,2));
420     auto projection = tree.closest_point_and_primitive(query);
421     const Point_3 closest_point = projection.first;
422     size_t fid = projection.second - triangles.begin();
423     bool fid_ori = false;
424 
425     // Gether all facets sharing the closest point.
426     typename std::vector<typename Tree::Primitive_id> intersected_faces;
427     tree.all_intersected_primitives(Segment_3(closest_point, query),
428         std::back_inserter(intersected_faces));
429     const size_t num_intersected_faces = intersected_faces.size();
430     std::vector<size_t> intersected_face_indices(num_intersected_faces);
431     std::transform(intersected_faces.begin(),
432         intersected_faces.end(),
433         intersected_face_indices.begin(),
434         [&](const typename Tree::Primitive_id& itr) -> size_t
435         { return I(itr-triangles.begin(), 0); });
436 
437     size_t element_index;
438     auto element_type = determine_element_type(closest_point, fid,
439         element_index);
440     switch(element_type) {
441       case VERTEX:
442         {
443           const auto& f = F.row(I(fid, 0));
444           const size_t s = f[element_index];
445           fid = process_vertex_case(i, s, I(fid, 0), fid_ori);
446         }
447         break;
448       case EDGE:
449         {
450           const auto& f = F.row(I(fid, 0));
451           const size_t s = f[(element_index+1)%3];
452           const size_t d = f[(element_index+2)%3];
453           fid = process_edge_case(i, s, d, I(fid, 0), fid_ori);
454         }
455         break;
456       case FACE:
457         {
458           fid = process_face_case(i, closest_point, fid, fid_ori);
459         }
460         break;
461       default:
462         throw std::runtime_error("Unknown element type.");
463     }
464 
465 
466     R(i,0) = fid;
467     S(i,0) = fid_ori;
468   }
469 }
470 
471 template<
472   typename DerivedV,
473   typename DerivedF,
474   typename DerivedP,
475   typename uE2EType,
476   typename DerivedEMAP,
477   typename DerivedR,
478   typename DerivedS >
closest_facet(const Eigen::PlainObjectBase<DerivedV> & V,const Eigen::PlainObjectBase<DerivedF> & F,const Eigen::PlainObjectBase<DerivedP> & P,const std::vector<std::vector<uE2EType>> & uE2E,const Eigen::PlainObjectBase<DerivedEMAP> & EMAP,Eigen::PlainObjectBase<DerivedR> & R,Eigen::PlainObjectBase<DerivedS> & S)479 IGL_INLINE void igl::copyleft::cgal::closest_facet(
480     const Eigen::PlainObjectBase<DerivedV>& V,
481     const Eigen::PlainObjectBase<DerivedF>& F,
482     const Eigen::PlainObjectBase<DerivedP>& P,
483     const std::vector<std::vector<uE2EType> >& uE2E,
484     const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
485     Eigen::PlainObjectBase<DerivedR>& R,
486     Eigen::PlainObjectBase<DerivedS>& S) {
487   const size_t num_faces = F.rows();
488   Eigen::VectorXi I = igl::LinSpaced<Eigen::VectorXi>(num_faces, 0, num_faces-1);
489   igl::copyleft::cgal::closest_facet(V, F, I, P, uE2E, EMAP, R, S);
490 }
491 
492 #ifdef IGL_STATIC_LIBRARY
493 // Explicit template instantiation
494 // generated by autoexplicit.sh
495 template void igl::copyleft::cgal::closest_facet<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, unsigned long, Eigen::Matrix<int, -1, 1, 0, -1, 1>, CGAL::Epeck, 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, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, CGAL::AABB_tree<CGAL::AABB_traits<CGAL::Epeck, CGAL::AABB_triangle_primitive<CGAL::Epeck, std::vector<CGAL::Epeck::Triangle_3, std::allocator<CGAL::Epeck::Triangle_3> >::iterator, CGAL::Boolean_tag<false> > > > const&, std::vector<CGAL::Epeck::Triangle_3, std::allocator<CGAL::Epeck::Triangle_3> > const&, std::vector<bool, std::allocator<bool> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
496 // generated by autoexplicit.sh
497 template void igl::copyleft::cgal::closest_facet<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -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, 1, -1, -1>, unsigned long, Eigen::Matrix<int, -1, 1, 0, -1, 1>, CGAL::Epeck, 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, 1, -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, 1, -1, -1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, CGAL::AABB_tree<CGAL::AABB_traits<CGAL::Epeck, CGAL::AABB_triangle_primitive<CGAL::Epeck, std::vector<CGAL::Epeck::Triangle_3, std::allocator<CGAL::Epeck::Triangle_3> >::iterator, CGAL::Boolean_tag<false> > > > const&, std::vector<CGAL::Epeck::Triangle_3, std::allocator<CGAL::Epeck::Triangle_3> > const&, std::vector<bool, std::allocator<bool> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
498 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::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::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> >&);
499 #ifdef WIN32
500 template void igl::copyleft::cgal::closest_facet<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>, unsigned __int64, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class CGAL::Epeck, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class CGAL::AABB_tree<class CGAL::AABB_traits<class CGAL::Epeck, class CGAL::AABB_triangle_primitive<class CGAL::Epeck, class std::_Vector_iterator<class std::_Vector_val<struct std::_Simple_types<class CGAL::Triangle_3<class CGAL::Epeck>>>>, struct CGAL::Boolean_tag<0>>>> const &, class std::vector<class CGAL::Triangle_3<class CGAL::Epeck>, class std::allocator<class CGAL::Triangle_3<class CGAL::Epeck>>> const &, class std::vector<bool, class std::allocator<bool>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
501 template void igl::copyleft::cgal::closest_facet<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, unsigned __int64, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class CGAL::Epeck, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class CGAL::AABB_tree<class CGAL::AABB_traits<class CGAL::Epeck, class CGAL::AABB_triangle_primitive<class CGAL::Epeck, class std::_Vector_iterator<class std::_Vector_val<struct std::_Simple_types<class CGAL::Triangle_3<class CGAL::Epeck>>>>, struct CGAL::Boolean_tag<0>>>> const &, class std::vector<class CGAL::Triangle_3<class CGAL::Epeck>, class std::allocator<class CGAL::Triangle_3<class CGAL::Epeck>>> const &, class std::vector<bool, class std::allocator<bool>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
502 template void igl::copyleft::cgal::closest_facet<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, 3, 1, -1, 3>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, unsigned __int64, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class CGAL::Epeck, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 1, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class CGAL::AABB_tree<class CGAL::AABB_traits<class CGAL::Epeck, class CGAL::AABB_triangle_primitive<class CGAL::Epeck, class std::_Vector_iterator<class std::_Vector_val<struct std::_Simple_types<class CGAL::Triangle_3<class CGAL::Epeck>>>>, struct CGAL::Boolean_tag<0>>>> const &, class std::vector<class CGAL::Triangle_3<class CGAL::Epeck>, class std::allocator<class CGAL::Triangle_3<class CGAL::Epeck>>> const &, class std::vector<bool, class std::allocator<bool>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
503 #endif
504 #endif
505