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
123template <typename Scalar>
125 const Eigen::Matrix<Scalar, 3, 1>& x,
126 Eigen::Matrix<Scalar, 3, 1>& y,
127 Eigen::Matrix<Scalar, 3, 1>& z)
128{
129 constexpr Scalar one(1);
130 const Eigen::Matrix<Scalar, 3, 1> n = x.stableNormalized();
131 const Scalar sign = std::copysign(one, n.z());
132 const Scalar a = -one / (sign + n.z());
133 const Scalar b = n.x() * n.y() * a;
134 y = Eigen::Matrix<Scalar, 3, 1>(one + sign * n.x() * n.x() * a, sign * b, -sign * n.x());
135 z = Eigen::Matrix<Scalar, 3, 1>(b, sign + n.y() * n.y() * a, -n.y());
136}
137
148template <typename Scalar>
149Eigen::Vector3<Scalar> triangle_circumcenter_3d(
150 const Eigen::Vector3<Scalar>& p1,
151 const Eigen::Vector3<Scalar>& p2,
152 const Eigen::Vector3<Scalar>& p3)
153{
154 // Edge vectors
155 Eigen::Matrix<Scalar, 3, 1> a = p2 - p1;
156 Eigen::Matrix<Scalar, 3, 1> b = p3 - p1;
157
158 // Normal of the triangle plane
159 Eigen::Matrix<Scalar, 3, 1> n = a.cross(b);
160 Scalar n_norm2 = n.squaredNorm();
161
162 // Degenerate case: points are collinear or nearly so
163 if (n_norm2 < std::numeric_limits<Scalar>::epsilon()) return (p1 + p2 + p3) / Scalar(3);
164
165 // Compute circumcenter in 3D
166 // Formula: p1 + [ (|a|^2 * (b × n) + |b|^2 * (n × a)) ] / (2 * |n|^2)
167 Eigen::Matrix<Scalar, 3, 1> term1 = a.squaredNorm() * (b.cross(n));
168 Eigen::Matrix<Scalar, 3, 1> term2 = b.squaredNorm() * (n.cross(a));
169 Eigen::Matrix<Scalar, 3, 1> circumcenter = p1 + (term1 + term2) / (Scalar(2) * n_norm2);
170
171 return circumcenter;
172}
173
174
175} // 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:124
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:149
int sign(T val)
Get the sign of the value Returns either -1, 0, or 1.
Definition utils.h:44
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