1 #ifndef MEDUSA_BITS_DOMAINS_NURBSPATCH_HPP_
2 #define MEDUSA_BITS_DOMAINS_NURBSPATCH_HPP_
16 template <
typename vec_t,
typename param_vec_t>
19 const std::array<int, param_dim>& in_p) :
20 weighted_control_points{ wcp }, knots{ ks }, p{ in_p },
21 der_structure{
nullptr } {
22 assert_msg(param_dim <= 2,
"Only NURBS curves and surfaces are currently supported.");
25 template <
typename vec_t,
typename param_vec_t>
28 const std::array<int, param_dim>& in_p) :
29 knots{ ks }, p{ in_p }, der_structure{
nullptr } {
30 assert_msg(param_dim <= 2,
"Only NURBS curves and surfaces are currently supported.");
32 weighted_control_points = nurbs_patch_internal::NURBSPatchHelper<vec_t, param_vec_t>::
36 template <
typename vec_t,
typename param_vec_t>
38 : weighted_control_points{ patch.weighted_control_points },
39 knots{ patch.knots }, p { patch.p } {
40 if (patch.der_structure !=
nullptr) {
41 der_structure = std::unique_ptr<std::array<NURBSPatch<vec_t, param_vec_t>, param_dim>>(
42 new std::array<NURBSPatch<vec_t, param_vec_t>, param_dim>(*patch.der_structure));
46 template <
typename vec_t,
typename param_vec_t>
49 weighted_control_points = other.weighted_control_points;
53 if (other.der_structure ==
nullptr && der_structure !=
nullptr) {
54 der_structure =
nullptr;
55 }
else if (other.der_structure !=
nullptr) {
56 der_structure = std::unique_ptr<std::array<NURBSPatch<vec_t, param_vec_t>, param_dim>>(
57 new std::array<NURBSPatch<vec_t, param_vec_t>, param_dim>(*other.der_structure));
63 template <
typename vec_t,
typename param_vec_t>
68 template <
typename vec_t,
typename param_vec_t>
73 for (
int i = 0; i <
dim; i++) {
74 pt(i) = weighted_pt(i) / weighted_pt(proj_dim - 1);
76 *w = weighted_pt(proj_dim - 1);
80 template <
typename vec_t,
typename param_vec_t>
83 return evaluate(t, &w);
86 template <
typename vec_t,
typename param_vec_t>
92 template <
typename vec_t,
typename param_vec_t>
100 template <
typename vec_t,
typename param_vec_t>
105 vec_t pt = evaluate(t, &w);
106 return jacobian(t, pt, w);
109 template <
typename vec_t,
typename param_vec_t>
116 vec_t pt = evaluate(t, &w);
117 Eigen::Matrix<scalar_t, dim, param_dim> jm = jacobian(t, pt, w);
118 return std::pair<vec_t, Eigen::Matrix<scalar_t, dim, param_dim>>(pt, jm);
121 template <
typename vec_t,
typename param_vec_t>
123 param_vec_t beg, end;
124 for (
int i = 0; i < param_dim; i++) {
125 beg(i) = knots[i].front();
126 end(i) = knots[i].back();
132 template <
typename vec_t,
typename param_vec_t>
139 template <
typename vec_t,
typename param_vec_t>
146 template <
typename vec_t,
typename param_vec_t>
155 template <
typename vec_t>
162 typedef Vec<scalar_t, proj_dim> proj_vec_t;
164 static Range<Range<proj_vec_t>> cpToWcp(
const Range<Range<vec_t>>& cp,
165 const Range<Range<double>>& w) {
166 Range<Range<proj_vec_t>> weighted_control_points;
168 weighted_control_points.resize(cp.size());
169 for (
int i = 0; i < cp.size(); i++) {
170 weighted_control_points[i].resize(cp[i].size());
171 for (
int j = 0; j < cp[i].size(); j++) {
174 for (
int y = 0; y <
dim; y++) {
175 temp(y) = w[i][j] * cp[i][j](y);
177 temp(proj_dim - 1) = w[i][j];
179 weighted_control_points[i][j] = temp;
183 return weighted_control_points;
186 static void computeDerivativeStructure(NURBSPatch<vec_t, param_vec_t>& patch) {
187 if (patch.der_structure !=
nullptr) {
192 Range<Range<proj_vec_t>> v_der_wcp(patch.weighted_control_points.size());
193 for (
int i = 0; i < patch.weighted_control_points.size(); i++) {
195 patch.weighted_control_points[i], patch.knots[1], v_der_wcp[i]);
199 Range<scalar_t> v_der_knots;
205 Range<Range<proj_vec_t>> u_der_wcp_initial(patch.weighted_control_points[0].size());
206 for (
int i = 0; i < patch.weighted_control_points[0].size(); i++) {
207 Range<proj_vec_t> temp_range(patch.weighted_control_points.size());
208 for (
int j = 0; j < patch.weighted_control_points.size(); j++) {
209 temp_range[j] = patch.weighted_control_points[j][i];
212 patch.knots[0], u_der_wcp_initial[i]);
215 Range<Range<proj_vec_t>> u_der_wcp(patch.weighted_control_points.size() - 1);
216 for (
int i = 0; i < patch.weighted_control_points.size() - 1; i++) {
217 u_der_wcp[i].resize(patch.weighted_control_points[0].size());
218 for (
int j = 0; j < patch.weighted_control_points[0].size(); j++) {
219 u_der_wcp[i][j] = u_der_wcp_initial[j][i];
224 Range<scalar_t> u_der_knots;
228 patch.der_structure =
229 std::unique_ptr<std::array<NURBSPatch<vec_t, param_vec_t>, param_dim>>(
230 new std::array<NURBSPatch<vec_t, param_vec_t>, param_dim>{
231 NURBSPatch<vec_t, param_vec_t>(u_der_wcp,
232 std::array<Range<scalar_t>, param_dim>{u_der_knots, patch.knots[1]},
233 std::array<int, param_dim>{patch.p[0] - 1, patch.p[1]}),
234 NURBSPatch<vec_t, param_vec_t>(v_der_wcp,
235 std::array<Range<scalar_t>, param_dim>{patch.knots[0], v_der_knots},
236 std::array<int, param_dim>{patch.p[0], patch.p[1] - 1})});
239 static proj_vec_t evaluateWeighted(
const NURBSPatch<vec_t, param_vec_t>& patch,
240 const param_vec_t& t) {
245 Range<proj_vec_t> secondary_control_points(patch.weighted_control_points.size());
246 for (
int i = 0; i < patch.weighted_control_points.size(); i++) {
248 patch.weighted_control_points[i], patch.knots[1]);
256 static Eigen::Matrix<scalar_t, dim, param_dim> jacobian(
257 const NURBSPatch<vec_t, param_vec_t>& patch,
const param_vec_t& t,
const vec_t& pt,
259 assert_msg(patch.der_structure !=
nullptr,
"Derivative structure not initialised, "
260 "call initDerivative() before calling this function.");
263 proj_vec_t der_u_pt = (*patch.der_structure)[0].evaluateWeighted(t);
267 for (
int i = 0; i <
dim; i++) {
268 der_u(i) = (der_u_pt(i) - der_u_pt(proj_dim - 1) * pt(i)) / w;
272 proj_vec_t der_v_pt = (*patch.der_structure)[1].evaluateWeighted(t);
276 for (
int i = 0; i <
dim; i++) {
277 der_v(i) = (der_v_pt(i) - der_v_pt(proj_dim - 1) * pt(i)) / w;
281 Eigen::Matrix<scalar_t, dim, 2> jm;
289 static Range<NURBSPatch<vec_t,
Vec<
scalar_t, param_dim - 1>>> getBoundaries(
290 const NURBSPatch<vec_t, param_vec_t>& patch) {
292 NURBSPatch<vec_t,
Vec<
scalar_t, param_dim - 1>> b1(patch.weighted_control_points.front(),
293 {patch.knots[1]}, {patch.p[1]});
294 NURBSPatch<vec_t,
Vec<
scalar_t, param_dim - 1>> b2(patch.weighted_control_points.back(),
295 {patch.knots[1]}, {patch.p[1]});
298 Range<proj_vec_t> wcp_front(patch.weighted_control_points.size());
299 Range<proj_vec_t> wcp_back(patch.weighted_control_points.size());
300 for (
int i = 0; i < patch.weighted_control_points.size(); i++) {
301 wcp_front[i] = patch.weighted_control_points[i].front();
302 wcp_back[i] = patch.weighted_control_points[i].back();
306 NURBSPatch<vec_t,
Vec<
scalar_t, param_dim - 1>> b3(wcp_front, {patch.knots[0]},
308 NURBSPatch<vec_t,
Vec<
scalar_t, param_dim - 1>> b4(wcp_back, {patch.knots[0]},
311 return Range<NURBSPatch<vec_t,
Vec<
scalar_t, param_dim - 1>>>{b1, b2, b3, b4};
314 static param_vec_t getPatchParameterFromBoundaryParameter(
315 const NURBSPatch<vec_t, param_vec_t>& patch,
const Vec<scalar_t, param_dim - 1>& t,
317 scalar_t eps_1 = epsilon * (patch.knots[0].back() - patch.knots[0].front());
318 scalar_t eps_2 = epsilon * (patch.knots[1].back() - patch.knots[1].front());
320 if (i == 0)
return Vec<scalar_t, 2>(patch.knots[0].front() + eps_1, t(0));
321 else if (i == 1)
return Vec<scalar_t, 2>(patch.knots[0].back() - eps_1, t(0));
322 else if (i == 2)
return Vec<scalar_t, 2>(t(0), patch.knots[1].front() + eps_2);
323 else if (i == 3)
return Vec<scalar_t, 2>(t(0), patch.knots[1].back() - eps_2);
325 assert_msg(
false,
"Invalid boundary index, should be 0 <= i <= 3, got %d.", i);
329 static Vec<
scalar_t, param_dim - 1> getBoundaryParameterFromPatchParameter(
330 const NURBSPatch<vec_t, param_vec_t>& patch,
const param_vec_t& t,
int i) {
331 if (i == 0 || i == 1)
return Vec<
scalar_t, param_dim - 1>(t(1));
332 else if (i == 2 || i == 3)
return Vec<
scalar_t, param_dim - 1>(t(0));
334 assert_msg(
false,
"Invalid edge index, should be 0 <= i <= 3, got %d.", i);
339 template <
typename vec_t>
340 struct nurbs_patch_internal::NURBSPatchHelper<vec_t,
Vec<typename vec_t::
scalar_t, 1>> {
341 typedef Vec<typename vec_t::scalar_t, 1> param_vec_t;
346 typedef Vec<scalar_t, proj_dim> proj_vec_t;
348 static Range<proj_vec_t> cpToWcp(
const Range<vec_t>& cp,
const Range<double>& w) {
349 Range<proj_vec_t> weighted_control_points;
351 weighted_control_points.resize(cp.size());
352 for (
int i = 0; i < cp.size(); i++) {
355 for (
int j = 0; j <
dim; j++) {
356 temp(j) = w[i] * cp[i](j);
358 temp(proj_dim - 1) = w[i];
360 weighted_control_points[i] = temp;
363 return weighted_control_points;
366 static void computeDerivativeStructure(NURBSPatch<vec_t, param_vec_t>& patch) {
367 if (patch.der_structure !=
nullptr || patch.p[0] == 0) {
371 Range<proj_vec_t> derivative_weighted_control_points;
372 Range<scalar_t> derivative_knots;
374 patch.knots[0], derivative_weighted_control_points, derivative_knots);
376 patch.der_structure =
377 std::unique_ptr<std::array<NURBSPatch<vec_t, param_vec_t>, param_dim>>(
378 new std::array<NURBSPatch<vec_t, param_vec_t>, param_dim>{
379 NURBSPatch<vec_t, param_vec_t>(derivative_weighted_control_points,
380 {derivative_knots}, {patch.p[0] - 1})});
383 static proj_vec_t evaluateWeighted(
const NURBSPatch<vec_t, param_vec_t>& patch,
384 const param_vec_t& t) {
389 static Eigen::Matrix<scalar_t, dim, param_dim> jacobian(
390 const NURBSPatch<vec_t, param_vec_t>& patch,
const param_vec_t& t,
const vec_t& pt,
392 if (patch.p[0] == 0) {
395 assert_msg(patch.der_structure !=
nullptr,
"Derivative structure not initialised, "
396 "call initDerivative() before calling this function.");
399 proj_vec_t der_pt = (*patch.der_structure)[0].evaluateWeighted(t);
403 for (
int i = 0; i <
dim; i++) {
404 jacobian(i) = (der_pt(i) - der_pt(proj_dim - 1) * pt(i)) / w;
410 static Range<NURBSPatch<vec_t,
Vec<
scalar_t, param_dim - 1>>> getBoundaries(
411 const NURBSPatch<vec_t, param_vec_t>& patch) {
412 return {NURBSPatch<vec_t,
Vec<
scalar_t, param_dim - 1>>({}, {}, {}),
413 NURBSPatch<vec_t, Vec<scalar_t, param_dim - 1>>({}, {}, {})};
416 static param_vec_t getPatchParameterFromBoundaryParameter(
417 const NURBSPatch<vec_t, param_vec_t>& patch,
const Vec<scalar_t, param_dim - 1>& t,
419 BoxShape<param_vec_t> dom = patch.getDomain();
420 scalar_t eps = epsilon * (patch.knots[0].back() - patch.knots[0].front());
422 if (i == 0)
return dom.beg() + param_vec_t(eps);
423 else if (i == 1)
return dom.end() - param_vec_t(eps);
425 assert_msg(
false,
"Invalid boundary index, should be 0 <= i <= 1, got %d.", i);
429 static Vec<
scalar_t, param_dim - 1> getBoundaryParameterFromPatchParameter(
430 const NURBSPatch<vec_t, param_vec_t>& patch,
const param_vec_t& t,
int i) {
431 if (i == 0 || i == 1)
return {};
433 assert_msg(
false,
"Invalid edge index, should be 0 <= i <= 1, got %d.", i);
441 #endif // MEDUSA_BITS_DOMAINS_NURBSPATCH_HPP_