MeshLib C++ Docs
Loading...
Searching...
No Matches
MRTriangleIntersection.h
Go to the documentation of this file.
1#pragma once
2
3#include "MRVector3.h"
5#include "MRTriPoint.h"
6#include "MRLineSegm.h"
7
8#include <algorithm>
9#include <optional>
10
11namespace MR
12{
13
17
18struct TriIntersectResult
19{
20 // barycentric representation
21 TriPointf bary;
22 // distance from ray origin to p in dir length units
23 float t = 0;
24 TriIntersectResult(float U, float V, float dist)
25 {
26 bary.a = U; bary.b = V; t = dist;
27 }
28};
29
32template <typename T>
36)
37{
38 const auto abcd = mixed( a - d, b - d, c - d );
39 const auto abce = mixed( a - e, b - e, c - e );
40 const auto abcf = mixed( a - f, b - f, c - f );
41 const auto abc_de = abcd * abce >= 0; // segment DE is located at one side of the plane ABC
42 const auto abc_fd = abcf * abcd >= 0; // segment FD is located at one side of the plane ABC
43
44 if ( abc_de && abc_fd && abce * abcf >= 0 )
45 return false; // triangle DEF is located at one side of the plane ABC
46
47 const auto defa = mixed( d - a, e - a, f - a );
48 const auto defb = mixed( d - b, e - b, f - b );
49 const auto defc = mixed( d - c, e - c, f - c );
50 const auto def_ab = defa * defb >= 0; // segment AB is located at one side of the plane DEF
51 const auto def_ca = defc * defa >= 0; // segment CA is located at one side of the plane DEF
52
53 if ( def_ab && def_ca && defb * defc >= 0 )
54 return false; // triangle ABC is located at one side of the plane DEF
55
56 if ( abc_de )
57 std::swap( d, f );
58 else if( abc_fd )
59 std::swap( d, e );
60 // now segments DE and FD are crossed by the plane ABC: D at one side and EF at the other
61
62 if ( def_ab )
63 std::swap( a, c );
64 else if ( def_ca )
65 std::swap( a, b );
66 // now segments AB and CA are crossed by the plane DEF: A at one side and BC at the other
67
68 const auto abde = mixed( a - e, b - e, d - e );
69 const auto abdf = mixed( a - f, b - f, d - f );
70
71 if ( abde * abdf < 0 )
72 return true; // AB segment penetrates triangle DEF since points E and F are at distinct sides of ABD
73
74 const auto acde = mixed( a - e, c - e, d - e );
75
76 if ( abde * acde < 0 )
77 return true; // DE segment penetrates triangle ABC since points B and C are at distinct sides of ADE
78
79 if ( abdf == 0 && acde == 0 )
80 return true; // AB and DF segments are in the same plane, and AC and DE segments are in other same plane => triangles intersect, but no edge intersect the interior of other triangle
81
82 const auto acdf = mixed( a - f, c - f, d - f );
83
84 if ( acde * acdf < 0 )
85 return true; // AC segment penetrates triangle DEF since points E and F are at distinct sides of ACD
86
87 if ( abdf * acdf < 0 )
88 return true; // DF segment penetrates triangle ABC since points B and C are at distinct sides of ADF
89
90 if ( abde == 0 && acdf == 0 )
91 return true; // AB and DE segments are in the same plane, and AC and DF segments are in other same plane => triangles intersect, but no edge intersect the interior of other triangle
92
93 return false;
94}
95
97template<typename T>
98bool isPointInPlane( const Vector3<T>& p, const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& c )
99{
100 return mixed( p - a, p - b, p - c ) == T( 0 );
101}
102
103MR_BIND_TEMPLATE( bool isPointInPlane( const Vector3<float>& p, const Vector3<float>& a, const Vector3<float>& b, const Vector3<float>& c ) )
104MR_BIND_TEMPLATE( bool isPointInPlane( const Vector3<double>& p, const Vector3<double>& a, const Vector3<double>& b, const Vector3<double>& c ) )
105
106
107template<typename T>
108bool isPointInLine( const Vector3<T>& p, const Vector3<T>& a, const Vector3<T>& b )
109{
110 return cross( p - a, p - b ).lengthSq() == T( 0 );
111}
112
114template<typename T>
115bool isPointInLine( const Vector2<T>& p, const Vector2<T>& a, const Vector2<T>& b )
116{
117 return cross( p - a, p - b ) == T( 0 );
118}
119
121template<typename T>
122bool isPointInSegm( const Vector3<T>& p, const Vector3<T>& a, const Vector3<T>& b )
123{
124 if ( !isPointInLine( p, a, b ) )
125 return false;
126
127 return dot( p - a, b - a ) >= 0 && dot( p - b, a - b ) >= 0;
128}
129
131template<typename T>
132bool isPointInSegm( const Vector2<T>& p, const Vector2<T>& a, const Vector2<T>& b )
133{
134 if ( !isPointInLine( p, a, b ) )
135 return false;
136
137 return dot( p - a, b - a ) >= 0 && dot( p - b, a - b ) >= 0;
138}
139
140MR_BIND_TEMPLATE( bool isPointInLine( const Vector3<float>& p, const Vector3<float>& a, const Vector3<float>& b ) )
141MR_BIND_TEMPLATE( bool isPointInLine( const Vector3<double>& p, const Vector3<double>& a, const Vector3<double>& b ) )
142MR_BIND_TEMPLATE( bool isPointInSegm( const Vector3<float>& p, const Vector3<float>& a, const Vector3<float>& b ) )
143MR_BIND_TEMPLATE( bool isPointInSegm( const Vector3<double>& p, const Vector3<double>& a, const Vector3<double>& b ) )
144
145
146template<typename T>
147bool isPointInTriangle( const Vector3<T>& p, const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& c )
148{
149 if ( !isPointInPlane( p, a, b, c ) )
150 return false;
151 const auto normDir = cross( b - a, c - a );
152 if ( dot( normDir, cross( b - a, p - a ) ) < 0 )
153 return false;
154 if ( dot( normDir, cross( c - b, p - b ) ) < 0 )
155 return false;
156 if ( dot( normDir, cross( a - c, p - c ) ) < 0 )
157 return false;
158 if ( normDir.lengthSq() == 0 )
159 {
160
161 // ab parallel ac
162 if ( a == b && b == c && p != a )
163 return false; // fully degenerated
164 if ( dot( b - a, c - a ) <= 0 )
165 return isPointInSegm( p, b, c ); // ab ac looking in the opposite directions so check BC segm
166 else if ( ( b - a ).lengthSq() > ( c - a ).lengthSq() )
167 return isPointInSegm( p, a, b ); // ab ac looking in the same direction and AB is longer so check AB segm
168 else
169 return isPointInSegm( p, a, c ); // ab ac looking in the same direction and AC is longer so check AC segm
170 }
171 return true;
172}
173
175template<typename T>
176bool isPointInTriangle( const Vector2<T>& p, const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& c )
177{
178 const auto normSign = cross( b - a, c - a );
179 if ( normSign * cross( b - a, p - a ) < 0 )
180 return false;
181 if ( normSign * cross( c - b, p - b ) < 0 )
182 return false;
183 if ( normSign * cross( a - c, p - c ) < 0 )
184 return false;
185 if ( normSign == 0 )
186 {
187 // ab parallel ac
188 if ( a == b && b == c && p != a )
189 return false; // fully degenerated
190 if ( dot( b - a, c - a ) <= 0 )
191 return isPointInSegm( p, b, c ); // ab ac looking in the opposite directions so check BC segm
192 else if ( ( b - a ).lengthSq() > ( c - a ).lengthSq() )
193 return isPointInSegm( p, a, b ); // ab ac looking in the same direction and AB is longer so check AB segm
194 else
195 return isPointInSegm( p, a, c ); // ab ac looking in the same direction and AC is longer so check AC segm
196 }
197
198 return true;
199}
200
201MR_BIND_TEMPLATE( bool isPointInTriangle( const Vector3<float>& p, const Vector3<float>& a, const Vector3<float>& b, const Vector3<float>& c ) )
202MR_BIND_TEMPLATE( bool isPointInTriangle( const Vector3<double>& p, const Vector3<double>& a, const Vector3<double>& b, const Vector3<double>& c ) )
203MR_BIND_TEMPLATE( bool isPointInTriangle( const Vector2<float>& p, const Vector2<float>& a, const Vector2<float>& b, const Vector2<float>& c ) )
204MR_BIND_TEMPLATE( bool isPointInTriangle( const Vector2<double>& p, const Vector2<double>& a, const Vector2<double>& b, const Vector2<double>& c ) )
205
206
207template <typename T>
209 const Vector3<T> & x, const Vector3<T> & y, const Vector3<T> & z,
210 const Vector3<T> & u, const Vector3<T> & v, const Vector3<T> & w,
211 Vector3<T> d // approximate normal of the plane
212)
213{
214 const auto xy = ( y - x ).normalized();
215 d = ( d - xy * dot( xy, d ) ).normalized();
216 // now d is orthogonal to xy
217 const auto dz = dot( d, z - x );
218 return
219 dz * dot( d, u - x ) < 0 &&
220 dz * dot( d, v - x ) < 0 &&
221 dz * dot( d, w - x ) < 0;
222}
223
226template <typename T>
228 const Vector3<T> & a, const Vector3<T> & b, const Vector3<T> & c,
229 const Vector3<T> & d, const Vector3<T> & e, const Vector3<T> & f
230)
231{
232 if ( !doTrianglesIntersect( a, b, c, d, e, f ) )
233 return false;
234
235 // direction from center to center
236 const auto dir = a + b + c - d - e - f;
237
238 return
239 !doesEdgeXySeparate( a, b, c, d, e, f, dir ) &&
240 !doesEdgeXySeparate( b, c, a, d, e, f, dir ) &&
241 !doesEdgeXySeparate( c, a, b, d, e, f, dir ) &&
242 !doesEdgeXySeparate( d, e, f, a, b, c, dir ) &&
243 !doesEdgeXySeparate( e, f, d, a, b, c, dir ) &&
244 !doesEdgeXySeparate( f, d, e, a, b, c, dir );
245}
246
248template <typename T>
250 const Vector3<T> & a, const Vector3<T> & b, const Vector3<T> & c,
251 const Vector3<T> & d, const Vector3<T> & e
252)
253{
254 const auto dabe = mixed( d - e, a - e, b - e );
255 const auto dbce = mixed( d - e, b - e, c - e );
256 if ( dabe * dbce <= 0 )
257 return false; // segment AC is located at one side of the plane DEB
258
259 const auto dcae = mixed( d - e, c - e, a - e );
260 if ( dbce * dcae <= 0 )
261 return false; // segment AB is located at one side of the plane DEC
262
263 if ( dcae * dabe <= 0 )
264 return false; // segment BC is located at one side of the plane DEA
265
266 return true;
267}
268
270template <typename T>
272 const Vector3<T> & a, const Vector3<T> & b, const Vector3<T> & c,
273 const Vector3<T> & d, const Vector3<T> & e
274)
275{
276 const auto abcd = mixed( a - d, b - d, c - d );
277 const auto abce = mixed( a - e, b - e, c - e );
278 if ( abcd * abce >= 0 )
279 return false; // segment DE is located at one side of the plane ABC
280 return doTriangleLineIntersect( a, b, c, d, e );
281}
282
284template <typename T>
286 const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& c,
287 const Vector3<T>& d, const Vector3<T>& e
288)
289{
290 const auto abcd = std::abs( mixed( a - d, b - d, c - d ) );
291 const auto abce = std::abs( mixed( a - e, b - e, c - e ) );
292 auto r = std::clamp( abcd / ( abcd + abce ), T( 0 ), T( 1 ) );
293 return r * e + ( 1 - r ) * d;
294}
295
298template <typename T>
299std::optional<Vector3<T>> findTriangleTriangleIntersection(
300 const Vector3<T>& a, const Vector3<T>& b, const Vector3<T>& c,
301 const Vector3<T>& d, const Vector3<T>& e, const Vector3<T>& f )
302{
303 if ( doTriangleSegmentIntersect( a, b, c, d, e ) )
304 return findTriangleSegmentIntersection( a, b, c, d, e );
305 if ( doTriangleSegmentIntersect( a, b, c, e, f ) )
306 return findTriangleSegmentIntersection( a, b, c, e, f );
307 if ( doTriangleSegmentIntersect( a, b, c, f, d ) )
308 return findTriangleSegmentIntersection( a, b, c, f, d );
309
310 if ( doTriangleSegmentIntersect( d, e, f, a, b ) )
311 return findTriangleSegmentIntersection( d, e, f, a, b );
312 if ( doTriangleSegmentIntersect( d, e, f, b, c ) )
313 return findTriangleSegmentIntersection( d, e, f, b, c );
314 if ( doTriangleSegmentIntersect( d, e, f, c, a ) )
315 return findTriangleSegmentIntersection( d, e, f, c, a );
316 return std::nullopt;
317}
318
319template <typename T>
320std::optional<TriIntersectResult> rayTriangleIntersect( const Vector3<T>& oriA, const Vector3<T>& oriB, const Vector3<T>& oriC,
321 const IntersectionPrecomputes<T>& prec )
322{
323 const T& Sx = prec.Sx;
324 const T& Sy = prec.Sy;
325 const T& Sz = prec.Sz;
326
327 const T Ax = oriA[prec.idxX] - Sx * oriA[prec.maxDimIdxZ];
328 const T Ay = oriA[prec.idxY] - Sy * oriA[prec.maxDimIdxZ];
329 const T Bx = oriB[prec.idxX] - Sx * oriB[prec.maxDimIdxZ];
330 const T By = oriB[prec.idxY] - Sy * oriB[prec.maxDimIdxZ];
331 const T Cx = oriC[prec.idxX] - Sx * oriC[prec.maxDimIdxZ];
332 const T Cy = oriC[prec.idxY] - Sy * oriC[prec.maxDimIdxZ];
333
334 // due to fused multiply-add (FMA): (A*B-A*B) can be different from zero, so we need epsilon
335 const T eps = std::numeric_limits<T>::epsilon() * std::max( { Ax, Bx, Cx, Ay, By, Cy } );
336 T U = Cx * By - Cy * Bx;
337 T V = Ax * Cy - Ay * Cx;
338 T W = Bx * Ay - By * Ax;
339
340 if( U < -eps || V < -eps || W < -eps )
341 {
342 if( U > eps || V > eps || W > eps )
343 {
344 // U,V,W have clearly different signs, so the ray misses the triangle
345 return std::nullopt;
346 }
347 }
348
349 T det = U + V + W;
350 if( det == T( 0 ) )
351 return std::nullopt;
352 const T Az = Sz * oriA[prec.maxDimIdxZ];
353 const T Bz = Sz * oriB[prec.maxDimIdxZ];
354 const T Cz = Sz * oriC[prec.maxDimIdxZ];
355 const T t = U * Az + V * Bz + W * Cz;
356
357 auto invDet = T( 1 ) / det;
358 return TriIntersectResult( float( V * invDet ), float( W * invDet ), float( t * invDet ) );
359}
360
361MR_BIND_TEMPLATE( std::optional<TriIntersectResult> rayTriangleIntersect( const Vector3<float >& oriA, const Vector3<float >& oriB, const Vector3<float >& oriC, const IntersectionPrecomputes<float >& prec ) )
362MR_BIND_TEMPLATE( std::optional<TriIntersectResult> rayTriangleIntersect( const Vector3<double>& oriA, const Vector3<double>& oriB, const Vector3<double>& oriC, const IntersectionPrecomputes<double>& prec ) )
363
364template <typename T>
365std::optional<TriIntersectResult> rayTriangleIntersect( const Vector3<T>& oriA, const Vector3<T>& oriB, const Vector3<T>& oriC,
366 const Vector3<T>& dir )
367{
368 const IntersectionPrecomputes<T> prec( dir );
369 return rayTriangleIntersect( oriA, oriB, oriC, prec );
370}
371
372MR_BIND_TEMPLATE( std::optional<TriIntersectResult> rayTriangleIntersect( const Vector3<float >& oriA, const Vector3<float >& oriB, const Vector3<float >& oriC, const Vector3<float >& dir ) )
373MR_BIND_TEMPLATE( std::optional<TriIntersectResult> rayTriangleIntersect( const Vector3<double>& oriA, const Vector3<double>& oriB, const Vector3<double>& oriC, const Vector3<double>& dir ) )
374
375
376template<typename T>
377bool doTrianglesOverlap( const Vector2<T>& a, const Vector2<T>& b, const Vector2<T>& c, const Vector2<T>& d, const Vector2<T>& e, const Vector2<T>& f )
378{
379 // TODO: probably some of the checks are excessive?
380
381 // check if AB intersects any of DEF sides
383 return true;
385 return true;
387 return true;
388
389 // check if AC intersects any of DEF sides
391 return true;
393 return true;
395 return true;
396
397 // check if BC intersects any of DEF sides
399 return true;
401 return true;
403 return true;
404
405 // no sides intersection:
406 // either ABC fully inside DEF or vice versa
407 if ( isPointInTriangle( a, d, e, f ) )
408 return true;
409 if ( isPointInTriangle( d, a, b, c ) )
410 return true;
411
412 return false;
413}
414
415MR_BIND_TEMPLATE( bool doTrianglesOverlap( const Vector2<float>& a, const Vector2<float>& b, const Vector2<float>& c, const Vector2<float>& d, const Vector2<float>& e, const Vector2<float>& f ) )
416MR_BIND_TEMPLATE( bool doTrianglesOverlap( const Vector2<double>& a, const Vector2<double>& b, const Vector2<double>& c, const Vector2<double>& d, const Vector2<double>& e, const Vector2<double>& f ) )
417
418
419
420} // namespace MR
Definition MRTriangleIntersection.h:19
unsafe TriIntersectResult(MR.Const_TriIntersectResult _other)
int idxY
Definition MRIntersectionPrecomputes.h:124
T Sx
precomputed factors
Definition MRIntersectionPrecomputes.h:130
int idxX
Definition MRIntersectionPrecomputes.h:123
T Sz
Definition MRIntersectionPrecomputes.h:130
T Sy
Definition MRIntersectionPrecomputes.h:130
int maxDimIdxZ
Definition MRIntersectionPrecomputes.h:122
MRMESH_API TriangleSegmentIntersectResult doTriangleSegmentIntersect(const std::array< PreciseVertCoords, 5 > &vs)
std::optional< Vector3< T > > findTriangleTriangleIntersection(const Vector3< T > &a, const Vector3< T > &b, const Vector3< T > &c, const Vector3< T > &d, const Vector3< T > &e, const Vector3< T > &f)
Definition MRTriangleIntersection.h:299
bool isPointInPlane(const Vector3< T > &p, const Vector3< T > &a, const Vector3< T > &b, const Vector3< T > &c)
returns true if ABC plane contains point P
Definition MRTriangleIntersection.h:98
bool doTrianglesIntersect(Vector3< T > a, Vector3< T > b, Vector3< T > c, Vector3< T > d, Vector3< T > e, Vector3< T > f)
Definition MRTriangleIntersection.h:33
std::optional< TriIntersectResult > rayTriangleIntersect(const Vector3< T > &oriA, const Vector3< T > &oriB, const Vector3< T > &oriC, const IntersectionPrecomputes< T > &prec)
Definition MRTriangleIntersection.h:320
bool doesEdgeXySeparate(const Vector3< T > &x, const Vector3< T > &y, const Vector3< T > &z, const Vector3< T > &u, const Vector3< T > &v, const Vector3< T > &w, Vector3< T > d)
returns true if a plane containing edge XY separates point Z from triangle UVW
Definition MRTriangleIntersection.h:208
bool isPointInTriangle(const Vector3< T > &p, const Vector3< T > &a, const Vector3< T > &b, const Vector3< T > &c)
returns true if ABC triangle contains point P
Definition MRTriangleIntersection.h:147
bool doTriangleLineIntersect(const Vector3< T > &a, const Vector3< T > &b, const Vector3< T > &c, const Vector3< T > &d, const Vector3< T > &e)
checks whether triangle ABC and infinite line DE intersect
Definition MRTriangleIntersection.h:249
Vector3< T > findTriangleSegmentIntersection(const Vector3< T > &a, const Vector3< T > &b, const Vector3< T > &c, const Vector3< T > &d, const Vector3< T > &e)
this function input should have intersection
Definition MRTriangleIntersection.h:285
bool doTrianglesIntersectExt(const Vector3< T > &a, const Vector3< T > &b, const Vector3< T > &c, const Vector3< T > &d, const Vector3< T > &e, const Vector3< T > &f)
Definition MRTriangleIntersection.h:227
bool doTrianglesOverlap(const Vector2< T > &a, const Vector2< T > &b, const Vector2< T > &c, const Vector2< T > &d, const Vector2< T > &e, const Vector2< T > &f)
returns true if ABC and DEF overlaps or touches
Definition MRTriangleIntersection.h:377
bool isPointInLine(const Vector3< T > &p, const Vector3< T > &a, const Vector3< T > &b)
returns true if AB line contains point P
Definition MRTriangleIntersection.h:108
bool isPointInSegm(const Vector3< T > &p, const Vector3< T > &a, const Vector3< T > &b)
returns true if AB segment contains point P
Definition MRTriangleIntersection.h:122
Definition MRCameraOrientationPlugin.h:8
bool doSegmentsIntersect(const LineSegm< V > &x, const LineSegm< V > &y, typename V::ValueType *xPos=nullptr, typename V::ValueType *yPos=nullptr)
Definition MRLineSegm.h:53
Definition MRMeshFwd.h:503
Definition MRLineSegm.h:12
Definition MRVector2.h:29
Definition MRMesh/MRVector3.h:30