Saga3D API Documentation  1.0-RC4
triangle3d.h
Go to the documentation of this file.
1 // Copyright (C) 2002-2012 Nikolaus Gebhardt
2 // This file is part of the "Irrlicht Engine".
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
4 
5 #ifndef __IRR_TRIANGLE_3D_H_INCLUDED__
6 #define __IRR_TRIANGLE_3D_H_INCLUDED__
7 
8 #include "line3d.h"
9 #include "plane3d.h"
10 #include "aabbox3d.h"
11 
12 namespace saga
13 {
14 namespace core
15 {
16 
18  template <class T>
19  class triangle3d
20  {
21  public:
22 
26  triangle3d(const glm::vec3& v1, const glm::vec3& v2, const glm::vec3& v3) : pointA(v1), pointB(v2), pointC(v3) {}
27 
29  bool operator==(const triangle3d<T>& other) const
30  {
31  return other.pointA==pointA && other.pointB==pointB && other.pointC==pointC;
32  }
33 
35  bool operator!=(const triangle3d<T>& other) const
36  {
37  return !(*this==other);
38  }
39 
41 
43  bool isTotalInsideBox(const aabbox3d<T>& box) const
44  {
45  return (box.isPointInside(pointA) &&
46  box.isPointInside(pointB) &&
47  box.isPointInside(pointC));
48  }
49 
51 
53  bool isTotalOutsideBox(const aabbox3d<T>& box) const
54  {
55  return ((pointA.x > box.MaxEdge.X && pointB.x > box.MaxEdge.X && pointC.x > box.MaxEdge.X) ||
56 
57  (pointA.y > box.MaxEdge.Y && pointB.y > box.MaxEdge.Y && pointC.y > box.MaxEdge.Y) ||
58  (pointA.z > box.MaxEdge.Z && pointB.z > box.MaxEdge.Z && pointC.z > box.MaxEdge.Z) ||
59  (pointA.x < box.MinEdge.X && pointB.x < box.MinEdge.X && pointC.x < box.MinEdge.X) ||
60  (pointA.y < box.MinEdge.Y && pointB.y < box.MinEdge.Y && pointC.y < box.MinEdge.Y) ||
61  (pointA.z < box.MinEdge.Z && pointB.z < box.MinEdge.Z && pointC.z < box.MinEdge.Z));
62  }
63 
65 
67  glm::vec3 closestPointOnTriangle(const glm::vec3& p) const
68  {
69  const glm::vec3 rab = line3d<T>(pointA, pointB).getClosestPoint(p);
70  const glm::vec3 rbc = line3d<T>(pointB, pointC).getClosestPoint(p);
71  const glm::vec3 rca = line3d<T>(pointC, pointA).getClosestPoint(p);
72 
73  const T d1 = glm::distance(rab, p);
74  const T d2 = glm::distance(rbc, p);
75  const T d3 = glm::distance(rca, p);
76 
77  if (d1 < d2)
78  return d1 < d3 ? rab : rca;
79 
80  return d2 < d3 ? rbc : rca;
81  }
82 
84  /*
85  \param p Point to test. Assumes that this point is already
86  on the plane of the triangle.
87  \return True if the point is inside the triangle, otherwise false. */
88  bool isPointInside(const glm::vec3& p) const
89  {
90  glm::vec3 adouble((double)pointA.x, (double)pointA.y, (double)pointA.z);
91  glm::vec3 bdouble((double)pointB.x, (double)pointB.y, (double)pointB.z);
92  glm::vec3 cdouble((double)pointC.x, (double)pointC.y, (double)pointC.z);
93  glm::vec3 pdouble((double)p.x, (double)p.y, (double)p.z);
94  return (isOnSameSide(pdouble, adouble, bdouble, cdouble) &&
95  isOnSameSide(pdouble, bdouble, adouble, cdouble) &&
96  isOnSameSide(pdouble, cdouble, adouble, bdouble));
97  }
98 
100 
107  bool isPointInsideFast(const glm::vec3& p) const
108  {
109  const glm::vec3 a = pointC - pointA;
110  const glm::vec3 b = pointB - pointA;
111  const glm::vec3 c = p - pointA;
112 
113  const double dotAA = glm::dot(a, a);
114  const double dotAB = glm::dot(b, b);
115  const double dotAC = glm::dot(a, c);
116  const double dotBB = glm::dot(b, b);
117  const double dotBC = glm::dot(b, c);
118 
119  // get coordinates in barycentric coordinate system
120  const double invDenom = 1/(dotAA * dotBB - dotAB * dotAB);
121  const double u = (dotBB * dotAC - dotAB * dotBC) * invDenom;
122  const double v = (dotAA * dotBC - dotAB * dotAC) * invDenom;
123 
124  // We count border-points as inside to keep downward compatibility.
125  // Rounding-error also needed for some test-cases.
126  return (u > -ROUNDING_ERROR_float) && (v >= 0) && (u + v < 1+ROUNDING_ERROR_float);
127 
128  }
129 
130 
132 
136  glm::vec3& outIntersection) const
137  {
138  return getIntersectionWithLine(line.start,
139  line.getVector(), outIntersection) &&
140  isBetweenPoints(outIntersection, line.start, line.end);
141  }
142 
143 
145 
153  bool getIntersectionWithLine(const glm::vec3& linePoint,
154  const glm::vec3& lineVect, glm::vec3& outIntersection) const
155  {
156  if (getIntersectionOfPlaneWithLine(linePoint, lineVect, outIntersection))
157  return isPointInside(outIntersection);
158 
159  return false;
160  }
161 
162 
164 
168  bool getIntersectionOfPlaneWithLine(const glm::vec3& linePoint,
169  const glm::vec3& lineVect, glm::vec3& outIntersection) const
170  {
171  // Work with double to get more precise results (makes enough difference to be worth the casts).
172  const glm::vec3 linePointdouble(linePoint.x, linePoint.y, linePoint.z);
173  const glm::vec3 lineVectdouble(lineVect.x, lineVect.y, lineVect.z);
174  glm::vec3 outIntersectiondouble;
175 
176  core::triangle3d<double> triangledouble(glm::vec3((double)pointA.x, (double)pointA.y, (double)pointA.z)
177  ,glm::vec3((double)pointB.x, (double)pointB.y, (double)pointB.z)
178  , glm::vec3((double)pointC.x, (double)pointC.y, (double)pointC.z));
179  const glm::vec3 normaldouble = glm::normalize(triangledouble.getNormal());
180  double t2;
181 
182  if (core::iszero (t2 = glm::dot(normaldouble, lineVectdouble)))
183  return false;
184 
185  double d = glm::dot(triangledouble.pointA, normaldouble);
186  double t = -(glm::dot(normaldouble, linePointdouble) - d) / t2;
187  outIntersectiondouble = linePointdouble + (lineVectdouble * float(t));
188 
189  outIntersection.x = (T)outIntersectiondouble.x;
190  outIntersection.y = (T)outIntersectiondouble.y;
191  outIntersection.z = (T)outIntersectiondouble.z;
192  return true;
193  }
194 
195 
197 
198  glm::vec3 getNormal() const
199  {
200  return glm::cross(pointB - pointA, pointC - pointA);
201  }
202 
204 
209  bool isFrontFacing(const glm::vec3& lookDirection) const
210  {
211  const glm::vec3 n = getNormal().normalize();
212  const float d = (float) glm::dot(n, lookDirection);
213  return F32_LOWER_EQUAL_0(d);
214  }
215 
218  {
219  return plane3d<T>(pointA, pointB, pointC);
220  }
221 
223  T getArea() const
224  {
225  return glm::length(glm::cross(pointB - pointA, pointC - pointA)) * 0.5f;
226 
227  }
228 
230  void set(const glm::vec3& a, const glm::vec3& b, const glm::vec3& c)
231  {
232  pointA = a;
233  pointB = b;
234  pointC = c;
235  }
236 
238  glm::vec3 pointA;
239  glm::vec3 pointB;
240  glm::vec3 pointC;
241 
242  private:
243  // Using double instead of <T> to avoid integer overflows when T=int (maybe also less floating point troubles).
244  bool isOnSameSide(const glm::vec3& p1, const glm::vec3& p2,
245  const glm::vec3& a, const glm::vec3& b) const
246  {
247  glm::vec3 bminusa = b - a;
248  glm::vec3 cp1 = glm::cross(bminusa, p1 - a);
249  glm::vec3 cp2 = glm::cross(bminusa, p2 - a);
250  double res = glm::dot(cp1, cp2);
251  if (res < 0)
252  {
253  // This catches some floating point troubles.
254  // Unfortunately slightly expensive and we don't really know the best epsilon for iszero.
255  glm::vec3 cp1 = glm::cross(glm::normalize(bminusa), (p1 - a));
256  cp1 = glm::normalize(cp1);
257  if (core::iszero(cp1.x, (double)ROUNDING_ERROR_float)
258  && core::iszero(cp1.y, (double)ROUNDING_ERROR_float)
259  && core::iszero(cp1.z, (double)ROUNDING_ERROR_float))
260  {
261  res = 0.f;
262  }
263  }
264  return (res >= 0.0f);
265  }
266  };
267 
268 
271 
274 
275 } // namespace core
276 } // namespace saga
277 
278 #endif
279 
saga::core::line3d::getClosestPoint
glm::vec3 getClosestPoint(const glm::vec3 &point) const
Get the closest point on this line to a point.
Definition: line3d.h:88
plane3d.h
saga::core::plane3d
Template plane class with some intersection testing methods.
Definition: plane3d.h:34
saga::core::triangle3d::set
void set(const glm::vec3 &a, const glm::vec3 &b, const glm::vec3 &c)
sets the triangle's points
Definition: triangle3d.h:230
saga::core::triangle3d::pointB
glm::vec3 pointB
Definition: triangle3d.h:239
saga::core::triangle3di
triangle3d< std::int32_t > triangle3di
Typedef for an integer 3d triangle.
Definition: triangle3d.h:273
saga::core::aabbox3d::isPointInside
bool isPointInside(const glm::vec3 &p) const
Determines if a point is within this box.
Definition: aabbox3d.h:208
saga::core::triangle3d::getIntersectionWithLimitedLine
bool getIntersectionWithLimitedLine(const line3d< T > &line, glm::vec3 &outIntersection) const
Get an intersection with a 3d line.
Definition: triangle3d.h:135
saga::core::triangle3d::operator!=
bool operator!=(const triangle3d< T > &other) const
Inequality operator.
Definition: triangle3d.h:35
saga::core::triangle3d::pointC
glm::vec3 pointC
Definition: triangle3d.h:240
saga::core::triangle3df
triangle3d< float > triangle3df
Typedef for a float 3d triangle.
Definition: triangle3d.h:270
saga::core::triangle3d::getArea
T getArea() const
Get the area of the triangle.
Definition: triangle3d.h:223
saga::core::aabbox3d::MinEdge
glm::vec3 MinEdge
The near edge.
Definition: aabbox3d.h:343
aabbox3d.h
saga::core::line3d
3D line between two points with intersection methods.
Definition: line3d.h:17
saga::core::triangle3d::isTotalOutsideBox
bool isTotalOutsideBox(const aabbox3d< T > &box) const
Determines if the triangle is totally outside a bounding box.
Definition: triangle3d.h:53
saga::core::triangle3d::isFrontFacing
bool isFrontFacing(const glm::vec3 &lookDirection) const
Test if the triangle would be front or backfacing from any point.
Definition: triangle3d.h:209
saga::core::aabbox3d
Axis aligned bounding box in 3d dimensional space.
Definition: aabbox3d.h:20
saga::core::triangle3d::getIntersectionOfPlaneWithLine
bool getIntersectionOfPlaneWithLine(const glm::vec3 &linePoint, const glm::vec3 &lineVect, glm::vec3 &outIntersection) const
Calculates the intersection between a 3d line and the plane the triangle is on.
Definition: triangle3d.h:168
saga::core::isBetweenPoints
bool isBetweenPoints(const glm::vec3 &point, const glm::vec3 &begin, const glm::vec3 &end)
Definition: irrMath.h:65
saga::core::ROUNDING_ERROR_float
const float ROUNDING_ERROR_float
Definition: irrMath.h:29
saga::core::triangle3d::isPointInside
bool isPointInside(const glm::vec3 &p) const
Check if a point is inside the triangle (border-points count also as inside)
Definition: triangle3d.h:88
saga::core::line3d::end
glm::vec3 end
End point of line.
Definition: line3d.h:131
saga::core::line3d::getVector
glm::vec3 getVector() const
Get vector of line.
Definition: line3d.h:70
saga::core::line3d::start
glm::vec3 start
Start point of line.
Definition: line3d.h:129
F32_LOWER_EQUAL_0
#define F32_LOWER_EQUAL_0(n)
Definition: irrMath.h:462
saga::core::triangle3d::getIntersectionWithLine
bool getIntersectionWithLine(const glm::vec3 &linePoint, const glm::vec3 &lineVect, glm::vec3 &outIntersection) const
Get an intersection with a 3d line.
Definition: triangle3d.h:153
saga::core::triangle3d::closestPointOnTriangle
glm::vec3 closestPointOnTriangle(const glm::vec3 &p) const
Get the closest point on a triangle to a point on the same plane.
Definition: triangle3d.h:67
saga::core::triangle3d::getNormal
glm::vec3 getNormal() const
Get the normal of the triangle.
Definition: triangle3d.h:198
saga::core::triangle3d::triangle3d
triangle3d(const glm::vec3 &v1, const glm::vec3 &v2, const glm::vec3 &v3)
Constructor for triangle with given three vertices.
Definition: triangle3d.h:26
saga::core::triangle3d::isTotalInsideBox
bool isTotalInsideBox(const aabbox3d< T > &box) const
Determines if the triangle is totally inside a bounding box.
Definition: triangle3d.h:43
saga::core::aabbox3d::MaxEdge
glm::vec3 MaxEdge
The far edge.
Definition: aabbox3d.h:346
saga::core::triangle3d::getPlane
plane3d< T > getPlane() const
Get the plane of this triangle.
Definition: triangle3d.h:217
saga::core::iszero
bool iszero(const double a, const double tolerance=ROUNDING_ERROR_double)
returns if a equals zero, taking rounding errors into account
Definition: irrMath.h:346
saga::core::triangle3d
3d triangle template class for doing collision detection and other things.
Definition: triangle3d.h:19
line3d.h
saga::core::triangle3d::pointA
glm::vec3 pointA
the three points of the triangle
Definition: triangle3d.h:238
saga::core::triangle3d::isPointInsideFast
bool isPointInsideFast(const glm::vec3 &p) const
Check if a point is inside the triangle (border-points count also as inside)
Definition: triangle3d.h:107
saga
Definition: aabbox3d.h:11
saga::core::triangle3d::operator==
bool operator==(const triangle3d< T > &other) const
Equality operator.
Definition: triangle3d.h:29
saga::core::triangle3d::triangle3d
triangle3d()
Constructor for an all 0 triangle.
Definition: triangle3d.h:24