Blender V5.0
curves_sculpt_delete.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
6
7#include "BLI_math_geom.h"
9#include "BLI_vector.hh"
10
11#include "DEG_depsgraph.hh"
12
13#include "BKE_brush.hh"
14#include "BKE_context.hh"
15#include "BKE_curves.hh"
16#include "BKE_mesh.hh"
17#include "BKE_mesh_runtime.hh"
18#include "BKE_paint.hh"
19
20#include "DNA_brush_enums.h"
21#include "DNA_brush_types.h"
22#include "DNA_curves_types.h"
23#include "DNA_object_types.h"
24#include "DNA_screen_types.h"
25
26#include "ED_screen.hh"
27#include "ED_view3d.hh"
28
29#include "WM_api.hh"
30
37
39
40using blender::bke::CurvesGeometry;
41
43 private:
44 CurvesBrush3D brush_3d_;
50 Vector<float3> deformed_positions_;
51
53
54 public:
55 void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override;
56};
57
61
62 Object *object_ = nullptr;
63 Curves *curves_id_ = nullptr;
65
68
70 const Brush *brush_ = nullptr;
73
75
77
79
80 void execute(DeleteOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
81 {
82 self_ = &self;
84
85 curves_id_ = static_cast<Curves *>(object_->data);
86 curves_ = &curves_id_->geometry.wrap();
87
89
90 curves_sculpt_ = ctx_.scene->toolsettings->curves_sculpt;
94
95 brush_pos_re_ = stroke_extension.mouse_position;
96
98
99 const eBrushFalloffShape falloff_shape = eBrushFalloffShape(brush_->falloff_shape);
100
101 if (stroke_extension.is_first) {
102 if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE || (U.uiflag & USER_ORBIT_SELECTION)) {
104 }
105 const bke::crazyspace::GeometryDeformation deformation =
107 self_->deformed_positions_ = deformation.positions;
108 }
109
110 Array<bool> curves_to_keep(curves_->curves_num(), true);
111 if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
112 this->delete_projected_with_symmetry(curves_to_keep);
113 }
114 else if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
115 this->delete_spherical_with_symmetry(curves_to_keep);
116 }
117 else {
119 }
120
121 IndexMaskMemory mask_memory;
122 const IndexMask mask_to_keep = IndexMask::from_bools(curves_to_keep, mask_memory);
123
124 /* Remove deleted curves from the stored deformed positions. */
125 const OffsetIndices points_by_curve = curves_->points_by_curve();
126 Vector<float3> new_deformed_positions;
127 mask_to_keep.foreach_index([&](const int64_t i) {
128 new_deformed_positions.extend(
129 self_->deformed_positions_.as_span().slice(points_by_curve[i]));
130 });
131 self_->deformed_positions_ = std::move(new_deformed_positions);
132
133 *curves_ = bke::curves_copy_curve_selection(*curves_, mask_to_keep, {});
134
138 }
139
141 {
142 const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
144 for (const float4x4 &brush_transform : symmetry_brush_transforms) {
145 this->delete_projected(brush_transform, curves_to_keep);
146 }
147 }
148
149 void delete_projected(const float4x4 &brush_transform, MutableSpan<bool> curves_to_keep)
150 {
151 const float4x4 brush_transform_inv = math::invert(brush_transform);
152
153 const float4x4 projection = ED_view3d_ob_project_mat_get(ctx_.rv3d, object_);
154
155 const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
156 const float brush_radius_sq_re = pow2f(brush_radius_re);
157 const OffsetIndices points_by_curve = curves_->points_by_curve();
158
159 curve_selection_.foreach_segment(GrainSize(512), [&](const IndexMaskSegment segment) {
160 for (const int curve_i : segment) {
161 const IndexRange points = points_by_curve[curve_i];
162 if (points.size() == 1) {
163 const float3 pos_cu = math::transform_point(brush_transform_inv,
164 self_->deformed_positions_[points.first()]);
165 const float2 pos_re = ED_view3d_project_float_v2_m4(ctx_.region, pos_cu, projection);
166
167 if (math::distance_squared(brush_pos_re_, pos_re) <= brush_radius_sq_re) {
168 curves_to_keep[curve_i] = false;
169 }
170 continue;
171 }
172
173 for (const int segment_i : points.drop_back(1)) {
174 const float3 pos1_cu = math::transform_point(brush_transform_inv,
175 self_->deformed_positions_[segment_i]);
176 const float3 pos2_cu = math::transform_point(brush_transform_inv,
177 self_->deformed_positions_[segment_i + 1]);
178
179 const float2 pos1_re = ED_view3d_project_float_v2_m4(ctx_.region, pos1_cu, projection);
180 const float2 pos2_re = ED_view3d_project_float_v2_m4(ctx_.region, pos2_cu, projection);
181
182 const float dist_sq_re = dist_squared_to_line_segment_v2(
183 brush_pos_re_, pos1_re, pos2_re);
184 if (dist_sq_re <= brush_radius_sq_re) {
185 curves_to_keep[curve_i] = false;
186 break;
187 }
188 }
189 }
190 });
191 }
192
194 {
195 float3 brush_wo;
197 ctx_.v3d,
198 ctx_.region,
199 math::transform_point(transforms_.curves_to_world, self_->brush_3d_.position_cu),
201 brush_wo);
202 const float3 brush_cu = math::transform_point(transforms_.world_to_curves, brush_wo);
203
204 const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
206
207 for (const float4x4 &brush_transform : symmetry_brush_transforms) {
208 this->delete_spherical(math::transform_point(brush_transform, brush_cu), curves_to_keep);
209 }
210 }
211
212 void delete_spherical(const float3 &brush_cu, MutableSpan<bool> curves_to_keep)
213 {
214 const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
215 const float brush_radius_sq_cu = pow2f(brush_radius_cu);
216 const OffsetIndices points_by_curve = curves_->points_by_curve();
217
218 curve_selection_.foreach_segment(GrainSize(512), [&](const IndexMaskSegment segment) {
219 for (const int curve_i : segment) {
220 const IndexRange points = points_by_curve[curve_i];
221
222 if (points.size() == 1) {
223 const float3 &pos_cu = self_->deformed_positions_[points.first()];
224 const float distance_sq_cu = math::distance_squared(pos_cu, brush_cu);
225 if (distance_sq_cu < brush_radius_sq_cu) {
226 curves_to_keep[curve_i] = false;
227 }
228 continue;
229 }
230
231 for (const int segment_i : points.drop_back(1)) {
232 const float3 &pos1_cu = self_->deformed_positions_[segment_i];
233 const float3 &pos2_cu = self_->deformed_positions_[segment_i + 1];
234
235 const float distance_sq_cu = dist_squared_to_line_segment_v3(brush_cu, pos1_cu, pos2_cu);
236 if (distance_sq_cu > brush_radius_sq_cu) {
237 continue;
238 }
239 curves_to_keep[curve_i] = false;
240 break;
241 }
242 }
243 });
244 }
245
247 {
248 std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(*ctx_.depsgraph,
249 *ctx_.region,
250 *ctx_.v3d,
251 *ctx_.rv3d,
252 *object_,
255 if (brush_3d.has_value()) {
256 self_->brush_3d_ = *brush_3d;
259 math::transform_point(transforms_.curves_to_world, self_->brush_3d_.position_cu));
260 }
261 }
262};
263
265 const StrokeExtension &stroke_extension)
266{
267 DeleteOperationExecutor executor{C};
268 executor.execute(*this, C, stroke_extension);
269}
270
271std::unique_ptr<CurvesSculptStrokeOperation> new_delete_operation()
272{
273 return std::make_unique<DeleteOperation>();
274}
275
276} // namespace blender::ed::sculpt_paint
float BKE_brush_radius_get(const Paint *paint, const Brush *brush)
Definition brush.cc:1272
Object * CTX_data_active_object(const bContext *C)
Low-level operations for curves.
const Brush * BKE_paint_brush_for_read(const Paint *paint)
Definition paint.cc:650
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
MINLINE float pow2f(float x)
float dist_squared_to_line_segment_v3(const float p[3], const float l1[3], const float l2[3])
Definition math_geom.cc:519
float dist_squared_to_line_segment_v2(const float p[2], const float l1[2], const float l2[2])
Definition math_geom.cc:291
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1074
eBrushFalloffShape
@ PAINT_FALLOFF_SHAPE_SPHERE
@ PAINT_FALLOFF_SHAPE_TUBE
eCurvesSymmetryType
Object is a sort of wrapper for general info.
@ USER_ORBIT_SELECTION
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:618
blender::float2 ED_view3d_project_float_v2_m4(const ARegion *region, const float co[3], const blender::float4x4 &mat)
void ED_view3d_win_to_3d(const View3D *v3d, const ARegion *region, const float depth_pt[3], const float mval[2], float r_out[3])
blender::float4x4 ED_view3d_ob_project_mat_get(const RegionView3D *rv3d, const Object *ob)
#define C
Definition RandGen.cpp:29
#define NC_GEOM
Definition WM_types.hh:393
#define ND_DATA
Definition WM_types.hh:509
#define U
PyObject * self
long long int int64_t
static IndexMask from_bools(Span< bool > bools, IndexMaskMemory &memory)
constexpr int64_t first() const
constexpr IndexRange drop_back(int64_t n) const
constexpr int64_t size() const
void extend(Span< T > array)
void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override
void foreach_index(Fn &&fn) const
GeometryDeformation get_evaluated_curves_deformation(const Object *ob_eval, const Object &ob_orig)
CurvesGeometry curves_copy_curve_selection(const CurvesGeometry &curves, const IndexMask &curves_to_copy, const AttributeFilter &attribute_filter)
IndexMask retrieve_selected_curves(const bke::CurvesGeometry &curves, IndexMaskMemory &memory)
std::optional< CurvesBrush3D > sample_curves_3d_brush(const Depsgraph &depsgraph, const ARegion &region, const View3D &v3d, const RegionView3D &rv3d, const Object &curves_object, const float2 &brush_pos_re, const float brush_radius_re)
void remember_stroke_position(CurvesSculpt &curves_sculpt, const float3 &brush_position_wo)
std::unique_ptr< CurvesSculptStrokeOperation > new_delete_operation()
Vector< float4x4 > get_symmetry_brush_transforms(const eCurvesSymmetryType symmetry)
float brush_radius_factor(const Brush &brush, const StrokeExtension &stroke_extension)
CartesianBasis invert(const CartesianBasis &basis)
T distance_squared(const VecBase< T, Size > &a, const VecBase< T, Size > &b)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
MatBase< float, 4, 4 > float4x4
VecBase< float, 2 > float2
VecBase< float, 3 > float3
void delete_projected(const float4x4 &brush_transform, MutableSpan< bool > curves_to_keep)
void delete_spherical_with_symmetry(MutableSpan< bool > curves_to_keep)
void execute(DeleteOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
void delete_projected_with_symmetry(MutableSpan< bool > curves_to_keep)
void delete_spherical(const float3 &brush_cu, MutableSpan< bool > curves_to_keep)
i
Definition text_draw.cc:230
void WM_main_add_notifier(uint type, void *reference)