Curves: add subdivide curves edit mode operator

This commit is contained in:
Jacques Lucke 2024-04-05 13:50:09 +02:00
parent 6c25c66194
commit 548df007a5
2 changed files with 70 additions and 0 deletions

@ -5923,6 +5923,7 @@ class VIEW3D_MT_edit_curves_segments(Menu):
def draw(self, _context):
layout = self.layout
layout.operator("curves.subdivide")
layout.operator("curves.switch_direction")

@ -65,6 +65,7 @@
#include "GEO_reverse_uv_sampler.hh"
#include "GEO_set_curve_type.hh"
#include "GEO_subdivide_curves.hh"
/**
* The code below uses a suffix naming convention to indicate the coordinate space:
@ -1457,6 +1458,73 @@ static void CURVES_OT_switch_direction(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
namespace subdivide {
static int exec(bContext *C, wmOperator *op)
{
const int number_cuts = RNA_int_get(op->ptr, "number_cuts");
for (Curves *curves_id : get_unique_editable_curves(*C)) {
bke::CurvesGeometry &curves = curves_id->geometry.wrap();
const int points_num = curves.points_num();
IndexMaskMemory memory;
const IndexMask points_selection = retrieve_selected_points(*curves_id, memory);
if (points_selection.is_empty()) {
continue;
}
Array<bool> points_selection_span(points_num);
points_selection.to_bools(points_selection_span);
Array<int> segment_cuts(points_num, number_cuts);
const OffsetIndices points_by_curve = curves.points_by_curve();
threading::parallel_for(points_by_curve.index_range(), 512, [&](const IndexRange range) {
for (const int curve_i : range) {
const IndexRange points = points_by_curve[curve_i];
if (points.size() <= 1) {
continue;
}
for (const int point_i : points.drop_back(1)) {
if (!points_selection_span[point_i] || !points_selection_span[point_i + 1]) {
segment_cuts[point_i] = 0;
}
}
/* Cyclic segment. Doesn't matter if it is computed even if the curve is not cyclic. */
if (!points_selection_span[points.last()] || !points_selection_span[points.first()]) {
segment_cuts[points.last()] = 0;
}
}
});
curves = geometry::subdivide_curves(
curves, curves.curves_range(), VArray<int>::ForSpan(segment_cuts), {});
DEG_id_tag_update(&curves_id->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, curves_id);
}
return OPERATOR_FINISHED;
}
} // namespace subdivide
static void CURVES_OT_subdivide(wmOperatorType *ot)
{
ot->name = "Subdivide";
ot->idname = __func__;
ot->description = "Subdivide selected curve segments";
ot->exec = subdivide::exec;
ot->poll = editable_curves_in_edit_mode_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
PropertyRNA *prop;
prop = RNA_def_int(ot->srna, "number_cuts", 1, 1, 1000, "Number of Cuts", "", 1, 10);
/* Avoid re-using last value because it can cause an unexpectedly high number of subdivisions. */
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
void operatortypes_curves()
{
WM_operatortype_append(CURVES_OT_attribute_set);
@ -1479,6 +1547,7 @@ void operatortypes_curves()
WM_operatortype_append(CURVES_OT_cyclic_toggle);
WM_operatortype_append(CURVES_OT_curve_type_set);
WM_operatortype_append(CURVES_OT_switch_direction);
WM_operatortype_append(CURVES_OT_subdivide);
}
void operatormacros_curves()