Lagrange
point_triangle_squared_distance.h
1// Source: https://github.com/alicevision/geogram/blob/master/src/lib/geogram/basic/geometry_nd.h
2// SPDX-License-Identifier: BSD-3-Clause
3//
4// Copyright (c) 2012-2014, Bruno Levy
5// All rights reserved.
6//
7// Redistribution and use in source and binary forms, with or without
8// modification, are permitted provided that the following conditions are met:
9//
10// * Redistributions of source code must retain the above copyright notice,
11// this list of conditions and the following disclaimer.
12// * Redistributions in binary form must reproduce the above copyright notice,
13// this list of conditions and the following disclaimer in the documentation
14// and/or other materials provided with the distribution.
15// * Neither the name of the ALICE Project-Team nor the names of its
16// contributors may be used to endorse or promote products derived from this
17// software without specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29// POSSIBILITY OF SUCH DAMAGE.
30//
31// If you modify this software, you should include a notice giving the
32// name of the person performing the modification, the date of modification,
33// and the reason for such modification.
34//
35// Contact: Bruno Levy
36//
37// Bruno.Levy@inria.fr
38// http://www.loria.fr/~levy
39//
40// ALICE Project
41// LORIA, INRIA Lorraine,
42// Campus Scientifique, BP 239
43// 54506 VANDOEUVRE LES NANCY CEDEX
44// FRANCE
45//
46// This file has been modified by Adobe.
47//
48// All modifications are Copyright 2020 Adobe.
49//
50#pragma once
51
52#include <lagrange/common.h>
53#include <lagrange/utils/point_segment_squared_distance.h>
54
55#include <Eigen/Core>
56
57namespace lagrange {
58
76template <typename PointType>
78 const Eigen::MatrixBase<PointType>& point,
79 const Eigen::MatrixBase<PointType>& V0,
80 const Eigen::MatrixBase<PointType>& V1,
81 const Eigen::MatrixBase<PointType>& V2,
82 Eigen::PlainObjectBase<PointType>& closest_point,
83 ScalarOf<PointType>& lambda0,
84 ScalarOf<PointType>& lambda1,
85 ScalarOf<PointType>& lambda2) -> ScalarOf<PointType>
86{
87 using Scalar = ScalarOf<PointType>;
88
89 Eigen::Vector3d diff = V0.template cast<double>() - point.template cast<double>();
90 Eigen::Vector3d edge0 = V1.template cast<double>() - V0.template cast<double>();
91 Eigen::Vector3d edge1 = V2.template cast<double>() - V0.template cast<double>();
92 double a00 = edge0.squaredNorm();
93 double a01 = edge0.dot(edge1);
94 double a11 = edge1.squaredNorm();
95 double b0 = diff.dot(edge0);
96 double b1 = diff.dot(edge1);
97 double c = diff.squaredNorm();
98 double det = std::fabs(a00 * a11 - a01 * a01);
99 double s = a01 * b1 - a11 * b0;
100 double t = a01 * b0 - a00 * b1;
101 double sqr_distance;
102
103 // If the triangle is degenerate
104 if (det < 1e-30) {
105 Scalar cur_l1, cur_l2;
106 PointType cur_closest;
107 Scalar result;
108 Scalar cur_dist =
109 point_segment_squared_distance(point, V0, V1, cur_closest, cur_l1, cur_l2);
110 result = cur_dist;
111 closest_point = cur_closest;
112 lambda0 = cur_l1;
113 lambda1 = cur_l2;
114 lambda2 = 0;
115 cur_dist = point_segment_squared_distance(point, V0, V2, cur_closest, cur_l1, cur_l2);
116 if (cur_dist < result) {
117 result = cur_dist;
118 closest_point = cur_closest;
119 lambda0 = cur_l1;
120 lambda2 = cur_l2;
121 lambda1 = Scalar(0);
122 }
123 cur_dist = point_segment_squared_distance(point, V1, V2, cur_closest, cur_l1, cur_l2);
124 if (cur_dist < result) {
125 result = cur_dist;
126 closest_point = cur_closest;
127 lambda1 = cur_l1;
128 lambda2 = cur_l2;
129 lambda0 = Scalar(0);
130 }
131 return result;
132 }
133
134 if (s + t <= det) {
135 if (s < 0) {
136 if (t < 0) { // region 4
137 if (b0 < 0) {
138 t = 0;
139 if (-b0 >= a00) {
140 s = 1;
141 sqr_distance = a00 + 2 * b0 + c;
142 } else {
143 s = -b0 / a00;
144 sqr_distance = b0 * s + c;
145 }
146 } else {
147 s = 0;
148 if (b1 >= 0) {
149 t = 0;
150 sqr_distance = c;
151 } else if (-b1 >= a11) {
152 t = 1;
153 sqr_distance = a11 + 2 * b1 + c;
154 } else {
155 t = -b1 / a11;
156 sqr_distance = b1 * t + c;
157 }
158 }
159 } else { // region 3
160 s = 0;
161 if (b1 >= 0) {
162 t = 0;
163 sqr_distance = c;
164 } else if (-b1 >= a11) {
165 t = 1;
166 sqr_distance = a11 + 2 * b1 + c;
167 } else {
168 t = -b1 / a11;
169 sqr_distance = b1 * t + c;
170 }
171 }
172 } else if (t < 0) { // region 5
173 t = 0;
174 if (b0 >= 0) {
175 s = 0;
176 sqr_distance = c;
177 } else if (-b0 >= a00) {
178 s = 1;
179 sqr_distance = a00 + 2 * b0 + c;
180 } else {
181 s = -b0 / a00;
182 sqr_distance = b0 * s + c;
183 }
184 } else { // region 0
185 // minimum at interior point
186 double inv_det = double(1) / det;
187 s *= inv_det;
188 t *= inv_det;
189 sqr_distance = s * (a00 * s + a01 * t + 2 * b0) + t * (a01 * s + a11 * t + 2 * b1) + c;
190 }
191 } else {
192 double tmp0, tmp1, numer, denom;
193
194 if (s < 0) { // region 2
195 tmp0 = a01 + b0;
196 tmp1 = a11 + b1;
197 if (tmp1 > tmp0) {
198 numer = tmp1 - tmp0;
199 denom = a00 - 2 * a01 + a11;
200 if (numer >= denom) {
201 s = 1;
202 t = 0;
203 sqr_distance = a00 + 2 * b0 + c;
204 } else {
205 s = numer / denom;
206 t = 1 - s;
207 sqr_distance =
208 s * (a00 * s + a01 * t + 2 * b0) + t * (a01 * s + a11 * t + 2 * b1) + c;
209 }
210 } else {
211 s = 0;
212 if (tmp1 <= 0) {
213 t = 1;
214 sqr_distance = a11 + 2 * b1 + c;
215 } else if (b1 >= 0) {
216 t = 0;
217 sqr_distance = c;
218 } else {
219 t = -b1 / a11;
220 sqr_distance = b1 * t + c;
221 }
222 }
223 } else if (t < 0) { // region 6
224 tmp0 = a01 + b1;
225 tmp1 = a00 + b0;
226 if (tmp1 > tmp0) {
227 numer = tmp1 - tmp0;
228 denom = a00 - 2 * a01 + a11;
229 if (numer >= denom) {
230 t = 1;
231 s = 0;
232 sqr_distance = a11 + 2 * b1 + c;
233 } else {
234 t = numer / denom;
235 s = 1 - t;
236 sqr_distance =
237 s * (a00 * s + a01 * t + 2 * b0) + t * (a01 * s + a11 * t + 2 * b1) + c;
238 }
239 } else {
240 t = 0;
241 if (tmp1 <= 0) {
242 s = 1;
243 sqr_distance = a00 + 2 * b0 + c;
244 } else if (b0 >= 0) {
245 s = 0;
246 sqr_distance = c;
247 } else {
248 s = -b0 / a00;
249 sqr_distance = b0 * s + c;
250 }
251 }
252 } else { // region 1
253 numer = a11 + b1 - a01 - b0;
254 if (numer <= 0) {
255 s = 0;
256 t = 1;
257 sqr_distance = a11 + 2 * b1 + c;
258 } else {
259 denom = a00 - 2 * a01 + a11;
260 if (numer >= denom) {
261 s = 1;
262 t = 0;
263 sqr_distance = a00 + 2 * b0 + c;
264 } else {
265 s = numer / denom;
266 t = 1 - s;
267 sqr_distance =
268 s * (a00 * s + a01 * t + 2 * b0) + t * (a01 * s + a11 * t + 2 * b1) + c;
269 }
270 }
271 }
272 }
273
274 // Account for numerical round-off error.
275 if (sqr_distance < 0) {
276 sqr_distance = 0;
277 }
278
279 closest_point = (V0.template cast<double>() + s * edge0 + t * edge1).template cast<Scalar>();
280 lambda0 = Scalar(1 - s - t);
281 lambda1 = Scalar(s);
282 lambda2 = Scalar(t);
283 return Scalar(sqr_distance);
284}
285
299template <typename PointType>
301 const Eigen::MatrixBase<PointType>& point,
302 const Eigen::MatrixBase<PointType>& V0,
303 const Eigen::MatrixBase<PointType>& V1,
304 const Eigen::MatrixBase<PointType>& V2) -> ScalarOf<PointType>
305{
306 PointType closest_point;
307 ScalarOf<PointType> lambda1, lambda2, lambda3;
309 point,
310 V0,
311 V1,
312 V2,
313 closest_point,
314 lambda1,
315 lambda2,
316 lambda3);
317}
318
319} // namespace lagrange
Main namespace for Lagrange.
Definition: AABBIGL.h:30
auto point_segment_squared_distance(const Eigen::MatrixBase< PointType > &point, const Eigen::MatrixBase< PointType > &V0, const Eigen::MatrixBase< PointType > &V1, Eigen::PlainObjectBase< PointType > &closest_point, ScalarOf< PointType > &lambda0, ScalarOf< PointType > &lambda1) -> ScalarOf< PointType >
Computes the point closest to a given point in a nd segment.
Definition: point_segment_squared_distance.h:73
auto point_triangle_squared_distance(const Eigen::MatrixBase< PointType > &point, const Eigen::MatrixBase< PointType > &V0, const Eigen::MatrixBase< PointType > &V1, const Eigen::MatrixBase< PointType > &V2, Eigen::PlainObjectBase< PointType > &closest_point, ScalarOf< PointType > &lambda0, ScalarOf< PointType > &lambda1, ScalarOf< PointType > &lambda2) -> ScalarOf< PointType >
Computes the point closest to a given point in a nd triangle.
Definition: point_triangle_squared_distance.h:77