1+ #include " ipc/geometry/normal.hpp"
2+
3+ namespace ipc {
4+
5+ std::tuple<VectorMax3d, MatrixMax3d>
6+ normalization_and_jacobian (Eigen::ConstRef<VectorMax3d> x)
7+ {
8+ const double norm = x.norm ();
9+ const VectorMax3d xhat = x / norm;
10+ const auto I = MatrixMax3d::Identity (x.size (), x.size ());
11+ const MatrixMax3d J = (I - (xhat * xhat.transpose ())) / norm;
12+ return std::make_tuple (xhat, J);
13+ }
14+
15+ std::tuple<VectorMax3d, MatrixMax3d, std::array<MatrixMax3d, 3 >>
16+ normalization_and_jacobian_and_hessian (Eigen::ConstRef<VectorMax3d> x)
17+ {
18+ // const auto [xhat, J] = normalization_and_jacobian(x);
19+ const double norm = x.norm ();
20+ const VectorMax3d xhat = x / norm;
21+ const auto I = MatrixMax3d::Identity (x.size (), x.size ());
22+ const MatrixMax3d J = (I - (xhat * xhat.transpose ())) / norm;
23+
24+ std::array<MatrixMax3d, 3 > H;
25+ for (int i = 0 ; i < x.size (); i++) {
26+ H[i] = (xhat (i) * J + xhat * J.row (i) + J.col (i) * xhat.transpose ())
27+ / (-norm);
28+ }
29+
30+ return std::make_tuple (xhat, J, H);
31+ }
32+
33+ // --- edge-vertex normal functions -------------------------------------------
34+
35+ VectorMax3d edge_vertex_unnormalized_normal (
36+ Eigen::ConstRef<VectorMax3d> v,
37+ Eigen::ConstRef<VectorMax3d> e0 ,
38+ Eigen::ConstRef<VectorMax3d> e1 )
39+ {
40+ assert (v.size () == e0 .size () && v.size () == e1 .size ());
41+ assert (v.size () == 2 || v.size () == 3 );
42+ if (v.size () == 2 ) {
43+ // In 2D, the normal is simply the perpendicular vector to the edge
44+ const Eigen::Vector2d e = e1 .tail <2 >() - e0 .tail <2 >();
45+ return Eigen::Vector2d (-e.y (), e.x ());
46+ } else {
47+ // Use triple product expansion of the cross product -e × (e × d)
48+ // (https://en.wikipedia.org/wiki/Cross_product#Triple_product_expansion)
49+ // NOTE: This would work in 2D as well, but we handle that case above.
50+ const Eigen::Vector3d e = e1 - e0 ;
51+ const Eigen::Vector3d d = v - e0 ;
52+ return d * e.dot (e) - e * e.dot (d);
53+ }
54+ }
55+
56+ MatrixMax<double , 3 , 9 > edge_vertex_unnormalized_normal_jacobian (
57+ Eigen::ConstRef<VectorMax3d> v,
58+ Eigen::ConstRef<VectorMax3d> e0 ,
59+ Eigen::ConstRef<VectorMax3d> e1 )
60+ {
61+ assert (v.size () == e0 .size () && v.size () == e1 .size ());
62+ assert (v.size () == 2 || v.size () == 3 );
63+
64+ MatrixMax<double , 3 , 9 > dn (v.size (), 3 * v.size ());
65+
66+ if (v.size () == 2 ) {
67+ // In 2D, the normal is simply the perpendicular vector to the edge
68+ dn.leftCols <2 >().setZero ();
69+ dn.middleCols <2 >(2 ) << 0 , 1 , -1 , 0 ;
70+ dn.rightCols <2 >() << 0 , -1 , 1 , 0 ;
71+ return dn;
72+ } else {
73+ const Eigen::Vector3d e = e1 - e0 ;
74+ const Eigen::Vector3d d = v - e0 ;
75+
76+ const auto I = Eigen::Matrix3d::Identity ();
77+
78+ // ∂n/∂v
79+ dn.leftCols <3 >() = e.dot (e) * I - e * e.transpose ();
80+ // ∂n/∂e1
81+ dn.rightCols <3 >() =
82+ -e.dot (d) * I - e * d.transpose () + (2 * d) * e.transpose ();
83+ // ∂n/∂e0
84+ dn.middleCols <3 >(3 ) = -dn.leftCols <3 >() - dn.rightCols <3 >();
85+ }
86+
87+ return dn;
88+ }
89+
90+ } // namespace ipc
0 commit comments