WIP: GEO: Copy curve selection #117869
|
@ -38,6 +38,7 @@
|
|||
#include "ED_object.hh"
|
||||
#include "ED_screen.hh"
|
||||
|
||||
#include "GEO_curve_copy_selection.hh"
|
||||
#include "GEO_join_geometries.hh"
|
||||
#include "GEO_reorder.hh"
|
||||
#include "GEO_smooth_curves.hh"
|
||||
|
@ -347,96 +348,6 @@ static void GREASE_PENCIL_OT_stroke_simplify(wmOperatorType *ot)
|
|||
/** \name Delete Operator
|
||||
* \{ */
|
||||
|
||||
static bke::CurvesGeometry remove_points_and_split(const bke::CurvesGeometry &curves,
|
||||
const IndexMask &mask)
|
||||
{
|
||||
const OffsetIndices<int> points_by_curve = curves.points_by_curve();
|
||||
const VArray<bool> src_cyclic = curves.cyclic();
|
||||
|
||||
Array<bool> points_to_delete(curves.points_num());
|
||||
mask.to_bools(points_to_delete.as_mutable_span());
|
||||
const int total_points = points_to_delete.as_span().count(false);
|
||||
|
||||
/* Return if deleting everything. */
|
||||
if (total_points == 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
int curr_dst_point_id = 0;
|
||||
Array<int> dst_to_src_point(total_points);
|
||||
Vector<int> dst_curve_counts;
|
||||
Vector<int> dst_to_src_curve;
|
||||
Vector<bool> dst_cyclic;
|
||||
|
||||
for (const int curve_i : curves.curves_range()) {
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
const Span<bool> curve_points_to_delete = points_to_delete.as_span().slice(points);
|
||||
const bool curve_cyclic = src_cyclic[curve_i];
|
||||
|
||||
/* Note, these ranges start at zero and needed to be shifted by `points.first()` */
|
||||
const Vector<IndexRange> ranges_to_keep = array_utils::find_all_ranges(curve_points_to_delete,
|
||||
false);
|
||||
|
||||
if (ranges_to_keep.is_empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const bool is_last_segment_selected = curve_cyclic && ranges_to_keep.first().first() == 0 &&
|
||||
ranges_to_keep.last().last() == points.size() - 1;
|
||||
const bool is_curve_self_joined = is_last_segment_selected && ranges_to_keep.size() != 1;
|
||||
const bool is_cyclic = ranges_to_keep.size() == 1 && is_last_segment_selected;
|
||||
|
||||
IndexRange range_ids = ranges_to_keep.index_range();
|
||||
/* Skip the first range because it is joined to the end of the last range. */
|
||||
for (const int range_i : ranges_to_keep.index_range().drop_front(is_curve_self_joined)) {
|
||||
const IndexRange range = ranges_to_keep[range_i];
|
||||
|
||||
int count = range.size();
|
||||
for (const int src_point : range.shift(points.first())) {
|
||||
dst_to_src_point[curr_dst_point_id++] = src_point;
|
||||
}
|
||||
|
||||
/* Join the first range to the end of the last range. */
|
||||
if (is_curve_self_joined && range_i == range_ids.last()) {
|
||||
const IndexRange first_range = ranges_to_keep[range_ids.first()];
|
||||
for (const int src_point : first_range.shift(points.first())) {
|
||||
dst_to_src_point[curr_dst_point_id++] = src_point;
|
||||
}
|
||||
count += first_range.size();
|
||||
}
|
||||
|
||||
dst_curve_counts.append(count);
|
||||
dst_to_src_curve.append(curve_i);
|
||||
dst_cyclic.append(is_cyclic);
|
||||
}
|
||||
}
|
||||
|
||||
const int total_curves = dst_to_src_curve.size();
|
||||
|
||||
bke::CurvesGeometry dst_curves(total_points, total_curves);
|
||||
|
||||
MutableSpan<int> new_curve_offsets = dst_curves.offsets_for_write();
|
||||
array_utils::copy(dst_curve_counts.as_span(), new_curve_offsets.drop_back(1));
|
||||
offset_indices::accumulate_counts_to_offsets(new_curve_offsets);
|
||||
|
||||
bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write();
|
||||
const bke::AttributeAccessor src_attributes = curves.attributes();
|
||||
|
||||
/* Transfer curve attributes. */
|
||||
gather_attributes(
|
||||
src_attributes, bke::AttrDomain::Curve, {}, {"cyclic"}, dst_to_src_curve, dst_attributes);
|
||||
array_utils::copy(dst_cyclic.as_span(), dst_curves.cyclic_for_write());
|
||||
|
||||
/* Transfer point attributes. */
|
||||
gather_attributes(
|
||||
src_attributes, bke::AttrDomain::Point, {}, {}, dst_to_src_point, dst_attributes);
|
||||
|
||||
dst_curves.update_curve_types();
|
||||
dst_curves.remove_attributes_based_on_types();
|
||||
|
||||
return dst_curves;
|
||||
}
|
||||
|
||||
static int grease_pencil_delete_exec(bContext *C, wmOperator * /*op*/)
|
||||
{
|
||||
const Scene *scene = CTX_data_scene(C);
|
||||
|
@ -461,7 +372,8 @@ static int grease_pencil_delete_exec(bContext *C, wmOperator * /*op*/)
|
|||
curves.remove_curves(elements, {});
|
||||
}
|
||||
else if (selection_domain == bke::AttrDomain::Point) {
|
||||
curves = remove_points_and_split(curves, elements);
|
||||
const IndexMask inverted = elements.complement(IndexRange(curves.points_num()), memory);
|
||||
curves = geometry::copy_curve_points(curves, inverted, {});
|
||||
}
|
||||
info.drawing.tag_topology_changed();
|
||||
changed = true;
|
||||
|
@ -1926,7 +1838,10 @@ static bool grease_pencil_separate_selected(bContext &C,
|
|||
info.frame_number);
|
||||
drawing_dst.strokes_for_write() = bke::curves_copy_point_selection(
|
||||
curves_src, selected_points, {});
|
||||
curves_src = remove_points_and_split(curves_src, selected_points);
|
||||
|
||||
const IndexMask inverted = selected_points.complement(IndexRange(curves_src.points_num()),
|
||||
memory);
|
||||
curves_src = geometry::copy_curve_points(curves_src, inverted, {});
|
||||
|
||||
info.drawing.tag_topology_changed();
|
||||
drawing_dst.tag_topology_changed();
|
||||
|
|
|
@ -17,6 +17,7 @@ set(INC_SYS
|
|||
set(SRC
|
||||
intern/add_curves_on_mesh.cc
|
||||
intern/curve_constraints.cc
|
||||
intern/curve_copy_selection.cc
|
||||
intern/fillet_curves.cc
|
||||
intern/join_geometries.cc
|
||||
intern/mesh_copy_selection.cc
|
||||
|
@ -49,6 +50,7 @@ set(SRC
|
|||
|
||||
GEO_add_curves_on_mesh.hh
|
||||
GEO_curve_constraints.hh
|
||||
GEO_curve_copy_selection.hh
|
||||
GEO_fillet_curves.hh
|
||||
GEO_join_geometries.hh
|
||||
GEO_mesh_copy_selection.hh
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BKE_anonymous_attribute_id.hh"
|
||||
|
||||
#include "BLI_index_mask.hh"
|
||||
|
||||
#include "BKE_curves.hh"
|
||||
|
||||
namespace blender::geometry {
|
||||
|
||||
bke::CurvesGeometry copy_curve_points(
|
||||
const bke::CurvesGeometry &src_curves,
|
||||
const IndexMask &points_mask,
|
||||
const bke::AnonymousAttributePropagationInfo &propagation_info);
|
||||
|
||||
} // namespace blender::geometry
|
|
@ -0,0 +1,103 @@
|
|||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "BKE_anonymous_attribute_id.hh"
|
||||
#include "BKE_attribute.hh"
|
||||
|
||||
#include "BLI_index_mask.hh"
|
||||
|
||||
#include "BKE_curves.hh"
|
||||
|
||||
namespace blender::geometry {
|
||||
|
||||
static void split_mask_for_ranges(const OffsetIndices<int> groups,
|
||||
const IndexMask mask,
|
||||
MutableSpan<IndexMask> masks)
|
||||
{
|
||||
threading::parallel_for(groups.index_range(), 2048, [&](const IndexRange range) {
|
||||
const IndexMask local_mask = mask.slice_content(groups[range]);
|
||||
if (local_mask.is_empty()) {
|
||||
return;
|
||||
}
|
||||
for (const int64_t i : range) {
|
||||
masks[i] = local_mask.slice_content(groups[i]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void count_ranges(const Span<IndexMask> masks, MutableSpan<int> ranges)
|
||||
{
|
||||
threading::parallel_for(masks.index_range(), 2048, [&](const IndexRange range) {
|
||||
for (const int64_t i : range) {
|
||||
masks[i].foreach_range([&](const IndexRange /*range*/) { ranges[i]++; });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void fill_groups_by_indices(const OffsetIndices<int> groups, MutableSpan<int> indices)
|
||||
{
|
||||
threading::parallel_for(groups.index_range(), 2048, [&](const IndexRange range) {
|
||||
for (const int64_t i : range) {
|
||||
indices.slice(groups[i]).fill(i);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void ranges_to_sizes(const IndexMask &mask, MutableSpan<int> r_offsets)
|
||||
{
|
||||
int offset_i = 0;
|
||||
mask.foreach_range([&](const IndexRange range) {
|
||||
r_offsets[offset_i] = range.size();
|
||||
offset_i++;
|
||||
});
|
||||
}
|
||||
|
||||
bke::CurvesGeometry copy_curve_points(
|
||||
const bke::CurvesGeometry &src_curves,
|
||||
const IndexMask &points_mask,
|
||||
const bke::AnonymousAttributePropagationInfo &propagation_info)
|
||||
{
|
||||
const OffsetIndices<int> points_by_curve = src_curves.points_by_curve();
|
||||
|
||||
IndexMaskMemory memory;
|
||||
Array<IndexMask> curves_masks(points_by_curve.size());
|
||||
split_mask_for_ranges(points_by_curve, points_mask, curves_masks);
|
||||
Array<int> curves_subdivision(points_by_curve.size() + 1, 0);
|
||||
count_ranges(curves_masks, curves_subdivision);
|
||||
const OffsetIndices<int> curves_subdivision_offset =
|
||||
offset_indices::accumulate_counts_to_offsets(curves_subdivision);
|
||||
const int64_t total_curves = curves_subdivision_offset.total_size();
|
||||
|
||||
bke::CurvesGeometry dst_curves(points_mask.size(), total_curves);
|
||||
|
||||
MutableSpan<int> dst_offsets = dst_curves.offsets_for_write();
|
||||
threading::parallel_for(points_by_curve.index_range(), 2048, [&](const IndexRange range) {
|
||||
for (const int64_t i : range) {
|
||||
ranges_to_sizes(curves_masks[i], dst_offsets.slice(curves_subdivision_offset[i]));
|
||||
}
|
||||
});
|
||||
offset_indices::accumulate_counts_to_offsets(dst_offsets);
|
||||
|
||||
Array<int> curve_indices(total_curves);
|
||||
fill_groups_by_indices(curves_subdivision_offset, curve_indices);
|
||||
|
||||
const bke::AttributeAccessor src_attributes = src_curves.attributes();
|
||||
bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write();
|
||||
|
||||
bke::gather_attributes(
|
||||
src_attributes, bke::AttrDomain::Point, propagation_info, {}, points_mask, dst_attributes);
|
||||
bke::gather_attributes(src_attributes,
|
||||
bke::AttrDomain::Curve,
|
||||
propagation_info,
|
||||
{},
|
||||
curve_indices.as_span(),
|
||||
dst_attributes);
|
||||
|
||||
dst_curves.update_curve_types();
|
||||
return dst_curves;
|
||||
}
|
||||
|
||||
} // namespace blender::geometry
|
Loading…
Reference in New Issue