TDME2  1.9.200
LineSegment.cpp
Go to the documentation of this file.
2 
3 #include <tdme/tdme.h>
6 #include <tdme/math/Math.h>
7 #include <tdme/math/Vector3.h>
8 
12 using tdme::math::Math;
14 
15 void LineSegment::computeClosestPointOnLineSegment(const Vector3& p1, const Vector3& q1, const Vector3& p, Vector3& c) {
16  // see https://forum.unity.com/threads/how-do-i-find-the-closest-point-on-a-line.340058/
17  Vector3 lineDirection = q1.clone().sub(p1);
18  float lineLength = lineDirection.computeLength();
19  lineDirection.normalize();
20  Vector3 pSubP1 = p.clone().sub(p1);
21  float t = Vector3::computeDotProduct(pSubP1, lineDirection);
22  if (t < 0.0f) t = 0.0f;
23  if (t > lineLength) t = lineLength;
24  c.set(p1).add(lineDirection.scale(t));
25 }
26 
27 bool LineSegment::doesLineSegmentsCollide(const Vector3& p1, const Vector3& q1, const Vector3& p2, const Vector3& q2, Vector3& p)
28 {
29  Vector3 c1;
30  Vector3 c2;
31  computeClosestPointsOnLineSegments(p1, q1, p2, q2, c1, c2);
32  if (c1.sub(c2).computeLength() < Math::EPSILON) {
33  p.set(c2);
34  return true;
35  } else {
36  return false;
37  }
38 }
39 
40 void LineSegment::computeClosestPointsOnLineSegments(const Vector3& p1, const Vector3& q1, const Vector3& p2, const Vector3& q2, Vector3& c1, Vector3& c2)
41 {
42  Vector3 d1;
43  Vector3 d2;
44  Vector3 r;
45  d1.set(q1).sub(p1);
46  d2.set(q2).sub(p2);
47  r.set(p1).sub(p2);
48  auto a = Vector3::computeDotProduct(d1, d1);
49  auto e = Vector3::computeDotProduct(d2, d2);
50  auto f = Vector3::computeDotProduct(d2, r);
51  // both line segments degenerate into points?
52  if (a <= Math::EPSILON && e <= Math::EPSILON) {
53  c1 = p1;
54  c2 = p2;
55  return;
56  }
57  // first line segment degenerates into point?
58  float s;
59  float t;
60  if (a <= Math::EPSILON) {
61  s = 0.0f;
62  t = f / e;
63  t = Math::clamp(t, 0.0f, 1.0f);
64  } else {
65  auto c = Vector3::computeDotProduct(d1, r);
66  // second line segment degenerates into point?
67  if (e <= Math::EPSILON) {
68  t = 0.0f;
69  s = Math::clamp(-c / a, 0.0f, 1.0f);
70  } else {
71  // nope, use general case
72  auto b = Vector3::computeDotProduct(d1, d2);
73  auto denom = a * e - b * b;
74  if (denom != 0.0f) {
75  s = Math::clamp((b * f - c * e) / denom, 0.0f, 1.0f);
76  } else {
77  s = 0.0f;
78  }
79  t = (b * s + f) / e;
80  if (t < 0.0f) {
81  t = 0.0f;
82  s = Math::clamp(-c / a, 0.0f, 1.0f);
83  } else if (t > 1.0f) {
84  t = 1.0f;
85  s = Math::clamp((b - c) / a, 0.0f, 1.0f);
86  }
87  }
88  }
89  c1.set(p1).add(d1.scale(s));
90  c2.set(p2).add(d2.scale(t));
91 }
92 
93 bool LineSegment::doesBoundingBoxCollideWithLineSegment(BoundingBox* boundingBox, const Vector3& p, const Vector3& q, Vector3& contactMin, Vector3& contactMax)
94 {
95  Vector3 d;
96  Vector3 d1;
97  Vector3 d2;
98  auto tmin = 0.0f;
99  auto tmax = 1.0f;
100  auto minXYZ = boundingBox->getMin().getArray();
101  auto maxXYZ = boundingBox->getMax().getArray();
102  d.set(q).sub(p);
103  for (auto i = 0; i < 3; i++) {
104  if (Math::abs(d[i]) < Math::EPSILON &&
105  (p[i] <= minXYZ[i] || p[i] >= maxXYZ[i])) {
106  return false;
107  } else {
108  auto odd = 1.0f / d[i];
109  auto t1 = (minXYZ[i] - p[i]) * odd;
110  auto t2 = (maxXYZ[i] - p[i]) * odd;
111  if (t1 > t2) {
112  auto tmp = t1;
113  t1 = t2;
114  t2 = tmp;
115  }
116  tmin = Math::max(tmin, t1);
117  tmax = Math::min(tmax, t2);
118  if (tmin > tmax)
119  return false;
120 
121  }
122  }
123  if (tmin > 1.0) return false;
124  // compute contact points
125  contactMin.set(p).add(d1.set(d).scale(tmin));
126  contactMax.set(p).add(d2.set(d).scale(tmax));
127  // we have a collision
128  return true;
129 }
130 
131 bool LineSegment::doesOrientedBoundingBoxCollideWithLineSegment(OrientedBoundingBox* orientedBoundingBox, const Vector3& p, const Vector3& q, Vector3& contactMin, Vector3& contactMax)
132 {
133  Vector3 d;
134  Vector3 d1;
135  Vector3 d2;
136  auto tmin = 0.0f;
137  auto tmax = 1.0f;
138  const auto& obbAxes = orientedBoundingBox->getAxes();
139  const auto& obbCenter = orientedBoundingBox->getCenter();
140  const auto& obbHalfExtension = orientedBoundingBox->getHalfExtension();
141  d.set(q).sub(p);
142  for (auto i = 0; i < 3; i++) {
143  auto directionLengthOnAxis = Vector3::computeDotProduct(d, obbAxes[i]);
144  auto obbExtensionLengthOnAxis = obbHalfExtension[i];
145  auto obbCenterLengthOnAxis = Vector3::computeDotProduct(obbCenter, obbAxes[i]);
146  auto pointLengthOnAxis = Vector3::computeDotProduct(p, obbAxes[i]);
147  if (Math::abs(directionLengthOnAxis) < Math::EPSILON &&
148  (pointLengthOnAxis <= obbCenterLengthOnAxis - obbExtensionLengthOnAxis ||
149  pointLengthOnAxis >= obbCenterLengthOnAxis + obbExtensionLengthOnAxis)) {
150  return false;
151  } else {
152  auto odd = 1.0f / directionLengthOnAxis;
153  auto t1 = (obbCenterLengthOnAxis - obbExtensionLengthOnAxis - pointLengthOnAxis) * odd;
154  auto t2 = (obbCenterLengthOnAxis + obbExtensionLengthOnAxis - pointLengthOnAxis) * odd;
155  if (t1 > t2) {
156  auto tmp = t1;
157  t1 = t2;
158  t2 = tmp;
159  }
160  tmin = Math::max(tmin, t1);
161  tmax = Math::min(tmax, t2);
162  if (tmin > tmax)
163  return false;
164 
165  }
166  }
167  if (tmin > 1.0) return false;
168  // compute contact points
169  contactMin.set(p).add(d1.set(d).scale(tmin));
170  contactMax.set(p).add(d2.set(d).scale(tmax));
171  // we have a collision
172  return true;
173 }
174 
175 bool LineSegment::doesLineSegmentCollideWithTriangle(const Vector3& p1, const Vector3& p2, const Vector3& p3, const Vector3& r1, const Vector3& r2, Vector3& contact)
176 {
177  // see: https://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm
178  auto rayVector = r2.clone().sub(r1).normalize();
179  float a,f,u,v;
180  auto edge1 = p3.clone().sub(p1);
181  auto edge2 = p2.clone().sub(p1);
182  auto h = Vector3::computeCrossProduct(rayVector, edge2);
183  a = Vector3::computeDotProduct(edge1, h);
184  if (a > -Math::EPSILON && a < Math::EPSILON) {
185  // This ray is parallel to this triangle.
186  return false;
187  }
188  f = 1.0/a;
189  auto s = r1 - p1;
190  u = f * Vector3::computeDotProduct(s, h);
191  if (u < 0.0 || u > 1.0) {
192  return false;
193  }
194  auto q = Vector3::computeCrossProduct(s, edge1);
195  v = f * Vector3::computeDotProduct(rayVector, q);
196  if (v < 0.0 || u + v > 1.0) {
197  return false;
198  }
199  // At this stage we can compute t to find out where the intersection point is on the line.
200  float t = f * Vector3::computeDotProduct(edge2, q);
201  if (t > Math::EPSILON) {
202  // ray intersection
203  contact = r1 + rayVector * t;
204  return true;
205  } else {
206  // This means that there is a line intersection but not a ray intersection.
207  return false;
208  }
209 }
210 
211 bool LineSegment::doesLineSegmentCollideWithPlane(const Vector3& n, float d, const Vector3& p1, const Vector3& p2, Vector3& contact) {
212  // see: https://math.stackexchange.com/questions/83990/line-and-plane-intersection-in-3d
213  auto lineDirection = p2.clone().sub(p1);
214  auto lineLength = lineDirection.computeLength();
215  lineDirection.normalize();
216  float nDotP1 = Vector3::computeDotProduct(n, p1);
217  float nDotLineDirection = Vector3::computeDotProduct(n, lineDirection);
218  auto t = ((d - nDotP1) / nDotLineDirection);
219  if (t < 0.0 || t > lineLength) return false;
220  contact.set(p1 + (lineDirection * t));
221  return true;
222 }
Axis aligned bounding box used for frustum, this is not directly connectable with physics engine.
Definition: BoundingBox.h:26
Line segment helper functions.
Definition: LineSegment.h:16
static bool doesLineSegmentCollideWithPlane(const Vector3 &n, float d, const Vector3 &p1, const Vector3 &p2, Vector3 &contact)
Does line segment collide with plane.
static void computeClosestPointsOnLineSegments(const Vector3 &p1, const Vector3 &q1, const Vector3 &p2, const Vector3 &q2, Vector3 &c1, Vector3 &c2)
Computes closest points c1, c2 on line segment p1->q1, p2->q2 based on an algorithm from "Real-Time C...
Definition: LineSegment.cpp:40
static bool doesBoundingBoxCollideWithLineSegment(BoundingBox *boundingBox, const Vector3 &p, const Vector3 &q, Vector3 &contactMin, Vector3 &contactMax)
Check if segment collides with bounding box based on an algorithm from "Real-Time Collision Detection...
Definition: LineSegment.cpp:93
static bool doesOrientedBoundingBoxCollideWithLineSegment(OrientedBoundingBox *orientedBoundingBox, const Vector3 &p, const Vector3 &q, Vector3 &contactMin, Vector3 &contactMax)
Check if segment collides with oriented bounding box based on an algorithm from "Real-Time Collision ...
static bool doesLineSegmentCollideWithTriangle(const Vector3 &p1, const Vector3 &p2, const Vector3 &p3, const Vector3 &r1, const Vector3 &r2, Vector3 &contact)
Does line segment collides with triangle.
static bool doesLineSegmentsCollide(const Vector3 &p1, const Vector3 &q1, const Vector3 &p2, const Vector3 &q2, Vector3 &p)
Does line segments collide.
Definition: LineSegment.cpp:27
Oriented bounding box physics primitive.
const array< Vector3, 3 > & getAxes() const
Standard math functions.
Definition: Math.h:19
Vector3 class representing vector3 mathematical structure and operations with x, y,...
Definition: Vector3.h:20
float computeLength() const
Definition: Vector3.h:274
Vector3 & add(float scalar)
Adds a scalar.
Definition: Vector3.h:153
const array< float, 3 > & getArray() const
Definition: Vector3.h:366
Vector3 clone() const
Clones this vector3.
Definition: Vector3.h:374
Vector3 & sub(float scalar)
Subtracts a scalar.
Definition: Vector3.h:177
Vector3 & scale(float scalar)
Scales by scalar.
Definition: Vector3.h:201
Vector3 & set(float x, float y, float z)
Sets this vector3 by its components.
Definition: Vector3.h:70
Vector3 & normalize()
Normalizes this vector3.
Definition: Vector3.h:239