OGS
GeometricBasics.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
4#include "GeometricBasics.h"
5
6#include <Eigen/Geometry>
7
8#include "BaseLib/Logging.h"
9#include "Point3d.h"
10
11namespace MathLib
12{
14 MathLib::Point3d const& a,
15 MathLib::Point3d const& b,
16 MathLib::Point3d const& c)
17{
18 Eigen::Vector3d const u = p.asEigenVector3d() - a.asEigenVector3d();
19 Eigen::Vector3d const v = p.asEigenVector3d() - b.asEigenVector3d();
20 Eigen::Vector3d const w = p.asEigenVector3d() - c.asEigenVector3d();
21 return u.cross(v).dot(w);
22}
23
25 MathLib::Point3d const& b,
26 MathLib::Point3d const& c,
27 MathLib::Point3d const& d)
28{
29 Eigen::Vector3d const w = b.asEigenVector3d() - a.asEigenVector3d();
30 Eigen::Vector3d const u = c.asEigenVector3d() - a.asEigenVector3d();
31 Eigen::Vector3d const v = d.asEigenVector3d() - a.asEigenVector3d();
32 return std::abs(u.cross(v).dot(w)) / 6.0;
33}
34
36 MathLib::Point3d const& c)
37{
38 Eigen::Vector3d const u = c.asEigenVector3d() - a.asEigenVector3d();
39 Eigen::Vector3d const v = b.asEigenVector3d() - a.asEigenVector3d();
40 Eigen::Vector3d const w = u.cross(v);
41 return 0.5 * w.norm();
42}
43
45 MathLib::Point3d const& b, MathLib::Point3d const& c,
46 MathLib::Point3d const& d, double eps)
47{
48 double const d0(MathLib::orientation3d(d, a, b, c));
49 // if tetrahedron is not coplanar
50 if (std::abs(d0) > std::numeric_limits<double>::epsilon())
51 {
52 bool const d0_sign(d0 > 0);
53 // if p is on the same side of bcd as a
54 double const d1(MathLib::orientation3d(d, p, b, c));
55 if (!(d0_sign == (d1 >= 0) || std::abs(d1) < eps))
56 {
57 return false;
58 }
59 // if p is on the same side of acd as b
60 double const d2(MathLib::orientation3d(d, a, p, c));
61 if (!(d0_sign == (d2 >= 0) || std::abs(d2) < eps))
62 {
63 return false;
64 }
65 // if p is on the same side of abd as c
66 double const d3(MathLib::orientation3d(d, a, b, p));
67 if (!(d0_sign == (d3 >= 0) || std::abs(d3) < eps))
68 {
69 return false;
70 }
71 // if p is on the same side of abc as d
72 double const d4(MathLib::orientation3d(p, a, b, c));
73 return d0_sign == (d4 >= 0) || std::abs(d4) < eps;
74 }
75 return false;
76}
77
79 MathLib::Point3d const& a,
80 MathLib::Point3d const& b,
81 MathLib::Point3d const& c,
82 double eps_pnt_out_of_plane,
83 double eps_pnt_out_of_tri,
84 MathLib::TriangleTest algorithm)
85{
86 switch (algorithm)
87 {
88 case MathLib::GAUSS:
89 return gaussPointInTriangle(p, a, b, c, eps_pnt_out_of_plane,
90 eps_pnt_out_of_tri);
92 return barycentricPointInTriangle(p, a, b, c, eps_pnt_out_of_plane,
93 eps_pnt_out_of_tri);
94 default:
95 ERR("Selected algorithm for point in triangle testing not found, "
96 "falling back on default.");
97 }
98 return gaussPointInTriangle(p, a, b, c, eps_pnt_out_of_plane,
99 eps_pnt_out_of_tri);
100}
101
103 MathLib::Point3d const& a,
104 MathLib::Point3d const& b,
105 MathLib::Point3d const& c,
106 double eps_pnt_out_of_plane,
107 double eps_pnt_out_of_tri)
108{
109 auto const& pa = a.asEigenVector3d();
110 Eigen::Vector3d const v = b.asEigenVector3d() - pa;
111 Eigen::Vector3d const w = c.asEigenVector3d() - pa;
112
113 Eigen::Matrix2d mat;
114 mat(0, 0) = v.squaredNorm();
115 mat(0, 1) = v[0] * w[0] + v[1] * w[1] + v[2] * w[2];
116 mat(1, 0) = mat(0, 1);
117 mat(1, 1) = w.squaredNorm();
118 Eigen::Vector2d y(
119 v[0] * (q[0] - a[0]) + v[1] * (q[1] - a[1]) + v[2] * (q[2] - a[2]),
120 w[0] * (q[0] - a[0]) + w[1] * (q[1] - a[1]) + w[2] * (q[2] - a[2]));
121
122 y = mat.partialPivLu().solve(y);
123
124 const double lower(eps_pnt_out_of_tri);
125 const double upper(1 + lower);
126
127 if (-lower <= y[0] && y[0] <= upper && -lower <= y[1] && y[1] <= upper &&
128 y[0] + y[1] <= upper)
129 {
130 MathLib::Point3d const q_projected(std::array<double, 3>{
131 {a[0] + y[0] * v[0] + y[1] * w[0], a[1] + y[0] * v[1] + y[1] * w[1],
132 a[2] + y[0] * v[2] + y[1] * w[2]}});
133 if (MathLib::sqrDist(q, q_projected) <= eps_pnt_out_of_plane)
134 {
135 return true;
136 }
137 }
138
139 return false;
140}
141
143 MathLib::Point3d const& a,
144 MathLib::Point3d const& b,
145 MathLib::Point3d const& c,
146 double eps_pnt_out_of_plane,
147 double eps_pnt_out_of_tri)
148{
149 if (std::abs(MathLib::orientation3d(p, a, b, c)) > eps_pnt_out_of_plane)
150 {
151 return false;
152 }
153
154 auto const& vp = p.asEigenVector3d();
155 Eigen::Vector3d const& pa = a.asEigenVector3d() - vp;
156 Eigen::Vector3d const& pb = b.asEigenVector3d() - vp;
157 Eigen::Vector3d const& pc = c.asEigenVector3d() - vp;
158 double const area_x_2(calcTriangleArea(a, b, c) * 2);
159
160 double const alpha((pb.cross(pc).norm()) / area_x_2);
161 if (alpha < -eps_pnt_out_of_tri || alpha > 1 + eps_pnt_out_of_tri)
162 {
163 return false;
164 }
165 double const beta((pc.cross(pa).norm()) / area_x_2);
166 if (beta < -eps_pnt_out_of_tri || beta > 1 + eps_pnt_out_of_tri)
167 {
168 return false;
169 }
170 double const gamma(1 - alpha - beta);
171 return !(gamma < -eps_pnt_out_of_tri || gamma > 1 + eps_pnt_out_of_tri);
172}
173
175 MathLib::Point3d const& a,
176 MathLib::Point3d const& b,
177 MathLib::Point3d const& c)
178{
179 // criterion: p-a = u0 * (b-a) + u1 * (c-a); 0 <= u0, u1 <= 1, u0+u1 <= 1
180 Eigen::Matrix2d mat;
181 mat(0, 0) = b[0] - a[0];
182 mat(0, 1) = c[0] - a[0];
183 mat(1, 0) = b[1] - a[1];
184 mat(1, 1) = c[1] - a[1];
185 Eigen::Vector2d y;
186 y << p[0] - a[0], p[1] - a[1];
187
188 y = mat.partialPivLu().solve(y);
189
190 // check if u0 and u1 fulfills the condition
191 return 0 <= y[0] && y[0] <= 1 && 0 <= y[1] && y[1] <= 1 && y[0] + y[1] <= 1;
192}
193
195 const MathLib::Point3d& c, const MathLib::Point3d& d)
196{
197 for (unsigned x = 0; x < 3; ++x)
198 {
199 const unsigned y = (x + 1) % 3;
200 const double abc =
201 (b[x] - a[x]) * (c[y] - a[y]) - (b[y] - a[y]) * (c[x] - a[x]);
202 const double abd =
203 (b[x] - a[x]) * (d[y] - a[y]) - (b[y] - a[y]) * (d[x] - a[x]);
204
205 if ((abc > 0 && abd < 0) || (abc < 0 && abd > 0))
206 {
207 return true;
208 }
209 }
210 return false;
211}
212
214 const MathLib::Point3d& c, const MathLib::Point3d& d)
215{
216 Eigen::Vector3d const ab = b.asEigenVector3d() - a.asEigenVector3d();
217 Eigen::Vector3d const ac = c.asEigenVector3d() - a.asEigenVector3d();
218 Eigen::Vector3d const ad = d.asEigenVector3d() - a.asEigenVector3d();
219
220 auto const eps_squared =
221 std::pow(std::numeric_limits<double>::epsilon(), 2);
222 if (ab.squaredNorm() < eps_squared || ac.squaredNorm() < eps_squared ||
223 ad.squaredNorm() < eps_squared)
224 {
225 return true;
226 }
227
228 // In exact arithmetic <ac*ad^T, ab> should be zero
229 // if all four points are coplanar.
230 const double sqr_scalar_triple(std::pow(ac.cross(ad).dot(ab), 2));
231 // Due to evaluating the above numerically some cancellation or rounding
232 // can occur. For this reason a normalisation factor is introduced.
233 const double normalisation_factor =
234 (ab.squaredNorm() * ac.squaredNorm() * ad.squaredNorm());
235
236 // tolerance 1e-11 is chosen such that
237 // a = (0,0,0), b=(1,0,0), c=(0,1,0) and d=(1,1,1e-6) are considered as
238 // coplanar
239 // a = (0,0,0), b=(1,0,0), c=(0,1,0) and d=(1,1,1e-5) are considered as not
240 // coplanar
241 return (sqr_scalar_triple / normalisation_factor < 1e-11);
242}
243
244} // end namespace MathLib
void ERR(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:40
Eigen::Vector3d const & asEigenVector3d() const
Definition Point3d.h:55
static const double q
double orientation3d(MathLib::Point3d const &p, MathLib::Point3d const &a, MathLib::Point3d const &b, MathLib::Point3d const &c)
bool gaussPointInTriangle(MathLib::Point3d const &q, MathLib::Point3d const &a, MathLib::Point3d const &b, MathLib::Point3d const &c, double eps_pnt_out_of_plane, double eps_pnt_out_of_tri)
double calcTriangleArea(MathLib::Point3d const &a, MathLib::Point3d const &b, MathLib::Point3d const &c)
bool isCoplanar(const MathLib::Point3d &a, const MathLib::Point3d &b, const MathLib::Point3d &c, const MathLib::Point3d &d)
Checks if the four given points are located on a plane.
static const double p
bool dividedByPlane(const MathLib::Point3d &a, const MathLib::Point3d &b, const MathLib::Point3d &c, const MathLib::Point3d &d)
bool isPointInTriangle(MathLib::Point3d const &p, MathLib::Point3d const &a, MathLib::Point3d const &b, MathLib::Point3d const &c, double eps_pnt_out_of_plane, double eps_pnt_out_of_tri, MathLib::TriangleTest algorithm)
static const double u
bool barycentricPointInTriangle(MathLib::Point3d const &p, MathLib::Point3d const &a, MathLib::Point3d const &b, MathLib::Point3d const &c, double eps_pnt_out_of_plane, double eps_pnt_out_of_tri)
static const double v
double sqrDist(MathLib::Point3d const &p0, MathLib::Point3d const &p1)
Definition Point3d.cpp:19
double calcTetrahedronVolume(MathLib::Point3d const &a, MathLib::Point3d const &b, MathLib::Point3d const &c, MathLib::Point3d const &d)
bool isPointInTetrahedron(MathLib::Point3d const &p, MathLib::Point3d const &a, MathLib::Point3d const &b, MathLib::Point3d const &c, MathLib::Point3d const &d, double eps)
bool isPointInTriangleXY(MathLib::Point3d const &p, MathLib::Point3d const &a, MathLib::Point3d const &b, MathLib::Point3d const &c)