Lagrange
Loading...
Searching...
No Matches
geometry3d.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/MeshTrait.h>
15#include <Eigen/Dense>
16
17#include <limits>
18
19namespace lagrange {
20
24template <typename Scalar, int _Rows, int _Cols>
26 const Eigen::Matrix<Scalar, _Rows, _Cols>& v1,
27 const Eigen::Matrix<Scalar, _Rows, _Cols>& v2)
28{
29 static_assert((_Rows == 1 && _Cols == 3) || (_Rows == 3 && _Cols == 1), "");
30 Scalar dot = v1.dot(v2);
31 if (dot < -1) return Scalar(-1.0);
32 if (dot > 1) return Scalar(1.0);
33 return dot;
34}
35
37template <typename Scalar, int _Rows, int _Cols>
39 const Eigen::Matrix<Scalar, _Rows, _Cols>& v1,
40 const Eigen::Matrix<Scalar, _Rows, _Cols>& v2)
41{
42 static_assert((_Rows == 1 && _Cols == 3) || (_Rows == 3 && _Cols == 1), "");
43 return std::atan2(v1.cross(v2).norm(), v1.dot(v2));
44}
45
49template <typename Scalar, int _Rows, int _Cols>
50Eigen::Matrix<Scalar, _Rows, _Cols> project_on_line(
51 const Eigen::Matrix<Scalar, _Rows, _Cols>& v1,
52 const Eigen::Matrix<Scalar, _Rows, _Cols>& v2)
53{
54 static_assert((_Rows == 1 && _Cols == 3) || (_Rows == 3 && _Cols == 1), "");
55 return v1.dot(v2) * v2;
56}
57
60template <typename Scalar, int _Rows, int _Cols>
61Eigen::Matrix<Scalar, _Rows, _Cols> project_on_plane(
62 const Eigen::Matrix<Scalar, _Rows, _Cols>& v,
63 const Eigen::Matrix<Scalar, _Rows, _Cols>& n)
64{
65 static_assert((_Rows == 1 && _Cols == 3) || (_Rows == 3 && _Cols == 1), "");
66 return v - project_on_line(v, n);
67}
68
71template <typename Scalar, int _Rows, int _Cols>
73 const Eigen::Matrix<Scalar, _Rows, _Cols>& v1,
74 const Eigen::Matrix<Scalar, _Rows, _Cols>& v2,
75 const Eigen::Matrix<Scalar, _Rows, _Cols>& n)
76{
77 static_assert((_Rows == 1 && _Cols == 3) || (_Rows == 3 && _Cols == 1), "");
78 const Eigen::Matrix<Scalar, _Rows, _Cols> proj1 = project_on_plane(v1, n).stableNormalized();
79 const Eigen::Matrix<Scalar, _Rows, _Cols> proj2 = project_on_plane(v2, n).stableNormalized();
80 return cos_angle_between(proj1, proj2);
81}
82
85template <typename Scalar, int _Rows, int _Cols>
87 const Eigen::Matrix<Scalar, _Rows, _Cols>& v1,
88 const Eigen::Matrix<Scalar, _Rows, _Cols>& v2,
89 const Eigen::Matrix<Scalar, _Rows, _Cols>& n)
90{
91 static_assert((_Rows == 1 && _Cols == 3) || (_Rows == 3 && _Cols == 1), "");
92 const Eigen::Matrix<Scalar, _Rows, _Cols> proj1 = project_on_plane(v1, n);
93 const Eigen::Matrix<Scalar, _Rows, _Cols> proj2 = project_on_plane(v2, n);
94 return std::atan2(proj1.cross(proj2).norm(), proj1.dot(proj2));
95}
96
105template <typename MeshType>
106auto vector_between(const MeshType& mesh, typename MeshType::Index v1, typename MeshType::Index v2)
107{
108 static_assert(MeshTrait<MeshType>::is_mesh(), "MeshType is not a mesh");
109 return mesh.get_vertices().row(v2) - mesh.get_vertices().row(v1);
110}
111
121template <typename Scalar>
123 const Eigen::Matrix<Scalar, 3, 1>& x,
124 Eigen::Matrix<Scalar, 3, 1>& y,
125 Eigen::Matrix<Scalar, 3, 1>& z)
126{
127 int imin;
128 x.array().abs().minCoeff(&imin);
129 Eigen::Matrix<Scalar, 3, 1> u;
130 for (int i = 0, s = -1; i < 3; ++i) {
131 if (i == imin) {
132 u[i] = 0;
133 } else {
134 int j = (i + 1) % 3;
135 if (j == imin) {
136 j = (i + 2) % 3;
137 }
138 u[i] = s * x[j];
139 s *= -1;
140 }
141 }
142 z = x.cross(u).stableNormalized();
143 y = z.cross(x).stableNormalized();
144}
145
156template <typename Scalar>
157Eigen::Vector3<Scalar> triangle_circumcenter_3d(
158 const Eigen::Vector3<Scalar>& p1,
159 const Eigen::Vector3<Scalar>& p2,
160 const Eigen::Vector3<Scalar>& p3)
161{
162 // Edge vectors
163 Eigen::Matrix<Scalar, 3, 1> a = p2 - p1;
164 Eigen::Matrix<Scalar, 3, 1> b = p3 - p1;
165
166 // Normal of the triangle plane
167 Eigen::Matrix<Scalar, 3, 1> n = a.cross(b);
168 Scalar n_norm2 = n.squaredNorm();
169
170 // Degenerate case: points are collinear or nearly so
171 if (n_norm2 < std::numeric_limits<Scalar>::epsilon()) return (p1 + p2 + p3) / Scalar(3);
172
173 // Compute circumcenter in 3D
174 // Formula: p1 + [ (|a|^2 * (b × n) + |b|^2 * (n × a)) ] / (2 * |n|^2)
175 Eigen::Matrix<Scalar, 3, 1> term1 = a.squaredNorm() * (b.cross(n));
176 Eigen::Matrix<Scalar, 3, 1> term2 = b.squaredNorm() * (n.cross(a));
177 Eigen::Matrix<Scalar, 3, 1> circumcenter = p1 + (term1 + term2) / (Scalar(2) * n_norm2);
178
179 return circumcenter;
180}
181
182
183} // namespace lagrange
@ Scalar
Mesh attribute must have exactly 1 channel.
Definition AttributeFwd.h:56
Main namespace for Lagrange.
void orthogonal_frame(const Eigen::Matrix< Scalar, 3, 1 > &x, Eigen::Matrix< Scalar, 3, 1 > &y, Eigen::Matrix< Scalar, 3, 1 > &z)
Build an orthogonal frame given a single vector.
Definition geometry3d.h:122
Scalar projected_cos_angle_between(const Eigen::Matrix< Scalar, _Rows, _Cols > &v1, const Eigen::Matrix< Scalar, _Rows, _Cols > &v2, const Eigen::Matrix< Scalar, _Rows, _Cols > &n)
Returns the angle between the vectors v1 and v2 projected on the plane defined by its normal n.
Definition geometry3d.h:72
Scalar projected_angle_between(const Eigen::Matrix< Scalar, _Rows, _Cols > &v1, const Eigen::Matrix< Scalar, _Rows, _Cols > &v2, const Eigen::Matrix< Scalar, _Rows, _Cols > &n)
Returns the angle between the vectors v1 and v2 projected on the plane defined by its normal n.
Definition geometry3d.h:86
Eigen::Vector3< Scalar > triangle_circumcenter_3d(const Eigen::Vector3< Scalar > &p1, const Eigen::Vector3< Scalar > &p2, const Eigen::Vector3< Scalar > &p3)
Returns the circumcenter of a 3D triangle.
Definition geometry3d.h:157
Eigen::Matrix< Scalar, _Rows, _Cols > project_on_plane(const Eigen::Matrix< Scalar, _Rows, _Cols > &v, const Eigen::Matrix< Scalar, _Rows, _Cols > &n)
Project the vector on the plane defined by its normal n.
Definition geometry3d.h:61
auto vector_between(const MeshType &mesh, typename MeshType::Index v1, typename MeshType::Index v2)
Returns the vector from v1 to v2.
Definition geometry3d.h:106
Eigen::Matrix< Scalar, _Rows, _Cols > project_on_line(const Eigen::Matrix< Scalar, _Rows, _Cols > &v1, const Eigen::Matrix< Scalar, _Rows, _Cols > &v2)
Project the vector v1 on the line defined by its vector v2.
Definition geometry3d.h:50
Scalar cos_angle_between(const Eigen::Matrix< Scalar, _Rows, _Cols > &v1, const Eigen::Matrix< Scalar, _Rows, _Cols > &v2)
Returns the cosine of the angle between two 3d vectors.
Definition geometry3d.h:25
Scalar angle_between(const Eigen::Matrix< Scalar, _Rows, _Cols > &v1, const Eigen::Matrix< Scalar, _Rows, _Cols > &v2)
Returns the angle between two 3d vectors.
Definition geometry3d.h:38