Curves: Provide resample functions that don't depend on field evaluation
This splits the core part of `resample_to_uniform` into it's own function, so that it doesn't depend on field evaluation. From there, new versions of `resample_to_count`, `resample_to_length`, and `resample_to_evaluated` are provided. Pull Request: https://projects.blender.org/blender/blender/pulls/118551
This commit is contained in:
parent
1bff17cc99
commit
584d26106a
|
@ -25,6 +25,10 @@ struct ResampleCurvesOutputAttributeIDs {
|
|||
*
|
||||
* \note The values provided by the #count_field are clamped to 1 or greater.
|
||||
*/
|
||||
CurvesGeometry resample_to_count(const CurvesGeometry &src_curves,
|
||||
const IndexMask &selection,
|
||||
const VArray<int> &counts,
|
||||
const ResampleCurvesOutputAttributeIDs &output_ids = {});
|
||||
CurvesGeometry resample_to_count(const CurvesGeometry &src_curves,
|
||||
const fn::FieldContext &field_context,
|
||||
const fn::Field<bool> &selection_field,
|
||||
|
@ -36,6 +40,10 @@ CurvesGeometry resample_to_count(const CurvesGeometry &src_curves,
|
|||
* #segment_length field input, rounded to make the length of each segment the same.
|
||||
* The accuracy will depend on the curve's resolution parameter.
|
||||
*/
|
||||
CurvesGeometry resample_to_length(const CurvesGeometry &src_curves,
|
||||
const IndexMask &selection,
|
||||
const VArray<float> &sample_lengths,
|
||||
const ResampleCurvesOutputAttributeIDs &output_ids = {});
|
||||
CurvesGeometry resample_to_length(const CurvesGeometry &src_curves,
|
||||
const fn::FieldContext &field_context,
|
||||
const fn::Field<bool> &selection_field,
|
||||
|
@ -45,6 +53,9 @@ CurvesGeometry resample_to_length(const CurvesGeometry &src_curves,
|
|||
/**
|
||||
* Evaluate each selected curve to its implicit evaluated points.
|
||||
*/
|
||||
CurvesGeometry resample_to_evaluated(const CurvesGeometry &src_curves,
|
||||
const IndexMask &selection,
|
||||
const ResampleCurvesOutputAttributeIDs &output_ids = {});
|
||||
CurvesGeometry resample_to_evaluated(const CurvesGeometry &src_curves,
|
||||
const fn::FieldContext &field_context,
|
||||
const fn::Field<bool> &selection_field,
|
||||
|
|
|
@ -245,37 +245,21 @@ static void normalize_curve_point_data(const IndexMaskSegment curve_selection,
|
|||
}
|
||||
}
|
||||
|
||||
static CurvesGeometry resample_to_uniform(const CurvesGeometry &src_curves,
|
||||
const fn::FieldContext &field_context,
|
||||
const fn::Field<bool> &selection_field,
|
||||
const fn::Field<int> &count_field,
|
||||
const ResampleCurvesOutputAttributeIDs &output_ids)
|
||||
static void resample_to_uniform(const CurvesGeometry &src_curves,
|
||||
const IndexMask &selection,
|
||||
const ResampleCurvesOutputAttributeIDs &output_ids,
|
||||
CurvesGeometry &dst_curves)
|
||||
{
|
||||
if (src_curves.curves_range().is_empty()) {
|
||||
return {};
|
||||
return;
|
||||
}
|
||||
|
||||
const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
|
||||
const OffsetIndices evaluated_points_by_curve = src_curves.evaluated_points_by_curve();
|
||||
const VArray<bool> curves_cyclic = src_curves.cyclic();
|
||||
const VArray<int8_t> curve_types = src_curves.curve_types();
|
||||
const Span<float3> evaluated_positions = src_curves.evaluated_positions();
|
||||
|
||||
CurvesGeometry dst_curves = bke::curves::copy_only_curve_domain(src_curves);
|
||||
MutableSpan<int> dst_offsets = dst_curves.offsets_for_write();
|
||||
|
||||
fn::FieldEvaluator evaluator{field_context, src_curves.curves_num()};
|
||||
evaluator.set_selection(selection_field);
|
||||
evaluator.add_with_destination(count_field, dst_offsets.drop_back(1));
|
||||
evaluator.evaluate();
|
||||
const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
|
||||
IndexMaskMemory memory;
|
||||
const IndexMask unselected = selection.complement(src_curves.curves_range(), memory);
|
||||
|
||||
/* Fill the counts for the curves that aren't selected and accumulate the counts into offsets. */
|
||||
offset_indices::copy_group_sizes(src_points_by_curve, unselected, dst_offsets);
|
||||
offset_indices::accumulate_counts_to_offsets(dst_offsets);
|
||||
dst_curves.resize(dst_offsets.last(), dst_curves.curves_num());
|
||||
|
||||
/* All resampled curves are poly curves. */
|
||||
dst_curves.fill_curve_types(selection, CURVE_TYPE_POLY);
|
||||
|
||||
|
@ -385,11 +369,74 @@ static CurvesGeometry resample_to_uniform(const CurvesGeometry &src_curves,
|
|||
}
|
||||
});
|
||||
|
||||
IndexMaskMemory memory;
|
||||
const IndexMask unselected = selection.complement(src_curves.curves_range(), memory);
|
||||
copy_or_defaults_for_unselected_curves(src_curves, unselected, attributes, dst_curves);
|
||||
|
||||
for (bke::GSpanAttributeWriter &attribute : attributes.dst_attributes) {
|
||||
attribute.finish();
|
||||
}
|
||||
}
|
||||
|
||||
static CurvesGeometry resample_to_uniform(const CurvesGeometry &src_curves,
|
||||
const fn::FieldContext &field_context,
|
||||
const fn::Field<bool> &selection_field,
|
||||
const fn::Field<int> &count_field,
|
||||
const ResampleCurvesOutputAttributeIDs &output_ids)
|
||||
{
|
||||
if (src_curves.curves_range().is_empty()) {
|
||||
return {};
|
||||
}
|
||||
const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
|
||||
|
||||
CurvesGeometry dst_curves = bke::curves::copy_only_curve_domain(src_curves);
|
||||
MutableSpan<int> dst_offsets = dst_curves.offsets_for_write();
|
||||
|
||||
fn::FieldEvaluator evaluator{field_context, src_curves.curves_num()};
|
||||
evaluator.set_selection(selection_field);
|
||||
evaluator.add_with_destination(count_field, dst_offsets.drop_back(1));
|
||||
evaluator.evaluate();
|
||||
const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
|
||||
IndexMaskMemory memory;
|
||||
const IndexMask unselected = selection.complement(src_curves.curves_range(), memory);
|
||||
|
||||
/* Fill the counts for the curves that aren't selected and accumulate the counts into offsets. */
|
||||
offset_indices::copy_group_sizes(src_points_by_curve, unselected, dst_offsets);
|
||||
offset_indices::accumulate_counts_to_offsets(dst_offsets);
|
||||
dst_curves.resize(dst_offsets.last(), dst_curves.curves_num());
|
||||
|
||||
resample_to_uniform(src_curves, selection, output_ids, dst_curves);
|
||||
|
||||
return dst_curves;
|
||||
}
|
||||
|
||||
CurvesGeometry resample_to_count(const CurvesGeometry &src_curves,
|
||||
const IndexMask &selection,
|
||||
const VArray<int> &counts,
|
||||
const ResampleCurvesOutputAttributeIDs &output_ids)
|
||||
{
|
||||
if (src_curves.curves_range().is_empty()) {
|
||||
return {};
|
||||
}
|
||||
const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
|
||||
|
||||
CurvesGeometry dst_curves = bke::curves::copy_only_curve_domain(src_curves);
|
||||
MutableSpan<int> dst_offsets = dst_curves.offsets_for_write();
|
||||
|
||||
array_utils::copy(counts, selection, dst_offsets);
|
||||
|
||||
IndexMaskMemory memory;
|
||||
const IndexMask unselected = selection.complement(src_curves.curves_range(), memory);
|
||||
|
||||
/* Fill the counts for the curves that aren't selected and accumulate the counts into offsets. */
|
||||
offset_indices::copy_group_sizes(src_points_by_curve, unselected, dst_offsets);
|
||||
/* We assume the counts are at least 1. */
|
||||
BLI_assert(std::all_of(
|
||||
dst_offsets.begin(), dst_offsets.end(), [&](const int i) { return dst_offsets[i] > 0; }));
|
||||
offset_indices::accumulate_counts_to_offsets(dst_offsets);
|
||||
dst_curves.resize(dst_offsets.last(), dst_curves.curves_num());
|
||||
|
||||
resample_to_uniform(src_curves, selection, output_ids, dst_curves);
|
||||
|
||||
return dst_curves;
|
||||
}
|
||||
|
@ -407,6 +454,40 @@ CurvesGeometry resample_to_count(const CurvesGeometry &src_curves,
|
|||
output_ids);
|
||||
}
|
||||
|
||||
CurvesGeometry resample_to_length(const CurvesGeometry &src_curves,
|
||||
const IndexMask &selection,
|
||||
const VArray<float> &sample_lengths,
|
||||
const ResampleCurvesOutputAttributeIDs &output_ids)
|
||||
{
|
||||
if (src_curves.curves_range().is_empty()) {
|
||||
return {};
|
||||
}
|
||||
const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
|
||||
const VArray<bool> curves_cyclic = src_curves.cyclic();
|
||||
|
||||
CurvesGeometry dst_curves = bke::curves::copy_only_curve_domain(src_curves);
|
||||
MutableSpan<int> dst_offsets = dst_curves.offsets_for_write();
|
||||
|
||||
src_curves.ensure_evaluated_lengths();
|
||||
selection.foreach_index(GrainSize(1024), [&](const int curve_i) {
|
||||
const float curve_length = src_curves.evaluated_length_total_for_curve(curve_i,
|
||||
curves_cyclic[curve_i]);
|
||||
dst_offsets[curve_i] = int(curve_length / sample_lengths[curve_i]) + 1;
|
||||
});
|
||||
|
||||
IndexMaskMemory memory;
|
||||
const IndexMask unselected = selection.complement(src_curves.curves_range(), memory);
|
||||
|
||||
/* Fill the counts for the curves that aren't selected and accumulate the counts into offsets. */
|
||||
offset_indices::copy_group_sizes(src_points_by_curve, unselected, dst_offsets);
|
||||
offset_indices::accumulate_counts_to_offsets(dst_offsets);
|
||||
dst_curves.resize(dst_offsets.last(), dst_curves.curves_num());
|
||||
|
||||
resample_to_uniform(src_curves, selection, output_ids, dst_curves);
|
||||
|
||||
return dst_curves;
|
||||
}
|
||||
|
||||
CurvesGeometry resample_to_length(const CurvesGeometry &src_curves,
|
||||
const fn::FieldContext &field_context,
|
||||
const fn::Field<bool> &selection_field,
|
||||
|
@ -421,8 +502,7 @@ CurvesGeometry resample_to_length(const CurvesGeometry &src_curves,
|
|||
}
|
||||
|
||||
CurvesGeometry resample_to_evaluated(const CurvesGeometry &src_curves,
|
||||
const fn::FieldContext &field_context,
|
||||
const fn::Field<bool> &selection_field,
|
||||
const IndexMask &selection,
|
||||
const ResampleCurvesOutputAttributeIDs &output_ids)
|
||||
{
|
||||
if (src_curves.curves_range().is_empty()) {
|
||||
|
@ -432,10 +512,6 @@ CurvesGeometry resample_to_evaluated(const CurvesGeometry &src_curves,
|
|||
const OffsetIndices src_evaluated_points_by_curve = src_curves.evaluated_points_by_curve();
|
||||
const Span<float3> evaluated_positions = src_curves.evaluated_positions();
|
||||
|
||||
fn::FieldEvaluator evaluator{field_context, src_curves.curves_num()};
|
||||
evaluator.set_selection(selection_field);
|
||||
evaluator.evaluate();
|
||||
const IndexMask selection = evaluator.get_evaluated_selection_as_mask();
|
||||
IndexMaskMemory memory;
|
||||
const IndexMask unselected = selection.complement(src_curves.curves_range(), memory);
|
||||
|
||||
|
@ -511,4 +587,19 @@ CurvesGeometry resample_to_evaluated(const CurvesGeometry &src_curves,
|
|||
return dst_curves;
|
||||
}
|
||||
|
||||
CurvesGeometry resample_to_evaluated(const CurvesGeometry &src_curves,
|
||||
const fn::FieldContext &field_context,
|
||||
const fn::Field<bool> &selection_field,
|
||||
const ResampleCurvesOutputAttributeIDs &output_ids)
|
||||
{
|
||||
if (src_curves.curves_range().is_empty()) {
|
||||
return {};
|
||||
}
|
||||
fn::FieldEvaluator evaluator{field_context, src_curves.curves_num()};
|
||||
evaluator.set_selection(selection_field);
|
||||
evaluator.evaluate();
|
||||
return resample_to_evaluated(
|
||||
src_curves, evaluator.get_evaluated_selection_as_mask(), output_ids);
|
||||
}
|
||||
|
||||
} // namespace blender::geometry
|
||||
|
|
Loading…
Reference in New Issue