28
28
#include < algorithm>
29
29
#include < unordered_map>
30
30
31
- #include < Eigen/Dense>
32
-
33
31
namespace tmd
34
32
{
35
33
/* ========================================== 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
+
36
69
// Point-Triangle distance definitions
37
70
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);
39
72
// -----------------------------------
40
73
74
+ // Struct that contains the result of a distance query
41
75
struct Result
42
76
{
43
77
double distance = std::numeric_limits<double >::max();
44
- Eigen::Vector3d nearest_point;
78
+ Vec3d nearest_point;
45
79
tmd::NearestEntity nearest_entity;
46
80
int triangle_id = -1 ;
47
81
};
82
+ // -----------------------------------
48
83
84
+ /* *
85
+ * A class to compute signed and unsigned distances to a connected
86
+ * and watertight triangle mesh.
87
+ */
49
88
class TriangleMeshDistance
50
89
{
51
90
private:
52
91
/* Definitions */
53
92
struct BoundingSphere
54
93
{
55
- Eigen::Vector3d center;
94
+ Vec3d center;
56
95
double radius;
57
96
};
58
97
@@ -66,25 +105,25 @@ namespace tmd
66
105
67
106
struct Triangle
68
107
{
69
- std::array<Eigen::Vector3d , 3 > vertices;
108
+ std::array<Vec3d , 3 > vertices;
70
109
int id = -1 ;
71
110
};
72
111
73
112
74
113
/* Fields */
75
- std::vector<Eigen::Vector3d > vertices;
114
+ std::vector<Vec3d > vertices;
76
115
std::vector<std::array<int , 3 >> triangles;
77
116
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;
81
120
BoundingSphere root_bv;
82
121
bool is_constructed = false ;
83
122
84
123
/* Methods */
85
124
void _construct ();
86
125
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 ;
88
127
89
128
public:
90
129
@@ -132,22 +171,22 @@ namespace tmd
132
171
void construct (const std::vector<IndexableVector3double>& vertices, const std::vector<IndexableVector3int>& triangles);
133
172
134
173
/* *
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.
136
175
*
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}`.
138
177
*
139
178
* @return Result containing distance, nearest point on the mesh, nearest entity and the nearest triangle index.
140
179
*/
141
- Result unsigned_distance (const Eigen::Vector3d &point);
180
+ Result unsigned_distance (const Vec3d &point) const ;
142
181
143
182
/* *
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.
145
184
*
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}`.
147
186
*
148
187
* @return Result containing distance, nearest point on the mesh, nearest entity and the nearest triangle index.
149
188
*/
150
- Result signed_distance (const Eigen::Vector3d & point);
189
+ Result signed_distance (const Vec3d & point) const ;
151
190
};
152
191
}
153
192
@@ -204,12 +243,12 @@ inline void tmd::TriangleMeshDistance::construct(const std::vector<IndexableVect
204
243
this ->_construct ();
205
244
}
206
245
207
- inline tmd::Result tmd::TriangleMeshDistance::signed_distance (const Eigen::Vector3d & point)
246
+ inline tmd::Result tmd::TriangleMeshDistance::signed_distance (const Vec3d & point) const
208
247
{
209
248
Result result = this ->unsigned_distance (point);
210
249
211
250
const std::array<int , 3 >& triangle = this ->triangles [result.triangle_id ];
212
- Eigen::Vector3d pseudonormal;
251
+ Vec3d pseudonormal;
213
252
switch (result.nearest_entity )
214
253
{
215
254
case tmd::NearestEntity::V0:
@@ -238,13 +277,13 @@ inline tmd::Result tmd::TriangleMeshDistance::signed_distance(const Eigen::Vecto
238
277
break ;
239
278
}
240
279
241
- const Eigen::Vector3d u = point - result.nearest_point ;
280
+ const Vec3d u = point - result.nearest_point ;
242
281
result.distance *= (u.dot (pseudonormal) >= 0.0 ) ? 1.0 : -1.0 ;
243
282
244
283
return result;
245
284
}
246
285
247
- inline tmd::Result tmd::TriangleMeshDistance::unsigned_distance (const Eigen::Vector3d & point)
286
+ inline tmd::Result tmd::TriangleMeshDistance::unsigned_distance (const Vec3d & point) const
248
287
{
249
288
if (!this ->is_constructed ) {
250
289
std::cout << " DistanceTriangleMesh error: not constructed." << std::endl;
@@ -282,10 +321,10 @@ inline void tmd::TriangleMeshDistance::_construct()
282
321
283
322
// Compute pseudonormals
284
323
// // Edge data structure
285
- std::unordered_map<uint64_t , Eigen::Vector3d > edge_normals;
324
+ std::unordered_map<uint64_t , Vec3d > edge_normals;
286
325
std::unordered_map<uint64_t , int > edges_count;
287
326
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)
289
328
{
290
329
const uint64_t key = std::min (i, j) * n_vertices + std::max (i, j);
291
330
if (edge_normals.find (key) == edge_normals.end ()) {
@@ -311,11 +350,11 @@ inline void tmd::TriangleMeshDistance::_construct()
311
350
312
351
// Triangle
313
352
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 ]];
317
356
318
- const Eigen::Vector3d triangle_normal = (b - a).cross (c - a).normalized ();
357
+ const Vec3d triangle_normal = (b - a).cross (c - a).normalized ();
319
358
this ->pseudonormals_triangles [i] = triangle_normal;
320
359
321
360
// Vertex
@@ -332,7 +371,7 @@ inline void tmd::TriangleMeshDistance::_construct()
332
371
add_edge_normal (triangle[0 ], triangle[2 ], triangle_normal);
333
372
}
334
373
335
- for (Eigen::Vector3d & n : this ->pseudonormals_vertices ) {
374
+ for (Vec3d & n : this ->pseudonormals_vertices ) {
336
375
n.normalize ();
337
376
}
338
377
@@ -379,23 +418,32 @@ inline void tmd::TriangleMeshDistance::_build_tree(const int node_id, BoundingSp
379
418
380
419
// // Bounding sphere
381
420
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 ;
383
422
const double radius = std::max (std::max ((tri.vertices [0 ] - center).norm (), (tri.vertices [1 ] - center).norm ()), (tri.vertices [2 ] - center).norm ());
384
423
bounding_sphere.center = center;
385
424
bounding_sphere.radius = radius;
386
425
}
387
426
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 };
391
431
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
+ }
394
440
}
395
441
}
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 ]);
396
445
397
446
// Set node bounding sphere
398
- const Eigen::Vector3d center = aabb.center ();
399
447
double radius_sq = 0.0 ;
400
448
for (int tri_i = begin; tri_i < end; tri_i++) {
401
449
for (int i = 0 ; i < 3 ; i++) {
@@ -405,10 +453,6 @@ inline void tmd::TriangleMeshDistance::_build_tree(const int node_id, BoundingSp
405
453
bounding_sphere.center = center;
406
454
bounding_sphere.radius = std::sqrt (radius_sq);
407
455
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
-
412
456
// Sort the triangles according to their center along the split dimension
413
457
std::sort (triangles.begin () + begin, triangles.begin () + end,
414
458
[split_dim](const Triangle& a, const Triangle& b)
@@ -430,17 +474,17 @@ inline void tmd::TriangleMeshDistance::_build_tree(const int node_id, BoundingSp
430
474
}
431
475
}
432
476
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
434
478
{
435
479
// End of recursion
436
480
if (node.left == -1 ) {
437
481
const int triangle_id = node.right ;
438
482
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 ]];
442
486
443
- Eigen::Vector3d nearest_point;
487
+ Vec3d nearest_point;
444
488
tmd::NearestEntity nearest_entity;
445
489
const double distance_sq = tmd::point_triangle_sq_unsigned (nearest_entity, nearest_point, point, v0, v1, v2);
446
490
@@ -480,11 +524,11 @@ inline void tmd::TriangleMeshDistance::_query(Result& result, Node& node, const
480
524
}
481
525
}
482
526
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)
484
528
{
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;
488
532
double a00 = edge0.dot (edge0);
489
533
double a01 = edge0.dot (edge1);
490
534
double a11 = edge1.dot (edge1);
0 commit comments