Skip to content

Commit 5355b0f

Browse files
Merge pull request #1077 from Geode-solutions/fix/tri-tri-distance
fix(Geometry): new distance functions between triangles
2 parents 512e371 + a8f0328 commit 5355b0f

File tree

2 files changed

+223
-1
lines changed

2 files changed

+223
-1
lines changed

include/geode/geometry/distance.hpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,34 @@ namespace geode
136136
opengeode_geometry_api segment_triangle_distance(
137137
const Segment3D& segment, const Triangle3D& triangle );
138138

139+
/*!
140+
* Compute the smallest distance between two triangles
141+
* @return a tuple containing:
142+
* - the smallest distance.
143+
* - the closest point on the first triangle.
144+
* - the closest point on the second triangle.
145+
*/
146+
[[nodiscard]] std::tuple< double, Point3D, Point3D >
147+
opengeode_geometry_api triangle_triangle_distance(
148+
const Triangle3D& triangle0, const Triangle3D& triangle1 );
149+
150+
/*!
151+
* Compute the smallest distance between two triangles
152+
* @details if the two triangles are the same, return nullopt. Only non
153+
* conformal part of triangles are considered in computation of distance,
154+
* i.e. if the triangle have a common point, it iterates on opposite
155+
* segment, if the triangle have a common edge, it computes distance with
156+
* the opposite point
157+
* @return a tuple containing:
158+
* - the smallest distance.
159+
* - the closest point on the first triangle.
160+
* - the closest point on the second triangle.
161+
*/
162+
[[nodiscard]] std::optional< std::tuple< double, Point3D, Point3D > >
163+
opengeode_geometry_api
164+
triangle_triangle_distance_between_non_conformal_parts(
165+
const Triangle3D& triangle0, const Triangle3D& triangle1 );
166+
139167
/*!
140168
* Compute the distance between a point and a tetrahedron
141169
* @return a tuple containing:

src/geode/geometry/distance.cpp

Lines changed: 195 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
#include <optional>
2525

26+
#include <geode/basic/logger.hpp>
2627
#include <geode/geometry/distance.hpp>
2728

2829
#include <absl/algorithm/container.h>
@@ -339,6 +340,92 @@ namespace
339340
geode::point_point_distance( point, closest_point );
340341
return std::make_tuple( distance, std::move( closest_point ) );
341342
}
343+
344+
std::pair< std::vector< geode::local_index_t >,
345+
std::vector< geode::local_index_t > >
346+
find_non_colocated_triangles_points( const geode::Triangle3D& triangle0,
347+
const geode::Triangle3D& triangle1 )
348+
{
349+
std::pair< std::array< bool, 3 >, std::array< bool, 3 > > colocated{
350+
{ false, false, false }, { false, false, false }
351+
};
352+
const auto& vertices0 = triangle0.vertices();
353+
const auto& vertices1 = triangle1.vertices();
354+
for( const auto vertex0 : geode::LRange{ 3 } )
355+
{
356+
for( const auto vertex1 : geode::LRange{ 3 } )
357+
{
358+
if( geode::point_point_distance(
359+
vertices0[vertex0].get(), vertices1[vertex1].get() )
360+
<= geode::GLOBAL_EPSILON )
361+
{
362+
colocated.first[vertex0] = true;
363+
colocated.second[vertex1] = true;
364+
}
365+
}
366+
}
367+
368+
std::pair< std::vector< geode::local_index_t >,
369+
std::vector< geode::local_index_t > >
370+
result;
371+
for( const auto v : geode::LRange{ 3 } )
372+
{
373+
if( !colocated.first[v] )
374+
{
375+
result.first.push_back( v );
376+
}
377+
if( !colocated.second[v] )
378+
{
379+
result.second.push_back( v );
380+
}
381+
}
382+
return result;
383+
}
384+
385+
std::tuple< double, geode::Point3D, geode::Point3D > test_close_triangles(
386+
const std::vector< geode::local_index_t >& non_colocated_points,
387+
const geode::Triangle3D& base_triangle,
388+
const geode::Triangle3D& other_triangle )
389+
{
390+
const auto& base_vertices = base_triangle.vertices();
391+
double min_distance{ std::numeric_limits< double >::max() };
392+
geode::Point3D point0;
393+
geode::Point3D point1;
394+
for( const auto vertex0 : non_colocated_points )
395+
{
396+
for( const auto vertex1 : non_colocated_points )
397+
{
398+
if( vertex0 == vertex1 )
399+
{
400+
continue;
401+
}
402+
if( geode::point_point_distance( base_vertices[vertex0].get(),
403+
base_vertices[vertex1].get() )
404+
<= geode::GLOBAL_EPSILON )
405+
{
406+
DEBUG( vertex0 );
407+
DEBUG( vertex1 );
408+
SDEBUG( base_vertices[0].get() );
409+
SDEBUG( base_vertices[1].get() );
410+
SDEBUG( base_vertices[2].get() );
411+
SDEBUG( other_triangle.vertices()[0].get() );
412+
SDEBUG( other_triangle.vertices()[1].get() );
413+
SDEBUG( other_triangle.vertices()[2].get() );
414+
}
415+
const geode::Segment3D edge{ base_vertices[vertex0],
416+
base_vertices[vertex1] };
417+
auto [cur_distance, cur_pt0, cur_pt1] =
418+
geode::segment_triangle_distance( edge, other_triangle );
419+
if( cur_distance < min_distance )
420+
{
421+
min_distance = cur_distance;
422+
point0 = cur_pt0;
423+
point1 = cur_pt1;
424+
}
425+
}
426+
}
427+
return std::make_tuple( min_distance, point0, point1 );
428+
}
342429
} // namespace
343430

344431
namespace geode
@@ -923,6 +1010,112 @@ namespace geode
9231010
closest_on_segment, closest_on_triangle );
9241011
}
9251012

1013+
std::tuple< double, Point3D, Point3D >
1014+
opengeode_geometry_api triangle_triangle_distance(
1015+
const Triangle3D& triangle0, const Triangle3D& triangle1 )
1016+
{
1017+
const auto non_colocated_points =
1018+
find_non_colocated_triangles_points( triangle0, triangle1 );
1019+
if( non_colocated_points.first.size() < 3 )
1020+
{
1021+
for( const auto v : LRange{ 3 } )
1022+
{
1023+
if( !absl::c_contains( non_colocated_points.first, v ) )
1024+
{
1025+
auto& pt0 = triangle0.vertices()[v].get();
1026+
auto [distance, pt1] =
1027+
point_triangle_distance( pt0, triangle1 );
1028+
return std::tuple{ distance, pt0, pt1 };
1029+
}
1030+
}
1031+
}
1032+
if( non_colocated_points.second.size() < 3 )
1033+
{
1034+
for( const auto v : LRange{ 3 } )
1035+
{
1036+
if( !absl::c_contains( non_colocated_points.second, v ) )
1037+
{
1038+
auto& pt1 = triangle1.vertices()[v].get();
1039+
auto [distance, pt0] =
1040+
point_triangle_distance( pt1, triangle0 );
1041+
return std::tuple{ distance, pt0, pt1 };
1042+
}
1043+
}
1044+
}
1045+
auto [cur_distance0, cur_pt00, cur_pt01] = test_close_triangles(
1046+
non_colocated_points.first, triangle0, triangle1 );
1047+
auto [cur_distance1, cur_pt11, cur_pt10] = test_close_triangles(
1048+
non_colocated_points.second, triangle1, triangle0 );
1049+
if( cur_distance0 < cur_distance1 )
1050+
{
1051+
return std::tuple{ cur_distance0, cur_pt00, cur_pt01 };
1052+
}
1053+
return std::tuple{ cur_distance1, cur_pt10, cur_pt11 };
1054+
}
1055+
1056+
std::optional< std::tuple< double, Point3D, Point3D > >
1057+
triangle_triangle_distance_between_non_conformal_parts(
1058+
const Triangle3D& triangle0, const Triangle3D& triangle1 )
1059+
{
1060+
const auto [non_colocated_points0, non_colocated_points1] =
1061+
find_non_colocated_triangles_points( triangle0, triangle1 );
1062+
if( non_colocated_points0.size() == 0
1063+
|| non_colocated_points1.size() == 0 )
1064+
{
1065+
return std::nullopt;
1066+
}
1067+
const auto& vertices0 = triangle0.vertices();
1068+
const auto& vertices1 = triangle1.vertices();
1069+
double min_distance{ std::numeric_limits< double >::max() };
1070+
Point3D point0;
1071+
Point3D point1;
1072+
if( non_colocated_points0.size() == 1 )
1073+
{
1074+
auto [cur_distance, cur_pt] = point_triangle_distance(
1075+
vertices0[non_colocated_points0[0]].get(), triangle1 );
1076+
if( cur_distance < min_distance )
1077+
{
1078+
min_distance = cur_distance;
1079+
point0 = vertices0[non_colocated_points0[0]].get();
1080+
point1 = cur_pt;
1081+
}
1082+
}
1083+
if( non_colocated_points1.size() == 1 )
1084+
{
1085+
auto [cur_distance, cur_pt] = point_triangle_distance(
1086+
vertices1[non_colocated_points1[0]].get(), triangle0 );
1087+
if( cur_distance < min_distance )
1088+
{
1089+
min_distance = cur_distance;
1090+
point0 = cur_pt;
1091+
point1 = vertices1[non_colocated_points1[0]].get();
1092+
}
1093+
}
1094+
if( non_colocated_points0.size() > 1 )
1095+
{
1096+
auto [cur_distance, cur_pt0, cur_pt1] = test_close_triangles(
1097+
non_colocated_points0, triangle0, triangle1 );
1098+
if( cur_distance < min_distance )
1099+
{
1100+
min_distance = cur_distance;
1101+
point0 = cur_pt0;
1102+
point1 = cur_pt1;
1103+
}
1104+
}
1105+
if( non_colocated_points1.size() > 1 )
1106+
{
1107+
auto [cur_distance, cur_pt1, cur_pt0] = test_close_triangles(
1108+
non_colocated_points1, triangle1, triangle0 );
1109+
if( cur_distance < min_distance )
1110+
{
1111+
min_distance = cur_distance;
1112+
point0 = cur_pt0;
1113+
point1 = cur_pt1;
1114+
}
1115+
}
1116+
return std::tuple{ min_distance, point0, point1 };
1117+
}
1118+
9261119
std::tuple< double, Point3D > point_tetrahedron_distance(
9271120
const Point3D& point, const Tetrahedron& tetra )
9281121
{
@@ -1048,7 +1241,8 @@ namespace geode
10481241
}
10491242
OPENGEODE_ASSERT(
10501243
!circle.plane().normal().inexact_equal( other_direction ),
1051-
"[point_circle_distance] Problem while getting circle nearest "
1244+
"[point_circle_distance] Problem while getting circle "
1245+
"nearest "
10521246
"point" );
10531247
const Vector3D other_projected_on_plane =
10541248
other_direction

0 commit comments

Comments
 (0)