Blender  V3.3
curves_sculpt_delete.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include <algorithm>
4 
6 
7 #include "BLI_float4x4.hh"
8 #include "BLI_index_mask_ops.hh"
9 #include "BLI_kdtree.h"
10 #include "BLI_rand.hh"
11 #include "BLI_vector.hh"
12 
13 #include "PIL_time.h"
14 
15 #include "DEG_depsgraph.h"
16 
17 #include "BKE_attribute_math.hh"
18 #include "BKE_brush.h"
19 #include "BKE_bvhutils.h"
20 #include "BKE_context.h"
21 #include "BKE_curves.hh"
22 #include "BKE_mesh.h"
23 #include "BKE_mesh_runtime.h"
24 #include "BKE_paint.h"
25 
26 #include "DNA_brush_enums.h"
27 #include "DNA_brush_types.h"
28 #include "DNA_curves_types.h"
29 #include "DNA_mesh_types.h"
30 #include "DNA_meshdata_types.h"
31 #include "DNA_object_types.h"
32 #include "DNA_screen_types.h"
33 #include "DNA_space_types.h"
34 
35 #include "ED_screen.h"
36 #include "ED_view3d.h"
37 
38 #include "WM_api.h"
39 
47 namespace blender::ed::sculpt_paint {
48 
50 
52  private:
53  CurvesBrush3D brush_3d_;
59  Vector<float3> deformed_positions_;
60 
61  friend struct DeleteOperationExecutor;
62 
63  public:
64  void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override;
65 };
66 
68  DeleteOperation *self_ = nullptr;
70 
71  Object *object_ = nullptr;
72  Curves *curves_id_ = nullptr;
73  CurvesGeometry *curves_ = nullptr;
74 
77 
78  const CurvesSculpt *curves_sculpt_ = nullptr;
79  const Brush *brush_ = nullptr;
82 
84 
86 
88  {
89  }
90 
91  void execute(DeleteOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
92  {
93  self_ = &self;
95 
96  curves_id_ = static_cast<Curves *>(object_->data);
98 
101 
105  brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
106 
107  brush_pos_re_ = stroke_extension.mouse_position;
108 
110 
111  const eBrushFalloffShape falloff_shape = static_cast<eBrushFalloffShape>(
113 
114  if (stroke_extension.is_first) {
115  if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
117  }
118  const bke::crazyspace::GeometryDeformation deformation =
120  self_->deformed_positions_ = deformation.positions;
121  }
122 
123  Array<bool> curves_to_delete(curves_->curves_num(), false);
124  if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
125  this->delete_projected_with_symmetry(curves_to_delete);
126  }
127  else if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
128  this->delete_spherical_with_symmetry(curves_to_delete);
129  }
130  else {
132  }
133 
136  curves_->curves_range(), 4096, indices, [&](const int curve_i) {
137  return curves_to_delete[curve_i];
138  });
139 
140  /* Remove deleted curves from the stored deformed positions. */
141  const Vector<IndexRange> ranges_to_keep = mask_to_delete.extract_ranges_invert(
142  curves_->curves_range());
143  Vector<float3> new_deformed_positions;
144  for (const IndexRange curves_range : ranges_to_keep) {
145  new_deformed_positions.extend(
146  self_->deformed_positions_.as_span().slice(curves_->points_for_curves(curves_range)));
147  }
148  self_->deformed_positions_ = std::move(new_deformed_positions);
149 
150  curves_->remove_curves(mask_to_delete);
151 
155  }
156 
158  {
159  const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
161  for (const float4x4 &brush_transform : symmetry_brush_transforms) {
162  this->delete_projected(brush_transform, curves_to_delete);
163  }
164  }
165 
166  void delete_projected(const float4x4 &brush_transform, MutableSpan<bool> curves_to_delete)
167  {
168  const float4x4 brush_transform_inv = brush_transform.inverted();
169 
170  float4x4 projection;
172 
173  const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
174  const float brush_radius_sq_re = pow2f(brush_radius_re);
175 
177  for (const int curve_i : curve_selection_.slice(range)) {
178  const IndexRange points = curves_->points_for_curve(curve_i);
179  if (points.size() == 1) {
180  const float3 pos_cu = brush_transform_inv * self_->deformed_positions_[points.first()];
181  float2 pos_re;
182  ED_view3d_project_float_v2_m4(ctx_.region, pos_cu, pos_re, projection.values);
183 
184  if (math::distance_squared(brush_pos_re_, pos_re) <= brush_radius_sq_re) {
185  curves_to_delete[curve_i] = true;
186  }
187  continue;
188  }
189 
190  for (const int segment_i : points.drop_back(1)) {
191  const float3 pos1_cu = brush_transform_inv * self_->deformed_positions_[segment_i];
192  const float3 pos2_cu = brush_transform_inv * self_->deformed_positions_[segment_i + 1];
193 
194  float2 pos1_re, pos2_re;
195  ED_view3d_project_float_v2_m4(ctx_.region, pos1_cu, pos1_re, projection.values);
196  ED_view3d_project_float_v2_m4(ctx_.region, pos2_cu, pos2_re, projection.values);
197 
198  const float dist_sq_re = dist_squared_to_line_segment_v2(
199  brush_pos_re_, pos1_re, pos2_re);
200  if (dist_sq_re <= brush_radius_sq_re) {
201  curves_to_delete[curve_i] = true;
202  break;
203  }
204  }
205  }
206  });
207  }
208 
210  {
211  float4x4 projection;
212  ED_view3d_ob_project_mat_get(ctx_.rv3d, object_, projection.values);
213 
214  float3 brush_wo;
215  ED_view3d_win_to_3d(ctx_.v3d,
216  ctx_.region,
217  transforms_.curves_to_world * self_->brush_3d_.position_cu,
218  brush_pos_re_,
219  brush_wo);
220  const float3 brush_cu = transforms_.world_to_curves * brush_wo;
221 
222  const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
223  eCurvesSymmetryType(curves_id_->symmetry));
224 
225  for (const float4x4 &brush_transform : symmetry_brush_transforms) {
226  this->delete_spherical(brush_transform * brush_cu, curves_to_delete);
227  }
228  }
229 
230  void delete_spherical(const float3 &brush_cu, MutableSpan<bool> curves_to_delete)
231  {
232  const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
233  const float brush_radius_sq_cu = pow2f(brush_radius_cu);
234 
235  threading::parallel_for(curve_selection_.index_range(), 512, [&](const IndexRange range) {
236  for (const int curve_i : curve_selection_.slice(range)) {
237  const IndexRange points = curves_->points_for_curve(curve_i);
238 
239  if (points.size() == 1) {
240  const float3 &pos_cu = self_->deformed_positions_[points.first()];
241  const float distance_sq_cu = math::distance_squared(pos_cu, brush_cu);
242  if (distance_sq_cu < brush_radius_sq_cu) {
243  curves_to_delete[curve_i] = true;
244  }
245  continue;
246  }
247 
248  for (const int segment_i : points.drop_back(1)) {
249  const float3 &pos1_cu = self_->deformed_positions_[segment_i];
250  const float3 &pos2_cu = self_->deformed_positions_[segment_i + 1];
251 
252  const float distance_sq_cu = dist_squared_to_line_segment_v3(brush_cu, pos1_cu, pos2_cu);
253  if (distance_sq_cu > brush_radius_sq_cu) {
254  continue;
255  }
256  curves_to_delete[curve_i] = true;
257  break;
258  }
259  }
260  });
261  }
262 
264  {
265  std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(*ctx_.depsgraph,
266  *ctx_.region,
267  *ctx_.v3d,
268  *ctx_.rv3d,
269  *object_,
270  brush_pos_re_,
271  brush_radius_base_re_);
272  if (brush_3d.has_value()) {
273  self_->brush_3d_ = *brush_3d;
274  }
275  }
276 };
277 
278 void DeleteOperation::on_stroke_extended(const bContext &C,
279  const StrokeExtension &stroke_extension)
280 {
281  DeleteOperationExecutor executor{C};
282  executor.execute(*this, C, stroke_extension);
283 }
284 
285 std::unique_ptr<CurvesSculptStrokeOperation> new_delete_operation()
286 {
287  return std::make_unique<DeleteOperation>();
288 }
289 
290 } // namespace blender::ed::sculpt_paint
int BKE_brush_size_get(const struct Scene *scene, const struct Brush *brush)
struct Object * CTX_data_active_object(const bContext *C)
Definition: context.c:1353
Low-level operations for curves.
const struct Brush * BKE_paint_brush_for_read(const struct Paint *p)
#define BLI_assert_unreachable()
Definition: BLI_assert.h:93
A KD-tree for nearest neighbor search.
MINLINE float pow2f(float x)
void DEG_id_tag_update(struct ID *id, int flag)
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:791
eBrushFalloffShape
@ PAINT_FALLOFF_SHAPE_SPHERE
@ PAINT_FALLOFF_SHAPE_TUBE
struct CurvesGeometry CurvesGeometry
eCurvesSymmetryType
Object is a sort of wrapper for general info.
void ED_region_tag_redraw(struct ARegion *region)
Definition: area.c:655
void ED_view3d_ob_project_mat_get(const struct RegionView3D *v3d, const struct Object *ob, float r_pmat[4][4])
void ED_view3d_win_to_3d(const struct View3D *v3d, const struct ARegion *region, const float depth_pt[3], const float mval[2], float r_out[3])
Platform independent time functions.
#define C
Definition: RandGen.cpp:25
#define NC_GEOM
Definition: WM_types.h:343
#define ND_DATA
Definition: WM_types.h:456
Vector< IndexRange > extract_ranges_invert(const IndexRange full_range, Vector< int64_t > *r_skip_amounts=nullptr) const
Definition: index_mask.cc:100
IndexRange index_range() const
void extend(Span< T > array)
Definition: BLI_vector.hh:530
IndexRange curves_range() const
Definition: BKE_curves.hh:795
IndexRange points_for_curves(IndexRange curves) const
Definition: BKE_curves.hh:832
void remove_curves(IndexMask curves_to_delete)
static CurvesGeometry & wrap(::CurvesGeometry &dna_struct)
Definition: BKE_curves.hh:138
void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override
ccl_gpu_kernel_postfix int ccl_global int * indices
GeometryDeformation get_evaluated_curves_deformation(const Depsgraph &depsgraph, const Object &ob_orig)
Definition: crazyspace.cc:595
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()
static IndexMask retrieve_selected_curves(const CurvesGeometry &curves, const eAttrDomain domain, Vector< int64_t > &r_indices)
Vector< float4x4 > get_symmetry_brush_transforms(const eCurvesSymmetryType symmetry)
float brush_radius_factor(const Brush &brush, const StrokeExtension &stroke_extension)
IndexMask find_indices_based_on_predicate(const IndexMask indices_to_check, const int64_t parallel_grain_size, Vector< int64_t > &r_indices, const Predicate &predicate)
void parallel_for(IndexRange range, int64_t grain_size, const Function &function)
Definition: BLI_task.hh:51
char falloff_shape
CurvesGeometry geometry
struct Object * surface
void * data
struct ToolSettings * toolsettings
CurvesSculpt * curves_sculpt
void delete_spherical(const float3 &brush_cu, MutableSpan< bool > curves_to_delete)
void execute(DeleteOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
void delete_projected(const float4x4 &brush_transform, MutableSpan< bool > curves_to_delete)
void delete_spherical_with_symmetry(MutableSpan< bool > curves_to_delete)
void delete_projected_with_symmetry(MutableSpan< bool > curves_to_delete)
float values[4][4]
Definition: BLI_float4x4.hh:13
float4x4 inverted() const
void WM_main_add_notifier(unsigned int type, void *reference)