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
This commit is contained in:
Casey Bianco-Davis
2025-08-25 23:37:12 +02:00
committed by casey-bianco-davis
parent 899a8bcdac
commit 346d5b7407
9 changed files with 90 additions and 31 deletions

View File

@@ -469,6 +469,10 @@ IndexMask curve_to_point_selection(OffsetIndices<int> 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<int> points_by_curve,
const IndexMask &curve_selection,
GPointer value,

View File

@@ -24,6 +24,19 @@ IndexMask curve_to_point_selection(OffsetIndices<int> 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<int> points_by_curve,
const IndexMask &curve_selection,
const GPointer value,

View File

@@ -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<IndexMask, 3> 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) {

View File

@@ -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<bool>(".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<IndexMask> 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<bool>(attribute_name, bke::AttrDomain::Point, true),
memory);
const VArray<bool> selected = *curves.attributes().lookup_or_default<bool>(
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)

View File

@@ -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);

View File

@@ -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

View File

@@ -350,7 +350,7 @@ static CurvesPointSelectionStatus init_curves_point_selection_status(
const Span<float3> 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<Span<float3>> 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<float> tilt = median.tilt ? curves.tilt_for_write() : MutableSpan<float>{};
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<float3> 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;
}

View File

@@ -302,12 +302,6 @@ static void createTransCurvesVerts(bContext *C, TransInfo *t)
curves);
std::array<IndexMask, 3> 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);

View File

@@ -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(