Lagrange
Loading...
Searching...
No Matches
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, typename PointType2>
78 const Eigen::MatrixBase<PointType>& point,
79 const Eigen::MatrixBase<PointType2>& V0,
80 const Eigen::MatrixBase<PointType2>& V1,
81 const Eigen::MatrixBase<PointType2>& 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 using DoublePointType =
89 Eigen::Matrix<double, PointType::RowsAtCompileTime, PointType::ColsAtCompileTime>;
90
91 DoublePointType diff = V0.template cast<double>() - point.template cast<double>();
92 DoublePointType edge0 = V1.template cast<double>() - V0.template cast<double>();
93 DoublePointType edge1 = V2.template cast<double>() - V0.template cast<double>();
94 double a00 = edge0.squaredNorm();
95 double a01 = edge0.dot(edge1);
96 double a11 = edge1.squaredNorm();
97 double b0 = diff.dot(edge0);
98 double b1 = diff.dot(edge1);
99 double c = diff.squaredNorm();
100 double det = std::fabs(a00 * a11 - a01 * a01);
101 double s = a01 * b1 - a11 * b0;
102 double t = a01 * b0 - a00 * b1;
103 double sqr_distance;
104
105 // If the triangle is degenerate
106 if (det < 1e-30) {
107 Scalar cur_l1, cur_l2;
108 PointType cur_closest;
109 Scalar result;
110 Scalar cur_dist =
111 point_segment_squared_distance(point, V0, V1, cur_closest, cur_l1, cur_l2);
112 result = cur_dist;
113 closest_point = cur_closest;
114 lambda0 = cur_l1;
115 lambda1 = cur_l2;
116 lambda2 = 0;
117 cur_dist = point_segment_squared_distance(point, V0, V2, cur_closest, cur_l1, cur_l2);
118 if (cur_dist < result) {
119 result = cur_dist;
120 closest_point = cur_closest;
121 lambda0 = cur_l1;
122 lambda2 = cur_l2;
123 lambda1 = Scalar(0);
124 }
125 cur_dist = point_segment_squared_distance(point, V1, V2, cur_closest, cur_l1, cur_l2);
126 if (cur_dist < result) {
127 result = cur_dist;
128 closest_point = cur_closest;
129 lambda1 = cur_l1;
130 lambda2 = cur_l2;
131 lambda0 = Scalar(0);
132 }
133 return result;
134 }
135
136 if (s + t <= det) {
137 if (s < 0) {
138 if (t < 0) { // region 4
139 if (b0 < 0) {
140 t = 0;
141 if (-b0 >= a00) {
142 s = 1;
143 sqr_distance = a00 + 2 * b0 + c;
144 } else {
145 s = -b0 / a00;
146 sqr_distance = b0 * s + c;
147 }
148 } else {
149 s = 0;
150 if (b1 >= 0) {
151 t = 0;
152 sqr_distance = c;
153 } else if (-b1 >= a11) {
154 t = 1;
155 sqr_distance = a11 + 2 * b1 + c;
156 } else {
157 t = -b1 / a11;
158 sqr_distance = b1 * t + c;
159 }
160 }
161 } else { // region 3
162 s = 0;
163 if (b1 >= 0) {
164 t = 0;
165 sqr_distance = c;
166 } else if (-b1 >= a11) {
167 t = 1;
168 sqr_distance = a11 + 2 * b1 + c;
169 } else {
170 t = -b1 / a11;
171 sqr_distance = b1 * t + c;
172 }
173 }
174 } else if (t < 0) { // region 5
175 t = 0;
176 if (b0 >= 0) {
177 s = 0;
178 sqr_distance = c;
179 } else if (-b0 >= a00) {
180 s = 1;
181 sqr_distance = a00 + 2 * b0 + c;
182 } else {
183 s = -b0 / a00;
184 sqr_distance = b0 * s + c;
185 }
186 } else { // region 0
187 // minimum at interior point
188 double inv_det = double(1) / det;
189 s *= inv_det;
190 t *= inv_det;
191 sqr_distance = s * (a00 * s + a01 * t + 2 * b0) + t * (a01 * s + a11 * t + 2 * b1) + c;
192 }
193 } else {
194 double tmp0, tmp1, numer, denom;
195
196 if (s < 0) { // region 2
197 tmp0 = a01 + b0;
198 tmp1 = a11 + b1;
199 if (tmp1 > tmp0) {
200 numer = tmp1 - tmp0;
201 denom = a00 - 2 * a01 + a11;
202 if (numer >= denom) {
203 s = 1;
204 t = 0;
205 sqr_distance = a00 + 2 * b0 + c;
206 } else {
207 s = numer / denom;
208 t = 1 - s;
209 sqr_distance =
210 s * (a00 * s + a01 * t + 2 * b0) + t * (a01 * s + a11 * t + 2 * b1) + c;
211 }
212 } else {
213 s = 0;
214 if (tmp1 <= 0) {
215 t = 1;
216 sqr_distance = a11 + 2 * b1 + c;
217 } else if (b1 >= 0) {
218 t = 0;
219 sqr_distance = c;
220 } else {
221 t = -b1 / a11;
222 sqr_distance = b1 * t + c;
223 }
224 }
225 } else if (t < 0) { // region 6
226 tmp0 = a01 + b1;
227 tmp1 = a00 + b0;
228 if (tmp1 > tmp0) {
229 numer = tmp1 - tmp0;
230 denom = a00 - 2 * a01 + a11;
231 if (numer >= denom) {
232 t = 1;
233 s = 0;
234 sqr_distance = a11 + 2 * b1 + c;
235 } else {
236 t = numer / denom;
237 s = 1 - t;
238 sqr_distance =
239 s * (a00 * s + a01 * t + 2 * b0) + t * (a01 * s + a11 * t + 2 * b1) + c;
240 }
241 } else {
242 t = 0;
243 if (tmp1 <= 0) {
244 s = 1;
245 sqr_distance = a00 + 2 * b0 + c;
246 } else if (b0 >= 0) {
247 s = 0;
248 sqr_distance = c;
249 } else {
250 s = -b0 / a00;
251 sqr_distance = b0 * s + c;
252 }
253 }
254 } else { // region 1
255 numer = a11 + b1 - a01 - b0;
256 if (numer <= 0) {
257 s = 0;
258 t = 1;
259 sqr_distance = a11 + 2 * b1 + c;
260 } else {
261 denom = a00 - 2 * a01 + a11;
262 if (numer >= denom) {
263 s = 1;
264 t = 0;
265 sqr_distance = a00 + 2 * b0 + c;
266 } else {
267 s = numer / denom;
268 t = 1 - s;
269 sqr_distance =
270 s * (a00 * s + a01 * t + 2 * b0) + t * (a01 * s + a11 * t + 2 * b1) + c;
271 }
272 }
273 }
274 }
275
276 // Account for numerical round-off error.
277 if (sqr_distance < 0) {
278 sqr_distance = 0;
279 }
280
281 closest_point = (V0.template cast<double>() + s * edge0 + t * edge1).template cast<Scalar>();
282 lambda0 = Scalar(1 - s - t);
283 lambda1 = Scalar(s);
284 lambda2 = Scalar(t);
285 return Scalar(sqr_distance);
286}
287
301template <typename PointType>
303 const Eigen::MatrixBase<PointType>& point,
304 const Eigen::MatrixBase<PointType>& V0,
305 const Eigen::MatrixBase<PointType>& V1,
306 const Eigen::MatrixBase<PointType>& V2) -> ScalarOf<PointType>
307{
308 PointType closest_point;
309 ScalarOf<PointType> lambda1, lambda2, lambda3;
311 point,
312 V0,
313 V1,
314 V2,
315 closest_point,
316 lambda1,
317 lambda2,
318 lambda3);
319}
320
321} // namespace lagrange
@ Scalar
Mesh attribute must have exactly 1 channel.
Definition AttributeFwd.h:56
SurfaceMesh< ToScalar, ToIndex > cast(const SurfaceMesh< FromScalar, FromIndex > &source_mesh, const AttributeFilter &convertible_attributes={}, std::vector< std::string > *converted_attributes_names=nullptr)
Cast a mesh to a mesh of different scalar and/or index type.
Main namespace for Lagrange.
auto point_segment_squared_distance(const Eigen::MatrixBase< PointType > &point, const Eigen::MatrixBase< PointType2 > &V0, const Eigen::MatrixBase< PointType2 > &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< PointType2 > &V0, const Eigen::MatrixBase< PointType2 > &V1, const Eigen::MatrixBase< PointType2 > &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