From f59cbf251b13ffb63d66a5aef1a39d72192da794 Mon Sep 17 00:00:00 2001
From: Thomas Fischer <thomas.fischer@ufz.de>
Date: Tue, 27 May 2014 11:23:48 +0200
Subject: [PATCH] [GeoLib] Restructured and fix bug in isPointInTriangle code.

Impl. a new algorithm for checking if a point is within a triangle and removed old sources for this task.
---
 GeoLib/AnalyticalGeometry.cpp | 85 ++++++++++++++++-------------------
 GeoLib/AnalyticalGeometry.h   | 12 ++++-
 2 files changed, 49 insertions(+), 48 deletions(-)

diff --git a/GeoLib/AnalyticalGeometry.cpp b/GeoLib/AnalyticalGeometry.cpp
index 37771bc670b..ee398e49ecd 100644
--- a/GeoLib/AnalyticalGeometry.cpp
+++ b/GeoLib/AnalyticalGeometry.cpp
@@ -184,30 +184,51 @@ bool lineSegmentsIntersect(const GeoLib::Polyline* ply,
 	return false;
 }
 
-static
-bool isPointInTriangle(const double p[3], const double a[3], const double b[3], const double c[3])
+bool isPointInTriangle(const GeoLib::Point* p, const GeoLib::Point* a, const GeoLib::Point* b,
+                       const GeoLib::Point* c)
+{
+	return isPointInTriangle(*p, *a, *b, *c);
+}
+
+bool isPointInTriangle(GeoLib::Point const& q,
+                       GeoLib::Point const& a,
+                       GeoLib::Point const& b,
+                       GeoLib::Point const& c,
+                       double eps)
 {
-	// criterion: p-b = u0 * (b - a) + u1 * (b - c); 0 <= u0, u1 <= 1, u0+u1 <= 1
-	MathLib::DenseMatrix<double> mat(2, 2);
-	mat(0, 0) = a[0] - b[0];
-	mat(0, 1) = c[0] - b[0];
-	mat(1, 0) = a[1] - b[1];
-	mat(1, 1) = c[1] - b[1];
-	double rhs[2] = { p[0] - b[0], p[1] - b[1] };
+	MathLib::Vector3 const v(a, b);
+	MathLib::Vector3 const w(a, c);
+
+	MathLib::DenseMatrix<double> mat (2,2);
+	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();
+	double y[2] = {
+		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])
+	};
 
 	MathLib::GaussAlgorithm<MathLib::DenseMatrix<double>, double*> gauss(mat);
-	gauss.solve(rhs);
+	gauss.solve(y);
+
+	const double lower (std::numeric_limits<float>::epsilon());
+	const double upper (1 + lower);
+
+	if (-lower <= y[0] && y[0] <= upper && -lower <= y[1] && y[1] <= upper && y[0] + y[1] <=
+	    upper) {
+		GeoLib::Point const q_projected(
+			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)
+			return true;
+	}
 
-	if (0 <= rhs[0] && rhs[0] <= 1 && 0 <= rhs[1] && rhs[1] <= 1 && rhs[0] + rhs[1] <= 1)
-		return true;
 	return false;
 }
 
-bool isPointInTriangle(const GeoLib::Point* p, const GeoLib::Point* a, const GeoLib::Point* b,
-                       const GeoLib::Point* c)
-{
-	return isPointInTriangle(p->getCoords(), a->getCoords(), b->getCoords(), c->getCoords());
-}
 
 static
 double getOrientedTriArea(GeoLib::Point const& a, GeoLib::Point const& b, GeoLib::Point const& c)
@@ -218,36 +239,6 @@ double getOrientedTriArea(GeoLib::Point const& a, GeoLib::Point const& b, GeoLib
 	return 0.5 * sqrt(MathLib::scalarProduct(w, w));
 }
 
-bool isPointInTriangle(GeoLib::Point const& p, GeoLib::Point const& a, GeoLib::Point const& b,
-                       GeoLib::Point const& c, double eps)
-{
-	const unsigned dim(3);
-	MathLib::DenseMatrix<double> m(dim, dim);
-	for (unsigned i(0); i < dim; i++)
-		m(i, 0) = b[i] - a[i];
-	for (unsigned i(0); i < dim; i++)
-		m(i, 1) = c[i] - a[i];
-	for (unsigned i(0); i < dim; i++)
-		m(i, 2) = p[i] - a[i];
-
-	// point p is in the same plane as the triangle if and only if
-	// the following determinate of the 3x3 matrix equals zero (up to an eps)
-	double det3x3(m(0, 0) * (m(1, 1) * m(2, 2) - m(2, 1) * m(1, 2))
-	              - m(1, 0) * (m(2, 1) * m(0, 2) - m(0, 1) * m(2, 2))
-	              + m(2, 0) * (m(0, 1) * m(1, 2) - m(1, 1) * m(0, 2)));
-	if (fabs(det3x3) > eps)
-		return false;
-
-	double total_area(getOrientedTriArea(a, b, c));
-	double abp_area(getOrientedTriArea(a, b, p));
-	double bcp_area(getOrientedTriArea(b, c, p));
-	double cap_area(getOrientedTriArea(c, a, p));
-
-	if (fabs(abp_area + bcp_area + cap_area - total_area) < eps)
-		return true;
-	return false;
-}
-
 // NewellPlane from book Real-Time Collision detection p. 494
 void getNewellPlane(const std::vector<GeoLib::Point*>& pnts, MathLib::Vector3 &plane_normal, double& d)
 {
diff --git a/GeoLib/AnalyticalGeometry.h b/GeoLib/AnalyticalGeometry.h
index 9aed682d823..123034a74c7 100644
--- a/GeoLib/AnalyticalGeometry.h
+++ b/GeoLib/AnalyticalGeometry.h
@@ -101,9 +101,19 @@ void rotatePointsToXZ(std::vector<GeoLib::Point*> &pnts);
 bool isPointInTriangle (const GeoLib::Point* p,
 		const GeoLib::Point* a, const GeoLib::Point* b, const GeoLib::Point* c);
 
+/**
+ * Tests if the given point p is within the triangle, defined by its edge nodes a, b and c.
+ * Using the eps it is possible to test a 'epsilon' neighbourhood around the triangle.
+ * @param p test point
+ * @param a edge node of triangle
+ * @param b edge node of triangle
+ * @param c edge node of triangle
+ * @param eps size of neighbourhood (orthogonal distance to the plane spaned by triangle)
+ * @return true if the test point p is within the 'epsilon'-neighbourhood of the triangle
+ */
 bool isPointInTriangle(GeoLib::Point const& p,
 				GeoLib::Point const& a, GeoLib::Point const& b, GeoLib::Point const& c,
-				double eps = std::numeric_limits<double>::epsilon());
+				double eps = std::numeric_limits<float>::epsilon());
 
 /**
  * test for intersections of the line segments of the Polyline
-- 
GitLab