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.
|
* \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,
|
CurvesGeometry resample_to_count(const CurvesGeometry &src_curves,
|
||||||
const fn::FieldContext &field_context,
|
const fn::FieldContext &field_context,
|
||||||
const fn::Field<bool> &selection_field,
|
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.
|
* #segment_length field input, rounded to make the length of each segment the same.
|
||||||
* The accuracy will depend on the curve's resolution parameter.
|
* 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,
|
CurvesGeometry resample_to_length(const CurvesGeometry &src_curves,
|
||||||
const fn::FieldContext &field_context,
|
const fn::FieldContext &field_context,
|
||||||
const fn::Field<bool> &selection_field,
|
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.
|
* 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,
|
CurvesGeometry resample_to_evaluated(const CurvesGeometry &src_curves,
|
||||||
const fn::FieldContext &field_context,
|
const fn::FieldContext &field_context,
|
||||||
const fn::Field<bool> &selection_field,
|
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,
|
static void resample_to_uniform(const CurvesGeometry &src_curves,
|
||||||
const fn::FieldContext &field_context,
|
const IndexMask &selection,
|
||||||
const fn::Field<bool> &selection_field,
|
const ResampleCurvesOutputAttributeIDs &output_ids,
|
||||||
const fn::Field<int> &count_field,
|
CurvesGeometry &dst_curves)
|
||||||
const ResampleCurvesOutputAttributeIDs &output_ids)
|
|
||||||
{
|
{
|
||||||
if (src_curves.curves_range().is_empty()) {
|
if (src_curves.curves_range().is_empty()) {
|
||||||
return {};
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
|
const OffsetIndices src_points_by_curve = src_curves.points_by_curve();
|
||||||
const OffsetIndices evaluated_points_by_curve = src_curves.evaluated_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<bool> curves_cyclic = src_curves.cyclic();
|
||||||
const VArray<int8_t> curve_types = src_curves.curve_types();
|
const VArray<int8_t> curve_types = src_curves.curve_types();
|
||||||
const Span<float3> evaluated_positions = src_curves.evaluated_positions();
|
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. */
|
/* All resampled curves are poly curves. */
|
||||||
dst_curves.fill_curve_types(selection, CURVE_TYPE_POLY);
|
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);
|
copy_or_defaults_for_unselected_curves(src_curves, unselected, attributes, dst_curves);
|
||||||
|
|
||||||
for (bke::GSpanAttributeWriter &attribute : attributes.dst_attributes) {
|
for (bke::GSpanAttributeWriter &attribute : attributes.dst_attributes) {
|
||||||
attribute.finish();
|
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;
|
return dst_curves;
|
||||||
}
|
}
|
||||||
|
@ -407,6 +454,40 @@ CurvesGeometry resample_to_count(const CurvesGeometry &src_curves,
|
||||||
output_ids);
|
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,
|
CurvesGeometry resample_to_length(const CurvesGeometry &src_curves,
|
||||||
const fn::FieldContext &field_context,
|
const fn::FieldContext &field_context,
|
||||||
const fn::Field<bool> &selection_field,
|
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,
|
CurvesGeometry resample_to_evaluated(const CurvesGeometry &src_curves,
|
||||||
const fn::FieldContext &field_context,
|
const IndexMask &selection,
|
||||||
const fn::Field<bool> &selection_field,
|
|
||||||
const ResampleCurvesOutputAttributeIDs &output_ids)
|
const ResampleCurvesOutputAttributeIDs &output_ids)
|
||||||
{
|
{
|
||||||
if (src_curves.curves_range().is_empty()) {
|
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 OffsetIndices src_evaluated_points_by_curve = src_curves.evaluated_points_by_curve();
|
||||||
const Span<float3> evaluated_positions = src_curves.evaluated_positions();
|
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;
|
IndexMaskMemory memory;
|
||||||
const IndexMask unselected = selection.complement(src_curves.curves_range(), 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;
|
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
|
} // namespace blender::geometry
|
||||||
|
|
Loading…
Reference in New Issue