PolyFEM
Loading...
Searching...
No Matches
WSPolygonalBasis2d.cpp
Go to the documentation of this file.
1
4
5#include <memory>
6
7namespace polyfem
8{
9 namespace basis
10 {
11
12 namespace
13 {
14 template <typename Expr>
15 inline Eigen::RowVector2d rotatePi_2(const Expr &p) // rotation of pi/2
16 {
17 return Eigen::RowVector2d(-p(1), p(0));
18 }
19 } // anonymous namespace
20
22
23 void WSPolygonalBasis2d::wachspress(const Eigen::MatrixXd &polygon, const Eigen::RowVector2d &point, Eigen::MatrixXd &b, const double tol)
24 {
25 const int n_boundary = polygon.rows();
26
27 Eigen::MatrixXd segments(n_boundary, 2);
28 Eigen::VectorXd radii(n_boundary);
29 Eigen::VectorXd areas(n_boundary);
30 Eigen::VectorXd Cs(n_boundary);
31 Eigen::Matrix2d mat;
32
33 b.resize(n_boundary, 1);
34 b.setZero();
35
36 for (int i = 0; i < n_boundary; ++i)
37 {
38 const int ip1 = (i + 1) == n_boundary ? 0 : (i + 1);
39 const int im1 = i == 0 ? (n_boundary - 1) : (i - 1);
40
41 mat.row(0) = polygon.row(im1) - polygon.row(i);
42 mat.row(1) = polygon.row(ip1) - polygon.row(i);
43
44 Cs(i) = mat.determinant();
45 }
46
47 for (int i = 0; i < n_boundary; ++i)
48 {
49 segments.row(i) = polygon.row(i) - point;
50 radii(i) = segments.row(i).norm();
51
52 // we are on the vertex
53 if (radii(i) < tol)
54 {
55 b(i) = 1;
56 return;
57 }
58 }
59
60 for (int i = 0; i < n_boundary; ++i)
61 {
62 const int ip1 = (i + 1) == n_boundary ? 0 : (i + 1);
63
64 mat.row(0) = segments.row(i);
65 mat.row(1) = segments.row(ip1);
66
67 areas(i) = mat.determinant();
68 const double prod = segments.row(i).dot(segments.row(ip1));
69
70 // we are on the edge
71 if (fabs(areas[i]) < tol && prod < 0)
72 {
73 const double denominator = 1.0 / (radii(i) + radii(ip1));
74
75 b(i) = radii(ip1) * denominator;
76 b(ip1) = radii(i) * denominator;
77
78 return;
79 }
80 }
81
82 double W = 0;
83 for (int i = 0; i < n_boundary; ++i)
84 {
85 const int im1 = i == 0 ? (n_boundary - 1) : (i - 1);
86
87 b(i) = Cs(i) / (areas(im1) * areas(i));
88 W += b(i);
89 }
90
91 b /= W;
92 }
93
94 void WSPolygonalBasis2d::wachspress_derivative(const Eigen::MatrixXd &polygon, const Eigen::RowVector2d &point, Eigen::MatrixXd &derivatives, const double tol)
95 {
96 const int n_boundary = polygon.rows();
97
98 derivatives.resize(n_boundary, 2);
99 derivatives.setZero();
100
101 Eigen::MatrixXd segments(n_boundary, 2);
102 Eigen::VectorXd radii(n_boundary);
103 Eigen::VectorXd areas(n_boundary);
104 Eigen::VectorXd Cs(n_boundary);
105 Eigen::Matrix2d mat;
106
107 Eigen::MatrixXd areas_prime(n_boundary, 2);
108 Eigen::MatrixXd w_prime(n_boundary, 2);
109
110 for (int i = 0; i < n_boundary; ++i)
111 {
112 const int ip1 = (i + 1) == n_boundary ? 0 : (i + 1);
113 const int im1 = i == 0 ? (n_boundary - 1) : (i - 1);
114
115 mat.row(0) = polygon.row(im1) - polygon.row(i);
116 mat.row(1) = polygon.row(ip1) - polygon.row(i);
117
118 Cs(i) = mat.determinant();
119 }
120
121 for (int i = 0; i < n_boundary; ++i)
122 {
123 segments.row(i) = polygon.row(i) - point;
124 radii(i) = segments.row(i).norm();
125
126 // we are on the vertex
127 if (radii(i) < tol)
128 {
129 assert(false);
130 // b(i) = 1;
131 return;
132 }
133 }
134
135 int on_edge = -1;
136 double w0 = 0, w1 = 0;
137
138 for (int i = 0; i < n_boundary; ++i)
139 {
140 const int ip1 = (i + 1) == n_boundary ? 0 : (i + 1);
141
142 mat.row(0) = segments.row(i);
143 mat.row(1) = segments.row(ip1);
144
145 areas(i) = mat.determinant();
146 const double prod = segments.row(i).dot(segments.row(ip1));
147
148 // we are on the edge
149 if (fabs(areas[i]) < tol && prod < 0)
150 {
151 assert(false);
152 return;
153 }
154
155 const Eigen::RowVector2d vi = polygon.row(i);
156 const Eigen::RowVector2d vip1 = polygon.row(ip1);
157
158 areas_prime(i, 0) = vi(1) - vip1(1);
159 areas_prime(i, 1) = vip1(0) - vi(0);
160 }
161
162 double W = 0;
163 Eigen::RowVector2d W_prime;
164 W_prime.setZero();
165
166 for (int i = 0; i < n_boundary; ++i)
167 {
168 const int im1 = (i > 0) ? (i - 1) : (n_boundary - 1);
169
170 w_prime.row(i) = Cs(i) / (areas(im1) * areas(i)) / (areas(im1) * areas(i)) * (areas_prime.row(im1) * areas(i) + areas(im1) * areas_prime.row(i));
171
172 W_prime += w_prime.row(i);
173
174 W += Cs(i) / (areas(im1) * areas(i));
175 }
176
177 for (int i = 0; i < n_boundary; ++i)
178 {
179 const int im1 = (i > 0) ? (i - 1) : (n_boundary - 1);
180
181 const double wi = Cs(i) / (areas(im1) * areas(i));
182 derivatives.row(i) = -(w_prime.row(i) * W - wi * W_prime) / (W * W);
183 }
184 }
185
187 const std::string &assembler_name,
188 const int dim,
189 const mesh::Mesh2D &mesh,
190 const int n_bases,
191 const int quadrature_order,
192 const int mass_quadrature_order,
193 std::vector<ElementBases> &bases,
194 std::vector<mesh::LocalBoundary> &local_boundary,
195 std::map<int, Eigen::MatrixXd> &mapped_boundary)
196 {
197 return BarycentricBasis2d::build_bases(assembler_name, dim, mesh, n_bases, quadrature_order, mass_quadrature_order, wachspress, wachspress_derivative, bases, local_boundary, mapped_boundary);
198 }
199
200 } // namespace basis
201} // namespace polyfem
Eigen::MatrixXd mat
static int build_bases(const std::string &assembler_name, const int dim, const mesh::Mesh2D &mesh, const int n_bases, const int quadrature_order, const int mass_quadrature_order, const std::function< void(const Eigen::MatrixXd &, const Eigen::RowVector2d &, Eigen::MatrixXd &, const double)> bc, const std::function< void(const Eigen::MatrixXd &, const Eigen::RowVector2d &, Eigen::MatrixXd &, const double)> bc_prime, std::vector< ElementBases > &bases, std::vector< mesh::LocalBoundary > &local_boundary, std::map< int, Eigen::MatrixXd > &mapped_boundary)
static void wachspress(const Eigen::MatrixXd &polygon, const Eigen::RowVector2d &point, Eigen::MatrixXd &b, const double tol)
static void wachspress_derivative(const Eigen::MatrixXd &polygon, const Eigen::RowVector2d &point, Eigen::MatrixXd &derivatives, const double tol)
static int build_bases(const std::string &assembler_name, const int dim, const mesh::Mesh2D &mesh, const int n_bases, const int quadrature_order, const int mass_quadrature_order, std::vector< ElementBases > &bases, std::vector< mesh::LocalBoundary > &local_boundary, std::map< int, Eigen::MatrixXd > &mapped_boundary)