Fix T102537: Curve subdivide mishandles single point curves

Also, single point cyclic Catmull Rom curves aren't evaluated properly.
Cyclic is meant to make no difference in that case. Now they correctly
evaluate to a single point.
This commit is contained in:
Hans Goudey 2022-11-15 18:52:02 -06:00
parent 4401c93e45
commit f7e0317b96
Notes: blender-bot 2023-02-14 06:23:08 +01:00
Referenced by issue #100749, Blender LTS: Maintenance Task 3.3
Referenced by issue #102537, GN: Undefined behavior for subdivided cyclical single-point Catmull-Rom splines
2 changed files with 18 additions and 9 deletions

View File

@ -12,8 +12,12 @@ namespace blender::bke::curves::catmull_rom {
int calculate_evaluated_num(const int points_num, const bool cyclic, const int resolution)
{
const int eval_num = resolution * segments_num(points_num, cyclic);
if (cyclic) {
/* Make sure there is a single evaluated point for the single-point curve case. */
return std::max(eval_num, 1);
}
/* If the curve isn't cyclic, one last point is added to the final point. */
return cyclic ? eval_num : eval_num + 1;
return eval_num + 1;
}
/* Adapted from Cycles #catmull_rom_basis_eval function. */

View File

@ -37,16 +37,21 @@ static void calculate_result_offsets(const bke::CurvesGeometry &src_curves,
const IndexRange src_segments = curve_dst_offsets(src_points, curve_i);
MutableSpan<int> point_offsets = dst_point_offsets.slice(src_segments);
MutableSpan<int> point_counts = point_offsets.drop_back(1);
cuts.materialize_compressed(src_points, point_counts);
for (int &count : point_counts) {
/* Make sure the number of cuts is greater than zero and add one for the existing point. */
count = std::max(count, 0) + 1;
if (src_points.size() == 1) {
point_counts.first() = 1;
}
if (!cyclic[curve_i]) {
/* The last point only has a segment to be subdivided if the curve isn't cyclic. */
point_counts.last() = 1;
else {
cuts.materialize_compressed(src_points, point_counts);
for (int &count : point_counts) {
/* Make sure there at least one cut, and add one for the existing point. */
count = std::max(count, 0) + 1;
}
if (!cyclic[curve_i]) {
/* The last point only has a segment to be subdivided if the curve isn't cyclic. */
point_counts.last() = 1;
}
}
bke::curves::accumulate_counts_to_offsets(point_offsets);