Blender V5.0
curves/intern/separate.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2025 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BLI_index_mask.hh"
6#include "BLI_task.hh"
7#include "BLI_vector_set.hh"
8
9#include "BKE_context.hh"
10#include "BKE_layer.hh"
11#include "BKE_lib_id.hh"
12
13#include "BKE_curves.hh"
14
15#include "ED_curves.hh"
16#include "ED_object.hh"
17
18#include "DNA_layer_types.h"
19
20#include "DEG_depsgraph.hh"
22
24
25#include "WM_api.hh"
26
27namespace blender::ed::curves {
28
30{
31 Main *bmain = CTX_data_main(C);
32 Scene *scene = CTX_data_scene(C);
33 ViewLayer *view_layer = CTX_data_view_layer(C);
34
36 scene, view_layer, CTX_wm_view3d(C));
37
38 VectorSet<Curves *> src_curves;
39 for (Base *base_src : bases) {
40 src_curves.add(static_cast<Curves *>(base_src->object->data));
41 }
42
43 /* Modify new curves and generate new curves in parallel. */
44 Array<std::optional<bke::CurvesGeometry>> dst_geometry(src_curves.size());
45 threading::parallel_for(dst_geometry.index_range(), 1, [&](const IndexRange range) {
46 for (const int i : range) {
47 Curves &src = *src_curves[i];
48 IndexMaskMemory memory;
49 switch (bke::AttrDomain(src.selection_domain)) {
50 case bke::AttrDomain::Point: {
51 const IndexMask selection = retrieve_selected_points(src, memory);
52 if (selection.is_empty()) {
53 continue;
54 }
55 bke::CurvesGeometry separated;
56 bke::CurvesGeometry retained;
57 separate_points(src.geometry.wrap(), selection, separated, retained);
58
59 separated.calculate_bezier_auto_handles();
60 retained.calculate_bezier_auto_handles();
61
62 dst_geometry[i] = std::move(separated);
63 src.geometry.wrap() = std::move(retained);
64 break;
65 }
66 case bke::AttrDomain::Curve: {
67 const IndexMask selection = retrieve_selected_curves(src, memory);
68 if (selection.is_empty()) {
69 continue;
70 }
71 dst_geometry[i] = bke::curves_copy_curve_selection(src.geometry.wrap(), selection, {});
72 src.geometry.wrap().remove_curves(selection, {});
73 break;
74 }
75 default:
76 BLI_assert_unreachable();
77 break;
78 }
79 }
80 });
81
82 /* Move new curves into main data-base. */
83 Array<Curves *> dst_curves(src_curves.size(), nullptr);
84 for (const int i : dst_curves.index_range()) {
85 if (std::optional<bke::CurvesGeometry> &dst = dst_geometry[i]) {
86 dst_curves[i] = BKE_curves_add(bmain, BKE_id_name(src_curves[i]->id));
87 dst_curves[i]->geometry.wrap() = std::move(*dst);
88 bke::curves_copy_parameters(*src_curves[i], *dst_curves[i]);
89 }
90 }
91
92 /* Skip processing objects with no selected elements. */
93 bases.remove_if([&](Base *base) {
94 Curves *curves = static_cast<Curves *>(base->object->data);
95 return dst_curves[src_curves.index_of(curves)] == nullptr;
96 });
97
98 if (bases.is_empty()) {
99 return OPERATOR_CANCELLED;
100 }
101
102 /* Add new objects for the new curves. */
103 for (Base *base_src : bases) {
104 Curves *src = static_cast<Curves *>(base_src->object->data);
105 Curves *dst = dst_curves[src_curves.index_of(src)];
106
107 Base *base_dst = object::add_duplicate(
108 bmain, scene, view_layer, base_src, eDupli_ID_Flags(U.dupflag) & USER_DUP_ACT);
109 Object *object_dst = base_dst->object;
110 object_dst->mode = OB_MODE_OBJECT;
111 object_dst->data = dst;
112
115 WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, base_src->object);
117 }
118
120 return OPERATOR_FINISHED;
121}
122
124{
125 ot->name = "Separate";
126 ot->idname = "CURVES_OT_separate";
127 ot->description = "Separate selected geometry into a new object";
128
129 ot->exec = separate_exec;
131
133}
134
135} // namespace blender::ed::curves
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
View3D * CTX_wm_view3d(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
struct Curves * BKE_curves_add(struct Main *bmain, const char *name)
Low-level operations for curves.
blender::Vector< Base * > BKE_view_layer_array_from_bases_in_edit_mode(const Scene *scene, ViewLayer *view_layer, const View3D *v3d)
const char * BKE_id_name(const ID &id)
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_relations_tag_update(Main *bmain)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1074
struct Curves Curves
struct Base Base
@ OB_MODE_OBJECT
struct Object Object
eDupli_ID_Flags
@ USER_DUP_ACT
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
#define C
Definition RandGen.cpp:29
#define ND_DRAW
Definition WM_types.hh:461
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define NC_OBJECT
Definition WM_types.hh:379
#define U
IndexRange index_range() const
Definition BLI_array.hh:360
bool add(const Key &key)
int64_t size() const
void curves_copy_parameters(const Curves &src, Curves &dst)
static wmOperatorStatus separate_exec(bContext *C, wmOperator *)
bool editable_curves_in_edit_mode_poll(bContext *C)
void CURVES_OT_separate(wmOperatorType *ot)
Base * add_duplicate(Main *bmain, Scene *scene, ViewLayer *view_layer, Base *base, eDupli_ID_Flags dupflag)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
struct Object * object
i
Definition text_draw.cc:230
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition wm_files.cc:4237