MeshLib C++ Docs
Loading...
Searching...
No Matches
MRTriMath.h
Go to the documentation of this file.
1#pragma once
2// triangle-related mathematical functions are here
3
4#include "MRVector2.h"
5#include "MRVector3.h"
6#include <algorithm>
7#include <cassert>
8#include <cmath>
9#include <limits>
10#include <optional>
11
12namespace MR
13{
14
17template <typename T>
18[[nodiscard]] T circumcircleDiameterSq( const Vector3<T> & a, const Vector3<T> & b, const Vector3<T> & c )
19{
20 const auto ab = ( b - a ).lengthSq();
21 const auto ca = ( a - c ).lengthSq();
22 const auto bc = ( c - b ).lengthSq();
23 if ( ab <= 0 )
24 return ca;
25 if ( ca <= 0 )
26 return bc;
27 if ( bc <= 0 )
28 return ab;
29 const auto f = cross( b - a, c - a ).lengthSq();
30 if ( f <= 0 )
31 return std::numeric_limits<T>::infinity();
32 return ab * ca * bc / f;
33}
34
37template <typename T>
38[[nodiscard]] inline T circumcircleDiameter( const Vector3<T> & a, const Vector3<T> & b, const Vector3<T> & c )
39{
40 return std::sqrt( circumcircleDiameterSq( a, b, c ) );
41}
42
44template <typename T>
45[[nodiscard]] Vector3<T> circumcircleCenter( const Vector3<T> & a, const Vector3<T> & b )
46{
47 const auto xabSq = cross( a, b ).lengthSq();
48 const auto aa = a.lengthSq();
49 const auto bb = b.lengthSq();
50 if ( xabSq <= 0 )
51 {
52 if ( aa <= 0 )
53 return b / T(2);
54 // else b == 0 || a == b
55 return a / T(2);
56 }
57 const auto ab = dot( a, b );
58 return ( bb * ( aa - ab ) * a + aa * ( bb - ab ) * b ) / ( 2 * xabSq );
59}
60
62template <typename T>
63[[nodiscard]] inline Vector3<T> circumcircleCenter( const Vector3<T> & a, const Vector3<T> & b, const Vector3<T> & c )
64{
65 return circumcircleCenter( a - c, b - c ) + c;
66}
67
70template <typename T>
71[[nodiscard]] bool circumballCenters( const Vector3<T> & a, const Vector3<T> & b, const Vector3<T> & c, T radius,
72 Vector3<T> & centerPos, // ball's center from the positive side of triangle
73 Vector3<T> & centerNeg )// ball's center from the negative side of triangle
74{
75 const auto rr = sqr( radius );
76 const auto circRadSq = circumcircleDiameterSq( a, b, c ) / T( 4 );
77 if ( rr < circRadSq )
78 return false;
79
80 const auto x = std::sqrt( rr - circRadSq );
81 const auto xn = x * normal( a, b, c );
82 const auto circCenter = circumcircleCenter( a, b, c );
83 centerPos = circCenter + xn;
84 centerNeg = circCenter - xn;
85
86 return true;
87}
88
91template <typename T>
92[[nodiscard]] T minTriangleAngleSin( const Vector3<T> & a, const Vector3<T> & b, const Vector3<T> & c )
93{
94 const auto ab = ( b - a ).length();
95 const auto ca = ( a - c ).length();
96 const auto bc = ( c - b ).length();
97 if ( ab <= 0 || ca <= 0 || bc <= 0 )
98 return 0;
99 const auto f = cross( b - a, c - a ).length();
100 return f * std::min( { ab, ca, bc } ) / ( ab * ca * bc );
101}
102
103template <typename T>
104[[nodiscard]] T minTriangleAngle( const Vector3<T> & a, const Vector3<T> & b, const Vector3<T> & c )
105{
106 return std::asin( minTriangleAngleSin( a, b, c ) );
107}
108
111template<typename T>
112[[nodiscard]] T triangleAspectRatio( const Vector3<T> & a, const Vector3<T> & b, const Vector3<T> & c )
113{
114 const auto bc = ( c - b ).length();
115 const auto ca = ( a - c ).length();
116 const auto ab = ( b - a ).length();
117 auto halfPerimeter = ( bc + ca + ab ) / 2;
118 auto den = 8 * ( halfPerimeter - bc ) * ( halfPerimeter - ca ) * ( halfPerimeter - ab );
119 if ( den <= 0 )
120 return std::numeric_limits<T>::max();
121
122 return bc * ca * ab / den;
123}
124
126template<typename T>
127[[nodiscard]] inline Vector3<T> dirDblArea( const Triangle3<T> & t )
128{
129 return cross( t[1] - t[0], t[2] - t[0] );
130}
131
133template<typename T>
134[[nodiscard]] inline Vector3<T> dirDblArea( const Vector3<T> & q, const Vector3<T> & r )
135{
136 return cross( q, r );
137}
138
140template<typename T>
141[[nodiscard]] inline Vector3<T> dirDblArea( const Vector3<T> & p, const Vector3<T> & q, const Vector3<T> & r )
142{
143 return cross( q - p, r - p );
144}
145
147template<typename T>
148[[nodiscard]] inline Vector3<T> normal( const Vector3<T> & q, const Vector3<T> & r )
149{
150 return dirDblArea( q, r ).normalized();
151}
152
154template<typename T>
155[[nodiscard]] inline Vector3<T> normal( const Vector3<T> & p, const Vector3<T> & q, const Vector3<T> & r )
156{
157 return normal( q - p, r - p );
158}
159
161template<typename T>
162[[nodiscard]] inline Vector3<T> normal( const Triangle3<T> & t )
163{
164 return normal( t[1] - t[0], t[2] - t[0] );
165}
166
168template<typename T>
169[[nodiscard]] inline T dblAreaSq( const Vector3<T> & p, const Vector3<T> & q, const Vector3<T> & r )
170{
171 return dirDblArea( p, q, r ).lengthSq();
172}
173
175template<typename T>
176[[nodiscard]] inline T dblArea( const Triangle3<T> & t )
177{
178 return dirDblArea( t ).length();
179}
180
182template<typename T>
183[[nodiscard]] inline T dblArea( const Vector3<T> & p, const Vector3<T> & q, const Vector3<T> & r )
184{
185 return dirDblArea( p, q, r ).length();
186}
187
189template<typename T>
190[[nodiscard]] inline T area( const Vector3<T> & p, const Vector3<T> & q, const Vector3<T> & r )
191{
192 return dblArea( p, q, r ) / 2;
193}
194
196template<typename T>
197[[nodiscard]] inline T dblArea( const Vector2<T> & p, const Vector2<T> & q, const Vector2<T> & r )
198{
199 return std::abs( cross( q - p, r - p ) );
200}
201
203template<typename T>
204[[nodiscard]] inline T area( const Vector2<T> & p, const Vector2<T> & q, const Vector2<T> & r )
205{
206 return dblArea( p, q, r ) / 2;
207}
208
210template <typename T>
211[[nodiscard]] Triangle3<T> makeDegenerate( const Triangle3<T> & t )
212{
213 const auto c = ( t[0] + t[1] + t[2] ) / T(3);
214 int longest = 0;
215 T longestSq = 0;
216 for ( int i = 0; i < 3; ++i )
217 {
218 const auto sq = ( t[i] - c ).lengthSq();
219 if ( longestSq >= sq )
220 continue;
221 longest = i;
222 longestSq = sq;
223 }
224 const auto d = ( t[longest] - c ).normalized();
225
226 // project triangle on the line (c, d)
227 Triangle3<T> res;
228 for ( int i = 0; i < 3; ++i )
229 res[i] = c + d * dot( d, t[i] - c );
230 return res;
231}
232
235template <typename T>
236[[nodiscard]] Triangle3<T> triangleWithNormal( const Triangle3<T> & t, const Vector3<T> & n )
237{
238 const auto c = ( t[0] + t[1] + t[2] ) / T(3);
239 Triangle3<T> res;
240 for ( int i = 0; i < 3; ++i )
241 res[i] = t[i] - n * dot( n, t[i] - c );
242
243 if ( dot( n, dirDblArea( res ) ) < 0 ) // projected triangle has inversed normal
244 res = makeDegenerate( res );
245 return res;
246}
247
253template <typename T>
254[[nodiscard]] T dihedralAngleSin( const Vector3<T>& leftNorm, const Vector3<T>& rightNorm, const Vector3<T>& edgeVec )
255{
256 auto edgeDir = edgeVec.normalized();
257 return dot( edgeDir, cross( leftNorm, rightNorm ) );
258}
259
265template <typename T>
266[[nodiscard]] T dihedralAngleCos( const Vector3<T>& leftNorm, const Vector3<T>& rightNorm )
267{
268 return dot( leftNorm, rightNorm );
269}
270
277template <typename T>
278[[nodiscard]] T dihedralAngle( const Vector3<T>& leftNorm, const Vector3<T>& rightNorm, const Vector3<T>& edgeVec )
279{
280 auto sin = dihedralAngleSin( leftNorm, rightNorm, edgeVec );
281 auto cos = dihedralAngleCos( leftNorm, rightNorm );
282 return std::atan2( sin, cos );
283}
284
288template <typename T>
289[[nodiscard]] std::optional<Vector2<T>> posFromTriEdgeLengths( T a, T b, T c )
290{
291 if ( c == 0 )
292 {
293 if ( a == b )
294 return Vector2<T>{ a, 0 };
295 else
296 return {};
297 }
298 const auto aa = sqr( a );
299 const auto y = ( aa - sqr( b ) + sqr( c ) ) / ( 2 * c );
300 const auto yy = sqr( y );
301 if ( yy > aa )
302 return {};
303 const auto x = std::sqrt( aa - yy );
304 return Vector2<T>{ x, y };
305}
306
310template <typename T>
311[[nodiscard]] std::optional<T> quadrangleOtherDiagonal( T a, T b, T c, T a1, T b1 )
312{
313 const auto p = posFromTriEdgeLengths( a, b, c );
314 if ( !p )
315 return {};
316 auto p1 = posFromTriEdgeLengths( a1, b1, c );
317 if ( !p1 )
318 return {};
319 p1->x = -p1->x;
320 //where the other diagonal crosses axis Oy
321 auto y = ( p->x * p1->y - p1->x * p->y ) / ( p->x - p1->x );
322 if ( y < 0 || y > c )
323 return {};
324 return ( *p - *p1 ).length();
325}
326
330template <typename T>
331[[nodiscard]] inline T tanSqOfHalfAngle( T a, T b, T c )
332{
333 const T den = ( a + b + c ) * ( b + c - a );
334 if ( den <= 0 )
335 return std::numeric_limits<T>::infinity();
336 const T num = ( a + c - b ) * ( a + b - c );
337 if ( num <= 0 )
338 return 0;
339 return num / den;
340}
341
344template <typename T>
345[[nodiscard]] inline T cotan( const Triangle3<T> & t, T absMaxVal = std::numeric_limits<T>::max() )
346{
347 auto a = t[0] - t[2];
348 auto b = t[1] - t[2];
349 auto nom = dot( a, b );
350 auto den = cross( a, b ).length();
351 if ( fabs( nom ) >= absMaxVal * den )
352 return absMaxVal * sgn( nom );
353 return nom / den;
354}
355
359template <typename T>
360[[nodiscard]] inline T cotan( T a, T b, T c )
361{
362 const T den = ( a + b + c ) * ( b + c - a );
363 if ( den <= 0 )
364 return -std::numeric_limits<T>::infinity();
365 const T num = ( a + c - b ) * ( a + b - c );
366 if ( num <= 0 )
367 return std::numeric_limits<T>::infinity();
368 const auto tanSq = num / den;
369 return ( 1 - tanSq ) / ( 2 * std::sqrt( tanSq ) );
370}
371
374template <typename T>
375[[nodiscard]] std::optional<Vector3<T>> gradientInTri( const Vector3<T> & b, const Vector3<T> & c, T vb, T vc )
376{
377 const auto bb = dot( b, b );
378 const auto bc = dot( b, c );
379 const auto cc = dot( c, c );
380 const auto det = bb * cc - bc * bc;
381 if ( det <= 0 )
382 return {};
383 const auto kb = ( 1 / det ) * ( cc * vb - bc * vc );
384 const auto kc = ( 1 / det ) * (-bc * vb + bb * vc );
385 return kb * b + kc * c;
386}
387
390template <typename T>
391[[nodiscard]] std::optional<Vector3<T>> gradientInTri( const Vector3<T> & a, const Vector3<T> & b, const Vector3<T> & c, T va, T vb, T vc )
392{
393 return gradientInTri( b - a, c - a, vb - va, vc - va );
394}
395
396// consider triangle 0BC, where gradient of linear scalar field is given;
397// computes the intersection of the ray (org=0, dir=-grad) with the open line segment BC
398template <typename T>
399[[nodiscard]] std::optional<T> findTriExitPos( const Vector3<T> & b, const Vector3<T> & c, const Vector3<T> & grad )
400{
401 const auto gradSq = grad.lengthSq();
402 if ( gradSq <= 0 )
403 return {};
404 const auto d = c - b;
405 // gort is a vector in the triangle plane orthogonal to grad
406 const auto gort = d - ( dot( d, grad ) / gradSq ) * grad;
407 const auto god = dot( gort, d );
408 if ( god <= 0 )
409 return {};
410 const auto gob = -dot( gort, b );
411 if ( gob <= 0 || gob >= god )
412 return {};
413 const auto a = gob / god;
414 assert( a < std::numeric_limits<T>::max() );
415 const auto ip = a * c + ( 1 - a ) * b;
416 if ( dot( grad, ip ) >= 0 )
417 return {}; // (b,c) is intersected in the direction +grad
418 return a;
419}
420
427template <typename T>
428[[nodiscard]] std::optional<Vector3<T>> tangentPlaneNormalToSpheres( const Vector3<T> & b, const Vector3<T> & c, T rb, T rc )
429{
430 auto grad = gradientInTri( b, c, rb, rc );
431 if ( !grad.has_value() )
432 return {}; // degenerate triangle
433 auto gradSq = grad->lengthSq();
434 if ( gradSq >= 1 )
435 return {}; // the larger of the spheres contains the origin inside - no touch plane exists
436 return sqrt( 1 - gradSq ) * normal( b, c ) - *grad; // unit normal
437}
438
445template <typename T>
446[[nodiscard]] std::optional<Plane3<T>> tangentPlaneToSpheres( const Vector3<T> & a, const Vector3<T> & b, const Vector3<T> & c, T ra, T rb, T rc )
447{
448 if ( auto n = tangentPlaneNormalToSpheres( b - a, c - a, rb - ra, rc - ra ) )
449 return Plane3<T>( *n, dot( *n, a ) + ra );
450 return {}; // the larger of the spheres contains another sphere inside - no touch plane exists
451}
452
453} // namespace MR
length
Definition MRObjectDimensionsEnum.h:14
T minTriangleAngleSin(const Vector3< T > &a, const Vector3< T > &b, const Vector3< T > &c)
Definition MRTriMath.h:92
Definition MRCameraOrientationPlugin.h:8
float area(const MeshTopology &topology, const VertCoords &points, FaceId f)
returns the area of given face
Definition MRMeshMath.h:165
constexpr T sqr(T x) noexcept
squared value
Definition MRMeshFwd.h:752
MRMESH_API float circumcircleDiameter(const MeshTopology &topology, const VertCoords &points, FaceId f)
returns circumcircle diameter of given mesh triangle
MRMESH_API float dihedralAngle(const MeshTopology &topology, const VertCoords &points, UndirectedEdgeId e)
Vector3< T > circumcircleCenter(const Vector3< T > &a, const Vector3< T > &b)
Computes the center of the the triangle's 0AB circumcircle.
Definition MRTriMath.h:45
MRMESH_API float dihedralAngleCos(const MeshTopology &topology, const VertCoords &points, UndirectedEdgeId e)
std::optional< T > findTriExitPos(const Vector3< T > &b, const Vector3< T > &c, const Vector3< T > &grad)
Definition MRTriMath.h:399
std::optional< T > quadrangleOtherDiagonal(T a, T b, T c, T a1, T b1)
Definition MRTriMath.h:311
Triangle3< T > makeDegenerate(const Triangle3< T > &t)
make degenerate triangle (all 3 points on a line) that maximally resembles the input one and has the ...
Definition MRTriMath.h:211
T tanSqOfHalfAngle(T a, T b, T c)
Definition MRTriMath.h:331
Triangle3< T > triangleWithNormal(const Triangle3< T > &t, const Vector3< T > &n)
Definition MRTriMath.h:236
Vector3f dirDblArea(const MeshTopology &topology, const VertCoords &points, FaceId f)
computes directed double area for a triangular face from its vertices
Definition MRMeshMath.h:150
MRMESH_API float triangleAspectRatio(const MeshTopology &topology, const VertCoords &points, FaceId f)
returns aspect ratio of given mesh triangle equal to the ratio of the circum-radius to twice its in-r...
constexpr int sgn(T x) noexcept
sign of given value in { -1, 0, 1 }
Definition MRMeshFwd.h:756
std::optional< Vector3< T > > gradientInTri(const Vector3< T > &b, const Vector3< T > &c, T vb, T vc)
Definition MRTriMath.h:375
std::optional< Plane3< T > > tangentPlaneToSpheres(const Vector3< T > &a, const Vector3< T > &b, const Vector3< T > &c, T ra, T rb, T rc)
Definition MRTriMath.h:446
MRMESH_API float circumcircleDiameterSq(const MeshTopology &topology, const VertCoords &points, FaceId f)
returns squared circumcircle diameter of given mesh triangle
bool circumballCenters(const Vector3< T > &a, const Vector3< T > &b, const Vector3< T > &c, T radius, Vector3< T > &centerPos, Vector3< T > &centerNeg)
Definition MRTriMath.h:71
std::optional< Vector3< T > > tangentPlaneNormalToSpheres(const Vector3< T > &b, const Vector3< T > &c, T rb, T rc)
Definition MRTriMath.h:428
float dblArea(const MeshTopology &topology, const VertCoords &points, FaceId f)
returns twice the area of given face
Definition MRMeshMath.h:159
T minTriangleAngle(const Vector3< T > &a, const Vector3< T > &b, const Vector3< T > &c)
Definition MRTriMath.h:104
std::optional< Vector2< T > > posFromTriEdgeLengths(T a, T b, T c)
Definition MRTriMath.h:289
float cotan(const MeshTopology &topology, const VertCoords &points, UndirectedEdgeId ue)
Definition MRMeshMath.h:312
Vector3f normal(const MeshTopology &topology, const VertCoords &points, FaceId f)
computes triangular face normal from its vertices
Definition MRMeshMath.h:221
T dblAreaSq(const Vector3< T > &p, const Vector3< T > &q, const Vector3< T > &r)
computes the square of double area of given triangle
Definition MRTriMath.h:169
MRMESH_API float dihedralAngleSin(const MeshTopology &topology, const VertCoords &points, UndirectedEdgeId e)
Definition MRPlane3.h:18
Definition MRVector2.h:29
Definition MRMesh/MRVector3.h:30
Vector3 normalized() const MR_REQUIRES_IF_SUPPORTED(std
Definition MRMesh/MRVector3.h:74
T lengthSq() const
Definition MRMesh/MRVector3.h:65
readonly unsafe float length()
readonly unsafe MR.Vector3f normalized()
readonly unsafe float lengthSq()