Skip to content

Commit

Permalink
Bugfix for #406
Browse files Browse the repository at this point in the history
  • Loading branch information
jzwar authored and j042 committed Apr 11, 2024
1 parent 73dd83b commit 66193bc
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 24 deletions.
11 changes: 2 additions & 9 deletions include/splinepy/splines/helpers/extract.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,7 @@ ExtractControlMeshSlice(const SplineType& spline,
*/
std::vector<std::vector<int>>
ExtractBezierPatchIDs(const std::vector<std::vector<int>>& 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
*
Expand Down Expand Up @@ -221,7 +220,6 @@ ExtractBezierPatches(const SplineType& spline) {
std::array<int, para_dim> degrees{};
input.SplinepyCurrentProperties(degrees.data(), nullptr, nullptr, nullptr);

std::array<int, para_dim> n_patches_per_para_dim{};
std::array<int, para_dim> n_ctps_per_para_dim{};

// Identify all internal knots and the number of required Bezier patches
Expand All @@ -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
Expand All @@ -247,9 +242,7 @@ ExtractBezierPatches(const SplineType& spline) {

// Retrieve id information
const std::vector<std::vector<int>>& 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();
Expand Down
8 changes: 1 addition & 7 deletions src/py/py_knot_insertion_matrix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -385,8 +385,6 @@ py::tuple BezierExtractionMatrices(const std::shared_ptr<PySpline>& spline,

// Here we compute the individual components that are required to initialize
// the sparse matrices in the python frontend
std::vector<int> n_patches_per_dimension{};
n_patches_per_dimension.reserve(n_para_dims);
// numpy view to call ComputeGlobalKnotInsertionMatrix
py::array_t<int> np_degrees(degrees.size(), degrees.data(), py::none());
for (int parametric_dimension{}; parametric_dimension < n_para_dims;
Expand All @@ -400,9 +398,6 @@ py::tuple BezierExtractionMatrices(const std::shared_ptr<PySpline>& 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,
Expand All @@ -428,8 +423,7 @@ py::tuple BezierExtractionMatrices(const std::shared_ptr<PySpline>& 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<int> bezier_ctps_ids(n_ctps_per_patch * n_patches);
Expand Down
30 changes: 22 additions & 8 deletions src/splines/helpers/extract.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,39 @@ namespace splinepy::splines::helpers {

std::vector<std::vector<int>>
ExtractBezierPatchIDs(const std::vector<std::vector<int>>& 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<std::size_t> bezier_index_offsets{};
bezier_index_offsets.reserve(para_dim);
bezier_index_offsets.push_back(1);
std::vector<std::size_t> control_mesh_resolution(para_dim);
std::vector<std::size_t> n_patches_per_para_dim(para_dim);

control_mesh_resolution[0] = std::accumulate(knot_multiplicities[0].begin(),
knot_multiplicities[0].end(),
static_cast<std::size_t>(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<std::size_t>(0))
- degrees[i_para_dim] - 1;
}

// Init return values
Expand Down Expand Up @@ -68,8 +83,7 @@ ExtractBezierPatchIDs(const std::vector<std::vector<int>>& 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);
}
Expand Down
12 changes: 12 additions & 0 deletions tests/test_bezier_extraction.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 66193bc

Please sign in to comment.