AGX Dynamics 2.40.0.0
Loading...
Searching...
No Matches
BasicPrimitiveTests.h
Go to the documentation of this file.
1/*
2Copyright 2007-2025. Algoryx Simulation AB.
3
4All AGX source code, intellectual property, documentation, sample code,
5tutorials, scene files and technical white papers, are copyrighted, proprietary
6and confidential material of Algoryx Simulation AB. You may not download, read,
7store, distribute, publish, copy or otherwise disseminate, use or expose this
8material unless having a written signed agreement with Algoryx Simulation AB, or having been
9advised so by Algoryx Simulation AB for a time limited evaluation, or having purchased a
10valid commercial license from Algoryx Simulation AB.
11
12Algoryx Simulation AB disclaims all responsibilities for loss or damage caused
13from using this software, unless otherwise stated in written agreements with
14Algoryx Simulation AB.
15*/
16
17#ifndef AGXCOLLIDE_BASICPRIMITIVETESTS_H
18#define AGXCOLLIDE_BASICPRIMITIVETESTS_H
19
20#include <agx/macros.h>
21
23
24#include <agx/agx_vector_types.h>
26#include <agx/StackArray.h>
27#include <agx/Plane.h>
28#include <agx/Integer.h>
29
30#ifndef _WIN32
31#include <float.h>
32#endif
33
34#include <agx/agx.h>
35#include <agx/Vec3.h>
36
37namespace agxCollide
38{
39 class Mesh;
40
41
43 const agx::Real parallelityThreshold = agx::Real(0.86602540378444); // sin(60 deg) and cos(30 deg); choice is motivated by testing.
44
45
54 bool areDirectionsParallel(const agx::Vec3& dir0, const agx::Vec3& dir1,
55 const agx::Real cosEpsilon = parallelityThreshold);
56
57
66 bool areDirectionsOrthogonal(const agx::Vec3& dir0, const agx::Vec3& dir1,
67 const agx::Real sinEpsilon = parallelityThreshold);
68
69
84 template <typename T>
85 bool intersectLineSegmentHyperPlane(
86 const T& lineP1,
87 const T& lineP2,
88 const T& normal,
89 agx::Real d,
90 agx::Real& t,
91 T& result,
92 const agx::Real epsilon );
93
94
109 template <typename T>
110 bool intersectLineHyperPlane(
111 const T& linePoint,
112 const T& lineDir,
113 const T& normal,
114 agx::Real d,
115 agx::Real& t,
116 T& result,
117 const agx::Real epsilon );
118
119
131 AGXPHYSICS_EXPORT agx::Vec3 closestPointPointTriangle( const agx::Vec3& p, const agx::Vec3& a,
132 const agx::Vec3& b, const agx::Vec3& c, uint8_t& voronoiRegion );
133
134
135
136 AGX_FORCE_INLINE bool pointOnLine( const agx::Vec3& point,
137 const agx::Vec3& lineP0, const agx::Vec3& lineP1, agx::Real epsilon )
138 {
139 const agx::Vec3 dir = lineP1 - lineP0;
140 const agx::Real dirLen2 = dir.length2();
142 // Line segment degenerates to point, measure distance from point to point.
143 return agx::equalsZero((lineP0 - point).length2(), epsilon * epsilon);
144 }
145 const agx::Vec3 pointP0 = lineP0 - point;
146 const agx::Vec3 dist = pointP0 - dir * (dir * pointP0) / dirLen2;
147 return dist.length2() < epsilon * epsilon;
148 }
149
150
161 AGXPHYSICS_EXPORT bool pointInTrianglePrism(
162 const agx::Vec3& p,
163 const agx::Vec3& pointA,
164 const agx::Vec3& pointB,
165 const agx::Vec3& pointC,
166 const agx::Real epsilon = agx::RealEpsilon );
167
168
180 AGXPHYSICS_EXPORT bool pointInTriangle(
181 const agx::Vec3& p,
182 const agx::Vec3& a,
183 const agx::Vec3& b,
184 const agx::Vec3& c,
185 const agx::Vec3& n,
186 const agx::Real epsilon = agx::RealEpsilon );
187
188
189#ifndef SWIG
197#endif
198 void AGXPHYSICS_EXPORT computeBarycentricCoordinates(
199 const agx::Vec3& p,
200 const agx::Vec3& a,
201 const agx::Vec3& b,
202 const agx::Vec3& c,
203 const agx::Vec3& /*n*/,
204 agx::Real& u,
205 agx::Real& v,
206 agx::Real& w);
207
216 AGXPHYSICS_EXPORT bool pointInBox(
217 const agx::Vec3& p,
218 const agx::Vec3& boxHalfExtents,
219 const agx::Real epsilon = agx::RealEpsilon );
220
238 AGXPHYSICS_EXPORT bool intersectLineSegmentTriangle(
239 const agx::Vec3& lineP1,
240 const agx::Vec3& lineP2,
241 const agx::Vec3& triangleP1,
242 const agx::Vec3& triangleP2,
243 const agx::Vec3& triangleP3,
244 const agx::Vec3& normal,
245 agx::Vec3& result,
246 agx::Real& t,
247 bool& isFrontFace,
248 const agx::Real epsilon = agx::RealEpsilon );
249
250
251 //=============================================================================
252
253
265 AGXPHYSICS_EXPORT bool intersectLineOpenCylinder( const agx::Vec3& p1, const agx::Vec3& p2,
266 const agx::Vec3& p, const agx::Vec3& q,
267 agx::Real r, agx::Real& t );
268
280 AGXPHYSICS_EXPORT bool intersectLineSphere( const agx::Vec3& p1, const agx::Vec3& p2, const agx::Vec3& center,
281 agx::Real r, agx::Vec3& q, agx::Real& t );
282
283 AGXPHYSICS_EXPORT bool sweptSphereTriangle( const agx::Vec3& p0, const agx::Vec3& p1, const
284 agx::Real& radius, const agx::Vec3& v0, const agx::Vec3& v1,
285 const agx::Vec3& v2, agx::Vec3& contactPoint,
286 agx::Vec3& normal, agx::Real& time );
287
288 AGXPHYSICS_EXPORT bool sphereTriangle( agx::Vec3 p0, agx::Vec3 p1, agx::Vec3 p2,
289 const agx::Vec3& center, const agx::Real& radius,
290 agx::Vec3& point, agx::Vec3& normal, agx::Real& depth );
291
292
309 AGXPHYSICS_EXPORT void closestPointsSegmentSegment(
310 const agx::Vec3& start1,
311 const agx::Vec3& end1,
312 const agx::Vec3& start2,
313 const agx::Vec3& end2,
314 agx::Vec3& pointOn1,
315 agx::Vec3& pointOn2,
316 agx::Real& t1,
317 agx::Real& t2,
318 bool& isParallel,
319 agx::Vec3& parallelPointOn1,
320 agx::Vec3& parallelPointOn2,
321 agx::Real& parallelT1,
322 agx::Real& parallelT2,
323 const agx::Real epsilon = agx::AGX_EQUIVALENT_EPSILON);
324
326 class ClosestPointsSolution
327 {
328 public:
329 agx::Vec3 pointOn1; //Closest point for first pair on first line segment.
330 agx::Vec3 pointOn2; //Closest point for first pair on second line segment.
331 agx::Real t1; //Parameter on first line segment (in interval [0, 1]).
332 agx::Real t2; //Parameter on second line segment (in interval [0, 1]).
333 };
334
335
346 void closestPointsSegmentSegment(
347 const agx::Vec3& start1,
348 const agx::Vec3& end1,
349 const agx::Vec3& start2,
350 const agx::Vec3& end2,
351 ClosestPointsSolution& solution,
352 bool& isParallel,
353 ClosestPointsSolution& parallelSolution,
355 );
356
357
366 agx::Vec3 closestPointPointSegment(
367 const agx::Vec3& p,
368 const agx::Vec3& s0,
369 const agx::Vec3& s1,
370 agx::Real& t );
371
372
373 // A convex polygon of n >= 3 vertices is clipped against slab
374 // (box open in 2 dimensions).
375 // The resulting polygon can have up to 2 more vertices than the input data.
376 // The result array should be allocated outside the function.
377 // \param cPolygon the points of the convex polygon,
378 // in counter clockwise or clockwise order
379 // \param slabDistance The distance in of the slab (in + and - in clipDim)
380 // \param clipDim the dimension which is clipped against. 0, 1 or 2
381 // \param result the resulting clipped points. Size N + 2
382 // \param relativeEpsilon epsilon for compensating errors due to
383 // floating point arithmetics
384 // \return found any vertices
385 // (if no, the polygon lies completely outside the slab)
386 template <size_t N>
387 bool clipConvexPolygonAgainstSlab(
388 const agx::StackArray<agx::Vec3, N>& cPolygon,
389 const agx::Real slabDistance,
390 const uint8_t clipDim,
392 const agx::Real relativeEpsilon );
393
394
395 // A convex polygon of n >= 3 vertices is clipped against slab
396 // (box open in 2 dimensions).
397 // The resulting polygon can have up to 2 more vertices than the input data.
398 // The result array should be allocated outside the function.
399 // \param cPolygon the points of the convex polygon,
400 // in counter clockwise or clockwise order
401 // \param boxHe The box half edge
402 // \param tmp Some temporary memory. Given for optimization purposes.
403 // \param result the resulting clipped points. Size N + 6
404 // \param relativeEpsilon epsilon for compensating errors due to
405 // floating point arithmetics
406 // \return found any vertices
407 // (if no, the polygon lies completely outside the slab)
408 template <size_t N>
409 bool clipConvexPolygonAgainstBox(
410 const agx::StackArray<agx::Vec3, N>& cPolygon,
411 const agx::Vec3& boxHe,
414 const agx::Real relativeEpsilon );
415
416
417 // A convex polygon of n >= 3 vertices is clipped against slab
418 // (box open in 2 dimensions).
419 // The resulting polygon can have up to 2 more vertices than the input data.
420 // The result array should be allocated outside the function.
421 // \param cPolygon the points of the convex polygon,
422 // in counter clockwise or clockwise order
423 // \param numVertsPolygon number of vertices in the polygon
424 // \param openDim the dimension which is clipped against. 0, 1 or 2
425 // \param result the resulting clipped points. Size N + 2
426 // \param relativeEpsilon epsilon for compensating errors due to
427 // floating point arithmetics
428 // \return found any vertices
429 // (if no, the polygon lies completely outside the slab)
430 AGXPHYSICS_EXPORT bool clipLineSegmentAgainstSlab(
431 const agx::Vec3& lineP0,
432 const agx::Vec3& lineP1,
433 const agx::Real slabDistance,
434 int clipDim,
436 const agx::Real relativeEpsilon );
437
438
439 // clips a line segment against a point in 1D.
440 // The input data is three dimensional, all three dimensions are clipped
441 // by the factor calculated from the 1d calculations.
442 // \param a segment's starting point
443 // \param a segment's ending point
444 // \param dim dimensional dim. 0, 1 or 2
445 // \param clipBoundary 1d value that the line segment should be clipped against
446 // \param result The clipped point. In parallel case, b.
447 // \param relativeEpsilon
448 // \retval Did the line segment get clipped? (No if both points on equal side)
449 bool clipSegmentLineSemi1D(
450 const agx::Vec3& a,
451 const agx::Vec3& b,
452 int dim,
453 agx::Real clipBoundary,
454 agx::Vec3& result,
455 const agx::Real relativeEpsilon = agx::RealEpsilon);
456
461 agx::Real AGXPHYSICS_EXPORT calculateDepthInCylinder ( agx::Real cylRadius,
462 agx::Real cylHeight, const agx::Vec3& point, const agx::Vec3& normal,
463 agx::Real relativeEpsilon );
464
465
467 bool AGXPHYSICS_EXPORT clipLineSegmentToCylinderMantle( agx::Real cylRadius,
468 const agx::Vec3& p0,
469 const agx::Vec3& p1,
471 const agx::Real epsilon = agx::REAL_SQRT_EPSILON );
472
473
478 bool AGXPHYSICS_EXPORT clipLineSegmentToCylinder(
479 agx::Real cylRadius, agx::Real cylHeight,
480 const agx::Vec3& p0, const agx::Vec3& p1,
482 const agx::Real epsilon = agx::RealEpsilon );
483
492 agx::Vec3 AGXPHYSICS_EXPORT closestPointCirclePoint3D(
493 agx::Real circleRadius, const agx::Vec3& point );
494
509 void AGXPHYSICS_EXPORT closestPointsCircleLineSegment3D(
510 agx::Real circleRadius,
511 const agx::Vec3& segmentP0, const agx::Vec3& segmentP1,
512 agx::Vec3& pointOnCircle, agx::Vec3& pointOnSegment,
513 agx::Real& lineT );
514
529 template<size_t N1, size_t N2>
530 void clipConvexPolygonAgainstConvexPolygon(
534 const agx::Real epsilon);
535
536
546 template<size_t N>
547 void clipLineSegmentAgainstConvexPolygon(
548 const agx::StackArray<agx::Vec2, 2>& segment,
551 const agx::Real epsilon);
552
565 void AGXPHYSICS_EXPORT clipLineSegmentAgainstConvexPolygon(
566 const agx::Vec2Vector& segment,
567 const agx::Vec2Vector& poly,
568 agx::Vec2Vector& result,
569 const agx::Real epsilon);
570
581 bool AGXPHYSICS_EXPORT intersectPlanePlane( const agx::Vec3 n1, const agx::Real& d1, const agx::Vec3& n2, const agx::Real& d2,
582 agx::Vec3& point, agx::Vec3& lineDirection );
583
584
599 void AGXPHYSICS_EXPORT clipConvexPolygonAgainstConvexPolygon(
600 const agx::Vec2Vector& poly1,
601 const agx::Vec2Vector& poly2,
602 agx::Vec2Vector& result,
603 const agx::Real epsilon);
604
615 AGXPHYSICS_EXPORT bool findIntersectionLineSegmentMesh(
616 const agx::Vec3& lineP0,
617 const agx::Vec3& lineP1,
618 const agxCollide::Mesh* mesh,
619 agx::Real& lineT,
620 unsigned int& triangleIndex);
621
635 AGXPHYSICS_EXPORT bool possibleOverlapBoxCylinder(
636 const agx::Vec3& boxHe,
637 agx::Real cylinderRadius,
638 agx::Real cylinderHeight,
639 const agx::Vec3& cylinderEnd0,
640 const agx::Vec3& cylinderEnd1);
641
642
655 AGX_FORCE_INLINE bool possibleOverlapBoxCapsule(
656 const agx::Vec3& boxHe,
657 agx::Real capsRadius,
658 const agx::Vec3& capsuleEnd0,
659 const agx::Vec3& capsuleEnd1 );
660
661
662 // Implementations
663
664 template <size_t N>
665 bool clipConvexPolygonAgainstSlab(
666 const agx::StackArray<agx::Vec3, N>& cPolygon,
667 const agx::Real slabDistance,
668 const uint8_t clipDim,
670 const agx::Real relativeEpsilon)
671 {
672 //
673 // Sutherland-Hodgman polygon clipping.
674 //
675
676 agxAssert( clipDim < 3 );
677
678 // The algorithm works only well for polygons (3 vertices or more).
679 // If the input is no polygon, but a point or a line, make it a degenerate
680 // polygon.
681 result.clear();
682 agxAssert( cPolygon.size() >= 3 && cPolygon.size() <= N );
683 if (cPolygon.size() == 0)
684 return false;
685
686 for (unsigned int i = 0; i < cPolygon.size(); ++i)
687 result.push_back(cPolygon[i]);
688
689 while(result.size() < 3)
690 result.push_back(cPolygon[0]);
691
692 // clip cPolygon1 against each infinite edge of box
693 for (int sign = -1; sign <=1; sign+=2) {
695 bool lastPointWasOutside = (result[0][clipDim] * sign > slabDistance + relativeEpsilon);
696 // test each edge of the cPolygon1
697 for (unsigned int j = 0; j < result.size(); ++j) {
698 int j_next = (j + 1) % (unsigned int)result.size();
699 bool nextPointIsOutside =
700 (result[j_next][clipDim] * sign > slabDistance + relativeEpsilon);
701 if (lastPointWasOutside != nextPointIsOutside) {
702 // crossing line of edge, clip
703 agx::Vec3 newPoint;
704 if (clipSegmentLineSemi1D( result[j], result[j_next], clipDim,
705 slabDistance * sign, newPoint, relativeEpsilon )) {
706 tmp.push_back(newPoint);
707 }
708 }
709 if (!nextPointIsOutside)
710 tmp.push_back(result[j_next]);
711 lastPointWasOutside = nextPointIsOutside;
712 }
713
714 result.clear();
715
716 if (tmp.size() == 0)
717 return false;
718
719 // do not use almost identical points
720 for (size_t j = 0; j < tmp.size(); ++j) {
721 bool addPoint = true;
722 if (result.size() > 0) {
723 if ((result.back() - tmp[j]).length2() < relativeEpsilon)
724 addPoint = false;
725 }
726 if (addPoint)
727 result.push_back(tmp[j]);
728 }
729 // maintain polygon property by creating a degenerate polygon instead of a
730 // point / line
731 while(result.size() > 0 && result.size() < 3)
732 result.push_back( result[0] );
733 }
734
735 return true;
736 }
737
738
739 template <size_t N>
740 bool clipConvexPolygonAgainstBox(
741 const agx::StackArray<agx::Vec3, N>& cPolygon,
742 const agx::Vec3& boxHe,
745 const agx::Real relativeEpsilon )
746 {
747 //
748 // Sutherland-Hodgman polygon clipping.
749 //
750 // The algorithm works only well for polygons (3 vertices or more).
751 // If the input is no polygon, but a point or a line, make it a degenerate
752 // polygon.
753 result.clear();
754 agxAssert( cPolygon.size() >= 3 && cPolygon.size() <= N );
755 if (cPolygon.size() == 0)
756 return false;
757
758 for (size_t i = 0; i < cPolygon.size(); ++i)
759 result.push_back(cPolygon[i]);
760
761 while (result.size() < 3)
762 result.push_back(cPolygon[0]);
763
764 // clip cPolygon1 against each infinite edge of box
765 for (agx::UInt8 dim = 0; dim < 3; dim++) {
766 agx::Real sign(1);
767 for (int i = 0; i < 2; ++i) {
768 sign *= agx::Real(-1);
769 tmp.clear();
770 bool lastPointWasOutside = (result[0][dim] * sign > boxHe[dim] + relativeEpsilon);
771 // test each edge of the cPolygon1
772 for (unsigned int j = 0; j < result.size(); ++j) {
773 const int j_next = (int)((j + 1) % result.size());
774 bool nextPointIsOutside = (result[j_next][dim] * sign > boxHe[dim] + relativeEpsilon);
775 if (lastPointWasOutside != nextPointIsOutside) {
776 // crossing line of edge, clip
777 agx::Vec3 newPoint;
778 if (clipSegmentLineSemi1D( result[j], result[j_next], dim, boxHe[dim] * sign, newPoint, relativeEpsilon ))
779 tmp.push_back(newPoint);
780 }
781 if (!nextPointIsOutside)
782 tmp.push_back(result[j_next]);
783 lastPointWasOutside = nextPointIsOutside;
784 }
785
786 result.clear();
787
788 if (tmp.size() == 0)
789 return false;
790
791 // do not use almost identical points
792 for (size_t j = 0; j < tmp.size(); ++j) {
793 if (result.size() > 0 && (result.back() - tmp[j]).length2() < relativeEpsilon)
794 continue;
795 result.push_back(tmp[j]);
796 }
797 // maintain polygon property by creating a degenerate polygon instead of a
798 // point / line
799 while (result.size() > 0 && result.size() < 3)
800 result.push_back( result[0] );
801 }
802 }
803 return true;
804 }
805
806
807 template<size_t N>
808 void clipLineSegmentAgainstConvexPolygon(
809 const agx::StackArray<agx::Vec2, 2>& segment,
812 const agx::Real epsilon)
813 {
814 result.clear();
815 if (segment.size() < 2 || poly.size() < 3)
816 return;
817
818 for (int i = 0; i < 2; ++i)
819 result.push_back( segment[i] );
820
821 // create plane normals
822 agx::StackArray<agx::Vec2, N> planeNormals; // these planeNormals are not normalized. Pointing outside from poly2.
824 for (int i = 0; i < int(poly.size()) - 1; ++i) {
825 agx::Vec2 tmp = (poly[(i + 1)] - poly[i]);
826 planeNormals.push_back( agx::Vec2(tmp.y(), -tmp.x()) ); // cross product with (0, 0, 1)
827 planeDists.push_back( poly[i] * planeNormals[i] );
828 }
829 // last element
830 {
831 agx::Vec2 tmp = poly[0] - poly.back();
832 planeNormals.push_back( agx::Vec2(tmp.y(), -tmp.x()) ); // cross product with (0, 0, 1)
833 planeDists.push_back( poly.back() * planeNormals.back() );
834 }
835
836 // clip convex polygon against each plane defined by polygon edges and normal
837 for (unsigned int i = 0; i < poly.size(); ++i) {
838 bool isInside[2];
839 isInside[0] = result[0] * planeNormals[i] - planeDists[i] < epsilon;
840 isInside[1] = result[1] * planeNormals[i] - planeDists[i] < epsilon;
841
842 if (isInside[0] == isInside[1]) {
843 if (!isInside[0]) {
844 result.clear();
845 return;
846 }
847 }
848 else {
849 agx::Vec2 secondPoint;
850 int first = isInside[0] ? 0 : 1;
851 int second = 1 - first;
852 agx::Real tmpT;
853 intersectLineSegmentHyperPlane( result[first], result[second], planeNormals[i],
854 planeDists[i], tmpT, secondPoint, epsilon ); // ignore true/false, since we've had that analysis above
855
856 result[second] = secondPoint;
857 }
858 }
859
860 if (equivalent( result[0], result[1], epsilon ))
861 result.pop_back();
862 }
863
864
865 template<size_t N1, size_t N2>
866 void clipConvexPolygonAgainstConvexPolygon(
870 const agx::Real epsilon)
871 {
872 //
873 // Modified Sutherland-Hodgman polygon clipping in 3D.
874 //
875 result.clear();
876
877 if (poly1.size() < 2 || poly2.size() < 2)
878 return;
879
880 if (poly1.size() == 2) {
881 agx::StackArray<agx::Vec2, 2> segment, segmentResult;
882 segment.push_back(poly1[0]);
883 segment.push_back(poly1[1]);
884 clipLineSegmentAgainstConvexPolygon(segment, poly2, segmentResult, epsilon);
885 for (size_t i = 0; i < segmentResult.size(); ++i)
886 result.push_back(segmentResult[i]);
887 return;
888 }
889
890 if (poly2.size() == 2) {
891 agx::StackArray<agx::Vec2, 2> segment, segmentResult;
892 segment.push_back(poly2[0]);
893 segment.push_back(poly2[1]);
894 clipLineSegmentAgainstConvexPolygon(segment, poly1, segmentResult, epsilon);
895 for (size_t i = 0; i < segmentResult.size(); ++i)
896 result.push_back(segmentResult[i]);
897 return;
898 }
899
900 for (size_t i = 0; i < poly1.size(); ++i)
901 result.push_back(poly1[i]);
902
903 // create plane normals
904 agx::StackArray<agx::Vec2, N2> planeNormals; // Pointing outside from poly2.
906 for (size_t i = 0; i < poly2.size(); ++i) {
907 size_t next = (i+1) % poly2.size();
908 agx::Vec2 tmp = (poly2[next] - poly2[i]);
909 planeNormals.push_back( agx::Vec2(tmp.y(), -tmp.x()) ); // cross product with (0, 0, 1)
910 planeNormals.back().normalize();
911 planeDists.push_back( poly2[i] * planeNormals[i] );
912 }
913
914 // clip convex polygon against each plane defined by triangle edges and normal
915 for (size_t i = 0; i < poly2.size(); ++i) {
916 if (planeNormals[i].x() * planeNormals[i].x() + planeNormals[i].y() * planeNormals[i].y() < epsilon)
917 continue;
918
920 bool lastPointWasOutside = result[0] * planeNormals[i] - planeDists[i] > epsilon;
921
922 // test each edge of the polygon
923 for (size_t j = 0; j < result.size(); ++j) {
924 int j_next = int((j + 1) % result.size());
925 bool nextPointIsOutside = result[j_next] * planeNormals[i] - planeDists[i] > epsilon;
926 if (lastPointWasOutside != nextPointIsOutside) {
927 // crossing plane of triangle, clip
928 agx::Vec2 newPoint;
929 agx::Real tmpT;
930 if (intersectLineSegmentHyperPlane( result[j], result[j_next], planeNormals[i], planeDists[i], tmpT, newPoint, epsilon )) {
931 tmpPoints.push_back(newPoint);
932 }
933 }
934 if (!nextPointIsOutside) {
935 tmpPoints.push_back(result[j_next]);
936 }
937 lastPointWasOutside = nextPointIsOutside;
938 }
939 result.clear();
940 if (tmpPoints.size() == 0)
941 return;
942
943 for (size_t j = 0; j < tmpPoints.size(); ++j) {
944 bool addPoint = true;
945 if (result.size() > 0) {
946 if ((result.back() - tmpPoints[j]).length2() < epsilon)
947 addPoint = false; // do not keep nearly identical points
948 if ((int)j == int(tmpPoints.size()) - 1) { // also check last against first
949 if ((result[0] - tmpPoints[j]).length2() < epsilon)
950 addPoint = false;
951 }
952 }
953 if (addPoint)
954 result.push_back(tmpPoints[j]);
955 }
956 }
957 return;
958 }
959
960
961 AGX_FORCE_INLINE void closestPointsSegmentSegment(
962 const agx::Vec3& start1,
963 const agx::Vec3& end1,
964 const agx::Vec3& start2,
965 const agx::Vec3& end2,
966 ClosestPointsSolution& solution,
967 bool& isParallel,
968 ClosestPointsSolution& parallelSolution,
969 const agx::Real epsilon/* = agx::AGX_EQUIVALENT_EPSILON*/
970 )
971 {
972 closestPointsSegmentSegment(start1, end1, start2, end2,
973 solution.pointOn1, solution.pointOn2, solution.t1, solution.t2,
974 isParallel,
975 parallelSolution.pointOn1, parallelSolution.pointOn2, parallelSolution.t1, parallelSolution.t2, epsilon);
976 }
977
978
979 AGX_FORCE_INLINE bool clipSegmentLineSemi1D(
980 const agx::Vec3& a,
981 const agx::Vec3& b,
982 int dim,
983 agx::Real clipBoundary,
984 agx::Vec3& result,
985 const agx::Real relativeEpsilon)
986 {
987
988 agxAssert (dim >= 0 && dim < 3);
989
990 agx::Real divisor = b[dim] - a[dim];
991
992 if (agx::equalsZero( divisor, relativeEpsilon )) {
993 // The two lines are parallel.
994 result = b;
995 return true;
996 }
997 else {
998 agx::Real t = (clipBoundary - a[dim]) / divisor;
999 result = a * (1 - t) + b * t;
1000 return (t >= 0 && t <= 1);
1001 }
1002 }
1003
1004
1005 template <typename T>
1006 AGX_FORCE_INLINE bool intersectLineHyperPlane(
1007 const T& linePoint,
1008 const T& lineDir,
1009 const T& normal,
1010 agx::Real d,
1011 agx::Real& t,
1012 T& result,
1013 const agx::Real epsilon )
1014 {
1015 // Used segment-plane intersection from Ericson, Real Time Collision Detection, p. 175f.
1016 agx::Real divisor = normal * lineDir;
1017
1018 if (agx::equalsZero( divisor, epsilon )) {
1019 // Segment coplanar to plane. Return second point if contained in plane.
1020 result = linePoint + lineDir;
1021 t = agx::Real(1);
1022 return agx::equalsZero( normal * result - d, epsilon );
1023 }
1024
1025 t = (d - normal * linePoint) / divisor;
1026
1027 result = linePoint + lineDir * t;
1028
1029 return true;
1030 }
1031
1032
1033 template <typename T>
1034 AGX_FORCE_INLINE bool intersectLineSegmentHyperPlane(
1035 const T& lineP1,
1036 const T& lineP2,
1037 const T& normal,
1038 agx::Real d,
1039 agx::Real& t,
1040 T& result,
1041 const agx::Real epsilon )
1042 {
1043 if (intersectLineHyperPlane(lineP1, lineP2 - lineP1, normal, d, t, result, epsilon)) {
1044 const bool isInInterval = (t > -epsilon && t < agx::Real(1) + epsilon);
1045 return isInInterval;
1046 }
1047 else
1048 return false;
1049 }
1050
1051
1052 AGX_FORCE_INLINE bool areDirectionsParallel(const agx::Vec3& dir0, const agx::Vec3& dir1,
1053 const agx::Real cosEpsilon)
1054 {
1055 const agx::Real cosAngle = dir0 * dir1;
1056 bool areParallel = (std::abs(cosAngle) >= cosEpsilon);
1057 return areParallel;
1058 }
1059
1060
1061 AGX_FORCE_INLINE bool areDirectionsOrthogonal(const agx::Vec3& dir0, const agx::Vec3& dir1,
1062 const agx::Real sinEpsilon)
1063 {
1064 const agx::Real cosAngle = dir0 * dir1;
1065 const agx::Real cosAngleSquared = cosAngle * cosAngle;
1066 const agx::Real sinAngleSquared = agx::Real(1) - cosAngleSquared;
1067 bool areOrthogonal = (sinAngleSquared >= sinEpsilon * sinEpsilon);
1068 return areOrthogonal;
1069 }
1070
1071
1072 AGX_FORCE_INLINE agx::Vec3 closestPointPointSegment(
1073 const agx::Vec3& p,
1074 const agx::Vec3& s0,
1075 const agx::Vec3& s1,
1076 agx::Real& t)
1077 {
1078 agx::Vec3 sDir = s1 - s0;
1079 agx::Real divisor = sDir.length2();
1080 if (agx::equalsZero( divisor )) {
1081 t = 0;
1082 return s0;
1083 }
1084
1085 t = ((p - s0) * sDir) / divisor;
1086 t = agx::clamp( t, agx::Real(0), agx::Real(1) );
1087 const agx::Vec3 point = s0 * (1 - t) + s1 * t;
1088 return point;
1089 }
1090
1091
1092 AGX_FORCE_INLINE bool possibleOverlapBoxCapsule(
1093 const agx::Vec3& boxHe,
1094 agx::Real capsRadius,
1095 const agx::Vec3& capsuleEnd0,
1096 const agx::Vec3& capsuleEnd1 )
1097 {
1098 // Approach: Use separating axis theorem.
1099 // We have 4 axes: The three from the box (local x, y and z),
1100 // and the one from closest point between local origin and capsule axis.
1101
1102 const agx::Vec3 capsMid = (capsuleEnd0 + capsuleEnd1) * agx::Real(0.5);
1103 const agx::Vec3 capsAbsMid = agx::absolute(capsMid);
1104
1105 const agx::Vec3 capsHalfExt = capsuleEnd1 - capsMid;
1106 const agx::Vec3 capsAbsHalfExt = agx::absolute(capsHalfExt);
1107
1108 // The three box axes: Trying to reach caps mid point by he, radius and capsHe.
1109 for (size_t i = 0; i < 3; ++i) {
1110 if (capsAbsMid[i] > boxHe[i] + capsRadius + capsAbsHalfExt[i])
1111 return false;
1112 }
1113
1114 // The fourth axis: find closest point to box origin.
1115 agx::Real t;
1116 agx::Vec3 closest = closestPointPointSegment(agx::Vec3(), capsuleEnd0, capsuleEnd1, t);
1117
1118 agx::Vec3 closestAbsDir = agx::absolute(closest);
1119 agx::Real closestDist = closestAbsDir.normalize();
1120
1121 // Try to reach point with radius and projection
1122 if (closestDist > capsRadius + closestAbsDir * boxHe )
1123 return false;
1124
1125 return true;
1126 }
1127
1128
1139 AGXPHYSICS_EXPORT agx::Vec3Vector intersectTrimeshWithPlane(
1140 const agxCollide::Mesh* trimesh,
1141 const agx::Plane& plane,
1142 const agx::AffineMatrix4x4& planeToWorld);
1143}
1144
1146#endif
#define AGXPHYSICS_EXPORT
Mesh is a common base class for triangle meshes, such as Mesh or HeightField.
Definition: Mesh.h:70
Class representing the mathematical concept of a plane, also called a half- space.
Definition: agx/Plane.h:32
Templated stack array class.
size_t size() const
Get the size of the array (number of filled slots).
void push_back(const T &value)
Real normalize()
Normalize the vector so that it has length unity.
Definition: Vec3Template.h:701
Real length2() const
Length squared of the vector = vec .
Definition: Vec3Template.h:689
Vector containing 'raw' data.
Definition: agx/Vector.h:246
#define agxAssert(expr)
Definition: debug.h:143
#define DOXYGEN_END_INTERNAL_BLOCK()
Definition: macros.h:89
#define DOXYGEN_START_INTERNAL_BLOCK()
Definition: macros.h:88
#define AGX_FORCE_INLINE
Definition: macros.h:58
This namespace consists of a set of classes for handling geometric intersection tests including boole...
T sign(T v)
Definition: Math.h:328
T absolute(T v)
return the absolute value.
Definition: Math.h:291
AGXCORE_EXPORT const Real REAL_SQRT_EPSILON
T1 clamp(T1 v, T2 minimum, T3 maximum)
Definition: Math.h:318
AGXCORE_EXPORT const Real RealEpsilon
AGXPHYSICS_EXPORT agx::Bool equalsZero(const agx::AddedMassInteraction::Matrix6x6 &matrix, agx::Real eps=agx::RealEpsilon)
double Real
Definition: Real.h:42
uint8_t UInt8
Definition: Integer.h:30
static constexpr Real AGX_EQUIVALENT_EPSILON
Definition: Math.h:57
AGXPHYSICS_EXPORT agx::Bool equivalent(const agx::AddedMassInteraction::Matrix6x6 &lhs, const agx::AddedMassInteraction::Matrix6x6 &rhs, agx::Real eps=agx::RealEpsilon)