From 66193bc77ab965da9ebd16f218b32427f4a838cc Mon Sep 17 00:00:00 2001 From: jzwar Date: Wed, 10 Apr 2024 15:44:36 +0200 Subject: [PATCH] Bugfix for #406 --- include/splinepy/splines/helpers/extract.hpp | 11 ++----- src/py/py_knot_insertion_matrix.cpp | 8 +----- src/splines/helpers/extract.cpp | 30 ++++++++++++++------ tests/test_bezier_extraction.py | 12 ++++++++ 4 files changed, 37 insertions(+), 24 deletions(-) diff --git a/include/splinepy/splines/helpers/extract.hpp b/include/splinepy/splines/helpers/extract.hpp index 77f095a1f..69020a6d9 100644 --- a/include/splinepy/splines/helpers/extract.hpp +++ b/include/splinepy/splines/helpers/extract.hpp @@ -192,8 +192,7 @@ ExtractControlMeshSlice(const SplineType& spline, */ std::vector> ExtractBezierPatchIDs(const std::vector>& knot_multiplicities, - const int* degrees, - const int* n_patches_per_para_dim); + const int* degrees); /** * @brief Extracts Bezier patches of a B-Spline/NURBS type * @@ -221,7 +220,6 @@ ExtractBezierPatches(const SplineType& spline) { std::array degrees{}; input.SplinepyCurrentProperties(degrees.data(), nullptr, nullptr, nullptr); - std::array n_patches_per_para_dim{}; std::array n_ctps_per_para_dim{}; // Identify all internal knots and the number of required Bezier patches @@ -233,9 +231,6 @@ ExtractBezierPatches(const SplineType& spline) { // Extract internal knots const auto bezier_information = parameter_space.DetermineBezierExtractionKnots(pd_query); - n_patches_per_para_dim[i_p_dim] = std::get<0>(bezier_information); - n_ctps_per_para_dim[i_p_dim] = - n_patches_per_para_dim[i_p_dim] * degrees[i_p_dim] + 1; const auto& required_knot_insertions = std::get<1>(bezier_information); // Insert knot into the copy of the spline before extraction @@ -247,9 +242,7 @@ ExtractBezierPatches(const SplineType& spline) { // Retrieve id information const std::vector>& ids = - ExtractBezierPatchIDs(input.SplinepyKnotMultiplicities(), - degrees.data(), - n_patches_per_para_dim.data()); + ExtractBezierPatchIDs(input.SplinepyKnotMultiplicities(), degrees.data()); // Number of total patches const int n_total_patches = ids.size(); diff --git a/src/py/py_knot_insertion_matrix.cpp b/src/py/py_knot_insertion_matrix.cpp index bd2cff1a1..6ce7aa584 100644 --- a/src/py/py_knot_insertion_matrix.cpp +++ b/src/py/py_knot_insertion_matrix.cpp @@ -385,8 +385,6 @@ py::tuple BezierExtractionMatrices(const std::shared_ptr& spline, // Here we compute the individual components that are required to initialize // the sparse matrices in the python frontend - std::vector n_patches_per_dimension{}; - n_patches_per_dimension.reserve(n_para_dims); // numpy view to call ComputeGlobalKnotInsertionMatrix py::array_t np_degrees(degrees.size(), degrees.data(), py::none()); for (int parametric_dimension{}; parametric_dimension < n_para_dims; @@ -400,9 +398,6 @@ py::tuple BezierExtractionMatrices(const std::shared_ptr& spline, const auto& new_kv = create_new_knot_vector(tmp_kv, degrees[parametric_dimension], new_knots); - n_patches_per_dimension.push_back( - (new_kv.size() - degrees[parametric_dimension] - 2) - / degrees[parametric_dimension]); // Add data to list list_of_tuples.append(ComputeGlobalKnotInsertionMatrix(tmp_kvs, @@ -428,8 +423,7 @@ py::tuple BezierExtractionMatrices(const std::shared_ptr& spline, // matrix. const auto& list_of_ids = splines::helpers::ExtractBezierPatchIDs(knot_multiplicities, - degrees.data(), - n_patches_per_dimension.data()); + degrees.data()); const int n_patches = list_of_ids.size(); const int n_ctps_per_patch = list_of_ids[0].size(); py::array_t bezier_ctps_ids(n_ctps_per_patch * n_patches); diff --git a/src/splines/helpers/extract.cpp b/src/splines/helpers/extract.cpp index d58f52d47..1c0b4285c 100644 --- a/src/splines/helpers/extract.cpp +++ b/src/splines/helpers/extract.cpp @@ -4,24 +4,39 @@ namespace splinepy::splines::helpers { std::vector> ExtractBezierPatchIDs(const std::vector>& knot_multiplicities, - const int* degrees, - const int* n_patches_per_para_dim) { + const int* degrees) { const int para_dim = knot_multiplicities.size(); - // Number of total patches and ctps per patch - int n_total_patches = n_patches_per_para_dim[0]; - int n_ctps_per_patch = degrees[0] + 1; - // Offsets for start values of individual patches std::vector bezier_index_offsets{}; bezier_index_offsets.reserve(para_dim); bezier_index_offsets.push_back(1); + std::vector control_mesh_resolution(para_dim); + std::vector n_patches_per_para_dim(para_dim); + + control_mesh_resolution[0] = std::accumulate(knot_multiplicities[0].begin(), + knot_multiplicities[0].end(), + static_cast(0)) + - degrees[0] - 1; + n_patches_per_para_dim[0] = knot_multiplicities[0].size() - 1; + + // Number of total patches and ctps per patch + int n_total_patches = n_patches_per_para_dim[0]; + int n_ctps_per_patch = degrees[0] + 1; + for (int i_para_dim{1}; i_para_dim < para_dim; i_para_dim++) { + n_patches_per_para_dim[i_para_dim] = + knot_multiplicities[i_para_dim].size() - 1; n_total_patches *= n_patches_per_para_dim[i_para_dim]; n_ctps_per_patch *= degrees[i_para_dim] + 1; bezier_index_offsets.push_back(bezier_index_offsets[i_para_dim - 1] * (degrees[i_para_dim - 1] + 1)); + control_mesh_resolution[i_para_dim] = + std::accumulate(knot_multiplicities[i_para_dim].begin(), + knot_multiplicities[i_para_dim].end(), + static_cast(0)) + - degrees[i_para_dim] - 1; } // Init return values @@ -68,8 +83,7 @@ ExtractBezierPatchIDs(const std::vector>& knot_multiplicities, global_id += (local_id + patch_ctp_id_offsets[i_para_dim]) * n_ctps_in_previous_layers; // Multiply to index offset - n_ctps_in_previous_layers *= - n_patches_per_para_dim[i_para_dim] * degrees[i_para_dim] + 1; + n_ctps_in_previous_layers *= control_mesh_resolution[i_para_dim]; } ids.push_back(global_id); } diff --git a/tests/test_bezier_extraction.py b/tests/test_bezier_extraction.py index 1d08b2600..0e8369ee6 100644 --- a/tests/test_bezier_extraction.py +++ b/tests/test_bezier_extraction.py @@ -42,6 +42,18 @@ def test_extraction(self): ) ) + def test_extraction_0th_degree(self): + """Edge case for 0th degree""" + test = c.splinepy.BSpline( + degrees=[0, 0], + control_points=[ + [0], [1], [2], [3], + ], + knot_vectors=[[0, .5, 1], [0, .5, 1]] + ) + for i, patch in enumerate(test.extract.beziers()): + self.assertTrue(c.np.allclose(test.cps[i], patch.cps[0])) + def test_extraction_matrices_bspline_3D(self): """Create matrices to extract splines""" # Init b-splines