Bembel
 
Loading...
Searching...
No Matches
Patch.hpp
1// This file is part of Bembel, the higher order C++ boundary element library.
2//
3// Copyright (C) 2022 see <http://www.bembel.eu>
4//
5// It was written as part of a cooperation of J. Doelz, H. Harbrecht, S. Kurz,
6// M. Multerer, S. Schoeps, and F. Wolf at Technische Universitaet Darmstadt,
7// Universitaet Basel, and Universita della Svizzera italiana, Lugano. This
8// source code is subject to the GNU General Public License version 3 and
9// provided WITHOUT ANY WARRANTY, see <http://www.bembel.eu> for further
10// information.
11#ifndef BEMBEL_SRC_GEOMETRY_PATCH_HPP_
12#define BEMBEL_SRC_GEOMETRY_PATCH_HPP_
13namespace Bembel {
14
20class Patch {
21 public:
25
28 Patch() {}
42 Patch(const std::vector<Eigen::Matrix<double, -1, -1>> &control_points,
43 const std::vector<double> &knots_x,
44 const std::vector<double> &knots_y) {
46 }
50
63 inline void init_Patch(const std::vector<Eigen::Matrix<double, -1, -1>> &xyzw,
64 const std::vector<double> &x_knots,
65 const std::vector<double> &y_knots) {
66 assert(xyzw.size() == 4);
67 const int xyzw_cols = xyzw[0].cols();
68 const int xyzw_rows = xyzw[0].rows();
69 unique_knots_x_ = Spl::ExtractUniqueKnotVector(x_knots);
70 unique_knots_y_ = Spl::ExtractUniqueKnotVector(y_knots);
71 const int xnumpatch = unique_knots_x_.size() - 1;
72 const int ynumpatch = unique_knots_y_.size() - 1;
73 polynomial_degree_x_ = x_knots.size() - xyzw_cols;
74 polynomial_degree_y_ = y_knots.size() - xyzw_rows;
75 data_.resize(4 * (polynomial_degree_x_ * xnumpatch * polynomial_degree_y_ *
76 ynumpatch));
77 {
78 // Since its only for initialization, I do not care about speed.
79 // Here I look weather the data given is already in bezier form.
80 if (unique_knots_x_.size() == 2 && unique_knots_y_.size() == 2) {
81 for (int i = 0; i < 4; i++) {
82 Eigen::Matrix<double, -1, 1> tmp = Spl::Unroll(xyzw[i]);
83 for (int j = 0; j < tmp.rows(); j++) data_[j * 4 + i] = (tmp[j]);
84 }
85 } else {
86 // If not, I construct the dynamic projection (i.e. solve
87 // systems for
88 // the coeffs) and project to the superspace.
89
90 Eigen::SparseMatrix<double> phi = Spl::MakeProjection(
91 x_knots, y_knots, unique_knots_x_, unique_knots_y_,
92 polynomial_degree_x_, polynomial_degree_y_);
93
94 for (int i = 0; i < 4; i++) {
95 Eigen::Matrix<double, -1, 1> tmp =
96 Spl::Unroll(xyzw[i]).transpose() * phi.transpose();
97
98 for (int j = 0; j < tmp.rows(); j++) data_[j * 4 + i] = (tmp[j]);
99 }
100 }
101 }
102
103 return;
104 }
115 Eigen::Vector3d eval(const Eigen::Vector2d &reference_point) const {
116 const int x_location =
117 Spl::FindLocationInKnotVector(reference_point(0), unique_knots_x_);
118 const int y_location =
119 Spl::FindLocationInKnotVector(reference_point(1), unique_knots_y_);
120 const int numy = (unique_knots_y_.size() - 1) * polynomial_degree_y_;
121 const double scaledx =
122 Spl::Rescale(reference_point(0), unique_knots_x_[x_location],
123 unique_knots_x_[x_location + 1]);
124 const double scaledy =
125 Spl::Rescale(reference_point(1), unique_knots_y_[y_location],
126 unique_knots_y_[y_location + 1]);
127
128 double *xbasis = new double[polynomial_degree_x_];
129 double *ybasis = new double[polynomial_degree_y_];
130
131 Bembel::Basis::ShapeFunctionHandler::evalBasis(polynomial_degree_x_ - 1,
132 xbasis, scaledx);
133 Bembel::Basis::ShapeFunctionHandler::evalBasis(polynomial_degree_y_ - 1,
134 ybasis, scaledy);
135
136 double tmp[4] = {0., 0., 0., 0.};
137
138 for (int i = 0; i < polynomial_degree_x_; i++) {
139 for (int j = 0; j < polynomial_degree_y_; j++) {
140 const double tpbasisval = xbasis[i] * ybasis[j];
141 const int accs = 4 * (numy * (polynomial_degree_x_ * x_location + i) +
142 polynomial_degree_y_ * y_location + j);
143#pragma omp simd
144 for (int k = 0; k < 4; k++) tmp[k] += data_[accs + k] * tpbasisval;
145 }
146 }
147
148 delete[] xbasis;
149 delete[] ybasis;
150
151 Eigen::Vector3d out(tmp[0], tmp[1], tmp[2]);
152 // Rescaling by the NRBS weight, i.e. projection to 3D from 4D hom
153
154 return out / tmp[3];
155 }
156
163 Eigen::Matrix<double, 3, 2> evalJacobian(
164 const Eigen::Vector2d &reference_point) const {
165 const int x_location =
166 Spl::FindLocationInKnotVector(reference_point(0), unique_knots_x_);
167 const int y_location =
168 Spl::FindLocationInKnotVector(reference_point(1), unique_knots_y_);
169 const int numy = (unique_knots_y_.size() - 1) * polynomial_degree_y_;
170 const double scaledx =
171 Spl::Rescale(reference_point(0), unique_knots_x_[x_location],
172 unique_knots_x_[x_location + 1]);
173 const double scaledy =
174 Spl::Rescale(reference_point(1), unique_knots_y_[y_location],
175 unique_knots_y_[y_location + 1]);
176
177 double *xbasis = new double[polynomial_degree_x_];
178 double *ybasis = new double[polynomial_degree_y_];
179 double *xbasisD = new double[polynomial_degree_x_];
180 double *ybasisD = new double[polynomial_degree_y_];
181
182 Bembel::Basis::ShapeFunctionHandler::evalBasis(polynomial_degree_x_ - 1,
183 xbasis, scaledx);
184 Bembel::Basis::ShapeFunctionHandler::evalBasis(polynomial_degree_y_ - 1,
185 ybasis, scaledy);
186 Bembel::Basis::ShapeFunctionHandler::evalDerBasis(polynomial_degree_x_ - 1,
188 Bembel::Basis::ShapeFunctionHandler::evalDerBasis(polynomial_degree_y_ - 1,
190
191 double tmp[4] = {0., 0., 0., 0.};
192 double tmpDx[4] = {0., 0., 0., 0.};
193 double tmpDy[4] = {0., 0., 0., 0.};
194
195 for (int i = 0; i < polynomial_degree_x_; i++) {
196 for (int j = 0; j < polynomial_degree_y_; j++) {
197 const double tpbasisval = xbasis[i] * ybasis[j];
198 const double tpbasisvalDx = xbasisD[i] * ybasis[j];
199 const double tpbasisvalDy = xbasis[i] * ybasisD[j];
200 const int accs = 4 * (numy * (polynomial_degree_x_ * x_location + i) +
201 polynomial_degree_y_ * y_location + j);
202
203 // Here I add up the values of the basis functions in the dc
204 // basis
205#pragma omp simd
206 for (int k = 0; k < 4; k++) {
207 tmp[k] += data_[accs + k] * tpbasisval;
208 tmpDx[k] += data_[accs + k] * tpbasisvalDx;
209 tmpDy[k] += data_[accs + k] * tpbasisvalDy;
210 }
211 }
212 }
213
214 delete[] xbasis;
215 delete[] ybasis;
216 delete[] xbasisD;
217 delete[] ybasisD;
218
219 Eigen::Matrix<double, 3, 2> out;
220
221 // Eigen::Vector3d out;
222
223 double bot = 1. / (tmp[3] * tmp[3]);
224
225#pragma omp simd
226 for (int k = 0; k < 3; k++) {
227 out(k, 0) = (tmpDx[k] * tmp[3] - tmp[k] * tmpDx[3]) * bot;
228 out(k, 1) = (tmpDy[k] * tmp[3] - tmp[k] * tmpDy[3]) * bot;
229 }
230
231 return out;
232 }
233
240 inline Eigen::Matrix<double, 3, 1> evalNormal(
241 const Eigen::Vector2d &reference_point) const {
242 Eigen::Matrix<double, 3, 2> jac = evalJacobian(reference_point);
243 return jac.col(0).cross(jac.col(1));
244 }
245
257 inline Eigen::Vector3d eval(double x, double y) const {
258 return eval(Eigen::Vector2d(x, y));
259 }
267 inline Eigen::Matrix<double, 3, 2> evalJacobian(double x, double y) const {
268 return evalJacobian(Eigen::Vector2d(x, y));
269 }
277 inline Eigen::Matrix<double, 3, 1> evalNormal(double x, double y) const {
278 return evalNormal(Eigen::Vector2d(x, y));
279 }
280
281 //
295 const Eigen::Vector2d &ref_pt, double w,
296 const Eigen::Vector2d &xi) const {
297 const int x_location =
298 Spl::FindLocationInKnotVector(ref_pt(0), unique_knots_x_);
299 const int y_location =
300 Spl::FindLocationInKnotVector(ref_pt(1), unique_knots_y_);
301 const int numy = (unique_knots_y_.size() - 1) * polynomial_degree_y_;
302 const double scaledx = Spl::Rescale(ref_pt(0), unique_knots_x_[x_location],
303 unique_knots_x_[x_location + 1]);
304 const double scaledy = Spl::Rescale(ref_pt(1), unique_knots_y_[y_location],
305 unique_knots_y_[y_location + 1]);
306
307 // TODO(Felix) Do not use variable-length arrays in accordance to Google
308 // Style guide
309 double *buffer =
310 new double[2 * (polynomial_degree_x_ + polynomial_degree_y_) + 12];
311 for (int i = 0; i < 12; ++i) buffer[i] = 0;
312
313 double *tmp = buffer;
314 double *tmpDx = tmp + 4;
315 double *tmpDy = tmpDx + 4;
316 double *xbasis = tmpDy + 4;
317 double *ybasis = xbasis + polynomial_degree_x_;
318 double *xbasisD = ybasis + polynomial_degree_y_;
319 double *ybasisD = xbasisD + polynomial_degree_x_;
320
321 Bembel::Basis::ShapeFunctionHandler::evalBasis(polynomial_degree_x_ - 1,
322 xbasis, scaledx);
323 Bembel::Basis::ShapeFunctionHandler::evalBasis(polynomial_degree_y_ - 1,
324 ybasis, scaledy);
325 Bembel::Basis::ShapeFunctionHandler::evalDerBasis(polynomial_degree_x_ - 1,
327 Bembel::Basis::ShapeFunctionHandler::evalDerBasis(polynomial_degree_y_ - 1,
329
330 for (int i = 0; i < polynomial_degree_x_; ++i) {
331 for (int j = 0; j < polynomial_degree_y_; ++j) {
332 const double tpbasisval = xbasis[i] * ybasis[j];
333 const double tpbasisvalDx = xbasisD[i] * ybasis[j];
334 const double tpbasisvalDy = xbasis[i] * ybasisD[j];
335 const int accs = 4 * (numy * (polynomial_degree_x_ * x_location + i) +
336 polynomial_degree_y_ * y_location + j);
337
338 // Here I add up the values of the basis functions in the dc
339 // basis
340 for (int k = 0; k < 4; ++k) {
341 tmp[k] += data_[accs + k] * tpbasisval;
342 tmpDx[k] += data_[accs + k] * tpbasisvalDx;
343 tmpDy[k] += data_[accs + k] * tpbasisvalDy;
344 }
345 }
346 }
347
348 const double bot = 1. / tmp[3];
349 const double botsqr = bot * bot;
350
351 (*srf_pt)(0) = xi(0);
352 (*srf_pt)(1) = xi(1);
353 (*srf_pt)(2) = w;
354 (*srf_pt)(3) = tmp[0] * bot;
355 (*srf_pt)(4) = tmp[1] * bot;
356 (*srf_pt)(5) = tmp[2] * bot;
357 (*srf_pt)(6) = (tmpDx[0] * tmp[3] - tmp[0] * tmpDx[3]) * botsqr;
358 (*srf_pt)(7) = (tmpDx[1] * tmp[3] - tmp[1] * tmpDx[3]) * botsqr;
359 (*srf_pt)(8) = (tmpDx[2] * tmp[3] - tmp[2] * tmpDx[3]) * botsqr;
360 (*srf_pt)(9) = (tmpDy[0] * tmp[3] - tmp[0] * tmpDy[3]) * botsqr;
361 (*srf_pt)(10) = (tmpDy[1] * tmp[3] - tmp[1] * tmpDy[3]) * botsqr;
362 (*srf_pt)(11) = (tmpDy[2] * tmp[3] - tmp[2] * tmpDy[3]) * botsqr;
363 delete[] buffer;
364 return;
365 }
366
370
371 std::vector<double> data_; // Controllpoints in Bezier-Extracted Format.
372 int polynomial_degree_x_; // Degree in x
373 int polynomial_degree_y_; // Degree in y
374 std::vector<double>
375 unique_knots_x_; // The knot vectors, where each knot is unique
376 std::vector<double>
377 unique_knots_y_; // The knot vectors, where each knot is unique
378};
379
386inline std::vector<Patch> PatchShredder(const Patch &patch) noexcept {
387 // Already a Bezier patch
388 if (patch.unique_knots_y_.size() == 2 && patch.unique_knots_x_.size() == 2) {
389 return {patch};
390 }
391
392 // number of subpatches in x and y directions
393 const int xchips = patch.unique_knots_x_.size() - 1;
394 const int ychips = patch.unique_knots_y_.size() - 1;
395
396 const int xp = patch.polynomial_degree_x_;
397 const int yp = patch.polynomial_degree_y_;
398 const int numy = ychips * yp;
399
400 std::vector<Patch> out(xchips * ychips);
401
402 for (int ix = 0; ix < xchips; ix++) {
403 for (int iy = 0; iy < ychips; iy++) {
404 const int index = ix * ychips + iy;
405
406 out[index].unique_knots_x_ = {0, 1};
407 out[index].unique_knots_y_ = {0, 1};
408 out[index].polynomial_degree_x_ = xp;
409 out[index].polynomial_degree_y_ = yp;
410 out[index].data_.reserve(xp * yp * 4);
411 }
412 }
413
414 for (int ix = 0; ix < xchips; ix++) {
415 for (int iy = 0; iy < ychips; iy++) {
416 const int index = ix * ychips + iy;
417 for (int jx = 0; jx < xp; jx++) {
418 for (int jy = 0; jy < yp; jy++) {
419 const int accs = 4 * (numy * (xp * ix + jx) + yp * iy + jy);
420 for (int k = 0; k < 4; k++) {
421 out[index].data_.push_back(patch.data_[accs + k]);
422 }
423 }
424 }
425 }
426 }
427
428 return out;
429}
430
437inline std::vector<Patch> PatchShredder(
438 const std::vector<Patch> &patches) noexcept {
439 std::vector<Patch> out;
440 const int input_size = patches.size();
441
442 for (int i = 0; i < input_size; i++) {
443 std::vector<Patch> tmp = PatchShredder(patches[i]);
444
445 const int tmp_size = tmp.size();
446
447 for (int j = 0; j < tmp_size; j++) out.push_back(tmp[j]);
448 }
449
450 out.shrink_to_fit();
451
452 return out;
453}
454
455} // namespace Bembel
456
457#endif // BEMBEL_SRC_GEOMETRY_PATCH_HPP_
handles a single patch
Definition Patch.hpp:20
Eigen::Matrix< double, 3, 1 > evalNormal(double x, double y) const
Evaluate normal vector at given point.
Definition Patch.hpp:277
Eigen::Matrix< double, 3, 2 > evalJacobian(const Eigen::Vector2d &reference_point) const
Evaluate Jacobian of the parametrization at given point.
Definition Patch.hpp:163
Patch(const std::vector< Eigen::Matrix< double, -1, -1 > > &control_points, const std::vector< double > &knots_x, const std::vector< double > &knots_y)
Constructor of a Patch.
Definition Patch.hpp:42
Eigen::Matrix< double, 3, 2 > evalJacobian(double x, double y) const
Evaluate Jacobian of the parametrization at given point.
Definition Patch.hpp:267
void init_Patch(const std::vector< Eigen::Matrix< double, -1, -1 > > &xyzw, const std::vector< double > &x_knots, const std::vector< double > &y_knots)
init
Definition Patch.hpp:63
Eigen::Matrix< double, 3, 1 > evalNormal(const Eigen::Vector2d &reference_point) const
Evaluate normal vector at given point.
Definition Patch.hpp:240
Patch()
constructors
Definition Patch.hpp:28
Eigen::Vector3d eval(double x, double y) const
Evaluate patch at given point.
Definition Patch.hpp:257
Eigen::Vector3d eval(const Eigen::Vector2d &reference_point) const
Evaluate patch at given point.
Definition Patch.hpp:115
std::vector< double > data_
getter
Definition Patch.hpp:371
void updateSurfacePoint(SurfacePoint *srf_pt, const Eigen::Vector2d &ref_pt, double w, const Eigen::Vector2d &xi) const
Updates the surface point and returns the physical point and the derivatives there.
Definition Patch.hpp:294
Eigen::Matrix< double, 12, 1 > SurfacePoint
typedef of SurfacePoint
Eigen::SparseMatrix< T > MakeProjection(const std::vector< T > &x_knots, const std::vector< T > &y_knots, const std::vector< T > &x_unique_knots, const std::vector< T > &y_unique_knots, const int polynomial_degree_x, const int polynomial_degree_y) noexcept
implements Bezier extraction via the solution of an interpolation problem.
Eigen::Matrix< T, -1, 1 > Unroll(const Eigen::Matrix< T, -1, -1 > &input_matrix) noexcept
Tiny helper functions.
Definition Unroll.hpp:23
Routines for the evalutation of pointwise errors.
constexpr int getFunctionSpaceOutputDimension()
std::vector< Patch > PatchShredder(const Patch &patch) noexcept
This function cuts a patch along internal knots, if any.
Definition Patch.hpp:386