"git@gitlab.opengeosys.org:ozgurozansen/ogs.git" did not exist on "7ed5ae6c9513ab66eb895b05f09fede9c039b827"
Newer
Older
* Copyright (c) 2012-2020, OpenGeoSys Community (http://www.opengeosys.org)
* Distributed under a Modified BSD License.
* See accompanying file LICENSE.txt or
* http://www.opengeosys.org/project/license
*/
#include "BaseLib/Logging.h"
#include <Eigen/Dense>
#include "Point3d.h"
#include "Vector3.h"
#include "GeometricBasics.h"
namespace MathLib
{
double orientation3d(MathLib::Point3d const& p,
MathLib::Point3d const& a,
MathLib::Point3d const& b,
MathLib::Point3d const& c)
{
auto const pp = Eigen::Map<Eigen::Vector3d const>(p.getCoords());
auto const pa = Eigen::Map<Eigen::Vector3d const>(a.getCoords());
auto const pb = Eigen::Map<Eigen::Vector3d const>(b.getCoords());
auto const pc = Eigen::Map<Eigen::Vector3d const>(c.getCoords());
Eigen::Vector3d const ap = pp - pa;
Eigen::Vector3d const bp = pp - pb;
Eigen::Vector3d const cp = pp - pc;
return MathLib::scalarTriple(bp, cp, ap);
double calcTetrahedronVolume(MathLib::Point3d const& a,
MathLib::Point3d const& b,
MathLib::Point3d const& c,
MathLib::Point3d const& d)
{
auto const va = Eigen::Map<Eigen::Vector3d const>(a.getCoords());
auto const vb = Eigen::Map<Eigen::Vector3d const>(b.getCoords());
auto const vc = Eigen::Map<Eigen::Vector3d const>(c.getCoords());
auto const vd = Eigen::Map<Eigen::Vector3d const>(d.getCoords());
Eigen::Vector3d const ab = vb - va;
Eigen::Vector3d const ac = vc - va;
Eigen::Vector3d const ad = vd - va;
return std::abs(MathLib::scalarTriple(ac, ad, ab)) / 6.0;
}
double calcTriangleArea(MathLib::Point3d const& a, MathLib::Point3d const& b,
MathLib::Point3d const& c)
{
MathLib::Vector3 const u(a, c);
MathLib::Vector3 const v(a, b);
MathLib::Vector3 const w(MathLib::crossProduct(u, v));
return 0.5 * w.getLength();
}
bool isPointInTetrahedron(MathLib::Point3d const& p, MathLib::Point3d const& a,
MathLib::Point3d const& b, MathLib::Point3d const& c,
MathLib::Point3d const& d, double eps)
{
double const d0 (MathLib::orientation3d(d,a,b,c));
// if tetrahedron is not coplanar
if (std::abs(d0) > std::numeric_limits<double>::epsilon())
{
bool const d0_sign (d0>0);
// if p is on the same side of bcd as a
double const d1 (MathLib::orientation3d(d, p, b, c));
if (!(d0_sign == (d1 >= 0) || std::abs(d1) < eps))
{
// if p is on the same side of acd as b
double const d2 (MathLib::orientation3d(d, a, p, c));
if (!(d0_sign == (d2 >= 0) || std::abs(d2) < eps))
{
// if p is on the same side of abd as c
double const d3 (MathLib::orientation3d(d, a, b, p));
if (!(d0_sign == (d3 >= 0) || std::abs(d3) < eps))
{
// if p is on the same side of abc as d
double const d4 (MathLib::orientation3d(p, a, b, c));
return d0_sign == (d4 >= 0) || std::abs(d4) < eps;
}
return false;
}
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
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)
{
switch (algorithm)
{
case MathLib::GAUSS:
return gaussPointInTriangle(p, a, b, c, eps_pnt_out_of_plane,
eps_pnt_out_of_tri);
case MathLib::BARYCENTRIC:
return barycentricPointInTriangle(p, a, b, c, eps_pnt_out_of_plane,
eps_pnt_out_of_tri);
default:
ERR("Selected algorithm for point in triangle testing not found, "
"falling back on default.");
}
return gaussPointInTriangle(p, a, b, c, eps_pnt_out_of_plane,
eps_pnt_out_of_tri);
}
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)
{
MathLib::Vector3 const v(a, b);
MathLib::Vector3 const w(a, c);
mat(0, 0) = v.getSqrLength();
mat(0, 1) = v[0] * w[0] + v[1] * w[1] + v[2] * w[2];
mat(1, 0) = mat(0, 1);
mat(1, 1) = w.getSqrLength();
Eigen::Vector2d y;
y << v[0] * (q[0] - a[0]) + v[1] * (q[1] - a[1]) + v[2] * (q[2] - a[2]),
w[0] * (q[0] - a[0]) + w[1] * (q[1] - a[1]) + w[2] * (q[2] - a[2]);
y = mat.partialPivLu().solve(y);
const double lower(eps_pnt_out_of_tri);
const double upper(1 + lower);
if (-lower <= y[0] && y[0] <= upper && -lower <= y[1] && y[1] <= upper &&
y[0] + y[1] <= upper)
{
MathLib::Point3d const q_projected(std::array<double, 3>{
{a[0] + y[0] * v[0] + y[1] * w[0], a[1] + y[0] * v[1] + y[1] * w[1],
a[2] + y[0] * v[2] + y[1] * w[2]}});
if (MathLib::sqrDist(q, q_projected) <= eps_pnt_out_of_plane)
}
return false;
}
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)
{
if (std::abs(MathLib::orientation3d(p, a, b, c)) > eps_pnt_out_of_plane)
MathLib::Vector3 const pa(p, a);
MathLib::Vector3 const pb(p, b);
MathLib::Vector3 const pc(p, c);
double const area_x_2(calcTriangleArea(a, b, c) * 2);
double const alpha((MathLib::crossProduct(pb, pc).getLength()) / area_x_2);
if (alpha < -eps_pnt_out_of_tri || alpha > 1 + eps_pnt_out_of_tri)
double const beta((MathLib::crossProduct(pc, pa).getLength()) / area_x_2);
if (beta < -eps_pnt_out_of_tri || beta > 1 + eps_pnt_out_of_tri)
double const gamma(1 - alpha - beta);
return !(gamma < -eps_pnt_out_of_tri || gamma > 1 + eps_pnt_out_of_tri);
bool isPointInTriangleXY(MathLib::Point3d const& p,
MathLib::Point3d const& a,
MathLib::Point3d const& b,
MathLib::Point3d const& c)
{
// criterion: p-a = u0 * (b-a) + u1 * (c-a); 0 <= u0, u1 <= 1, u0+u1 <= 1
mat(0, 0) = b[0] - a[0];
mat(0, 1) = c[0] - a[0];
mat(1, 0) = b[1] - a[1];
mat(1, 1) = c[1] - a[1];
Eigen::Vector2d y;
y << p[0] - a[0], p[1] - a[1];
y = mat.partialPivLu().solve(y);
// check if u0 and u1 fulfills the condition
return 0 <= y[0] && y[0] <= 1 && 0 <= y[1] && y[1] <= 1 && y[0] + y[1] <= 1;
bool dividedByPlane(const MathLib::Point3d& a, const MathLib::Point3d& b,
const MathLib::Point3d& c, const MathLib::Point3d& d)
{
for (unsigned x = 0; x < 3; ++x)
{
const unsigned y = (x + 1) % 3;
const double abc =
(b[x] - a[x]) * (c[y] - a[y]) - (b[y] - a[y]) * (c[x] - a[x]);
const double abd =
(b[x] - a[x]) * (d[y] - a[y]) - (b[y] - a[y]) * (d[x] - a[x]);
if ((abc > 0 && abd < 0) || (abc < 0 && abd > 0))
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
}
return false;
}
bool isCoplanar(const MathLib::Point3d& a, const MathLib::Point3d& b,
const MathLib::Point3d& c, const MathLib::Point3d& d)
{
const MathLib::Vector3 ab(a, b);
const MathLib::Vector3 ac(a, c);
const MathLib::Vector3 ad(a, d);
if (ab.getSqrLength() < pow(std::numeric_limits<double>::epsilon(), 2) ||
ac.getSqrLength() < pow(std::numeric_limits<double>::epsilon(), 2) ||
ad.getSqrLength() < pow(std::numeric_limits<double>::epsilon(), 2))
{
return true;
}
// In exact arithmetic <ac*ad^T, ab> should be zero
// if all four points are coplanar.
const double sqr_scalar_triple(
pow(MathLib::scalarProduct(MathLib::crossProduct(ac, ad), ab), 2));
// Due to evaluating the above numerically some cancellation or rounding
// can occur. For this reason a normalisation factor is introduced.
const double normalisation_factor =
(ab.getSqrLength() * ac.getSqrLength() * ad.getSqrLength());
// tolerance 1e-11 is choosen such that
// a = (0,0,0), b=(1,0,0), c=(0,1,0) and d=(1,1,1e-6) are considered as
// coplanar
// a = (0,0,0), b=(1,0,0), c=(0,1,0) and d=(1,1,1e-5) are considered as not
// coplanar
return (sqr_scalar_triple / normalisation_factor < 1e-11);
}
} // end namespace MathLib