coal 3.0.1
Coal, The Collision Detection Library. Previously known as HPP-FCL, fork of FCL -- The Flexible Collision Library
Loading...
Searching...
No Matches
intersect.hxx
Go to the documentation of this file.
1/*
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2011-2014, Willow Garage, Inc.
5 * Copyright (c) 2014-2015, Open Source Robotics Foundation
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer in the documentation and/or other materials provided
17 * with the distribution.
18 * * Neither the name of Open Source Robotics Foundation nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 */
35
38#ifndef COAL_INTERSECT_HXX
39#define COAL_INTERSECT_HXX
40
42#include "coal/internal/tools.h"
43
44#include <iostream>
45#include <limits>
46#include <vector>
47#include <cmath>
48
49namespace coal {
50
51template <typename Scalar>
52inline typename Project<Scalar>::ProjectResult Project<Scalar>::projectLine(
53 const Vec3& a, const Vec3& b, const Vec3& p) {
54 ProjectResult res;
55
56 const Vec3 d = b - a;
57 const Scalar l = d.squaredNorm();
58
59 if (l > 0) {
60 const Scalar t = (p - a).dot(d);
61 res.parameterization[1] = (t >= l) ? 1 : ((t <= 0) ? 0 : (t / l));
62 res.parameterization[0] = 1 - res.parameterization[1];
63 if (t >= l) {
64 res.sqr_distance = (p - b).squaredNorm();
65 res.encode = 2; /* 0x10 */
66 } else if (t <= 0) {
67 res.sqr_distance = (p - a).squaredNorm();
68 res.encode = 1; /* 0x01 */
69 } else {
70 res.sqr_distance = (a + d * res.parameterization[1] - p).squaredNorm();
71 res.encode = 3; /* 0x00 */
72 }
73 }
74
75 return res;
76}
77
78template <typename Scalar>
79inline typename Project<Scalar>::ProjectResult Project<Scalar>::projectTriangle(
80 const Vec3& a, const Vec3& b, const Vec3& c, const Vec3& p) {
81 ProjectResult res;
82
83 static const size_t nexti[3] = {1, 2, 0};
84 const Vec3* vt[] = {&a, &b, &c};
85 const Vec3 dl[] = {a - b, b - c, c - a};
86 const Vec3& n = dl[0].cross(dl[1]);
87 const Scalar l = n.squaredNorm();
88
89 if (l > 0) {
90 Scalar mindist = -1;
91 for (size_t i = 0; i < 3; ++i) {
92 if ((*vt[i] - p).dot(dl[i].cross(n)) >
93 0) // origin is to the outside part of the triangle edge, then the
94 // optimal can only be on the edge
95 {
96 size_t j = nexti[i];
97 ProjectResult res_line = projectLine(*vt[i], *vt[j], p);
98
99 if (mindist < 0 || res_line.sqr_distance < mindist) {
100 mindist = res_line.sqr_distance;
101 res.encode =
102 static_cast<unsigned int>(((res_line.encode & 1) ? 1 << i : 0) +
103 ((res_line.encode & 2) ? 1 << j : 0));
104 res.parameterization[i] = res_line.parameterization[0];
105 res.parameterization[j] = res_line.parameterization[1];
106 res.parameterization[nexti[j]] = 0;
107 }
108 }
109 }
110
111 if (mindist < 0) // the origin project is within the triangle
112 {
113 Scalar d = (a - p).dot(n);
114 Scalar s = std::sqrt(l);
115 Vec3 p_to_project = n * (d / l);
116 mindist = p_to_project.squaredNorm();
117 res.encode = 7; // m = 0x111
118 res.parameterization[0] = dl[1].cross(b - p - p_to_project).norm() / s;
119 res.parameterization[1] = dl[2].cross(c - p - p_to_project).norm() / s;
120 res.parameterization[2] =
121 1 - res.parameterization[0] - res.parameterization[1];
122 }
123
124 res.sqr_distance = mindist;
125 }
126
127 return res;
128}
129
130template <typename Scalar>
131inline typename Project<Scalar>::ProjectResult
132Project<Scalar>::projectTetrahedra(const Vec3& a, const Vec3& b, const Vec3& c,
133 const Vec3& d, const Vec3& p) {
134 ProjectResult res;
135
136 static const size_t nexti[] = {1, 2, 0};
137 const Vec3* vt[] = {&a, &b, &c, &d};
138 const Vec3 dl[3] = {a - d, b - d, c - d};
139 Scalar vl = triple(dl[0], dl[1], dl[2]);
140 bool ng = (vl * (a - p).dot((b - c).cross(a - b))) <= 0;
141 if (ng &&
142 std::abs(vl) > 0) // abs(vl) == 0, the tetrahedron is degenerated; if ng
143 // is false, then the last vertex in the tetrahedron
144 // does not grow toward the origin (in fact origin is
145 // on the other side of the abc face)
146 {
147 Scalar mindist = -1;
148
149 for (size_t i = 0; i < 3; ++i) {
150 size_t j = nexti[i];
151 Scalar s = vl * (d - p).dot(dl[i].cross(dl[j]));
152 if (s > 0) // the origin is to the outside part of a triangle face, then
153 // the optimal can only be on the triangle face
154 {
155 ProjectResult res_triangle = projectTriangle(*vt[i], *vt[j], d, p);
156 if (mindist < 0 || res_triangle.sqr_distance < mindist) {
157 mindist = res_triangle.sqr_distance;
158 res.encode =
159 static_cast<unsigned int>((res_triangle.encode & 1 ? 1 << i : 0) +
160 (res_triangle.encode & 2 ? 1 << j : 0) +
161 (res_triangle.encode & 4 ? 8 : 0));
162 res.parameterization[i] = res_triangle.parameterization[0];
163 res.parameterization[j] = res_triangle.parameterization[1];
164 res.parameterization[nexti[j]] = 0;
165 res.parameterization[3] = res_triangle.parameterization[2];
166 }
167 }
168 }
169
170 if (mindist < 0) {
171 mindist = 0;
172 res.encode = 15;
173 res.parameterization[0] = triple(c - p, b - p, d - p) / vl;
174 res.parameterization[1] = triple(a - p, c - p, d - p) / vl;
175 res.parameterization[2] = triple(b - p, a - p, d - p) / vl;
176 res.parameterization[3] =
177 1 - (res.parameterization[0] + res.parameterization[1] +
178 res.parameterization[2]);
179 }
180
181 res.sqr_distance = mindist;
182 } else if (!ng) {
183 res = projectTriangle(a, b, c, p);
184 res.parameterization[3] = 0;
185 }
186 return res;
187}
188
189template <typename Scalar>
190inline typename Project<Scalar>::ProjectResult
191Project<Scalar>::projectLineOrigin(const Vec3& a, const Vec3& b) {
192 ProjectResult res;
193
194 const Vec3 d = b - a;
195 const Scalar l = d.squaredNorm();
196
197 if (l > 0) {
198 const Scalar t = -a.dot(d);
199 res.parameterization[1] = (t >= l) ? 1 : ((t <= 0) ? 0 : (t / l));
200 res.parameterization[0] = 1 - res.parameterization[1];
201 if (t >= l) {
202 res.sqr_distance = b.squaredNorm();
203 res.encode = 2; /* 0x10 */
204 } else if (t <= 0) {
205 res.sqr_distance = a.squaredNorm();
206 res.encode = 1; /* 0x01 */
207 } else {
208 res.sqr_distance = (a + d * res.parameterization[1]).squaredNorm();
209 res.encode = 3; /* 0x00 */
210 }
211 }
212
213 return res;
214}
215
216template <typename Scalar>
217inline typename Project<Scalar>::ProjectResult
218Project<Scalar>::projectTriangleOrigin(const Vec3& a, const Vec3& b,
219 const Vec3& c) {
220 ProjectResult res;
221
222 static const size_t nexti[3] = {1, 2, 0};
223 const Vec3* vt[] = {&a, &b, &c};
224 const Vec3 dl[] = {a - b, b - c, c - a};
225 const Vec3& n = dl[0].cross(dl[1]);
226 const Scalar l = n.squaredNorm();
227
228 if (l > 0) {
229 Scalar mindist = -1;
230 for (size_t i = 0; i < 3; ++i) {
231 if (vt[i]->dot(dl[i].cross(n)) >
232 0) // origin is to the outside part of the triangle edge, then the
233 // optimal can only be on the edge
234 {
235 size_t j = nexti[i];
236 ProjectResult res_line = projectLineOrigin(*vt[i], *vt[j]);
237
238 if (mindist < 0 || res_line.sqr_distance < mindist) {
239 mindist = res_line.sqr_distance;
240 res.encode =
241 static_cast<unsigned int>(((res_line.encode & 1) ? 1 << i : 0) +
242 ((res_line.encode & 2) ? 1 << j : 0));
243 res.parameterization[i] = res_line.parameterization[0];
244 res.parameterization[j] = res_line.parameterization[1];
245 res.parameterization[nexti[j]] = 0;
246 }
247 }
248 }
249
250 if (mindist < 0) // the origin project is within the triangle
251 {
252 Scalar d = a.dot(n);
253 Scalar s = std::sqrt(l);
254 Vec3 o_to_project = n * (d / l);
255 mindist = o_to_project.squaredNorm();
256 res.encode = 7; // m = 0x111
257 res.parameterization[0] = dl[1].cross(b - o_to_project).norm() / s;
258 res.parameterization[1] = dl[2].cross(c - o_to_project).norm() / s;
259 res.parameterization[2] =
260 1 - res.parameterization[0] - res.parameterization[1];
261 }
262
263 res.sqr_distance = mindist;
264 }
265
266 return res;
267}
268
269template <typename Scalar>
270inline typename Project<Scalar>::ProjectResult
271Project<Scalar>::projectTetrahedraOrigin(const Vec3& a, const Vec3& b,
272 const Vec3& c, const Vec3& d) {
273 ProjectResult res;
274
275 static const size_t nexti[] = {1, 2, 0};
276 const Vec3* vt[] = {&a, &b, &c, &d};
277 const Vec3 dl[3] = {a - d, b - d, c - d};
278 Scalar vl = triple(dl[0], dl[1], dl[2]);
279 bool ng = (vl * a.dot((b - c).cross(a - b))) <= 0;
280 if (ng &&
281 std::abs(vl) > 0) // abs(vl) == 0, the tetrahedron is degenerated; if ng
282 // is false, then the last vertex in the tetrahedron
283 // does not grow toward the origin (in fact origin is
284 // on the other side of the abc face)
285 {
286 Scalar mindist = -1;
287
288 for (size_t i = 0; i < 3; ++i) {
289 size_t j = nexti[i];
290 Scalar s = vl * d.dot(dl[i].cross(dl[j]));
291 if (s > 0) // the origin is to the outside part of a triangle face, then
292 // the optimal can only be on the triangle face
293 {
294 ProjectResult res_triangle = projectTriangleOrigin(*vt[i], *vt[j], d);
295 if (mindist < 0 || res_triangle.sqr_distance < mindist) {
296 mindist = res_triangle.sqr_distance;
297 res.encode =
298 static_cast<unsigned int>((res_triangle.encode & 1 ? 1 << i : 0) +
299 (res_triangle.encode & 2 ? 1 << j : 0) +
300 (res_triangle.encode & 4 ? 8 : 0));
301 res.parameterization[i] = res_triangle.parameterization[0];
302 res.parameterization[j] = res_triangle.parameterization[1];
303 res.parameterization[nexti[j]] = 0;
304 res.parameterization[3] = res_triangle.parameterization[2];
305 }
306 }
307 }
308
309 if (mindist < 0) {
310 mindist = 0;
311 res.encode = 15;
312 res.parameterization[0] = triple(c, b, d) / vl;
313 res.parameterization[1] = triple(a, c, d) / vl;
314 res.parameterization[2] = triple(b, a, d) / vl;
315 res.parameterization[3] =
316 1 - (res.parameterization[0] + res.parameterization[1] +
317 res.parameterization[2]);
318 }
319
320 res.sqr_distance = mindist;
321 } else if (!ng) {
322 res = projectTriangleOrigin(a, b, c);
323 res.parameterization[3] = 0;
324 }
325 return res;
326}
327
328} // namespace coal
329
330#endif // COAL_INTERSECT_HXX
Main namespace.
Definition broadphase_bruteforce.h:44
double Scalar
Definition data_types.h:68