Lagrange
Loading...
Searching...
No Matches
compute_barycentric_coordinates.h
1/*
2 * Copyright 2020 Adobe. All rights reserved.
3 * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License. You may obtain a copy
5 * of the License at http://www.apache.org/licenses/LICENSE-2.0
6 *
7 * Unless required by applicable law or agreed to in writing, software distributed under
8 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9 * OF ANY KIND, either express or implied. See the License for the specific language
10 * governing permissions and limitations under the License.
11 */
12#pragma once
13
14#include <lagrange/utils/assert.h>
15
16// clang-format off
17#include <lagrange/utils/warnoff.h>
18#include <Eigen/Dense>
19#include <lagrange/utils/warnon.h>
20// clang-format on
21
22#include <cmath>
23#include <limits>
24
25namespace lagrange {
26
44template <typename PointType>
46 const Eigen::MatrixBase<PointType>& v0,
47 const Eigen::MatrixBase<PointType>& v1,
48 const Eigen::MatrixBase<PointType>& v2,
49 const Eigen::MatrixBase<PointType>& p) -> Eigen::Matrix<typename PointType::Scalar, 3, 1>
50{
51 using Scalar = typename PointType::Scalar;
52
53 // Compile-time size info. For fully dynamic vectors (e.g. VectorXd), both are Dynamic and we
54 // cap internal matrices at dim 3 to avoid heap allocation.
55 constexpr int Dim = PointType::SizeAtCompileTime;
56 constexpr int MaxDim = PointType::MaxSizeAtCompileTime;
57 // Cap at 3 for stack allocation: use known max if available, otherwise 3.
58 constexpr int EffectiveMaxDim = (MaxDim != Eigen::Dynamic) ? MaxDim : 3;
59 constexpr int Rows = (Dim != Eigen::Dynamic) ? Dim + 1 : Eigen::Dynamic;
60 constexpr int MaxRows = EffectiveMaxDim + 1;
61
62 const Eigen::Index dim = p.size();
63 la_debug_assert(dim <= EffectiveMaxDim && "Point dimension exceeds maximum supported size.");
64 la_debug_assert(v0.size() == dim);
65 la_debug_assert(v1.size() == dim);
66 la_debug_assert(v2.size() == dim);
67
68 // Fast path: solve 2x2 Gram matrix system via projection.
69 // e1 = v1 - v0, e2 = v2 - v0, ep = p - v0
70 // G = [e1·e1 e1·e2] b = [ep·e1]
71 // [e1·e2 e2·e2] [ep·e2]
72 // G * [u; v] = b => p ≈ (1-u-v)*v0 + u*v1 + v*v2
73 const auto e1 = (v1 - v0).eval();
74 const auto e2 = (v2 - v0).eval();
75 const auto ep = (p - v0).eval();
76
77 Eigen::Matrix<Scalar, 2, 2> G;
78 G(0, 0) = e1.squaredNorm();
79 G(0, 1) = e1.dot(e2);
80 G(1, 0) = G(0, 1);
81 G(1, 1) = e2.squaredNorm();
82
83 const Scalar det = G.determinant();
84 const Scalar tol = std::numeric_limits<Scalar>::epsilon() * G(0, 0) * G(1, 1);
85
86 if (std::abs(det) > tol) {
87 // Non-degenerate triangle: direct 2x2 solve.
88 const Eigen::Matrix<Scalar, 2, 1> b(ep.dot(e1), ep.dot(e2));
89 const Eigen::Matrix<Scalar, 2, 1> uv = G.inverse() * b;
90
91 Eigen::Matrix<Scalar, 3, 1> bary;
92 bary(0) = Scalar(1) - uv(0) - uv(1);
93 bary(1) = uv(0);
94 bary(2) = uv(1);
95 return bary;
96 }
97
98 // Slow path for degenerate triangles: constrained least-squares with partition-of-unity.
99 // [ v0 v1 v2 ] [ p ]
100 // [ 1 1 1 ] * b = [ 1 ]
101 Eigen::Matrix<Scalar, Rows, 3, 0, MaxRows, 3> M(dim + 1, 3);
102 M.row(dim).setOnes();
103 for (Eigen::Index d = 0; d < dim; ++d) {
104 M(d, 0) = v0[d];
105 M(d, 1) = v1[d];
106 M(d, 2) = v2[d];
107 }
108
109 Eigen::Matrix<Scalar, Rows, 1, 0, MaxRows, 1> rhs(dim + 1);
110 for (Eigen::Index d = 0; d < dim; ++d) {
111 rhs(d) = p[d];
112 }
113 rhs(dim) = Scalar(1);
114
115 return M.colPivHouseholderQr().solve(rhs);
116}
117
118
119} // namespace lagrange
@ Scalar
Mesh attribute must have exactly 1 channel.
Definition AttributeFwd.h:56
#define la_debug_assert(...)
Debug assertion check.
Definition assert.h:195
Main namespace for Lagrange.
auto compute_barycentric_coordinates(const Eigen::MatrixBase< PointType > &v0, const Eigen::MatrixBase< PointType > &v1, const Eigen::MatrixBase< PointType > &v2, const Eigen::MatrixBase< PointType > &p) -> Eigen::Matrix< typename PointType::Scalar, 3, 1 >
Compute the barycentric coordinates of point p with respect to triangle (v0, v1, v2).
Definition compute_barycentric_coordinates.h:45