GCC Code Coverage Report


Directory: Bembel/src/
File: Bembel/src/Geometry/Patch.hpp
Date: 2024-03-19 14:38:05
Exec Total Coverage
Lines: 178 178 100.0%
Functions: 9 9 100.0%
Branches: 112 166 67.5%

Line Branch Exec Source
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_
13 namespace Bembel {
14
15 /**
16 * \ingroup Geometry
17 * \class Patch
18 * \brief handles a single patch
19 */
20 class Patch {
21 public:
22 //////////////////////////////////////////////////////////////////////////////
23 /// constructors
24 //////////////////////////////////////////////////////////////////////////////
25 /**
26 * \brief Default constructor.
27 */
28 94 Patch() {}
29 /**
30 * \brief Constructor of a Patch.
31 *
32 * A patch is defined by a set of control points and knot vectors in the x and
33 * y directions. It is used to create complex surfaces in computer graphics
34 * and CAD applications.
35 *
36 * \param control_points std::vector<Eigen::MatrixXd> {x, y, z, w} where the
37 * rows are the control points in x direction.
38 * \param knots_x The knot vector
39 * in the x direction.
40 * \param knots_y The knot vector in the y direction.
41 */
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) {
45 init_Patch(control_points, knots_x, knots_y);
46 }
47 //////////////////////////////////////////////////////////////////////////////
48 /// init
49 //////////////////////////////////////////////////////////////////////////////
50 /**
51 * \brief Initializes a Patch.
52 *
53 * A patch is defined by a set of control points and knot vectors in the x and
54 * y directions. It is used to create complex surfaces in computer graphics
55 * and CAD applications.
56 *
57 * \param xyzw std::vector<Eigen::MatrixXd> {x, y, z, w} where the
58 * rows are the control points in x direction.
59 * \param x_knots The knot vector
60 * in the x direction.
61 * \param y_knots The knot vector in the y direction.
62 */
63 90 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
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 90 times.
90 assert(xyzw.size() == 4);
67 90 const int xyzw_cols = xyzw[0].cols();
68 90 const int xyzw_rows = xyzw[0].rows();
69 90 unique_knots_x_ = Spl::ExtractUniqueKnotVector(x_knots);
70 90 unique_knots_y_ = Spl::ExtractUniqueKnotVector(y_knots);
71 90 const int xnumpatch = unique_knots_x_.size() - 1;
72 90 const int ynumpatch = unique_knots_y_.size() - 1;
73 90 polynomial_degree_x_ = x_knots.size() - xyzw_cols;
74 90 polynomial_degree_y_ = y_knots.size() - xyzw_rows;
75 90 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
5/6
✓ Branch 1 taken 89 times.
✓ Branch 2 taken 1 times.
✓ Branch 4 taken 89 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 89 times.
✓ Branch 7 taken 1 times.
90 if (unique_knots_x_.size() == 2 && unique_knots_y_.size() == 2) {
81
2/2
✓ Branch 0 taken 356 times.
✓ Branch 1 taken 89 times.
445 for (int i = 0; i < 4; i++) {
82 356 Eigen::Matrix<double, -1, 1> tmp = Spl::Unroll(xyzw[i]);
83
3/4
✓ Branch 1 taken 5496 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 5496 times.
✓ Branch 6 taken 356 times.
5852 for (int j = 0; j < tmp.rows(); j++) data_[j * 4 + i] = (tmp[j]);
84 356 }
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 1 x_knots, y_knots, unique_knots_x_, unique_knots_y_,
92 1 polynomial_degree_x_, polynomial_degree_y_);
93
94
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 for (int i = 0; i < 4; i++) {
95 Eigen::Matrix<double, -1, 1> tmp =
96
4/8
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 4 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 4 times.
✗ Branch 13 not taken.
4 Spl::Unroll(xyzw[i]).transpose() * phi.transpose();
97
98
3/4
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 64 times.
✓ Branch 6 taken 4 times.
68 for (int j = 0; j < tmp.rows(); j++) data_[j * 4 + i] = (tmp[j]);
99 4 }
100 1 }
101 }
102
103 90 return;
104 }
105 /**
106 * \brief Evaluate patch at given point.
107 *
108 * I look up the position in the knot vector, scale the input arguments,
109 * evaluate the 1D basis functions and sum over them with the control points
110 * from data.
111 *
112 * \param reference_point Point in reference domain.
113 * \return Point in physical domain.
114 */
115 80241 Eigen::Vector3d eval(const Eigen::Vector2d &reference_point) const {
116 const int x_location =
117
1/2
✓ Branch 1 taken 80241 times.
✗ Branch 2 not taken.
80241 Spl::FindLocationInKnotVector(reference_point(0), unique_knots_x_);
118 const int y_location =
119
1/2
✓ Branch 1 taken 80241 times.
✗ Branch 2 not taken.
80241 Spl::FindLocationInKnotVector(reference_point(1), unique_knots_y_);
120 80241 const int numy = (unique_knots_y_.size() - 1) * polynomial_degree_y_;
121 const double scaledx =
122
1/2
✓ Branch 2 taken 80241 times.
✗ Branch 3 not taken.
80241 Spl::Rescale(reference_point(0), unique_knots_x_[x_location],
123 80241 unique_knots_x_[x_location + 1]);
124 const double scaledy =
125
1/2
✓ Branch 2 taken 80241 times.
✗ Branch 3 not taken.
80241 Spl::Rescale(reference_point(1), unique_knots_y_[y_location],
126 80241 unique_knots_y_[y_location + 1]);
127
128
2/4
✓ Branch 0 taken 80241 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 80241 times.
✗ Branch 5 not taken.
80241 double *xbasis = new double[polynomial_degree_x_];
129
2/4
✓ Branch 0 taken 80241 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 80241 times.
✗ Branch 5 not taken.
80241 double *ybasis = new double[polynomial_degree_y_];
130
131
1/2
✓ Branch 1 taken 80241 times.
✗ Branch 2 not taken.
80241 Bembel::Basis::ShapeFunctionHandler::evalBasis(polynomial_degree_x_ - 1,
132 xbasis, scaledx);
133
1/2
✓ Branch 1 taken 80241 times.
✗ Branch 2 not taken.
80241 Bembel::Basis::ShapeFunctionHandler::evalBasis(polynomial_degree_y_ - 1,
134 ybasis, scaledy);
135
136 80241 double tmp[4] = {0., 0., 0., 0.};
137
138
2/2
✓ Branch 0 taken 167151 times.
✓ Branch 1 taken 80241 times.
247392 for (int i = 0; i < polynomial_degree_x_; i++) {
139
2/2
✓ Branch 0 taken 368252 times.
✓ Branch 1 taken 167151 times.
535403 for (int j = 0; j < polynomial_degree_y_; j++) {
140 368252 const double tpbasisval = xbasis[i] * ybasis[j];
141 368252 const int accs = 4 * (numy * (polynomial_degree_x_ * x_location + i) +
142 368252 polynomial_degree_y_ * y_location + j);
143 #pragma omp simd
144
2/2
✓ Branch 1 taken 1473008 times.
✓ Branch 2 taken 368252 times.
1841260 for (int k = 0; k < 4; k++) tmp[k] += data_[accs + k] * tpbasisval;
145 }
146 }
147
148
1/2
✓ Branch 0 taken 80241 times.
✗ Branch 1 not taken.
80241 delete[] xbasis;
149
1/2
✓ Branch 0 taken 80241 times.
✗ Branch 1 not taken.
80241 delete[] ybasis;
150
151
1/2
✓ Branch 1 taken 80241 times.
✗ Branch 2 not taken.
80241 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
2/4
✓ Branch 1 taken 80241 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 80241 times.
✗ Branch 5 not taken.
160482 return out / tmp[3];
155 }
156
157 /**
158 * \brief Evaluate Jacobian of the parametrization at given point.
159 *
160 * \param reference_point Point in reference domain.
161 * \return 3x2 Matrix with the Jacobian.
162 */
163 1309 Eigen::Matrix<double, 3, 2> evalJacobian(
164 const Eigen::Vector2d &reference_point) const {
165 const int x_location =
166
1/2
✓ Branch 1 taken 1309 times.
✗ Branch 2 not taken.
1309 Spl::FindLocationInKnotVector(reference_point(0), unique_knots_x_);
167 const int y_location =
168
1/2
✓ Branch 1 taken 1309 times.
✗ Branch 2 not taken.
1309 Spl::FindLocationInKnotVector(reference_point(1), unique_knots_y_);
169 1309 const int numy = (unique_knots_y_.size() - 1) * polynomial_degree_y_;
170 const double scaledx =
171
1/2
✓ Branch 2 taken 1309 times.
✗ Branch 3 not taken.
1309 Spl::Rescale(reference_point(0), unique_knots_x_[x_location],
172 1309 unique_knots_x_[x_location + 1]);
173 const double scaledy =
174
1/2
✓ Branch 2 taken 1309 times.
✗ Branch 3 not taken.
1309 Spl::Rescale(reference_point(1), unique_knots_y_[y_location],
175 1309 unique_knots_y_[y_location + 1]);
176
177
2/4
✓ Branch 0 taken 1309 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 1309 times.
✗ Branch 5 not taken.
1309 double *xbasis = new double[polynomial_degree_x_];
178
2/4
✓ Branch 0 taken 1309 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 1309 times.
✗ Branch 5 not taken.
1309 double *ybasis = new double[polynomial_degree_y_];
179
2/4
✓ Branch 0 taken 1309 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 1309 times.
✗ Branch 5 not taken.
1309 double *xbasisD = new double[polynomial_degree_x_];
180
2/4
✓ Branch 0 taken 1309 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 1309 times.
✗ Branch 5 not taken.
1309 double *ybasisD = new double[polynomial_degree_y_];
181
182
1/2
✓ Branch 1 taken 1309 times.
✗ Branch 2 not taken.
1309 Bembel::Basis::ShapeFunctionHandler::evalBasis(polynomial_degree_x_ - 1,
183 xbasis, scaledx);
184
1/2
✓ Branch 1 taken 1309 times.
✗ Branch 2 not taken.
1309 Bembel::Basis::ShapeFunctionHandler::evalBasis(polynomial_degree_y_ - 1,
185 ybasis, scaledy);
186
1/2
✓ Branch 1 taken 1309 times.
✗ Branch 2 not taken.
1309 Bembel::Basis::ShapeFunctionHandler::evalDerBasis(polynomial_degree_x_ - 1,
187 xbasisD, scaledx);
188
1/2
✓ Branch 1 taken 1309 times.
✗ Branch 2 not taken.
1309 Bembel::Basis::ShapeFunctionHandler::evalDerBasis(polynomial_degree_y_ - 1,
189 ybasisD, scaledy);
190
191 1309 double tmp[4] = {0., 0., 0., 0.};
192 1309 double tmpDx[4] = {0., 0., 0., 0.};
193 1309 double tmpDy[4] = {0., 0., 0., 0.};
194
195
2/2
✓ Branch 0 taken 3959 times.
✓ Branch 1 taken 1309 times.
5268 for (int i = 0; i < polynomial_degree_x_; i++) {
196
2/2
✓ Branch 0 taken 15228 times.
✓ Branch 1 taken 3959 times.
19187 for (int j = 0; j < polynomial_degree_y_; j++) {
197 15228 const double tpbasisval = xbasis[i] * ybasis[j];
198 15228 const double tpbasisvalDx = xbasisD[i] * ybasis[j];
199 15228 const double tpbasisvalDy = xbasis[i] * ybasisD[j];
200 15228 const int accs = 4 * (numy * (polynomial_degree_x_ * x_location + i) +
201 15228 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
2/2
✓ Branch 0 taken 60912 times.
✓ Branch 1 taken 15228 times.
76140 for (int k = 0; k < 4; k++) {
207 60912 tmp[k] += data_[accs + k] * tpbasisval;
208 60912 tmpDx[k] += data_[accs + k] * tpbasisvalDx;
209 60912 tmpDy[k] += data_[accs + k] * tpbasisvalDy;
210 }
211 }
212 }
213
214
1/2
✓ Branch 0 taken 1309 times.
✗ Branch 1 not taken.
1309 delete[] xbasis;
215
1/2
✓ Branch 0 taken 1309 times.
✗ Branch 1 not taken.
1309 delete[] ybasis;
216
1/2
✓ Branch 0 taken 1309 times.
✗ Branch 1 not taken.
1309 delete[] xbasisD;
217
1/2
✓ Branch 0 taken 1309 times.
✗ Branch 1 not taken.
1309 delete[] ybasisD;
218
219
1/2
✓ Branch 1 taken 1309 times.
✗ Branch 2 not taken.
1309 Eigen::Matrix<double, 3, 2> out;
220
221 // Eigen::Vector3d out;
222
223 1309 double bot = 1. / (tmp[3] * tmp[3]);
224
225 #pragma omp simd
226
2/2
✓ Branch 0 taken 3927 times.
✓ Branch 1 taken 1309 times.
5236 for (int k = 0; k < 3; k++) {
227
1/2
✓ Branch 1 taken 3927 times.
✗ Branch 2 not taken.
3927 out(k, 0) = (tmpDx[k] * tmp[3] - tmp[k] * tmpDx[3]) * bot;
228
1/2
✓ Branch 1 taken 3927 times.
✗ Branch 2 not taken.
3927 out(k, 1) = (tmpDy[k] * tmp[3] - tmp[k] * tmpDy[3]) * bot;
229 }
230
231 2618 return out;
232 }
233
234 /**
235 * \brief Evaluate normal vector at given point.
236 *
237 * \param reference_point Point in reference domain.
238 * \return 3x1 normal vector.
239 */
240 1067 inline Eigen::Matrix<double, 3, 1> evalNormal(
241 const Eigen::Vector2d &reference_point) const {
242
1/2
✓ Branch 1 taken 1067 times.
✗ Branch 2 not taken.
1067 Eigen::Matrix<double, 3, 2> jac = evalJacobian(reference_point);
243
3/6
✓ Branch 1 taken 1067 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1067 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1067 times.
✗ Branch 8 not taken.
2134 return jac.col(0).cross(jac.col(1));
244 }
245
246 /**
247 * \brief Evaluate patch at given point.
248 *
249 * I look up the position in the knot vector, scale the input arguments,
250 * evaluate the 1D basis functions and sum over them with the control points
251 * from data.
252 *
253 * \param x Coordinate in reference domain.
254 * \param y Coordinate in reference domain.
255 * \return Point in physical domain.
256 */
257 77032 inline Eigen::Vector3d eval(double x, double y) const {
258
1/2
✓ Branch 2 taken 77032 times.
✗ Branch 3 not taken.
154064 return eval(Eigen::Vector2d(x, y));
259 }
260 /**
261 * \brief Evaluate Jacobian of the parametrization at given point.
262 *
263 * \param x Coordinate in reference domain.
264 * \param y Coordinate in reference domain.
265 * \return 3x2 Matrix with the Jacobian.
266 */
267 inline Eigen::Matrix<double, 3, 2> evalJacobian(double x, double y) const {
268 return evalJacobian(Eigen::Vector2d(x, y));
269 }
270 /**
271 * \brief Evaluate normal vector at given point.
272 *
273 * \param x Coordinate in reference domain.
274 * \param y Coordinate in reference domain.
275 * \return 3x1 normal vector.
276 */
277 inline Eigen::Matrix<double, 3, 1> evalNormal(double x, double y) const {
278 return evalNormal(Eigen::Vector2d(x, y));
279 }
280
281 //
282 /**
283 * \brief Updates the surface point and returns the physical point and the
284 * derivatives there.
285 *
286 * This is a combination of eval und evalJacobian, to avoid duplication of
287 * work.
288 *
289 * \param srf_pt Pointer to the SurfacePoint which gets updated.
290 * \param ref_pt Point in reference domain with respect to the patch.
291 * \param w quadrature weight.
292 * \param xi Point in reference domain with respect to the element.
293 */
294 99824430 void updateSurfacePoint(SurfacePoint *srf_pt,
295 const Eigen::Vector2d &ref_pt, double w,
296 const Eigen::Vector2d &xi) const {
297 const int x_location =
298 99824430 Spl::FindLocationInKnotVector(ref_pt(0), unique_knots_x_);
299 const int y_location =
300 99824430 Spl::FindLocationInKnotVector(ref_pt(1), unique_knots_y_);
301 99824430 const int numy = (unique_knots_y_.size() - 1) * polynomial_degree_y_;
302 99824430 const double scaledx = Spl::Rescale(ref_pt(0), unique_knots_x_[x_location],
303 99824430 unique_knots_x_[x_location + 1]);
304 99824430 const double scaledy = Spl::Rescale(ref_pt(1), unique_knots_y_[y_location],
305 99824430 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
1/2
✓ Branch 0 taken 99824430 times.
✗ Branch 1 not taken.
99824430 new double[2 * (polynomial_degree_x_ + polynomial_degree_y_) + 12];
311
2/2
✓ Branch 0 taken 1197893160 times.
✓ Branch 1 taken 99824430 times.
1297717590 for (int i = 0; i < 12; ++i) buffer[i] = 0;
312
313 99824430 double *tmp = buffer;
314 99824430 double *tmpDx = tmp + 4;
315 99824430 double *tmpDy = tmpDx + 4;
316 99824430 double *xbasis = tmpDy + 4;
317 99824430 double *ybasis = xbasis + polynomial_degree_x_;
318 99824430 double *xbasisD = ybasis + polynomial_degree_y_;
319 99824430 double *ybasisD = xbasisD + polynomial_degree_x_;
320
321 99824430 Bembel::Basis::ShapeFunctionHandler::evalBasis(polynomial_degree_x_ - 1,
322 xbasis, scaledx);
323 99824430 Bembel::Basis::ShapeFunctionHandler::evalBasis(polynomial_degree_y_ - 1,
324 ybasis, scaledy);
325 99824430 Bembel::Basis::ShapeFunctionHandler::evalDerBasis(polynomial_degree_x_ - 1,
326 xbasisD, scaledx);
327 99824430 Bembel::Basis::ShapeFunctionHandler::evalDerBasis(polynomial_degree_y_ - 1,
328 ybasisD, scaledy);
329
330
2/2
✓ Branch 0 taken 232534158 times.
✓ Branch 1 taken 99824430 times.
332358588 for (int i = 0; i < polynomial_degree_x_; ++i) {
331
2/2
✓ Branch 0 taken 629494806 times.
✓ Branch 1 taken 232534158 times.
862028964 for (int j = 0; j < polynomial_degree_y_; ++j) {
332 629494806 const double tpbasisval = xbasis[i] * ybasis[j];
333 629494806 const double tpbasisvalDx = xbasisD[i] * ybasis[j];
334 629494806 const double tpbasisvalDy = xbasis[i] * ybasisD[j];
335 629494806 const int accs = 4 * (numy * (polynomial_degree_x_ * x_location + i) +
336 629494806 polynomial_degree_y_ * y_location + j);
337
338 // Here I add up the values of the basis functions in the dc
339 // basis
340
2/2
✓ Branch 0 taken 2517979224 times.
✓ Branch 1 taken 629494806 times.
3147474030 for (int k = 0; k < 4; ++k) {
341 2517979224 tmp[k] += data_[accs + k] * tpbasisval;
342 2517979224 tmpDx[k] += data_[accs + k] * tpbasisvalDx;
343 2517979224 tmpDy[k] += data_[accs + k] * tpbasisvalDy;
344 }
345 }
346 }
347
348 99824430 const double bot = 1. / tmp[3];
349 99824430 const double botsqr = bot * bot;
350
351 99824430 (*srf_pt)(0) = xi(0);
352 99824430 (*srf_pt)(1) = xi(1);
353 99824430 (*srf_pt)(2) = w;
354 99824430 (*srf_pt)(3) = tmp[0] * bot;
355 99824430 (*srf_pt)(4) = tmp[1] * bot;
356 99824430 (*srf_pt)(5) = tmp[2] * bot;
357 99824430 (*srf_pt)(6) = (tmpDx[0] * tmp[3] - tmp[0] * tmpDx[3]) * botsqr;
358 99824430 (*srf_pt)(7) = (tmpDx[1] * tmp[3] - tmp[1] * tmpDx[3]) * botsqr;
359 99824430 (*srf_pt)(8) = (tmpDx[2] * tmp[3] - tmp[2] * tmpDx[3]) * botsqr;
360 99824430 (*srf_pt)(9) = (tmpDy[0] * tmp[3] - tmp[0] * tmpDy[3]) * botsqr;
361 99824430 (*srf_pt)(10) = (tmpDy[1] * tmp[3] - tmp[1] * tmpDy[3]) * botsqr;
362 99824430 (*srf_pt)(11) = (tmpDy[2] * tmp[3] - tmp[2] * tmpDy[3]) * botsqr;
363
1/2
✓ Branch 0 taken 99824430 times.
✗ Branch 1 not taken.
99824430 delete[] buffer;
364 99824430 return;
365 }
366
367 //////////////////////////////////////////////////////////////////////////////
368 /// getter
369 //////////////////////////////////////////////////////////////////////////////
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
380 /**
381 * \brief This function cuts a patch along internal knots, if any.
382 *
383 * \param patch Patch which gets checked and cut if there are internal knots.
384 * \return Vector of patches if it got cut, otherwise the vector is of size 1.
385 */
386 90 inline std::vector<Patch> PatchShredder(const Patch &patch) noexcept {
387 // Already a Bezier patch
388
5/6
✓ Branch 1 taken 89 times.
✓ Branch 2 taken 1 times.
✓ Branch 4 taken 89 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 89 times.
✓ Branch 7 taken 1 times.
90 if (patch.unique_knots_y_.size() == 2 && patch.unique_knots_x_.size() == 2) {
389
2/2
✓ Branch 4 taken 89 times.
✓ Branch 5 taken 89 times.
178 return {patch};
390 }
391
392 // number of subpatches in x and y directions
393 1 const int xchips = patch.unique_knots_x_.size() - 1;
394 1 const int ychips = patch.unique_knots_y_.size() - 1;
395
396 1 const int xp = patch.polynomial_degree_x_;
397 1 const int yp = patch.polynomial_degree_y_;
398 1 const int numy = ychips * yp;
399
400 1 std::vector<Patch> out(xchips * ychips);
401
402
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (int ix = 0; ix < xchips; ix++) {
403
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 for (int iy = 0; iy < ychips; iy++) {
404 4 const int index = ix * ychips + iy;
405
406 4 out[index].unique_knots_x_ = {0, 1};
407 4 out[index].unique_knots_y_ = {0, 1};
408 4 out[index].polynomial_degree_x_ = xp;
409 4 out[index].polynomial_degree_y_ = yp;
410 4 out[index].data_.reserve(xp * yp * 4);
411 }
412 }
413
414
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (int ix = 0; ix < xchips; ix++) {
415
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 for (int iy = 0; iy < ychips; iy++) {
416 4 const int index = ix * ychips + iy;
417
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
12 for (int jx = 0; jx < xp; jx++) {
418
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 8 times.
24 for (int jy = 0; jy < yp; jy++) {
419 16 const int accs = 4 * (numy * (xp * ix + jx) + yp * iy + jy);
420
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 16 times.
80 for (int k = 0; k < 4; k++) {
421 64 out[index].data_.push_back(patch.data_[accs + k]);
422 }
423 }
424 }
425 }
426 }
427
428 1 return out;
429 1 }
430
431 /**
432 * \brief This function cuts all patches along internal knots, if any.
433 *
434 * \param patches Vector with patches.
435 * \return Vector of patches if it got cut.
436 */
437 27 inline std::vector<Patch> PatchShredder(
438 const std::vector<Patch> &patches) noexcept {
439 27 std::vector<Patch> out;
440 27 const int input_size = patches.size();
441
442
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 27 times.
117 for (int i = 0; i < input_size; i++) {
443 90 std::vector<Patch> tmp = PatchShredder(patches[i]);
444
445 90 const int tmp_size = tmp.size();
446
447
2/2
✓ Branch 2 taken 93 times.
✓ Branch 3 taken 90 times.
183 for (int j = 0; j < tmp_size; j++) out.push_back(tmp[j]);
448 90 }
449
450 27 out.shrink_to_fit();
451
452 27 return out;
453 }
454
455 } // namespace Bembel
456
457 #endif // BEMBEL_SRC_GEOMETRY_PATCH_HPP_
458