From 346d5b74075957a7a6610089bb64e1f3f3312ae7 Mon Sep 17 00:00:00 2001 From: Casey Bianco-Davis Date: Mon, 25 Aug 2025 23:37:12 +0200 Subject: [PATCH] Fix: Curves: Don't treat non-bezier curves as selected when handles are The `retrieve_selected_points` function would treat points of non-bezier curves as selected if the handles were selected. And because the attributes `.selected_handle_left` and `.selected_handle_right` are created initialized to true for all points. The `retrieve_all_selected_points` would return that all points were selected. Only points of bezier curves should be used when getting the selection mask for handles. Pull Request: https://projects.blender.org/blender/blender/pulls/144824 --- source/blender/blenkernel/BKE_curves_utils.hh | 4 ++++ .../blender/blenkernel/intern/curves_utils.cc | 13 +++++++++++ .../editors/curves/intern/curves_data.cc | 14 ++++++++++-- .../editors/curves/intern/curves_selection.cc | 22 ++++++++++++++----- .../intern/grease_pencil_edit.cc | 12 +++++++--- source/blender/editors/include/ED_curves.hh | 8 ++++++- .../editors/space_view3d/view3d_buttons.cc | 16 ++++++++++---- .../transform/transform_convert_curves.cc | 12 +++++----- .../transform_convert_grease_pencil.cc | 20 ++++++++--------- 9 files changed, 90 insertions(+), 31 deletions(-) diff --git a/source/blender/blenkernel/BKE_curves_utils.hh b/source/blender/blenkernel/BKE_curves_utils.hh index 9da06d4ca3d..7e177c05f38 100644 --- a/source/blender/blenkernel/BKE_curves_utils.hh +++ b/source/blender/blenkernel/BKE_curves_utils.hh @@ -469,6 +469,10 @@ IndexMask curve_to_point_selection(OffsetIndices points_by_curve, const IndexMask &curve_selection, IndexMaskMemory &memory); +IndexMask curve_type_point_selection(const bke::CurvesGeometry &curves, + CurveType curve_type, + IndexMaskMemory &memory); + void fill_points(OffsetIndices points_by_curve, const IndexMask &curve_selection, GPointer value, diff --git a/source/blender/blenkernel/intern/curves_utils.cc b/source/blender/blenkernel/intern/curves_utils.cc index b752a50fe6b..92839764f47 100644 --- a/source/blender/blenkernel/intern/curves_utils.cc +++ b/source/blender/blenkernel/intern/curves_utils.cc @@ -24,6 +24,19 @@ IndexMask curve_to_point_selection(OffsetIndices points_by_curve, return IndexMask::from_initializers(point_ranges, memory); } +IndexMask curve_type_point_selection(const bke::CurvesGeometry &curves, + const CurveType curve_type, + IndexMaskMemory &memory) +{ + return curve_to_point_selection(curves.points_by_curve(), + indices_for_type(curves.curve_types(), + curves.curve_type_counts(), + curve_type, + curves.curves_range(), + memory), + memory); +} + void fill_points(const OffsetIndices points_by_curve, const IndexMask &curve_selection, const GPointer value, diff --git a/source/blender/editors/curves/intern/curves_data.cc b/source/blender/editors/curves/intern/curves_data.cc index e7583c88618..d376abf21e5 100644 --- a/source/blender/editors/curves/intern/curves_data.cc +++ b/source/blender/editors/curves/intern/curves_data.cc @@ -3,6 +3,7 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ #include "BKE_curves.hh" +#include "BKE_curves_utils.hh" #include "DNA_object_types.h" @@ -43,8 +44,17 @@ void transverts_from_curves_positions_create(bke::CurvesGeometry &curves, IndexMaskMemory memory; std::array selection; - for (const int i : selection_names.index_range()) { - selection[i] = ed::curves::retrieve_selected_points(curves, selection_names[i], memory); + if (selection_names.size() == 1) { + selection[0] = ed::curves::retrieve_selected_points(curves, memory); + } + else { + const IndexMask bezier_points = bke::curves::curve_type_point_selection( + curves, CURVE_TYPE_BEZIER, memory); + + for (const int i : selection_names.index_range()) { + selection[i] = ed::curves::retrieve_selected_points( + curves, selection_names[i], bezier_points, memory); + } } if (skip_handles) { diff --git a/source/blender/editors/curves/intern/curves_selection.cc b/source/blender/editors/curves/intern/curves_selection.cc index 6a1e83f3172..ed8c6cbac19 100644 --- a/source/blender/editors/curves/intern/curves_selection.cc +++ b/source/blender/editors/curves/intern/curves_selection.cc @@ -16,6 +16,7 @@ #include "BKE_attribute.hh" #include "BKE_crazyspace.hh" #include "BKE_curves.hh" +#include "BKE_curves_utils.hh" #include "ED_curves.hh" #include "ED_select_utils.hh" @@ -78,13 +79,18 @@ IndexMask retrieve_selected_curves(const Curves &curves_id, IndexMaskMemory &mem IndexMask retrieve_selected_points(const bke::CurvesGeometry &curves, IndexMaskMemory &memory) { - return retrieve_selected_points(curves, ".selection", memory); + return IndexMask::from_bools( + *curves.attributes().lookup_or_default(".selection", bke::AttrDomain::Point, true), + memory); } IndexMask retrieve_all_selected_points(const bke::CurvesGeometry &curves, const int handle_display, IndexMaskMemory &memory) { + const IndexMask bezier_points = bke::curves::curve_type_point_selection( + curves, CURVE_TYPE_BEZIER, memory); + Vector selection_by_attribute; for (const StringRef selection_name : ed::curves::get_curves_selection_attribute_names(curves)) { if (selection_name != ".selection" && handle_display == CURVE_HANDLE_NONE) { @@ -92,18 +98,24 @@ IndexMask retrieve_all_selected_points(const bke::CurvesGeometry &curves, } selection_by_attribute.append( - ed::curves::retrieve_selected_points(curves, selection_name, memory)); + ed::curves::retrieve_selected_points(curves, selection_name, bezier_points, memory)); } return IndexMask::from_union(selection_by_attribute, memory); } IndexMask retrieve_selected_points(const bke::CurvesGeometry &curves, StringRef attribute_name, + const IndexMask &bezier_points, IndexMaskMemory &memory) { - return IndexMask::from_bools( - *curves.attributes().lookup_or_default(attribute_name, bke::AttrDomain::Point, true), - memory); + const VArray selected = *curves.attributes().lookup_or_default( + attribute_name, bke::AttrDomain::Point, true); + + if (attribute_name == ".selection") { + return IndexMask::from_bools(selected, memory); + } + + return IndexMask::from_bools(bezier_points, selected, memory); } IndexMask retrieve_selected_points(const Curves &curves_id, IndexMaskMemory &memory) diff --git a/source/blender/editors/grease_pencil/intern/grease_pencil_edit.cc b/source/blender/editors/grease_pencil/intern/grease_pencil_edit.cc index c6f86987577..b39cfff8221 100644 --- a/source/blender/editors/grease_pencil/intern/grease_pencil_edit.cc +++ b/source/blender/editors/grease_pencil/intern/grease_pencil_edit.cc @@ -3222,11 +3222,14 @@ static wmOperatorStatus grease_pencil_reproject_exec(bContext *C, wmOperator *op const IndexMask editable_points = retrieve_editable_points( *object, info.drawing, info.layer_index, memory); + const IndexMask bezier_points = bke::curves::curve_type_point_selection( + curves, CURVE_TYPE_BEZIER, memory); + for (const StringRef selection_name : ed::curves::get_curves_selection_attribute_names(curves)) { const IndexMask selected_points = ed::curves::retrieve_selected_points( - curves, selection_name, memory); + curves, selection_name, bezier_points, memory); const IndexMask points_to_reproject = IndexMask::from_intersection( editable_points, selected_points, memory); @@ -3448,11 +3451,14 @@ static wmOperatorStatus grease_pencil_snap_to_grid_exec(bContext *C, wmOperator continue; } + IndexMaskMemory memory; + const IndexMask bezier_points = bke::curves::curve_type_point_selection( + curves, CURVE_TYPE_BEZIER, memory); + for (const StringRef selection_name : ed::curves::get_curves_selection_attribute_names(curves)) { - IndexMaskMemory memory; const IndexMask selected_points = ed::curves::retrieve_selected_points( - curves, selection_name, memory); + curves, selection_name, bezier_points, memory); const Layer &layer = grease_pencil.layer(drawing_info.layer_index); const float4x4 layer_to_world = layer.to_world_space(object); diff --git a/source/blender/editors/include/ED_curves.hh b/source/blender/editors/include/ED_curves.hh index 97f318c3aa4..e99f914440e 100644 --- a/source/blender/editors/include/ED_curves.hh +++ b/source/blender/editors/include/ED_curves.hh @@ -233,10 +233,16 @@ IndexMask retrieve_selected_curves(const Curves &curves_id, IndexMaskMemory &mem * or points in curves with a selection factor greater than zero). */ IndexMask retrieve_selected_points(const bke::CurvesGeometry &curves, IndexMaskMemory &memory); +IndexMask retrieve_selected_points(const Curves &curves_id, IndexMaskMemory &memory); +/** + * Find points that are selected, for a given attribute_name, requires mask of all Bezier points. + * Note: When retrieving ".selection_handle_left" or ".selection_handle_right" all non-Bezier + * points will be deselected even if the raw attribute is selected. + */ IndexMask retrieve_selected_points(const bke::CurvesGeometry &curves, StringRef attribute_name, + const IndexMask &bezier_points, IndexMaskMemory &memory); -IndexMask retrieve_selected_points(const Curves &curves_id, IndexMaskMemory &memory); /** * Find points that are selected (a selection factor greater than zero) or have diff --git a/source/blender/editors/space_view3d/view3d_buttons.cc b/source/blender/editors/space_view3d/view3d_buttons.cc index 27080a24b3f..640020fcd1c 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.cc +++ b/source/blender/editors/space_view3d/view3d_buttons.cc @@ -350,7 +350,7 @@ static CurvesPointSelectionStatus init_curves_point_selection_status( const Span positions = curves.positions(); IndexMaskMemory memory; - const IndexMask selection = retrieve_selected_points(curves, ".selection", memory); + const IndexMask selection = retrieve_selected_points(curves, memory); CurvesPointSelectionStatus status = threading::parallel_reduce( curves.curves_range(), @@ -386,11 +386,15 @@ static CurvesPointSelectionStatus init_curves_point_selection_status( return status; } + const IndexMask bezier_points = bke::curves::curve_type_point_selection( + curves, CURVE_TYPE_BEZIER, memory); + auto add_handles = [&](StringRef selection_attribute, std::optional> positions) { if (!positions) { return; } - const IndexMask selection = retrieve_selected_points(curves, selection_attribute, memory); + const IndexMask selection = retrieve_selected_points( + curves, selection_attribute, bezier_points, memory); if (selection.is_empty()) { return; } @@ -428,7 +432,7 @@ static bool apply_to_curves_point_selection(const int tot, const MutableSpan tilt = median.tilt ? curves.tilt_for_write() : MutableSpan{}; IndexMaskMemory memory; - const IndexMask selection = retrieve_selected_points(curves, ".selection", memory); + const IndexMask selection = retrieve_selected_points(curves, memory); const bool update_location = math::length_manhattan(float3(median.location)) > 0; MutableSpan positions = update_location && !selection.is_empty() ? curves.positions_for_write() : @@ -468,8 +472,12 @@ static bool apply_to_curves_point_selection(const int tot, return changed; } + const IndexMask bezier_points = bke::curves::curve_type_point_selection( + curves, CURVE_TYPE_BEZIER, memory); + auto apply_to_handles = [&](StringRef selection_attribute, StringRef handles_attribute) { - const IndexMask selection = retrieve_selected_points(curves, selection_attribute, memory); + const IndexMask selection = retrieve_selected_points( + curves, selection_attribute, bezier_points, memory); if (selection.is_empty()) { return; } diff --git a/source/blender/editors/transform/transform_convert_curves.cc b/source/blender/editors/transform/transform_convert_curves.cc index c92a32db337..2900ea879ba 100644 --- a/source/blender/editors/transform/transform_convert_curves.cc +++ b/source/blender/editors/transform/transform_convert_curves.cc @@ -302,12 +302,6 @@ static void createTransCurvesVerts(bContext *C, TransInfo *t) curves); std::array selection_per_attribute; - for (const int attribute_i : selection_attribute_names.index_range()) { - const StringRef &selection_name = selection_attribute_names[attribute_i]; - selection_per_attribute[attribute_i] = ed::curves::retrieve_selected_points( - curves, selection_name, curves_transform_data->memory); - } - bezier_curves[i] = bke::curves::indices_for_type(curves.curve_types(), curves.curve_type_counts(), CURVE_TYPE_BEZIER, @@ -317,6 +311,12 @@ static void createTransCurvesVerts(bContext *C, TransInfo *t) const IndexMask bezier_points = bke::curves::curve_to_point_selection( curves.points_by_curve(), bezier_curves[i], curves_transform_data->memory); + for (const int attribute_i : selection_attribute_names.index_range()) { + const StringRef &selection_name = selection_attribute_names[attribute_i]; + selection_per_attribute[attribute_i] = ed::curves::retrieve_selected_points( + curves, selection_name, bezier_points, curves_transform_data->memory); + } + /* Alter selection as in legacy curves bezt_select_to_transform_triple_flag(). */ if (!bezier_points.is_empty()) { update_handle_types_for_transform(t->mode, selection_per_attribute, bezier_points, curves); diff --git a/source/blender/editors/transform/transform_convert_grease_pencil.cc b/source/blender/editors/transform/transform_convert_grease_pencil.cc index e8189cb0273..6ff3b40a90d 100644 --- a/source/blender/editors/transform/transform_convert_grease_pencil.cc +++ b/source/blender/editors/transform/transform_convert_grease_pencil.cc @@ -92,16 +92,6 @@ static void createTransGreasePencilVerts(bContext *C, TransInfo *t) const IndexMask editable_strokes = ed::greasepencil::retrieve_editable_strokes( *object, info.drawing, info.layer_index, curves_transform_data->memory); - for (const int attribute_i : selection_attribute_names.index_range()) { - const StringRef &selection_name = selection_attribute_names[attribute_i]; - selection_per_attribute[attribute_i] = ed::curves::retrieve_selected_points( - curves, selection_name, curves_transform_data->memory); - - /* Make sure only editable points are used. */ - selection_per_attribute[attribute_i] = IndexMask::from_intersection( - selection_per_attribute[attribute_i], editable_points, curves_transform_data->memory); - } - bezier_curves[layer_offset] = bke::curves::indices_for_type(curves.curve_types(), curves.curve_type_counts(), CURVE_TYPE_BEZIER, @@ -111,6 +101,16 @@ static void createTransGreasePencilVerts(bContext *C, TransInfo *t) const IndexMask bezier_points = IndexMask::from_ranges( points_by_curve, bezier_curves[layer_offset], curves_transform_data->memory); + for (const int attribute_i : selection_attribute_names.index_range()) { + const StringRef &selection_name = selection_attribute_names[attribute_i]; + selection_per_attribute[attribute_i] = ed::curves::retrieve_selected_points( + curves, selection_name, bezier_points, curves_transform_data->memory); + + /* Make sure only editable points are used. */ + selection_per_attribute[attribute_i] = IndexMask::from_intersection( + selection_per_attribute[attribute_i], editable_points, curves_transform_data->memory); + } + /* Alter selection as in legacy curves bezt_select_to_transform_triple_flag(). */ if (!bezier_points.is_empty()) { if (curves::update_handle_types_for_transform(