Gazebo Math

API Reference

9.3.0
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
24namespace 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
42 {
43 this->Set(_ptA, _ptB);
44 }
45
51 public: Line3(const double _x1, const double _y1,
52 const double _x2, const double _y2)
53 {
54 this->Set(_x1, _y1, _x2, _y2);
55 }
56
64 public: Line3(const double _x1, const double _y1,
65 const double _z1, const double _x2,
66 const double _y2, const double _z2)
67 {
68 this->Set(_x1, _y1, _z1, _x2, _y2, _z2);
69 }
70
74 public: void Set(const math::Vector3<T> &_ptA,
76 {
77 this->pts[0] = _ptA;
78 this->pts[1] = _ptB;
79 }
80
83 public: void SetA(const math::Vector3<T> &_ptA)
84 {
85 this->pts[0] = _ptA;
86 }
87
90 public: void SetB(const math::Vector3<T> &_ptB)
91 {
92 this->pts[1] = _ptB;
93 }
94
103 public: void Set(const double _x1, const double _y1,
104 const double _x2, const double _y2,
105 const double _z = 0)
106 {
107 this->pts[0].Set(
108 static_cast<T>(_x1), static_cast<T>(_y1), static_cast<T>(_z));
109 this->pts[1].Set(
110 static_cast<T>(_x2), static_cast<T>(_y2), static_cast<T>(_z));
111 }
112
120 public: void Set(const double _x1, const double _y1,
121 const double _z1, const double _x2,
122 const double _y2, const double _z2)
123 {
124 this->pts[0].Set(
125 static_cast<T>(_x1), static_cast<T>(_y1), static_cast<T>(_z1));
126 this->pts[1].Set(
127 static_cast<T>(_x2), static_cast<T>(_y2), static_cast<T>(_z2));
128 }
129
133 {
134 return (this->pts[1] - this->pts[0]).Normalize();
135 }
136
139 public: T Length() const
140 {
141 return static_cast<T>(this->pts[0].Distance(this->pts[1]));
142 }
143
154 public: bool Distance(const Line3<T> &_line, Line3<T> &_result,
155 const double _epsilon = 1e-6) const
156 {
157 Vector3<T> p13 = this->pts[0] - _line[0];
158 Vector3<T> p43 = _line[1] - _line[0];
159
160 if (std::abs(p43.X()) < _epsilon && std::abs(p43.Y()) < _epsilon &&
161 std::abs(p43.Z()) < _epsilon)
162 {
163 return false;
164 }
165
166 Vector3<T> p21 = this->pts[1] - this->pts[0];
167
168 if (std::abs(p21.X()) < _epsilon && std::abs(p21.Y()) < _epsilon &&
169 std::abs(p21.Z()) < _epsilon)
170 {
171 return false;
172 }
173
174 double d1343 = p13.Dot(p43);
175 double d4321 = p43.Dot(p21);
176 double d1321 = p13.Dot(p21);
177 double d4343 = p43.Dot(p43);
178 double d2121 = p21.Dot(p21);
179
180 double denom = d2121 * d4343 - d4321 * d4321;
181
182 // In this case, we choose the first point in this line,
183 // and the closest point in the provided line.
184 if (std::abs(denom) < _epsilon)
185 {
186 double d1 = this->pts[0].Distance(_line[0]);
187 double d2 = this->pts[0].Distance(_line[1]);
188
189 double d3 = this->pts[1].Distance(_line[0]);
190 double d4 = this->pts[1].Distance(_line[1]);
191
192 if (d1 <= d2 && d1 <= d3 && d1 <= d4)
193 {
194 _result.SetA(this->pts[0]);
195 _result.SetB(_line[0]);
196 }
197 else if (d2 <= d3 && d2 <= d4)
198 {
199 _result.SetA(this->pts[0]);
200 _result.SetB(_line[1]);
201 }
202 else if (d3 <= d4)
203 {
204 _result.SetA(this->pts[1]);
205 _result.SetB(_line[0]);
206 }
207 else
208 {
209 _result.SetA(this->pts[1]);
210 _result.SetB(_line[1]);
211 }
212
213 return true;
214 }
215
216 double numer = d1343 * d4321 - d1321 * d4343;
217
218 double mua = clamp(numer / denom, 0.0, 1.0);
219 double mub = clamp((d1343 + d4321 * mua) / d4343, 0.0, 1.0);
220
221 _result.Set(this->pts[0] + (p21 * static_cast<T>(mua)),
222 _line[0] + (p43 * static_cast<T>(mub)));
223
224 return true;
225 }
226
230 public: T Distance(const Vector3<T> &_pt)
231 {
232 auto line = this->pts[1] - this->pts[0];
233 auto ptTo0 = _pt - this->pts[0];
234 auto ptTo1 = _pt - this->pts[1];
235
236 // Point is projected beyond pt0 or the line has length 0
237 if (ptTo0.Dot(line) <= static_cast<T>(0))
238 {
239 return ptTo0.Length();
240 }
241
242 // Point is projected beyond pt1
243 if (ptTo1.Dot(line) >= static_cast<T>(0))
244 {
245 return ptTo1.Length();
246 }
247
248 // Distance to point projected onto line
249 // line.Length() will have to be > 0 at this point otherwise it would
250 // return at line 244.
251 auto d = ptTo0.Cross(line);
252 auto lineLength = line.Length();
253 assert(lineLength > 0);
254 return d.Length() / lineLength;
255 }
256
262 public: bool Intersect(const Line3<T> &_line,
263 double _epsilon = 1e-6) const
264 {
265 math::Vector3<T> ignore;
266 return this->Intersect(_line, ignore, _epsilon);
267 }
268
274 public: bool Coplanar(const Line3<T> &_line,
275 const double _epsilon = 1e-6) const
276 {
277 return std::abs((_line[0] - this->pts[0]).Dot(
278 (this->pts[1] - this->pts[0]).Cross(_line[1] - _line[0])))
279 <= _epsilon;
280 }
281
287 public: bool Parallel(const Line3<T> &_line,
288 const double _epsilon = 1e-6) const
289 {
290 return (this->pts[1] - this->pts[0]).Cross(
291 _line[1] - _line[0]).Length() <= _epsilon;
292 }
293
303 double _epsilon = 1e-6) const
304 {
305 // Handle special case when lines are parallel
306 if (this->Parallel(_line, _epsilon))
307 {
308 // Check if _line's starting point is on the line.
309 if (this->Within(_line[0], _epsilon))
310 {
311 _pt = _line[0];
312 return true;
313 }
314 // Check if _line's ending point is on the line.
315 else if (this->Within(_line[1], _epsilon))
316 {
317 _pt = _line[1];
318 return true;
319 }
320 // Otherwise return false.
321 else
322 return false;
323 }
324
325 // Get the line that is the shortest distance between this and _line
327 this->Distance(_line, distLine, _epsilon);
328
329 // If the length of the line is less than epsilon, then they
330 // intersect.
331 if (distLine.Length() < _epsilon)
332 {
333 _pt = distLine[0];
334 return true;
335 }
336
337 return false;
338 }
339
346 public: bool Within(const math::Vector3<T> &_pt,
347 double _epsilon = 1e-6) const
348 {
349 auto eps = static_cast<T>(_epsilon);
350 return _pt.X() <= std::max(this->pts[0].X(),
351 this->pts[1].X()) + eps &&
352 _pt.X() >= std::min(this->pts[0].X(),
353 this->pts[1].X()) - eps &&
354 _pt.Y() <= std::max(this->pts[0].Y(),
355 this->pts[1].Y()) + eps &&
356 _pt.Y() >= std::min(this->pts[0].Y(),
357 this->pts[1].Y()) - eps &&
358 _pt.Z() <= std::max(this->pts[0].Z(),
359 this->pts[1].Z()) + eps &&
360 _pt.Z() >= std::min(this->pts[0].Z(),
361 this->pts[1].Z()) - eps;
362 }
363
367 public: bool operator==(const Line3<T> &_line) const
368 {
369 return this->pts[0] == _line[0] && this->pts[1] == _line[1];
370 }
371
375 public: bool operator!=(const Line3<T> &_line) const
376 {
377 return !(*this == _line);
378 }
379
383 public: math::Vector3<T> operator[](const size_t _index) const
384 {
385 return this->pts[clamp(_index, GZ_ZERO_SIZE_T, GZ_ONE_SIZE_T)];
386 }
387
392 public: friend std::ostream &operator<<(
394 {
395 _out << _line[0] << " " << _line[1];
396 return _out;
397 }
398
400 private: math::Vector3<T> pts[2];
401 };
402
406 } // namespace GZ_MATH_VERSION_NAMESPACE_
407} // namespace gz::math
408#endif // GZ_MATH_LINE3_HH_