Blender V4.3
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
5#include <algorithm>
6
8
9#include "BLI_kdtree.h"
10#include "BLI_math_geom.h"
12#include "BLI_rand.hh"
13#include "BLI_vector.hh"
14
15#include "DEG_depsgraph.hh"
16
17#include "BKE_attribute_math.hh"
18#include "BKE_brush.hh"
19#include "BKE_bvhutils.hh"
20#include "BKE_context.hh"
21#include "BKE_curves.hh"
22#include "BKE_mesh.hh"
23#include "BKE_mesh_runtime.hh"
24#include "BKE_paint.hh"
25
26#include "DNA_brush_enums.h"
27#include "DNA_brush_types.h"
28#include "DNA_curves_types.h"
29#include "DNA_object_types.h"
30#include "DNA_screen_types.h"
31#include "DNA_space_types.h"
32
33#include "ED_screen.hh"
34#include "ED_view3d.hh"
35
36#include "WM_api.hh"
37
46
48
50 private:
51 CurvesBrush3D brush_3d_;
57 Vector<float3> deformed_positions_;
58
60
61 public:
62 void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override;
63};
64
68
69 Object *object_ = nullptr;
70 Curves *curves_id_ = nullptr;
72
75
76 const CurvesSculpt *curves_sculpt_ = nullptr;
77 const Brush *brush_ = nullptr;
80
82
84
86
87 void execute(DeleteOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
88 {
89 self_ = &self;
91
92 curves_id_ = static_cast<Curves *>(object_->data);
93 curves_ = &curves_id_->geometry.wrap();
94
96
100 brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
101
102 brush_pos_re_ = stroke_extension.mouse_position;
103
105
107
108 if (stroke_extension.is_first) {
109 if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
111 }
112 const bke::crazyspace::GeometryDeformation deformation =
114 self_->deformed_positions_ = deformation.positions;
115 }
116
117 Array<bool> curves_to_keep(curves_->curves_num(), true);
118 if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
119 this->delete_projected_with_symmetry(curves_to_keep);
120 }
121 else if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
122 this->delete_spherical_with_symmetry(curves_to_keep);
123 }
124 else {
126 }
127
128 IndexMaskMemory mask_memory;
129 const IndexMask mask_to_keep = IndexMask::from_bools(curves_to_keep, mask_memory);
130
131 /* Remove deleted curves from the stored deformed positions. */
132 const OffsetIndices points_by_curve = curves_->points_by_curve();
133 Vector<float3> new_deformed_positions;
134 mask_to_keep.foreach_index([&](const int64_t i) {
135 new_deformed_positions.extend(
136 self_->deformed_positions_.as_span().slice(points_by_curve[i]));
137 });
138 self_->deformed_positions_ = std::move(new_deformed_positions);
139
140 *curves_ = bke::curves_copy_curve_selection(*curves_, mask_to_keep, {});
141
145 }
146
148 {
149 const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
151 for (const float4x4 &brush_transform : symmetry_brush_transforms) {
152 this->delete_projected(brush_transform, curves_to_keep);
153 }
154 }
155
156 void delete_projected(const float4x4 &brush_transform, MutableSpan<bool> curves_to_keep)
157 {
158 const float4x4 brush_transform_inv = math::invert(brush_transform);
159
161
162 const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
163 const float brush_radius_sq_re = pow2f(brush_radius_re);
164 const OffsetIndices points_by_curve = curves_->points_by_curve();
165
167 for (const int curve_i : segment) {
168 const IndexRange points = points_by_curve[curve_i];
169 if (points.size() == 1) {
170 const float3 pos_cu = math::transform_point(brush_transform_inv,
171 self_->deformed_positions_[points.first()]);
172 const float2 pos_re = ED_view3d_project_float_v2_m4(ctx_.region, pos_cu, projection);
173
174 if (math::distance_squared(brush_pos_re_, pos_re) <= brush_radius_sq_re) {
175 curves_to_keep[curve_i] = false;
176 }
177 continue;
178 }
179
180 for (const int segment_i : points.drop_back(1)) {
181 const float3 pos1_cu = math::transform_point(brush_transform_inv,
182 self_->deformed_positions_[segment_i]);
183 const float3 pos2_cu = math::transform_point(brush_transform_inv,
184 self_->deformed_positions_[segment_i + 1]);
185
186 const float2 pos1_re = ED_view3d_project_float_v2_m4(ctx_.region, pos1_cu, projection);
187 const float2 pos2_re = ED_view3d_project_float_v2_m4(ctx_.region, pos2_cu, projection);
188
189 const float dist_sq_re = dist_squared_to_line_segment_v2(
190 brush_pos_re_, pos1_re, pos2_re);
191 if (dist_sq_re <= brush_radius_sq_re) {
192 curves_to_keep[curve_i] = false;
193 break;
194 }
195 }
196 }
197 });
198 }
199
201 {
202 float3 brush_wo;
204 ctx_.v3d,
205 ctx_.region,
208 brush_wo);
209 const float3 brush_cu = math::transform_point(transforms_.world_to_curves, brush_wo);
210
211 const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
213
214 for (const float4x4 &brush_transform : symmetry_brush_transforms) {
215 this->delete_spherical(math::transform_point(brush_transform, brush_cu), curves_to_keep);
216 }
217 }
218
219 void delete_spherical(const float3 &brush_cu, MutableSpan<bool> curves_to_keep)
220 {
221 const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
222 const float brush_radius_sq_cu = pow2f(brush_radius_cu);
223 const OffsetIndices points_by_curve = curves_->points_by_curve();
224
226 for (const int curve_i : segment) {
227 const IndexRange points = points_by_curve[curve_i];
228
229 if (points.size() == 1) {
230 const float3 &pos_cu = self_->deformed_positions_[points.first()];
231 const float distance_sq_cu = math::distance_squared(pos_cu, brush_cu);
232 if (distance_sq_cu < brush_radius_sq_cu) {
233 curves_to_keep[curve_i] = false;
234 }
235 continue;
236 }
237
238 for (const int segment_i : points.drop_back(1)) {
239 const float3 &pos1_cu = self_->deformed_positions_[segment_i];
240 const float3 &pos2_cu = self_->deformed_positions_[segment_i + 1];
241
242 const float distance_sq_cu = dist_squared_to_line_segment_v3(brush_cu, pos1_cu, pos2_cu);
243 if (distance_sq_cu > brush_radius_sq_cu) {
244 continue;
245 }
246 curves_to_keep[curve_i] = false;
247 break;
248 }
249 }
250 });
251 }
252
254 {
255 std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(*ctx_.depsgraph,
256 *ctx_.region,
257 *ctx_.v3d,
258 *ctx_.rv3d,
259 *object_,
262 if (brush_3d.has_value()) {
263 self_->brush_3d_ = *brush_3d;
264 }
265 }
266};
267
269 const StrokeExtension &stroke_extension)
270{
271 DeleteOperationExecutor executor{C};
272 executor.execute(*this, C, stroke_extension);
273}
274
275std::unique_ptr<CurvesSculptStrokeOperation> new_delete_operation()
276{
277 return std::make_unique<DeleteOperation>();
278}
279
280} // namespace blender::ed::sculpt_paint
int BKE_brush_size_get(const Scene *scene, const Brush *brush)
Definition brush.cc:1075
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:654
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
A KD-tree for nearest neighbor search.
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:517
float dist_squared_to_line_segment_v2(const float p[2], const float l1[2], const float l2[2])
Definition math_geom.cc:289
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
eBrushFalloffShape
@ PAINT_FALLOFF_SHAPE_SPHERE
@ PAINT_FALLOFF_SHAPE_TUBE
eCurvesSymmetryType
Object is a sort of wrapper for general info.
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:634
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 NC_GEOM
Definition WM_types.hh:360
#define ND_DATA
Definition WM_types.hh:475
PyObject * self
void extend(Span< T > array)
OffsetIndices< int > points_by_curve() const
void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override
static IndexMask from_bools(Span< bool > bools, IndexMaskMemory &memory)
void foreach_index(Fn &&fn) const
void foreach_segment(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)
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)
__int64 int64_t
Definition stdint.h:89
char falloff_shape
CurvesGeometry geometry
struct Object * surface
struct ToolSettings * toolsettings
CurvesSculpt * curves_sculpt
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)
void WM_main_add_notifier(uint type, void *reference)