GteIntrLine3Cylinder3.h
Go to the documentation of this file.
1 // David Eberly, Geometric Tools, Redmond WA 98052
2 // Copyright (c) 1998-2017
3 // Distributed under the Boost Software License, Version 1.0.
4 // http://www.boost.org/LICENSE_1_0.txt
5 // http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
6 // File Version: 3.0.0 (2016/06/19)
7 
8 #pragma once
9 
10 #include <Mathematics/GteVector3.h>
12 #include <Mathematics/GteLine.h>
13 #include <Mathematics/GteFIQuery.h>
14 
15 // The queries consider the cylinder to be a solid.
16 
17 namespace gte
18 {
19 
20 template <typename Real>
21 class FIQuery<Real, Line3<Real>, Cylinder3<Real>>
22 {
23 public:
24  struct Result
25  {
26  bool intersect;
28  std::array<Real, 2> parameter;
29  std::array<Vector3<Real>, 2> point;
30  };
31 
32  Result operator()(Line3<Real> const& line,
33  Cylinder3<Real> const& cylinder);
34 
35 protected:
36  void DoQuery(Vector3<Real> const& lineOrigin,
37  Vector3<Real> const& lineDirection, Cylinder3<Real> const& cylinder,
38  Result& result);
39 };
40 
41 
42 template <typename Real>
45  Line3<Real> const& line, Cylinder3<Real> const& cylinder)
46 {
47  Result result;
48  DoQuery(line.origin, line.direction, cylinder, result);
49  for (int i = 0; i < result.numIntersections; ++i)
50  {
51  result.point[i] = line.origin + result.parameter[i] * line.direction;
52  }
53  return result;
54 }
55 
56 template <typename Real>
58  Vector3<Real> const& lineOrigin, Vector3<Real> const& lineDirection,
59  Cylinder3<Real> const& cylinder, Result& result)
60 {
61  // Initialize the result as if there is no intersection. If we discover
62  // an intersection, these values will be modified accordingly.
63  result.intersect = false;
64  result.numIntersections = 0;
65 
66  // Create a coordinate system for the cylinder. In this system, the
67  // cylinder segment center C is the origin and the cylinder axis direction
68  // W is the z-axis. U and V are the other coordinate axis directions.
69  // If P = x*U+y*V+z*W, the cylinder is x^2 + y^2 = r^2, where r is the
70  // cylinder radius. The end caps are |z| = h/2, where h is the cylinder
71  // height.
72  Vector3<Real> basis[3]; // {W, U, V}
73  basis[0] = cylinder.axis.direction;
75  Real halfHeight = ((Real)0.5) * cylinder.height;
76  Real rSqr = cylinder.radius * cylinder.radius;
77 
78  // Convert incoming line origin to capsule coordinates.
79  Vector3<Real> diff = lineOrigin - cylinder.axis.origin;
80  Vector3<Real> P{ Dot(basis[1], diff), Dot(basis[2], diff),
81  Dot(basis[0], diff) };
82 
83  // Get the z-value, in cylinder coordinates, of the incoming line's
84  // unit-length direction.
85  Real dz = Dot(basis[0], lineDirection);
86  if (std::abs(dz) == (Real)1)
87  {
88  // The line is parallel to the cylinder axis. Determine whether the
89  // line intersects the cylinder end disks.
90  Real radialSqrDist = rSqr - P[0] * P[0] - P[1] * P[1];
91  if (radialSqrDist >= (Real)0)
92  {
93  // The line intersects the cylinder end disks.
94  result.intersect = true;
95  result.numIntersections = 2;
96  if (dz > (Real)0)
97  {
98  result.parameter[0] = -P[2] - halfHeight;
99  result.parameter[1] = -P[2] + halfHeight;
100  }
101  else
102  {
103  result.parameter[0] = P[2] - halfHeight;
104  result.parameter[1] = P[2] + halfHeight;
105  }
106  }
107  // else: The line is outside the cylinder, no intersection.
108  return;
109  }
110 
111  // Convert the incoming line unit-length direction to cylinder
112  // coordinates.
113  Vector3<Real> D{ Dot(basis[1], lineDirection),
114  Dot(basis[2], lineDirection), dz };
115 
116  Real a0, a1, a2, discr, root, inv, tValue;
117 
118  if (D[2] == (Real)0)
119  {
120  // The line is perpendicular to the cylinder axis.
121  if (std::abs(P[2]) <= halfHeight)
122  {
123  // Test intersection of line P+t*D with infinite cylinder
124  // x^2+y^2 = r^2. This reduces to computing the roots of a
125  // quadratic equation. If P = (px,py,pz) and D = (dx,dy,dz),
126  // then the quadratic equation is
127  // (dx^2+dy^2)*t^2 + 2*(px*dx+py*dy)*t + (px^2+py^2-r^2) = 0
128  a0 = P[0] * P[0] + P[1] * P[1] - rSqr;
129  a1 = P[0] * D[0] + P[1] * D[1];
130  a2 = D[0] * D[0] + D[1] * D[1];
131  discr = a1 * a1 - a0 * a2;
132  if (discr > (Real)0)
133  {
134  // The line intersects the cylinder in two places.
135  result.intersect = true;
136  result.numIntersections = 2;
137  root = sqrt(discr);
138  inv = ((Real)1) / a2;
139  result.parameter[0] = (-a1 - root) * inv;
140  result.parameter[1] = (-a1 + root) * inv;
141  }
142  else if (discr == (Real)0)
143  {
144  // The line is tangent to the cylinder.
145  result.intersect = true;
146  result.numIntersections = 1;
147  result.parameter[0] = -a1 / a2;
148  // Used by derived classes.
149  result.parameter[1] = result.parameter[0];
150  }
151  // else: The line does not intersect the cylinder.
152  }
153  // else: The line is outside the planes of the cylinder end disks.
154  return;
155  }
156 
157  // Test for intersections with the planes of the end disks.
158  inv = ((Real)1) / D[2];
159 
160  Real t0 = (-halfHeight - P[2]) * inv;
161  Real xTmp = P[0] + t0 * D[0];
162  Real yTmp = P[1] + t0 * D[1];
163  if (xTmp * xTmp + yTmp * yTmp <= rSqr)
164  {
165  // Plane intersection inside the top cylinder end disk.
166  result.parameter[result.numIntersections++] = t0;
167  }
168 
169  Real t1 = (+halfHeight - P[2]) * inv;
170  xTmp = P[0] + t1 * D[0];
171  yTmp = P[1] + t1 * D[1];
172  if (xTmp * xTmp + yTmp * yTmp <= rSqr)
173  {
174  // Plane intersection inside the bottom cylinder end disk.
175  result.parameter[result.numIntersections++] = t1;
176  }
177 
178  if (result.numIntersections < 2)
179  {
180  // Test for intersection with the cylinder wall.
181  a0 = P[0] * P[0] + P[1] * P[1] - rSqr;
182  a1 = P[0] * D[0] + P[1] * D[1];
183  a2 = D[0] * D[0] + D[1] * D[1];
184  discr = a1 * a1 - a0 * a2;
185  if (discr >(Real)0)
186  {
187  root = sqrt(discr);
188  inv = ((Real)1) / a2;
189  tValue = (-a1 - root) * inv;
190  if (t0 <= t1)
191  {
192  if (t0 <= tValue && tValue <= t1)
193  {
194  result.parameter[result.numIntersections++] = tValue;
195  }
196  }
197  else
198  {
199  if (t1 <= tValue && tValue <= t0)
200  {
201  result.parameter[result.numIntersections++] = tValue;
202  }
203  }
204 
205  if (result.numIntersections < 2)
206  {
207  tValue = (-a1 + root) * inv;
208  if (t0 <= t1)
209  {
210  if (t0 <= tValue && tValue <= t1)
211  {
212  result.parameter[result.numIntersections++] = tValue;
213  }
214  }
215  else
216  {
217  if (t1 <= tValue && tValue <= t0)
218  {
219  result.parameter[result.numIntersections++] = tValue;
220  }
221  }
222  }
223  // else: Line intersects end disk and cylinder wall.
224  }
225  else if (discr == (Real)0)
226  {
227  tValue = -a1 / a2;
228  if (t0 <= t1)
229  {
230  if (t0 <= tValue && tValue <= t1)
231  {
232  result.parameter[result.numIntersections++] = tValue;
233  }
234  }
235  else
236  {
237  if (t1 <= tValue && tValue <= t0)
238  {
239  result.parameter[result.numIntersections++] = tValue;
240  }
241  }
242  }
243  // else: Line does not intersect cylinder wall.
244  }
245  // else: Line intersects both top and bottom cylinder end disks.
246 
247  if (result.numIntersections == 2)
248  {
249  result.intersect = true;
250  if (result.parameter[0] > result.parameter[1])
251  {
252  std::swap(result.parameter[0], result.parameter[1]);
253  }
254  }
255  else if (result.numIntersections == 1)
256  {
257  result.intersect = true;
258  // Used by derived classes.
259  result.parameter[1] = result.parameter[0];
260  }
261 }
262 
263 
264 }
gte::BSNumber< UIntegerType > abs(gte::BSNumber< UIntegerType > const &number)
Definition: GteBSNumber.h:966
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t0
Definition: glext.h:9013
Result operator()(Type0 const &primitive0, Type1 const &primitive1)
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat t1
Definition: glext.h:9013
DualQuaternion< Real > Dot(DualQuaternion< Real > const &d0, DualQuaternion< Real > const &d1)
Real ComputeOrthogonalComplement(int numInputs, Vector2< Real > *v, bool robust=false)
Definition: GteVector2.h:123
GLuint64EXT * result
Definition: glext.h:10003
Line3< Real > axis
Definition: GteCylinder3.h:31


geometric_tools_engine
Author(s): Yijiang Huang
autogenerated on Thu Jul 18 2019 04:00:00