Bembel
Bezierextraction.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_SPLINE_BEZIEREXTRACTION_HPP_
12 #define BEMBEL_SRC_SPLINE_BEZIEREXTRACTION_HPP_
13 
14 namespace Bembel {
15 namespace Spl {
16 
22 template <typename T>
23 Eigen::SparseMatrix<T> MakeProjection(const std::vector<T> &x_knots,
24  const std::vector<T> &y_knots,
25  const std::vector<T> &x_unique_knots,
26  const std::vector<T> &y_unique_knots,
27  const int polynomial_degree_x,
28  const int polynomial_degree_y) noexcept {
29  // In here phi refers to the BIG bezier basis, and psi refers to the small
30  // B-Spline basis given by x_knots,y_knots and xp,yp.
31  // Sparse does weird things. We need not be that accurate, since the right
32  // coeefs will be >=.1
33  constexpr double sparseTol = 0.001;
34  // Number of functions in X,Y and total
35  const int size_phi_x = (x_unique_knots.size() - 1) * polynomial_degree_x;
36  const int size_phi_y = (y_unique_knots.size() - 1) * polynomial_degree_y;
37  const int size_phi = size_phi_x * size_phi_y;
38  const int size_psi_x = x_knots.size() - polynomial_degree_x;
39  const int size_psi_y = y_knots.size() - polynomial_degree_y;
40  const int size_psi = size_psi_x * size_psi_y;
41 
42  // Interpolation points
43  const auto xmask = MakeInterpolationMask(polynomial_degree_x);
44  const auto ymaks = MakeInterpolationMask(polynomial_degree_y);
45 
46  const auto xpoint = MakeInterpolationPoints(x_unique_knots, xmask);
47  const auto ypoint = MakeInterpolationPoints(y_unique_knots, ymaks);
48 
49  assert(((int)(xmask.size() * (x_unique_knots.size() - 1))) == size_phi_x);
50  assert(((int)(xpoint.size())) == size_phi_x);
51  assert(((int)(ypoint.size())) == size_phi_y);
52 
53  Eigen::Matrix<T, -1, -1> tempsolver =
54  Eigen::Matrix<T, -1, -1>::Zero(size_phi, size_phi);
55 
56  double *coefficients_x = new double[polynomial_degree_x];
57  double *coefficients_y = new double[polynomial_degree_y];
58 
59  for (int i = 0; i < polynomial_degree_x; i++) coefficients_x[i] = 0;
60 
61  for (int i = 0; i < polynomial_degree_y; i++) coefficients_y[i] = 0;
62 
63  auto BezBasis = [](std::vector<double> uniq, int deg, int pos, double pt,
64  double *coef) {
65  std::div_t loc = std::div(pos, deg);
66  if (pt > uniq[loc.quot + 1] || pt < uniq[loc.quot]) {
67  return 0.;
68  } else {
69  coef[loc.rem] = 1;
70  double out = Bembel::Basis::ShapeFunctionHandler::evalCoef(
71  deg - 1, coef, Rescale(pt, uniq[loc.quot], uniq[loc.quot + 1]));
72  coef[loc.rem] = 0;
73  return out;
74  }
75  };
76 
77  // A matrix, each row corresponds to one tp-basisfunction, each col to one
78  // tp-interpolation point
79  for (int iy = 0; iy < size_phi_y; iy++) {
80  for (int ix = 0; ix < size_phi_x; ix++) {
81  for (int y = 0; y < size_phi_y; y++) {
82  for (int x = 0; x < size_phi_x; x++) {
83  tempsolver(y * size_phi_x + x, ix * size_phi_y + iy) =
84  BezBasis(x_unique_knots, polynomial_degree_x, ix, xpoint[x],
85  coefficients_x) *
86  BezBasis(y_unique_knots, polynomial_degree_y, iy, ypoint[y],
87  coefficients_y);
88  }
89  }
90  }
91  }
92 
93  delete[] coefficients_x;
94  delete[] coefficients_y;
95 
96  Eigen::FullPivLU<Eigen::Matrix<double, -1, -1>> lu_decomp(tempsolver);
97  assert(lu_decomp.rank() == size_phi);
99  Eigen::Matrix<T, -1, -1> solve = tempsolver.inverse();
100 
101  Eigen::Matrix<T, -1, -1> Proj(size_phi, size_psi);
102  Eigen::Matrix<T, -1, -1> unit =
103  Eigen::Matrix<T, -1, -1>::Zero(size_psi_y, size_psi_x);
104 
106  for (int i = 0; i < size_psi_x; i++)
107  for (int j = 0; j < size_psi_y; j++) {
108  unit(j, i) = 1.;
109  Eigen::Matrix<T, -1, 1> smallBase =
110  (Unroll(DeBoorTP(unit, x_knots, y_knots, xpoint, ypoint)));
111  Proj.col(i * size_psi_y + j) = (solve * smallBase).transpose();
112  unit(j, i) = 0.;
113  }
114 
115  return (Proj.sparseView()).pruned(sparseTol);
116 }
117 } // namespace Spl
118 } // namespace Bembel
119 #endif // BEMBEL_SRC_SPLINE_BEZIEREXTRACTION_HPP_
std::vector< T > MakeInterpolationPoints(const std::vector< T > &uniq, const std::vector< T > &mask) noexcept
Creates a T-vector of equidistant itnerpolation points for a given knot vector without any repetition...
Definition: Localize.hpp:47
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 > DeBoorTP(Eigen::Matrix< T, -1, -1 > const &control_points, std::vector< double > const &knots_x, std::vector< double > const &knots_y, std::vector< double > const &evaluation_points_x, std::vector< double > const &evaluation_points_y) noexcept
Simple TP Bsplines.
Definition: DeBoorTP.hpp:99
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.
Definition: AnsatzSpace.hpp:14