Gazebo Math

API Reference

7.7.0
gz/math/Line3.hh
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2015 Open Source Robotics Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16 */
17 #ifndef GZ_MATH_LINE3_HH_
18 #define GZ_MATH_LINE3_HH_
19 
20 #include <algorithm>
21 #include <gz/math/Vector3.hh>
22 #include <gz/math/config.hh>
23 
24 namespace gz::math
25 {
26  // Inline bracket to help doxygen filtering.
27  inline namespace GZ_MATH_VERSION_NAMESPACE {
28  //
32  template<typename T>
33  class Line3
34  {
36  public: Line3() = default;
37 
40  public: Line3(const Line3<T> &_line) = default;
41 
45  public: Line3(const math::Vector3<T> &_ptA, const math::Vector3<T> &_ptB)
46  {
47  this->Set(_ptA, _ptB);
48  }
49 
55  public: Line3(const double _x1, const double _y1,
56  const double _x2, const double _y2)
57  {
58  this->Set(_x1, _y1, _x2, _y2);
59  }
60 
68  public: Line3(const double _x1, const double _y1,
69  const double _z1, const double _x2,
70  const double _y2, const double _z2)
71  {
72  this->Set(_x1, _y1, _z1, _x2, _y2, _z2);
73  }
74 
78  public: void Set(const math::Vector3<T> &_ptA,
79  const math::Vector3<T> &_ptB)
80  {
81  this->pts[0] = _ptA;
82  this->pts[1] = _ptB;
83  }
84 
87  public: void SetA(const math::Vector3<T> &_ptA)
88  {
89  this->pts[0] = _ptA;
90  }
91 
94  public: void SetB(const math::Vector3<T> &_ptB)
95  {
96  this->pts[1] = _ptB;
97  }
98 
107  public: void Set(const double _x1, const double _y1,
108  const double _x2, const double _y2,
109  const double _z = 0)
110  {
111  this->pts[0].Set(
112  static_cast<T>(_x1), static_cast<T>(_y1), static_cast<T>(_z));
113  this->pts[1].Set(
114  static_cast<T>(_x2), static_cast<T>(_y2), static_cast<T>(_z));
115  }
116 
124  public: void Set(const double _x1, const double _y1,
125  const double _z1, const double _x2,
126  const double _y2, const double _z2)
127  {
128  this->pts[0].Set(
129  static_cast<T>(_x1), static_cast<T>(_y1), static_cast<T>(_z1));
130  this->pts[1].Set(
131  static_cast<T>(_x2), static_cast<T>(_y2), static_cast<T>(_z2));
132  }
133 
136  public: math::Vector3<T> Direction() const
137  {
138  return (this->pts[1] - this->pts[0]).Normalize();
139  }
140 
143  public: T Length() const
144  {
145  return static_cast<T>(this->pts[0].Distance(this->pts[1]));
146  }
147 
158  public: bool Distance(const Line3<T> &_line, Line3<T> &_result,
159  const double _epsilon = 1e-6) const
160  {
161  Vector3<T> p13 = this->pts[0] - _line[0];
162  Vector3<T> p43 = _line[1] - _line[0];
163 
164  if (std::abs(p43.X()) < _epsilon && std::abs(p43.Y()) < _epsilon &&
165  std::abs(p43.Z()) < _epsilon)
166  {
167  return false;
168  }
169 
170  Vector3<T> p21 = this->pts[1] - this->pts[0];
171 
172  if (std::abs(p21.X()) < _epsilon && std::abs(p21.Y()) < _epsilon &&
173  std::abs(p21.Z()) < _epsilon)
174  {
175  return false;
176  }
177 
178  double d1343 = p13.Dot(p43);
179  double d4321 = p43.Dot(p21);
180  double d1321 = p13.Dot(p21);
181  double d4343 = p43.Dot(p43);
182  double d2121 = p21.Dot(p21);
183 
184  double denom = d2121 * d4343 - d4321 * d4321;
185 
186  // In this case, we choose the first point in this line,
187  // and the closest point in the provided line.
188  if (std::abs(denom) < _epsilon)
189  {
190  double d1 = this->pts[0].Distance(_line[0]);
191  double d2 = this->pts[0].Distance(_line[1]);
192 
193  double d3 = this->pts[1].Distance(_line[0]);
194  double d4 = this->pts[1].Distance(_line[1]);
195 
196  if (d1 <= d2 && d1 <= d3 && d1 <= d4)
197  {
198  _result.SetA(this->pts[0]);
199  _result.SetB(_line[0]);
200  }
201  else if (d2 <= d3 && d2 <= d4)
202  {
203  _result.SetA(this->pts[0]);
204  _result.SetB(_line[1]);
205  }
206  else if (d3 <= d4)
207  {
208  _result.SetA(this->pts[1]);
209  _result.SetB(_line[0]);
210  }
211  else
212  {
213  _result.SetA(this->pts[1]);
214  _result.SetB(_line[1]);
215  }
216 
217  return true;
218  }
219 
220  double numer = d1343 * d4321 - d1321 * d4343;
221 
222  double mua = clamp(numer / denom, 0.0, 1.0);
223  double mub = clamp((d1343 + d4321 * mua) / d4343, 0.0, 1.0);
224 
225  _result.Set(this->pts[0] + (p21 * static_cast<T>(mua)),
226  _line[0] + (p43 * static_cast<T>(mub)));
227 
228  return true;
229  }
230 
234  public: T Distance(const Vector3<T> &_pt)
235  {
236  auto line = this->pts[1] - this->pts[0];
237  auto ptTo0 = _pt - this->pts[0];
238  auto ptTo1 = _pt - this->pts[1];
239 
240  // Point is projected beyond pt0 or the line has length 0
241  if (ptTo0.Dot(line) <= static_cast<T>(0))
242  {
243  return ptTo0.Length();
244  }
245 
246  // Point is projected beyond pt1
247  if (ptTo1.Dot(line) >= static_cast<T>(0))
248  {
249  return ptTo1.Length();
250  }
251 
252  // Distance to point projected onto line
253  // line.Length() will have to be > 0 at this point otherwise it would
254  // return at line 244.
255  auto d = ptTo0.Cross(line);
256  auto lineLength = line.Length();
257  assert(lineLength > 0);
258  return d.Length() / lineLength;
259  }
260 
266  public: bool Intersect(const Line3<T> &_line,
267  double _epsilon = 1e-6) const
268  {
269  static math::Vector3<T> ignore;
270  return this->Intersect(_line, ignore, _epsilon);
271  }
272 
278  public: bool Coplanar(const Line3<T> &_line,
279  const double _epsilon = 1e-6) const
280  {
281  return std::abs((_line[0] - this->pts[0]).Dot(
282  (this->pts[1] - this->pts[0]).Cross(_line[1] - _line[0])))
283  <= _epsilon;
284  }
285 
291  public: bool Parallel(const Line3<T> &_line,
292  const double _epsilon = 1e-6) const
293  {
294  return (this->pts[1] - this->pts[0]).Cross(
295  _line[1] - _line[0]).Length() <= _epsilon;
296  }
297 
306  public: bool Intersect(const Line3<T> &_line, math::Vector3<T> &_pt,
307  double _epsilon = 1e-6) const
308  {
309  // Handle special case when lines are parallel
310  if (this->Parallel(_line, _epsilon))
311  {
312  // Check if _line's starting point is on the line.
313  if (this->Within(_line[0], _epsilon))
314  {
315  _pt = _line[0];
316  return true;
317  }
318  // Check if _line's ending point is on the line.
319  else if (this->Within(_line[1], _epsilon))
320  {
321  _pt = _line[1];
322  return true;
323  }
324  // Otherwise return false.
325  else
326  return false;
327  }
328 
329  // Get the line that is the shortest distance between this and _line
330  math::Line3<T> distLine;
331  this->Distance(_line, distLine, _epsilon);
332 
333  // If the length of the line is less than epsilon, then they
334  // intersect.
335  if (distLine.Length() < _epsilon)
336  {
337  _pt = distLine[0];
338  return true;
339  }
340 
341  return false;
342  }
343 
350  public: bool Within(const math::Vector3<T> &_pt,
351  double _epsilon = 1e-6) const
352  {
353  auto eps = static_cast<T>(_epsilon);
354  return _pt.X() <= std::max(this->pts[0].X(),
355  this->pts[1].X()) + eps &&
356  _pt.X() >= std::min(this->pts[0].X(),
357  this->pts[1].X()) - eps &&
358  _pt.Y() <= std::max(this->pts[0].Y(),
359  this->pts[1].Y()) + eps &&
360  _pt.Y() >= std::min(this->pts[0].Y(),
361  this->pts[1].Y()) - eps &&
362  _pt.Z() <= std::max(this->pts[0].Z(),
363  this->pts[1].Z()) + eps &&
364  _pt.Z() >= std::min(this->pts[0].Z(),
365  this->pts[1].Z()) - eps;
366  }
367 
371  public: bool operator==(const Line3<T> &_line) const
372  {
373  return this->pts[0] == _line[0] && this->pts[1] == _line[1];
374  }
375 
379  public: bool operator!=(const Line3<T> &_line) const
380  {
381  return !(*this == _line);
382  }
383 
387  public: math::Vector3<T> operator[](const size_t _index) const
388  {
389  return this->pts[clamp(_index, GZ_ZERO_SIZE_T, GZ_ONE_SIZE_T)];
390  }
391 
396  public: friend std::ostream &operator<<(
397  std::ostream &_out, const Line3<T> &_line)
398  {
399  _out << _line[0] << " " << _line[1];
400  return _out;
401  }
402 
406  public: Line3 &operator=(const Line3<T> &_line) = default;
407 
409  private: math::Vector3<T> pts[2];
410  };
411 
415  } // namespace GZ_MATH_VERSION_NAMESPACE_
416 } // namespace gz::math
417 #endif // GZ_MATH_LINE3_HH_