Fix #130708: Grease Pencil: Cannot transform strokes with individual origin pivot

When using the "individual origin" pivot mode, calculate the center
based on the following:

* If the stroke is a Bézier stroke, use the center of each handle as the pivot.
* Otherwise, if the stroke is not a Bézier stroke, compute the mean position
  of the selected control points in the stroke and use this as the center.

This center value is then used e.g. by the rotation or scale transform modes.

Co-authored-by: Falk David <falk@blender.org>
Pull Request: https://projects.blender.org/blender/blender/pulls/130723
This commit is contained in:
Pratik Borhade
2024-12-19 15:39:58 +01:00
committed by Falk David
parent 2bb4136e56
commit 9d86fada03
2 changed files with 44 additions and 11 deletions

View File

@@ -466,11 +466,13 @@ void curve_populate_trans_data_structs(
const View3D *v3d = static_cast<const View3D *>(t.view);
const bool hide_handles = (v3d != nullptr) ? (v3d->overlay.handle_display == CURVE_HANDLE_NONE) :
false;
const bool use_individual_origin = (t.around == V3D_AROUND_LOCAL_ORIGINS);
const Span<float3> point_positions = curves.positions();
const VArray<bool> point_selection = *curves.attributes().lookup_or_default<bool>(
".selection", bke::AttrDomain::Point, true);
std::array<MutableSpan<float3>, 3> positions_per_selection_attr;
const VArray<int8_t> curve_types = curves.curve_types();
std::array<MutableSpan<float3>, 3> positions_per_selection_attr;
for (const int selection_i : points_to_transform_per_attr.index_range()) {
positions_per_selection_attr[selection_i] =
ed::transform::curves::append_positions_to_custom_data(
@@ -495,26 +497,58 @@ void curve_populate_trans_data_structs(
const float3x3 mtx_base = transform.view<3, 3>();
const float3x3 smtx_base = math::pseudo_invert(mtx_base);
const OffsetIndices<int> points_by_curve = curves.points_by_curve();
Array<float3> mean_center_point_per_curve(curves.curves_num());
if (use_individual_origin) {
affected_curves.foreach_index(GrainSize(512), [&](const int64_t curve_i) {
const IndexRange points = points_by_curve[curve_i];
IndexMaskMemory memory;
const IndexMask selection =
IndexMask::from_bools(point_selection, memory).slice_content(points);
if (selection.is_empty()) {
return;
}
float3 center(0.0f);
selection.foreach_index([&](const int64_t point_i) { center += point_positions[point_i]; });
center /= selection.size();
mean_center_point_per_curve[curve_i] = center;
});
}
const Array<int> point_to_curve_map = curves.point_to_curve_map();
for (const int selection_i : position_offsets_in_td.index_range()) {
if (position_offsets_in_td[selection_i].is_empty()) {
continue;
}
MutableSpan<TransData> tc_data = all_tc_data.slice(position_offsets_in_td[selection_i]);
MutableSpan<float3> positions = positions_per_selection_attr[selection_i];
IndexMask points_to_transform = points_to_transform_per_attr[selection_i];
VArray<bool> selection = selection_attrs[selection_i];
const IndexMask points_to_transform = points_to_transform_per_attr[selection_i];
const VArray<bool> selection = selection_attrs[selection_i];
points_to_transform.foreach_index(
GrainSize(1024), [&](const int64_t domain_i, const int64_t transform_i) {
const int curve_i = point_to_curve_map[domain_i];
TransData &td = tc_data[transform_i];
float3 *elem = &positions[transform_i];
float3 center;
const bool use_local_center = hide_handles || use_individual_origin ||
point_selection[domain_i];
const bool use_mean_center = use_individual_origin &&
!(curve_types[curve_i] == CURVE_TYPE_BEZIER);
if (use_mean_center) {
center = mean_center_point_per_curve[curve_i];
}
else if (use_local_center) {
center = point_positions[domain_i];
}
else {
center = td.iloc;
}
copy_v3_v3(td.iloc, *elem);
copy_v3_v3(td.center,
hide_handles || (t.around == V3D_AROUND_LOCAL_ORIGINS) ||
point_selection[domain_i] ?
point_positions[domain_i] :
td.iloc);
copy_v3_v3(td.center, center);
td.loc = *elem;
td.flag = 0;
@@ -544,8 +578,6 @@ void curve_populate_trans_data_structs(
});
}
if (use_connected_only) {
const VArray<int8_t> curve_types = curves.curve_types();
const OffsetIndices<int> points_by_curve = curves.points_by_curve();
Array<int> bezier_offsets_in_td(curves.curves_num() + 1, 0);
offset_indices::copy_group_sizes(points_by_curve, bezier_curves, bezier_offsets_in_td);
offset_indices::accumulate_counts_to_offsets(bezier_offsets_in_td);

View File

@@ -34,6 +34,7 @@ static void createTransGreasePencilVerts(bContext *C, TransInfo *t)
MutableSpan<TransDataContainer> trans_data_contrainers(t->data_container, t->data_container_len);
const bool use_proportional_edit = (t->flag & T_PROP_EDIT_ALL) != 0;
const bool use_connected_only = (t->flag & T_PROP_CONNECTED) != 0;
const bool use_individual_origins = (t->around == V3D_AROUND_LOCAL_ORIGINS);
ToolSettings *ts = scene->toolsettings;
const bool is_scale_thickness = ((t->mode == TFM_CURVE_SHRINKFATTEN) ||
(ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_SCALE_THICKNESS));
@@ -205,7 +206,7 @@ static void createTransGreasePencilVerts(bContext *C, TransInfo *t)
value_attribute = opacities;
}
const IndexMask affected_strokes = use_proportional_edit ?
const IndexMask affected_strokes = use_proportional_edit || use_individual_origins ?
ed::greasepencil::retrieve_editable_strokes(
*object, info.drawing, info.layer_index, memory) :
IndexMask();