2828#include < algorithm>
2929#include < unordered_map>
3030
31- #include < Eigen/Dense>
32-
3331namespace tmd
3432{
3533 /* ========================================== DEFINITIONS ========================================== */
34+ // Small vector 3D class class
35+ template <typename FLOAT>
36+ class Vec3r
37+ {
38+ public:
39+ std::array<FLOAT, 3 > v;
40+
41+ Vec3r () {};
42+ template <typename FLOAT_I>
43+ Vec3r (const FLOAT_I& x, const FLOAT_I& y, const FLOAT_I& z) { v[0 ] = static_cast <FLOAT>(x); v[1 ] = static_cast <FLOAT>(y); v[2 ] = static_cast <FLOAT>(z); }
44+ template <typename SIZE_T>
45+ const FLOAT& operator [](const SIZE_T& i) const { return v[i]; }
46+ template <typename SIZE_T>
47+ FLOAT& operator [](const SIZE_T& i) { return v[i]; }
48+ FLOAT dot (const Vec3r &u) const { return v[0 ]*u[0 ] + v[1 ]*u[1 ] + v[2 ]*u[2 ]; }
49+ Vec3r<FLOAT> cross (const Vec3r &u) const { return Vec3r (v[1 ]*u[2 ] - v[2 ]*u[1 ], -v[0 ]*u[2 ] + v[2 ]*u[0 ], v[0 ]*u[1 ] - v[1 ]*u[0 ]); }
50+ Vec3r<FLOAT> operator +(const Vec3r &u) const { return Vec3r (v[0 ]+u[0 ], v[1 ]+u[1 ], v[2 ]+u[2 ]); }
51+ Vec3r<FLOAT> operator -(const Vec3r &u) const { return Vec3r (v[0 ]-u[0 ], v[1 ]-u[1 ], v[2 ]-u[2 ]); }
52+ void operator +=(const Vec3r& u) { v[0 ] += u[0 ]; v[1 ] += u[1 ]; v[2 ] += u[2 ]; }
53+ template <typename FLOAT_I>
54+ Vec3r<FLOAT> operator *(const FLOAT_I &a) const { return Vec3r (static_cast <FLOAT>(a)*v[0 ], static_cast <FLOAT>(a)*v[1 ], static_cast <FLOAT>(a)*v[2 ]); }
55+ template <typename FLOAT_I>
56+ Vec3r<FLOAT> operator /(const FLOAT_I &a) const { return Vec3r (v[0 ]/static_cast <FLOAT>(a), v[1 ]/static_cast <FLOAT>(a), v[2 ]/static_cast <FLOAT>(a)); }
57+ template <typename FLOAT_I>
58+ void operator /=(const FLOAT_I& a) { v[0 ] /= static_cast <FLOAT>(a); v[1 ] /= static_cast <FLOAT>(a); v[2 ] /= static_cast <FLOAT>(a); }
59+ FLOAT squaredNorm () const { return this ->dot (*this ); }
60+ FLOAT norm () const { return std::sqrt (this ->squaredNorm ()); }
61+ Vec3r<FLOAT> normalized () const { return (*this ) / this ->norm (); }
62+ void normalize () { const FLOAT norm = this ->norm (); v[0 ] /= norm; v[1 ] /= norm; v[2 ] /= norm; }
63+ };
64+ template <typename FLOAT, typename FLOAT_I>
65+ static inline Vec3r<FLOAT> operator *(const FLOAT_I& a, const Vec3r<FLOAT>& v) { return Vec3r<FLOAT>(static_cast <FLOAT>(a) * v[0 ], static_cast <FLOAT>(a) * v[1 ], static_cast <FLOAT>(a) * v[2 ]); }
66+ using Vec3d = Vec3r<double >;
67+ // -----------------------------------
68+
3669 // Point-Triangle distance definitions
3770 enum class NearestEntity { V0, V1, V2, E01 , E12 , E02 , F };
38- double point_triangle_sq_unsigned (NearestEntity& nearest_entity, Eigen::Vector3d & nearest_point, const Eigen::Vector3d & point, const Eigen::Vector3d & v0, const Eigen::Vector3d & v1, const Eigen::Vector3d & v2);
71+ double point_triangle_sq_unsigned (NearestEntity& nearest_entity, Vec3d & nearest_point, const Vec3d & point, const Vec3d & v0, const Vec3d & v1, const Vec3d & v2);
3972 // -----------------------------------
4073
74+ // Struct that contains the result of a distance query
4175 struct Result
4276 {
4377 double distance = std::numeric_limits<double >::max();
44- Eigen::Vector3d nearest_point;
78+ Vec3d nearest_point;
4579 tmd::NearestEntity nearest_entity;
4680 int triangle_id = -1 ;
4781 };
82+ // -----------------------------------
4883
84+ /* *
85+ * A class to compute signed and unsigned distances to a connected
86+ * and watertight triangle mesh.
87+ */
4988 class TriangleMeshDistance
5089 {
5190 private:
5291 /* Definitions */
5392 struct BoundingSphere
5493 {
55- Eigen::Vector3d center;
94+ Vec3d center;
5695 double radius;
5796 };
5897
@@ -66,25 +105,25 @@ namespace tmd
66105
67106 struct Triangle
68107 {
69- std::array<Eigen::Vector3d , 3 > vertices;
108+ std::array<Vec3d , 3 > vertices;
70109 int id = -1 ;
71110 };
72111
73112
74113 /* Fields */
75- std::vector<Eigen::Vector3d > vertices;
114+ std::vector<Vec3d > vertices;
76115 std::vector<std::array<int , 3 >> triangles;
77116 std::vector<Node> nodes;
78- std::vector<Eigen::Vector3d > pseudonormals_triangles;
79- std::vector<std::array<Eigen::Vector3d , 3 >> pseudonormals_edges;
80- std::vector<Eigen::Vector3d > pseudonormals_vertices;
117+ std::vector<Vec3d > pseudonormals_triangles;
118+ std::vector<std::array<Vec3d , 3 >> pseudonormals_edges;
119+ std::vector<Vec3d > pseudonormals_vertices;
81120 BoundingSphere root_bv;
82121 bool is_constructed = false ;
83122
84123 /* Methods */
85124 void _construct ();
86125 void _build_tree (const int node_id, BoundingSphere& bounding_sphere, std::vector<Triangle> &triangles, const int begin, const int end);
87- void _query (Result &result, Node &node, const Eigen::Vector3d & point);
126+ void _query (Result &result, const Node &node, const Vec3d & point) const ;
88127
89128 public:
90129
@@ -132,22 +171,22 @@ namespace tmd
132171 void construct (const std::vector<IndexableVector3double>& vertices, const std::vector<IndexableVector3int>& triangles);
133172
134173 /* *
135- * @brief Computes the unsigned distance from a point to the triangle mesh.
174+ * @brief Computes the unsigned distance from a point to the triangle mesh. Thread safe.
136175 *
137- * @param point to query from. Typed to `Eigen::Vector3d ` but can be passed as `{x, y, z}`.
176+ * @param point to query from. Typed to `Vec3d ` but can be passed as `{x, y, z}`.
138177 *
139178 * @return Result containing distance, nearest point on the mesh, nearest entity and the nearest triangle index.
140179 */
141- Result unsigned_distance (const Eigen::Vector3d &point);
180+ Result unsigned_distance (const Vec3d &point) const ;
142181
143182 /* *
144- * @brief Computes the unsigned distance from a point to the triangle mesh.
183+ * @brief Computes the unsigned distance from a point to the triangle mesh. Thread safe.
145184 *
146- * @param point to query from. Typed to `Eigen::Vector3d ` but can be passed as `{x, y, z}`.
185+ * @param point to query from. Typed to `Vec3d ` but can be passed as `{x, y, z}`.
147186 *
148187 * @return Result containing distance, nearest point on the mesh, nearest entity and the nearest triangle index.
149188 */
150- Result signed_distance (const Eigen::Vector3d & point);
189+ Result signed_distance (const Vec3d & point) const ;
151190 };
152191}
153192
@@ -204,12 +243,12 @@ inline void tmd::TriangleMeshDistance::construct(const std::vector<IndexableVect
204243 this ->_construct ();
205244}
206245
207- inline tmd::Result tmd::TriangleMeshDistance::signed_distance (const Eigen::Vector3d & point)
246+ inline tmd::Result tmd::TriangleMeshDistance::signed_distance (const Vec3d & point) const
208247{
209248 Result result = this ->unsigned_distance (point);
210249
211250 const std::array<int , 3 >& triangle = this ->triangles [result.triangle_id ];
212- Eigen::Vector3d pseudonormal;
251+ Vec3d pseudonormal;
213252 switch (result.nearest_entity )
214253 {
215254 case tmd::NearestEntity::V0:
@@ -238,13 +277,13 @@ inline tmd::Result tmd::TriangleMeshDistance::signed_distance(const Eigen::Vecto
238277 break ;
239278 }
240279
241- const Eigen::Vector3d u = point - result.nearest_point ;
280+ const Vec3d u = point - result.nearest_point ;
242281 result.distance *= (u.dot (pseudonormal) >= 0.0 ) ? 1.0 : -1.0 ;
243282
244283 return result;
245284}
246285
247- inline tmd::Result tmd::TriangleMeshDistance::unsigned_distance (const Eigen::Vector3d & point)
286+ inline tmd::Result tmd::TriangleMeshDistance::unsigned_distance (const Vec3d & point) const
248287{
249288 if (!this ->is_constructed ) {
250289 std::cout << " DistanceTriangleMesh error: not constructed." << std::endl;
@@ -282,10 +321,10 @@ inline void tmd::TriangleMeshDistance::_construct()
282321
283322 // Compute pseudonormals
284323 // // Edge data structure
285- std::unordered_map<uint64_t , Eigen::Vector3d > edge_normals;
324+ std::unordered_map<uint64_t , Vec3d > edge_normals;
286325 std::unordered_map<uint64_t , int > edges_count;
287326 const uint64_t n_vertices = (uint64_t )this ->vertices .size ();
288- auto add_edge_normal = [&](const int i, const int j, const Eigen::Vector3d & triangle_normal)
327+ auto add_edge_normal = [&](const int i, const int j, const Vec3d & triangle_normal)
289328 {
290329 const uint64_t key = std::min (i, j) * n_vertices + std::max (i, j);
291330 if (edge_normals.find (key) == edge_normals.end ()) {
@@ -311,11 +350,11 @@ inline void tmd::TriangleMeshDistance::_construct()
311350
312351 // Triangle
313352 const std::array<int , 3 >& triangle = this ->triangles [i];
314- const Eigen::Vector3d & a = this ->vertices [triangle[0 ]];
315- const Eigen::Vector3d & b = this ->vertices [triangle[1 ]];
316- const Eigen::Vector3d & c = this ->vertices [triangle[2 ]];
353+ const Vec3d & a = this ->vertices [triangle[0 ]];
354+ const Vec3d & b = this ->vertices [triangle[1 ]];
355+ const Vec3d & c = this ->vertices [triangle[2 ]];
317356
318- const Eigen::Vector3d triangle_normal = (b - a).cross (c - a).normalized ();
357+ const Vec3d triangle_normal = (b - a).cross (c - a).normalized ();
319358 this ->pseudonormals_triangles [i] = triangle_normal;
320359
321360 // Vertex
@@ -332,7 +371,7 @@ inline void tmd::TriangleMeshDistance::_construct()
332371 add_edge_normal (triangle[0 ], triangle[2 ], triangle_normal);
333372 }
334373
335- for (Eigen::Vector3d & n : this ->pseudonormals_vertices ) {
374+ for (Vec3d & n : this ->pseudonormals_vertices ) {
336375 n.normalize ();
337376 }
338377
@@ -379,23 +418,32 @@ inline void tmd::TriangleMeshDistance::_build_tree(const int node_id, BoundingSp
379418
380419 // // Bounding sphere
381420 const Triangle& tri = triangles[begin];
382- const Eigen::Vector3d center = (tri.vertices [0 ] + tri.vertices [1 ] + tri.vertices [2 ]) / 3.0 ;
421+ const Vec3d center = (tri.vertices [0 ] + tri.vertices [1 ] + tri.vertices [2 ]) / 3.0 ;
383422 const double radius = std::max (std::max ((tri.vertices [0 ] - center).norm (), (tri.vertices [1 ] - center).norm ()), (tri.vertices [2 ] - center).norm ());
384423 bounding_sphere.center = center;
385424 bounding_sphere.radius = radius;
386425 }
387426 else {
388- // Compute AxisAligned Bounding Box of all current triangles
389- Eigen::AlignedBox3d aabb;
390- aabb.setEmpty ();
427+ // Compute AxisAligned Bounding Box center and largest dimension of all current triangles
428+ Vec3d top = { std::numeric_limits<double >::lowest (), std::numeric_limits<double >::lowest (), std::numeric_limits<double >::lowest () };
429+ Vec3d bottom = { std::numeric_limits<double >::max (), std::numeric_limits<double >::max (), std::numeric_limits<double >::max () };
430+ Vec3d center = {0 , 0 , 0 };
391431 for (int tri_i = begin; tri_i < end; tri_i++) {
392- for (int i = 0 ; i < 3 ; i++) {
393- aabb.extend (triangles[tri_i].vertices [i]);
432+ for (int vertex_i = 0 ; vertex_i < 3 ; vertex_i++) {
433+ const Vec3d& p = triangles[tri_i].vertices [vertex_i];
434+ center += p;
435+
436+ for (int coord_i = 0 ; coord_i < 3 ; coord_i++) {
437+ top[coord_i] = std::max (top[coord_i], p[coord_i]);
438+ bottom[coord_i] = std::min (bottom[coord_i], p[coord_i]);
439+ }
394440 }
395441 }
442+ center /= 3 *n_triangles;
443+ const Vec3d diagonal = top - bottom;
444+ const int split_dim = (int )(std::max_element (&diagonal[0 ], &diagonal[0 ] + 3 ) - &diagonal[0 ]);
396445
397446 // Set node bounding sphere
398- const Eigen::Vector3d center = aabb.center ();
399447 double radius_sq = 0.0 ;
400448 for (int tri_i = begin; tri_i < end; tri_i++) {
401449 for (int i = 0 ; i < 3 ; i++) {
@@ -405,10 +453,6 @@ inline void tmd::TriangleMeshDistance::_build_tree(const int node_id, BoundingSp
405453 bounding_sphere.center = center;
406454 bounding_sphere.radius = std::sqrt (radius_sq);
407455
408- // Find the split dimension (largest)
409- const Eigen::Vector3d diagonal = aabb.diagonal ();
410- const int split_dim = (int )(std::max_element (&diagonal[0 ], &diagonal[0 ] + 3 ) - &diagonal[0 ]);
411-
412456 // Sort the triangles according to their center along the split dimension
413457 std::sort (triangles.begin () + begin, triangles.begin () + end,
414458 [split_dim](const Triangle& a, const Triangle& b)
@@ -430,17 +474,17 @@ inline void tmd::TriangleMeshDistance::_build_tree(const int node_id, BoundingSp
430474 }
431475}
432476
433- inline void tmd::TriangleMeshDistance::_query (Result& result, Node& node, const Eigen::Vector3d & point)
477+ inline void tmd::TriangleMeshDistance::_query (Result& result, const Node& node, const Vec3d & point) const
434478{
435479 // End of recursion
436480 if (node.left == -1 ) {
437481 const int triangle_id = node.right ;
438482 const std::array<int , 3 >& triangle = this ->triangles [node.right ]; // If left == -1, right is the triangle_id
439- const Eigen::Vector3d & v0 = this ->vertices [triangle[0 ]];
440- const Eigen::Vector3d & v1 = this ->vertices [triangle[1 ]];
441- const Eigen::Vector3d & v2 = this ->vertices [triangle[2 ]];
483+ const Vec3d & v0 = this ->vertices [triangle[0 ]];
484+ const Vec3d & v1 = this ->vertices [triangle[1 ]];
485+ const Vec3d & v2 = this ->vertices [triangle[2 ]];
442486
443- Eigen::Vector3d nearest_point;
487+ Vec3d nearest_point;
444488 tmd::NearestEntity nearest_entity;
445489 const double distance_sq = tmd::point_triangle_sq_unsigned (nearest_entity, nearest_point, point, v0, v1, v2);
446490
@@ -480,11 +524,11 @@ inline void tmd::TriangleMeshDistance::_query(Result& result, Node& node, const
480524 }
481525}
482526
483- double tmd::point_triangle_sq_unsigned (NearestEntity& nearest_entity, Eigen::Vector3d & nearest_point, const Eigen::Vector3d & point, const Eigen::Vector3d & v0, const Eigen::Vector3d & v1, const Eigen::Vector3d & v2)
527+ double tmd::point_triangle_sq_unsigned (NearestEntity& nearest_entity, Vec3d & nearest_point, const Vec3d & point, const Vec3d & v0, const Vec3d & v1, const Vec3d & v2)
484528{
485- Eigen::Vector3d diff = v0 - point;
486- Eigen::Vector3d edge0 = v1 - v0;
487- Eigen::Vector3d edge1 = v2 - v0;
529+ Vec3d diff = v0 - point;
530+ Vec3d edge0 = v1 - v0;
531+ Vec3d edge1 = v2 - v0;
488532 double a00 = edge0.dot (edge0);
489533 double a01 = edge0.dot (edge1);
490534 double a11 = edge1.dot (edge1);
0 commit comments