Blender  V3.3
editmesh_select_similar.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2004 Blender Foundation. All rights reserved. */
3 
8 #include "MEM_guardedalloc.h"
9 
10 #include "BLI_bitmap.h"
11 #include "BLI_kdtree.h"
12 #include "BLI_listbase.h"
13 #include "BLI_math.h"
14 
15 #include "BLT_translation.h"
16 
17 #include "BKE_context.h"
18 #include "BKE_customdata.h"
19 #include "BKE_deform.h"
20 #include "BKE_editmesh.h"
21 #include "BKE_layer.h"
22 #include "BKE_material.h"
23 #include "BKE_report.h"
24 
25 #include "DNA_material_types.h"
26 #include "DNA_meshdata_types.h"
27 
28 #include "WM_api.h"
29 #include "WM_types.h"
30 
31 #include "RNA_access.h"
32 #include "RNA_define.h"
33 
34 #include "ED_mesh.h"
35 #include "ED_screen.h"
36 #include "ED_select_utils.h"
37 
38 #include "mesh_intern.h" /* own include */
39 
40 /* -------------------------------------------------------------------- */
45  {SIM_CMP_EQ, "EQUAL", 0, "Equal", ""},
46  {SIM_CMP_GT, "GREATER", 0, "Greater", ""},
47  {SIM_CMP_LT, "LESS", 0, "Less", ""},
48 
49  {0, NULL, 0, NULL, NULL},
50 };
51 
53  {SIMVERT_NORMAL, "NORMAL", 0, "Normal", ""},
54  {SIMVERT_FACE, "FACE", 0, "Amount of Adjacent Faces", ""},
55  {SIMVERT_VGROUP, "VGROUP", 0, "Vertex Groups", ""},
56  {SIMVERT_EDGE, "EDGE", 0, "Amount of Connecting Edges", ""},
57  {SIMVERT_CREASE, "VCREASE", 0, "Vertex Crease", ""},
58 
59  {SIMEDGE_LENGTH, "LENGTH", 0, "Length", ""},
60  {SIMEDGE_DIR, "DIR", 0, "Direction", ""},
61  {SIMEDGE_FACE, "FACE", 0, "Amount of Faces Around an Edge", ""},
62  {SIMEDGE_FACE_ANGLE, "FACE_ANGLE", 0, "Face Angles", ""},
63  {SIMEDGE_CREASE, "CREASE", 0, "Crease", ""},
64  {SIMEDGE_BEVEL, "BEVEL", 0, "Bevel", ""},
65  {SIMEDGE_SEAM, "SEAM", 0, "Seam", ""},
66  {SIMEDGE_SHARP, "SHARP", 0, "Sharpness", ""},
67 #ifdef WITH_FREESTYLE
68  {SIMEDGE_FREESTYLE, "FREESTYLE_EDGE", 0, "Freestyle Edge Marks", ""},
69 #endif
70 
71  {SIMFACE_MATERIAL, "MATERIAL", 0, "Material", ""},
72  {SIMFACE_AREA, "AREA", 0, "Area", ""},
73  {SIMFACE_SIDES, "SIDES", 0, "Polygon Sides", ""},
74  {SIMFACE_PERIMETER, "PERIMETER", 0, "Perimeter", ""},
75  {SIMFACE_NORMAL, "NORMAL", 0, "Normal", ""},
76  {SIMFACE_COPLANAR, "COPLANAR", 0, "Coplanar", ""},
77  {SIMFACE_SMOOTH, "SMOOTH", 0, "Flat/Smooth", ""},
78  {SIMFACE_FACEMAP, "FACE_MAP", 0, "Face Map", ""},
79 #ifdef WITH_FREESTYLE
80  {SIMFACE_FREESTYLE, "FREESTYLE_FACE", 0, "Freestyle Face Marks", ""},
81 #endif
82 
83  {0, NULL, 0, NULL, NULL},
84 };
85 
86 static int mesh_select_similar_compare_int(const int delta, const int compare)
87 {
88  switch (compare) {
89  case SIM_CMP_EQ:
90  return (delta == 0);
91  case SIM_CMP_GT:
92  return (delta > 0);
93  case SIM_CMP_LT:
94  return (delta < 0);
95  default:
96  BLI_assert(0);
97  return 0;
98  }
99 }
100 
103 /* -------------------------------------------------------------------- */
107 enum {
109  SIMFACE_DATA_TRUE = (1 << 0),
110  SIMFACE_DATA_FALSE = (1 << 1),
112 };
113 
119 static bool face_data_value_set(BMFace *face, const int hflag, int *r_value)
120 {
121  if (BM_elem_flag_test(face, hflag)) {
122  *r_value |= SIMFACE_DATA_TRUE;
123  }
124  else {
125  *r_value |= SIMFACE_DATA_FALSE;
126  }
127 
128  return *r_value != SIMFACE_DATA_ALL;
129 }
130 
134 static void face_to_plane(const Object *ob, BMFace *face, float r_plane[4])
135 {
136  float normal[3], co[3];
137  copy_v3_v3(normal, face->no);
140  mul_v3_m4v3(co, ob->obmat, BM_FACE_FIRST_LOOP(face)->v->co);
141  plane_from_point_normal_v3(r_plane, co, normal);
142 }
143 
144 /* TODO(dfelinto): `types` that should technically be compared in world space but are not:
145  * -SIMFACE_AREA
146  * -SIMFACE_PERIMETER
147  */
149 {
150  ViewLayer *view_layer = CTX_data_view_layer(C);
151 
152  const int type = RNA_enum_get(op->ptr, "type");
153  const float thresh = RNA_float_get(op->ptr, "threshold");
154  const float thresh_radians = thresh * (float)M_PI;
155  const int compare = RNA_enum_get(op->ptr, "compare");
156 
157  int tot_faces_selected_all = 0;
158  uint objects_len = 0;
160  view_layer, CTX_wm_view3d(C), &objects_len);
161 
162  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
163  Object *ob = objects[ob_index];
165  tot_faces_selected_all += em->bm->totfacesel;
166  }
167 
168  if (tot_faces_selected_all == 0) {
169  BKE_report(op->reports, RPT_ERROR, "No face selected");
170  MEM_freeN(objects);
171  return OPERATOR_CANCELLED;
172  }
173 
174  KDTree_1d *tree_1d = NULL;
175  KDTree_3d *tree_3d = NULL;
176  KDTree_4d *tree_4d = NULL;
177  GSet *gset = NULL;
178  GSet **gset_array = NULL;
179  int face_data_value = SIMFACE_DATA_NONE;
180 
181  switch (type) {
182  case SIMFACE_AREA:
183  case SIMFACE_PERIMETER:
184  tree_1d = BLI_kdtree_1d_new(tot_faces_selected_all);
185  break;
186  case SIMFACE_NORMAL:
187  tree_3d = BLI_kdtree_3d_new(tot_faces_selected_all);
188  break;
189  case SIMFACE_COPLANAR:
190  tree_4d = BLI_kdtree_4d_new(tot_faces_selected_all);
191  break;
192  case SIMFACE_SIDES:
193  case SIMFACE_MATERIAL:
194  gset = BLI_gset_ptr_new("Select similar face");
195  break;
196  case SIMFACE_FACEMAP:
197  gset_array = MEM_callocN(sizeof(GSet *) * objects_len,
198  "Select similar face: facemap gset array");
199  break;
200  }
201 
202  int tree_index = 0;
203  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
204  Object *ob = objects[ob_index];
206  BMesh *bm = em->bm;
207  Material ***material_array = NULL;
208  invert_m4_m4(ob->imat, ob->obmat);
209  int custom_data_offset = 0;
210 
211  if (bm->totfacesel == 0) {
212  continue;
213  }
214 
215  float ob_m3[3][3];
216  copy_m3_m4(ob_m3, ob->obmat);
217 
218  switch (type) {
219  case SIMFACE_MATERIAL: {
220  if (ob->totcol == 0) {
221  continue;
222  }
223  material_array = BKE_object_material_array_p(ob);
224  break;
225  }
226  case SIMFACE_FREESTYLE: {
228  face_data_value |= SIMFACE_DATA_FALSE;
229  continue;
230  }
231  break;
232  }
233  case SIMFACE_FACEMAP: {
234  custom_data_offset = CustomData_get_offset(&bm->pdata, CD_FACEMAP);
235  if (custom_data_offset == -1) {
236  continue;
237  }
238  gset_array[ob_index] = BLI_gset_ptr_new("Select similar face: facemap gset");
239  }
240  }
241 
242  BMFace *face; /* Mesh face. */
243  BMIter iter; /* Selected faces iterator. */
244 
245  BM_ITER_MESH (face, &iter, bm, BM_FACES_OF_MESH) {
246  if (BM_elem_flag_test(face, BM_ELEM_SELECT)) {
247  switch (type) {
248  case SIMFACE_SIDES:
249  BLI_gset_add(gset, POINTER_FROM_INT(face->len));
250  break;
251  case SIMFACE_MATERIAL: {
252  Material *material = (*material_array)[face->mat_nr];
253  if (material != NULL) {
254  BLI_gset_add(gset, material);
255  }
256  break;
257  }
258  case SIMFACE_AREA: {
259  float area = BM_face_calc_area_with_mat3(face, ob_m3);
260  BLI_kdtree_1d_insert(tree_1d, tree_index++, &area);
261  break;
262  }
263  case SIMFACE_PERIMETER: {
264  float perimeter = BM_face_calc_perimeter_with_mat3(face, ob_m3);
265  BLI_kdtree_1d_insert(tree_1d, tree_index++, &perimeter);
266  break;
267  }
268  case SIMFACE_NORMAL: {
269  float normal[3];
270  copy_v3_v3(normal, face->no);
273  BLI_kdtree_3d_insert(tree_3d, tree_index++, normal);
274  break;
275  }
276  case SIMFACE_COPLANAR: {
277  float plane[4];
278  face_to_plane(ob, face, plane);
279  BLI_kdtree_4d_insert(tree_4d, tree_index++, plane);
280  break;
281  }
282  case SIMFACE_SMOOTH: {
283  if (!face_data_value_set(face, BM_ELEM_SMOOTH, &face_data_value)) {
284  goto face_select_all;
285  }
286  break;
287  }
288  case SIMFACE_FREESTYLE: {
289  FreestyleFace *fface;
291  if ((fface == NULL) || ((fface->flag & FREESTYLE_FACE_MARK) == 0)) {
292  face_data_value |= SIMFACE_DATA_FALSE;
293  }
294  else {
295  face_data_value |= SIMFACE_DATA_TRUE;
296  }
297  if (face_data_value == SIMFACE_DATA_ALL) {
298  goto face_select_all;
299  }
300  break;
301  }
302  case SIMFACE_FACEMAP: {
303  BLI_assert(custom_data_offset != -1);
304  int *face_map = BM_ELEM_CD_GET_VOID_P(face, custom_data_offset);
305  BLI_gset_add(gset_array[ob_index], face_map);
306  break;
307  }
308  }
309  }
310  }
311  }
312 
313  BLI_assert((type != SIMFACE_FREESTYLE) || (face_data_value != SIMFACE_DATA_NONE));
314 
315  if (tree_1d != NULL) {
316  BLI_kdtree_1d_deduplicate(tree_1d);
317  BLI_kdtree_1d_balance(tree_1d);
318  }
319  if (tree_3d != NULL) {
320  BLI_kdtree_3d_deduplicate(tree_3d);
321  BLI_kdtree_3d_balance(tree_3d);
322  }
323  if (tree_4d != NULL) {
324  BLI_kdtree_4d_deduplicate(tree_4d);
325  BLI_kdtree_4d_balance(tree_4d);
326  }
327 
328  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
329  Object *ob = objects[ob_index];
331  BMesh *bm = em->bm;
332  bool changed = false;
333  Material ***material_array = NULL;
334  int custom_data_offset;
335 
336  float ob_m3[3][3];
337  copy_m3_m4(ob_m3, ob->obmat);
338 
339  bool has_custom_data_layer = false;
340  switch (type) {
341  case SIMFACE_MATERIAL: {
342  if (ob->totcol == 0) {
343  continue;
344  }
345  material_array = BKE_object_material_array_p(ob);
346  break;
347  }
348  case SIMFACE_FREESTYLE: {
349  has_custom_data_layer = CustomData_has_layer(&bm->pdata, CD_FREESTYLE_FACE);
350  if ((face_data_value == SIMFACE_DATA_TRUE) && !has_custom_data_layer) {
351  continue;
352  }
353  break;
354  }
355  case SIMFACE_FACEMAP: {
356  custom_data_offset = CustomData_get_offset(&bm->pdata, CD_FACEMAP);
357  if (custom_data_offset == -1) {
358  continue;
359  }
360  }
361  }
362 
363  BMFace *face; /* Mesh face. */
364  BMIter iter; /* Selected faces iterator. */
365 
366  BM_ITER_MESH (face, &iter, bm, BM_FACES_OF_MESH) {
368  bool select = false;
369  switch (type) {
370  case SIMFACE_SIDES: {
371  const int num_sides = face->len;
372  GSetIterator gs_iter;
373  GSET_ITER (gs_iter, gset) {
374  const int num_sides_iter = POINTER_AS_INT(BLI_gsetIterator_getKey(&gs_iter));
375  const int delta_i = num_sides - num_sides_iter;
376  if (mesh_select_similar_compare_int(delta_i, compare)) {
377  select = true;
378  break;
379  }
380  }
381  break;
382  }
383  case SIMFACE_MATERIAL: {
384  const Material *material = (*material_array)[face->mat_nr];
385  if (material == NULL) {
386  continue;
387  }
388 
389  GSetIterator gs_iter;
390  GSET_ITER (gs_iter, gset) {
391  const Material *material_iter = BLI_gsetIterator_getKey(&gs_iter);
392  if (material == material_iter) {
393  select = true;
394  break;
395  }
396  }
397  break;
398  }
399  case SIMFACE_AREA: {
400  float area = BM_face_calc_area_with_mat3(face, ob_m3);
401  if (ED_select_similar_compare_float_tree(tree_1d, area, thresh, compare)) {
402  select = true;
403  }
404  break;
405  }
406  case SIMFACE_PERIMETER: {
407  float perimeter = BM_face_calc_perimeter_with_mat3(face, ob_m3);
408  if (ED_select_similar_compare_float_tree(tree_1d, perimeter, thresh, compare)) {
409  select = true;
410  }
411  break;
412  }
413  case SIMFACE_NORMAL: {
414  float normal[3];
415  copy_v3_v3(normal, face->no);
418 
419  /* We are treating the normals as coordinates, the "nearest" one will
420  * also be the one closest to the angle. */
421  KDTreeNearest_3d nearest;
422  if (BLI_kdtree_3d_find_nearest(tree_3d, normal, &nearest) != -1) {
423  if (angle_normalized_v3v3(normal, nearest.co) <= thresh_radians) {
424  select = true;
425  }
426  }
427  break;
428  }
429  case SIMFACE_COPLANAR: {
430  float plane[4];
431  face_to_plane(ob, face, plane);
432 
433  KDTreeNearest_4d nearest;
434  if (BLI_kdtree_4d_find_nearest(tree_4d, plane, &nearest) != -1) {
435  if (nearest.dist <= thresh) {
436  if ((fabsf(plane[3] - nearest.co[3]) <= thresh) &&
437  (angle_v3v3(plane, nearest.co) <= thresh_radians)) {
438  select = true;
439  }
440  }
441  }
442  break;
443  }
444  case SIMFACE_SMOOTH:
445  if ((BM_elem_flag_test(face, BM_ELEM_SMOOTH) != 0) ==
446  ((face_data_value & SIMFACE_DATA_TRUE) != 0)) {
447  select = true;
448  }
449  break;
450  case SIMFACE_FREESTYLE: {
451  FreestyleFace *fface;
452 
453  if (!has_custom_data_layer) {
454  BLI_assert(face_data_value == SIMFACE_DATA_FALSE);
455  select = true;
456  break;
457  }
458 
460  if (((fface != NULL) && (fface->flag & FREESTYLE_FACE_MARK)) ==
461  ((face_data_value & SIMFACE_DATA_TRUE) != 0)) {
462  select = true;
463  }
464  break;
465  }
466  case SIMFACE_FACEMAP: {
467  const int *face_map = BM_ELEM_CD_GET_VOID_P(face, custom_data_offset);
468  GSetIterator gs_iter;
469  GSET_ITER (gs_iter, gset_array[ob_index]) {
470  const int *face_map_iter = BLI_gsetIterator_getKey(&gs_iter);
471  if (*face_map == *face_map_iter) {
472  select = true;
473  break;
474  }
475  }
476  break;
477  }
478  }
479 
480  if (select) {
481  BM_face_select_set(bm, face, true);
482  changed = true;
483  }
484  }
485  }
486 
487  if (changed) {
489  EDBM_update(ob->data,
490  &(const struct EDBMUpdate_Params){
491  .calc_looptri = false,
492  .calc_normals = false,
493  .is_destructive = false,
494  });
495  }
496  }
497 
498  if (false) {
499  face_select_all:
501 
502  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
503  Object *ob = objects[ob_index];
505  BMesh *bm = em->bm;
506 
507  BMFace *face; /* Mesh face. */
508  BMIter iter; /* Selected faces iterator. */
509 
510  BM_ITER_MESH (face, &iter, bm, BM_FACES_OF_MESH) {
511  if (!BM_elem_flag_test(face, BM_ELEM_SELECT)) {
512  BM_face_select_set(bm, face, true);
513  }
514  }
516  EDBM_update(ob->data,
517  &(const struct EDBMUpdate_Params){
518  .calc_looptri = false,
519  .calc_normals = false,
520  .is_destructive = false,
521  });
522  }
523  }
524 
525  MEM_freeN(objects);
526  BLI_kdtree_1d_free(tree_1d);
527  BLI_kdtree_3d_free(tree_3d);
528  BLI_kdtree_4d_free(tree_4d);
529  if (gset != NULL) {
530  BLI_gset_free(gset, NULL);
531  }
532  if (gset_array != NULL) {
533  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
534  if (gset_array[ob_index] != NULL) {
535  BLI_gset_free(gset_array[ob_index], NULL);
536  }
537  }
538  MEM_freeN(gset_array);
539  }
540 
541  return OPERATOR_FINISHED;
542 }
543 
546 /* -------------------------------------------------------------------- */
555 static void edge_pos_direction_worldspace_get(Object *ob, BMEdge *edge, float *r_dir)
556 {
557  float v1[3], v2[3];
558  copy_v3_v3(v1, edge->v1->co);
559  copy_v3_v3(v2, edge->v2->co);
560 
561  mul_m4_v3(ob->obmat, v1);
562  mul_m4_v3(ob->obmat, v2);
563 
564  sub_v3_v3v3(r_dir, v1, v2);
565  normalize_v3(r_dir);
566 
567  /* Make sure we have a consistent direction that can be checked regardless of
568  * the verts order of the edges. This spares us from storing dir and -dir in the tree_3d. */
569  if (fabs(r_dir[2]) < FLT_EPSILON) {
570  if (fabs(r_dir[1]) < FLT_EPSILON) {
571  if (r_dir[0] < 0.0f) {
572  mul_v3_fl(r_dir, -1.0f);
573  }
574  }
575  else if (r_dir[1] < 0.0f) {
576  mul_v3_fl(r_dir, -1.0f);
577  }
578  }
579  else if (r_dir[2] < 0.0f) {
580  mul_v3_fl(r_dir, -1.0f);
581  }
582 }
583 
585 {
586  float v1[3], v2[3];
587 
588  mul_v3_mat3_m4v3(v1, ob->obmat, edge->v1->co);
589  mul_v3_mat3_m4v3(v2, ob->obmat, edge->v2->co);
590 
591  return len_squared_v3v3(v1, v2);
592 }
593 
594 enum {
596  SIMEDGE_DATA_TRUE = (1 << 0),
597  SIMEDGE_DATA_FALSE = (1 << 1),
599 };
600 
606 static bool edge_data_value_set(BMEdge *edge, const int hflag, int *r_value)
607 {
608  if (BM_elem_flag_test(edge, hflag)) {
609  *r_value |= SIMEDGE_DATA_TRUE;
610  }
611  else {
612  *r_value |= SIMEDGE_DATA_FALSE;
613  }
614 
615  return *r_value != SIMEDGE_DATA_ALL;
616 }
617 
618 /* TODO(dfelinto): `types` that should technically be compared in world space but are not:
619  * -SIMEDGE_FACE_ANGLE
620  */
622 {
623  ViewLayer *view_layer = CTX_data_view_layer(C);
624 
625  const int type = RNA_enum_get(op->ptr, "type");
626  const float thresh = RNA_float_get(op->ptr, "threshold");
627  const float thresh_radians = thresh * (float)M_PI + FLT_EPSILON;
628  const int compare = RNA_enum_get(op->ptr, "compare");
629  int custom_data_type = -1;
630 
631  int tot_edges_selected_all = 0;
632  uint objects_len = 0;
634  view_layer, CTX_wm_view3d(C), &objects_len);
635 
636  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
637  Object *ob = objects[ob_index];
639  tot_edges_selected_all += em->bm->totedgesel;
640  }
641 
642  if (tot_edges_selected_all == 0) {
643  BKE_report(op->reports, RPT_ERROR, "No edge selected");
644  MEM_freeN(objects);
645  return OPERATOR_CANCELLED;
646  }
647 
648  KDTree_1d *tree_1d = NULL;
649  KDTree_3d *tree_3d = NULL;
650  GSet *gset = NULL;
651  int edge_data_value = SIMEDGE_DATA_NONE;
652 
653  switch (type) {
654  case SIMEDGE_CREASE:
655  case SIMEDGE_BEVEL:
656  case SIMEDGE_FACE_ANGLE:
657  case SIMEDGE_LENGTH:
658  tree_1d = BLI_kdtree_1d_new(tot_edges_selected_all);
659  break;
660  case SIMEDGE_DIR:
661  tree_3d = BLI_kdtree_3d_new(tot_edges_selected_all);
662  break;
663  case SIMEDGE_FACE:
664  gset = BLI_gset_ptr_new("Select similar edge: face");
665  break;
666  }
667 
668  switch (type) {
669  case SIMEDGE_CREASE:
670  custom_data_type = CD_CREASE;
671  break;
672  case SIMEDGE_BEVEL:
673  custom_data_type = CD_BWEIGHT;
674  break;
675  }
676 
677  int tree_index = 0;
678  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
679  Object *ob = objects[ob_index];
681  BMesh *bm = em->bm;
682 
683  if (bm->totedgesel == 0) {
684  continue;
685  }
686 
687  switch (type) {
688  case SIMEDGE_FREESTYLE: {
690  edge_data_value |= SIMEDGE_DATA_FALSE;
691  continue;
692  }
693  break;
694  }
695  case SIMEDGE_CREASE:
696  case SIMEDGE_BEVEL: {
697  if (!CustomData_has_layer(&bm->edata, custom_data_type)) {
698  BLI_kdtree_1d_insert(tree_1d, tree_index++, (float[1]){0.0f});
699  continue;
700  }
701  break;
702  }
703  }
704 
705  float ob_m3[3][3], ob_m3_inv[3][3];
706  copy_m3_m4(ob_m3, ob->obmat);
707  invert_m3_m3(ob_m3_inv, ob_m3);
708 
709  BMEdge *edge; /* Mesh edge. */
710  BMIter iter; /* Selected edges iterator. */
711 
712  BM_ITER_MESH (edge, &iter, bm, BM_EDGES_OF_MESH) {
713  if (BM_elem_flag_test(edge, BM_ELEM_SELECT)) {
714  switch (type) {
715  case SIMEDGE_FACE:
717  break;
718  case SIMEDGE_DIR: {
719  float dir[3];
720  edge_pos_direction_worldspace_get(ob, edge, dir);
721  BLI_kdtree_3d_insert(tree_3d, tree_index++, dir);
722  break;
723  }
724  case SIMEDGE_LENGTH: {
725  float length = edge_length_squared_worldspace_get(ob, edge);
726  BLI_kdtree_1d_insert(tree_1d, tree_index++, &length);
727  break;
728  }
729  case SIMEDGE_FACE_ANGLE: {
730  if (BM_edge_face_count_at_most(edge, 2) == 2) {
731  float angle = BM_edge_calc_face_angle_with_imat3(edge, ob_m3_inv);
732  BLI_kdtree_1d_insert(tree_1d, tree_index++, &angle);
733  }
734  break;
735  }
736  case SIMEDGE_SEAM:
737  if (!edge_data_value_set(edge, BM_ELEM_SEAM, &edge_data_value)) {
738  goto edge_select_all;
739  }
740  break;
741  case SIMEDGE_SHARP:
742  if (!edge_data_value_set(edge, BM_ELEM_SMOOTH, &edge_data_value)) {
743  goto edge_select_all;
744  }
745  break;
746  case SIMEDGE_FREESTYLE: {
747  FreestyleEdge *fedge;
748  fedge = CustomData_bmesh_get(&bm->edata, edge->head.data, CD_FREESTYLE_EDGE);
749  if ((fedge == NULL) || ((fedge->flag & FREESTYLE_EDGE_MARK) == 0)) {
750  edge_data_value |= SIMEDGE_DATA_FALSE;
751  }
752  else {
753  edge_data_value |= SIMEDGE_DATA_TRUE;
754  }
755  if (edge_data_value == SIMEDGE_DATA_ALL) {
756  goto edge_select_all;
757  }
758  break;
759  }
760  case SIMEDGE_CREASE:
761  case SIMEDGE_BEVEL: {
762  const float *value = CustomData_bmesh_get(
763  &bm->edata, edge->head.data, custom_data_type);
764  BLI_kdtree_1d_insert(tree_1d, tree_index++, value);
765  break;
766  }
767  }
768  }
769  }
770  }
771 
772  BLI_assert((type != SIMEDGE_FREESTYLE) || (edge_data_value != SIMEDGE_DATA_NONE));
773 
774  if (tree_1d != NULL) {
775  BLI_kdtree_1d_deduplicate(tree_1d);
776  BLI_kdtree_1d_balance(tree_1d);
777  }
778  if (tree_3d != NULL) {
779  BLI_kdtree_3d_deduplicate(tree_3d);
780  BLI_kdtree_3d_balance(tree_3d);
781  }
782 
783  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
784  Object *ob = objects[ob_index];
786  BMesh *bm = em->bm;
787  bool changed = false;
788 
789  bool has_custom_data_layer = false;
790  switch (type) {
791  case SIMEDGE_FREESTYLE: {
792  has_custom_data_layer = CustomData_has_layer(&bm->edata, CD_FREESTYLE_EDGE);
793  if ((edge_data_value == SIMEDGE_DATA_TRUE) && !has_custom_data_layer) {
794  continue;
795  }
796  break;
797  }
798  case SIMEDGE_CREASE:
799  case SIMEDGE_BEVEL: {
800  has_custom_data_layer = CustomData_has_layer(&bm->edata, custom_data_type);
801  if (!has_custom_data_layer) {
802  /* Proceed only if we have to select all the edges that have custom data value of 0.0f.
803  * In this case we will just select all the edges.
804  * Otherwise continue the for loop. */
805  if (!ED_select_similar_compare_float_tree(tree_1d, 0.0f, thresh, compare)) {
806  continue;
807  }
808  }
809  }
810  }
811 
812  float ob_m3[3][3], ob_m3_inv[3][3];
813  copy_m3_m4(ob_m3, ob->obmat);
814  invert_m3_m3(ob_m3_inv, ob_m3);
815 
816  BMEdge *edge; /* Mesh edge. */
817  BMIter iter; /* Selected edges iterator. */
818 
819  BM_ITER_MESH (edge, &iter, bm, BM_EDGES_OF_MESH) {
821  bool select = false;
822  switch (type) {
823  case SIMEDGE_FACE: {
824  const int num_faces = BM_edge_face_count(edge);
825  GSetIterator gs_iter;
826  GSET_ITER (gs_iter, gset) {
827  const int num_faces_iter = POINTER_AS_INT(BLI_gsetIterator_getKey(&gs_iter));
828  const int delta_i = num_faces - num_faces_iter;
829  if (mesh_select_similar_compare_int(delta_i, compare)) {
830  select = true;
831  break;
832  }
833  }
834  break;
835  }
836  case SIMEDGE_DIR: {
837  float dir[3];
838  edge_pos_direction_worldspace_get(ob, edge, dir);
839 
840  /* We are treating the direction as coordinates, the "nearest" one will
841  * also be the one closest to the intended direction. */
842  KDTreeNearest_3d nearest;
843  if (BLI_kdtree_3d_find_nearest(tree_3d, dir, &nearest) != -1) {
844  if (angle_normalized_v3v3(dir, nearest.co) <= thresh_radians) {
845  select = true;
846  }
847  }
848  break;
849  }
850  case SIMEDGE_LENGTH: {
851  float length = edge_length_squared_worldspace_get(ob, edge);
852  if (ED_select_similar_compare_float_tree(tree_1d, length, thresh, compare)) {
853  select = true;
854  }
855  break;
856  }
857  case SIMEDGE_FACE_ANGLE: {
858  if (BM_edge_face_count_at_most(edge, 2) == 2) {
859  float angle = BM_edge_calc_face_angle_with_imat3(edge, ob_m3_inv);
860  if (ED_select_similar_compare_float_tree(tree_1d, angle, thresh, SIM_CMP_EQ)) {
861  select = true;
862  }
863  }
864  break;
865  }
866  case SIMEDGE_SEAM:
867  if ((BM_elem_flag_test(edge, BM_ELEM_SEAM) != 0) ==
868  ((edge_data_value & SIMEDGE_DATA_TRUE) != 0)) {
869  select = true;
870  }
871  break;
872  case SIMEDGE_SHARP:
873  if ((BM_elem_flag_test(edge, BM_ELEM_SMOOTH) != 0) ==
874  ((edge_data_value & SIMEDGE_DATA_TRUE) != 0)) {
875  select = true;
876  }
877  break;
878  case SIMEDGE_FREESTYLE: {
879  FreestyleEdge *fedge;
880 
881  if (!has_custom_data_layer) {
882  BLI_assert(edge_data_value == SIMEDGE_DATA_FALSE);
883  select = true;
884  break;
885  }
886 
887  fedge = CustomData_bmesh_get(&bm->edata, edge->head.data, CD_FREESTYLE_EDGE);
888  if (((fedge != NULL) && (fedge->flag & FREESTYLE_EDGE_MARK)) ==
889  ((edge_data_value & SIMEDGE_DATA_TRUE) != 0)) {
890  select = true;
891  }
892  break;
893  }
894  case SIMEDGE_CREASE:
895  case SIMEDGE_BEVEL: {
896  if (!has_custom_data_layer) {
897  select = true;
898  break;
899  }
900 
901  const float *value = CustomData_bmesh_get(
902  &bm->edata, edge->head.data, custom_data_type);
903  if (ED_select_similar_compare_float_tree(tree_1d, *value, thresh, compare)) {
904  select = true;
905  }
906  break;
907  }
908  }
909 
910  if (select) {
911  BM_edge_select_set(bm, edge, true);
912  changed = true;
913  }
914  }
915  }
916 
917  if (changed) {
919  EDBM_update(ob->data,
920  &(const struct EDBMUpdate_Params){
921  .calc_looptri = false,
922  .calc_normals = false,
923  .is_destructive = false,
924  });
925  }
926  }
927 
928  if (false) {
929  edge_select_all:
931 
932  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
933  Object *ob = objects[ob_index];
935  BMesh *bm = em->bm;
936 
937  BMEdge *edge; /* Mesh edge. */
938  BMIter iter; /* Selected edges iterator. */
939 
940  BM_ITER_MESH (edge, &iter, bm, BM_EDGES_OF_MESH) {
941  if (!BM_elem_flag_test(edge, BM_ELEM_SELECT)) {
942  BM_edge_select_set(bm, edge, true);
943  }
944  }
946  EDBM_update(ob->data,
947  &(const struct EDBMUpdate_Params){
948  .calc_looptri = false,
949  .calc_normals = false,
950  .is_destructive = false,
951  });
952  }
953  }
954 
955  MEM_freeN(objects);
956  BLI_kdtree_1d_free(tree_1d);
957  BLI_kdtree_3d_free(tree_3d);
958  if (gset != NULL) {
959  BLI_gset_free(gset, NULL);
960  }
961 
962  return OPERATOR_FINISHED;
963 }
964 
967 /* -------------------------------------------------------------------- */
972 {
973  ViewLayer *view_layer = CTX_data_view_layer(C);
974 
975  /* get the type from RNA */
976  const int type = RNA_enum_get(op->ptr, "type");
977  const float thresh = RNA_float_get(op->ptr, "threshold");
978  const float thresh_radians = thresh * (float)M_PI + FLT_EPSILON;
979  const int compare = RNA_enum_get(op->ptr, "compare");
980 
981  int tot_verts_selected_all = 0;
982  uint objects_len = 0;
984  view_layer, CTX_wm_view3d(C), &objects_len);
985 
986  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
987  Object *ob = objects[ob_index];
989  tot_verts_selected_all += em->bm->totvertsel;
990  }
991 
992  if (tot_verts_selected_all == 0) {
993  BKE_report(op->reports, RPT_ERROR, "No vertex selected");
994  MEM_freeN(objects);
995  return OPERATOR_CANCELLED;
996  }
997 
998  KDTree_3d *tree_3d = NULL;
999  KDTree_1d *tree_1d = NULL;
1000  GSet *gset = NULL;
1001 
1002  switch (type) {
1003  case SIMVERT_NORMAL:
1004  tree_3d = BLI_kdtree_3d_new(tot_verts_selected_all);
1005  break;
1006  case SIMVERT_CREASE:
1007  tree_1d = BLI_kdtree_1d_new(tot_verts_selected_all);
1008  break;
1009  case SIMVERT_EDGE:
1010  case SIMVERT_FACE:
1011  gset = BLI_gset_ptr_new("Select similar vertex: edge/face");
1012  break;
1013  case SIMVERT_VGROUP:
1014  gset = BLI_gset_str_new("Select similar vertex: vertex groups");
1015  break;
1016  }
1017 
1018  int normal_tree_index = 0;
1019  int tree_1d_index = 0;
1020  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1021  Object *ob = objects[ob_index];
1023  BMesh *bm = em->bm;
1024  int cd_dvert_offset = -1;
1025  BLI_bitmap *defbase_selected = NULL;
1026  int defbase_len = 0;
1027 
1028  invert_m4_m4(ob->imat, ob->obmat);
1029 
1030  if (bm->totvertsel == 0) {
1031  continue;
1032  }
1033 
1034  if (type == SIMVERT_VGROUP) {
1035  cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT);
1036  if (cd_dvert_offset == -1) {
1037  continue;
1038  }
1039  defbase_len = BKE_object_defgroup_count(ob);
1040  if (defbase_len == 0) {
1041  continue;
1042  }
1043  defbase_selected = BLI_BITMAP_NEW(defbase_len, __func__);
1044  }
1045  else if (type == SIMVERT_CREASE) {
1047  BLI_kdtree_1d_insert(tree_1d, tree_1d_index++, (float[1]){0.0f});
1048  continue;
1049  }
1050  }
1051 
1052  BMVert *vert; /* Mesh vertex. */
1053  BMIter iter; /* Selected verts iterator. */
1054 
1055  BM_ITER_MESH (vert, &iter, bm, BM_VERTS_OF_MESH) {
1056  if (BM_elem_flag_test(vert, BM_ELEM_SELECT)) {
1057  switch (type) {
1058  case SIMVERT_FACE:
1060  break;
1061  case SIMVERT_EDGE:
1063  break;
1064  case SIMVERT_NORMAL: {
1065  float normal[3];
1066  copy_v3_v3(normal, vert->no);
1069 
1070  BLI_kdtree_3d_insert(tree_3d, normal_tree_index++, normal);
1071  break;
1072  }
1073  case SIMVERT_VGROUP: {
1074  MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(vert, cd_dvert_offset);
1075  MDeformWeight *dw = dvert->dw;
1076 
1077  for (int i = 0; i < dvert->totweight; i++, dw++) {
1078  if (dw->weight > 0.0f) {
1079  if (LIKELY(dw->def_nr < defbase_len)) {
1080  BLI_BITMAP_ENABLE(defbase_selected, dw->def_nr);
1081  }
1082  }
1083  }
1084  break;
1085  }
1086  case SIMVERT_CREASE: {
1087  const float *value = CustomData_bmesh_get(&bm->vdata, vert->head.data, CD_CREASE);
1088  BLI_kdtree_1d_insert(tree_1d, tree_1d_index++, value);
1089  break;
1090  }
1091  }
1092  }
1093  }
1094 
1095  if (type == SIMVERT_VGROUP) {
1096  /* We store the names of the vertex groups, so we can select
1097  * vertex groups with the same name in different objects. */
1098 
1099  const ListBase *defbase = BKE_object_defgroup_list(ob);
1100 
1101  int i = 0;
1102  LISTBASE_FOREACH (bDeformGroup *, dg, defbase) {
1103  if (BLI_BITMAP_TEST(defbase_selected, i)) {
1104  BLI_gset_add(gset, dg->name);
1105  }
1106  i += 1;
1107  }
1108  MEM_freeN(defbase_selected);
1109  }
1110  }
1111 
1112  if (type == SIMVERT_VGROUP) {
1113  if (BLI_gset_len(gset) == 0) {
1114  BKE_report(op->reports, RPT_INFO, "No vertex group among the selected vertices");
1115  }
1116  }
1117 
1118  /* Remove duplicated entries. */
1119  if (tree_1d != NULL) {
1120  BLI_kdtree_1d_deduplicate(tree_1d);
1121  BLI_kdtree_1d_balance(tree_1d);
1122  }
1123  if (tree_3d != NULL) {
1124  BLI_kdtree_3d_deduplicate(tree_3d);
1125  BLI_kdtree_3d_balance(tree_3d);
1126  }
1127 
1128  /* Run the matching operations. */
1129  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1130  Object *ob = objects[ob_index];
1132  BMesh *bm = em->bm;
1133  bool changed = false;
1134  bool has_crease_layer = false;
1135  int cd_dvert_offset = -1;
1136  BLI_bitmap *defbase_selected = NULL;
1137  int defbase_len = 0;
1138 
1139  if (type == SIMVERT_VGROUP) {
1140  cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT);
1141  if (cd_dvert_offset == -1) {
1142  continue;
1143  }
1144  const ListBase *defbase = BKE_object_defgroup_list(ob);
1145  defbase_len = BLI_listbase_count(defbase);
1146  if (defbase_len == 0) {
1147  continue;
1148  }
1149 
1150  /* We map back the names of the vertex groups to their corresponding indices
1151  * for this object. This is fast, and keep the logic for each vertex very simple. */
1152 
1153  defbase_selected = BLI_BITMAP_NEW(defbase_len, __func__);
1154  bool found_any = false;
1155  GSetIterator gs_iter;
1156  GSET_ITER (gs_iter, gset) {
1157  const char *name = BLI_gsetIterator_getKey(&gs_iter);
1158  int vgroup_id = BLI_findstringindex(defbase, name, offsetof(bDeformGroup, name));
1159  if (vgroup_id != -1) {
1160  BLI_BITMAP_ENABLE(defbase_selected, vgroup_id);
1161  found_any = true;
1162  }
1163  }
1164  if (found_any == false) {
1165  MEM_freeN(defbase_selected);
1166  continue;
1167  }
1168  }
1169  else if (type == SIMVERT_CREASE) {
1170  has_crease_layer = CustomData_has_layer(&bm->vdata, CD_CREASE);
1171  if (!has_crease_layer) {
1172  /* Proceed only if we have to select all the vertices that have custom data value of 0.0f.
1173  * In this case we will just select all the vertices.
1174  * Otherwise continue the for loop. */
1175  if (!ED_select_similar_compare_float_tree(tree_1d, 0.0f, thresh, compare)) {
1176  continue;
1177  }
1178  }
1179  }
1180 
1181  BMVert *vert; /* Mesh vertex. */
1182  BMIter iter; /* Selected verts iterator. */
1183 
1184  BM_ITER_MESH (vert, &iter, bm, BM_VERTS_OF_MESH) {
1186  bool select = false;
1187  switch (type) {
1188  case SIMVERT_EDGE: {
1189  const int num_edges = BM_vert_edge_count(vert);
1190  GSetIterator gs_iter;
1191  GSET_ITER (gs_iter, gset) {
1192  const int num_edges_iter = POINTER_AS_INT(BLI_gsetIterator_getKey(&gs_iter));
1193  const int delta_i = num_edges - num_edges_iter;
1194  if (mesh_select_similar_compare_int(delta_i, compare)) {
1195  select = true;
1196  break;
1197  }
1198  }
1199  break;
1200  }
1201  case SIMVERT_FACE: {
1202  const int num_faces = BM_vert_face_count(vert);
1203  GSetIterator gs_iter;
1204  GSET_ITER (gs_iter, gset) {
1205  const int num_faces_iter = POINTER_AS_INT(BLI_gsetIterator_getKey(&gs_iter));
1206  const int delta_i = num_faces - num_faces_iter;
1207  if (mesh_select_similar_compare_int(delta_i, compare)) {
1208  select = true;
1209  break;
1210  }
1211  }
1212  break;
1213  }
1214  case SIMVERT_NORMAL: {
1215  float normal[3];
1216  copy_v3_v3(normal, vert->no);
1219 
1220  /* We are treating the normals as coordinates, the "nearest" one will
1221  * also be the one closest to the angle. */
1222  KDTreeNearest_3d nearest;
1223  if (BLI_kdtree_3d_find_nearest(tree_3d, normal, &nearest) != -1) {
1224  if (angle_normalized_v3v3(normal, nearest.co) <= thresh_radians) {
1225  select = true;
1226  }
1227  }
1228  break;
1229  }
1230  case SIMVERT_VGROUP: {
1231  MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(vert, cd_dvert_offset);
1232  MDeformWeight *dw = dvert->dw;
1233 
1234  for (int i = 0; i < dvert->totweight; i++, dw++) {
1235  if (dw->weight > 0.0f) {
1236  if (LIKELY(dw->def_nr < defbase_len)) {
1237  if (BLI_BITMAP_TEST(defbase_selected, dw->def_nr)) {
1238  select = true;
1239  break;
1240  }
1241  }
1242  }
1243  }
1244  break;
1245  }
1246  case SIMVERT_CREASE: {
1247  if (!has_crease_layer) {
1248  select = true;
1249  break;
1250  }
1251  const float *value = CustomData_bmesh_get(&bm->vdata, vert->head.data, CD_CREASE);
1252  if (ED_select_similar_compare_float_tree(tree_1d, *value, thresh, compare)) {
1253  select = true;
1254  }
1255  break;
1256  }
1257  }
1258 
1259  if (select) {
1260  BM_vert_select_set(bm, vert, true);
1261  changed = true;
1262  }
1263  }
1264  }
1265 
1266  if (type == SIMVERT_VGROUP) {
1267  MEM_freeN(defbase_selected);
1268  }
1269 
1270  if (changed) {
1272  EDBM_update(ob->data,
1273  &(const struct EDBMUpdate_Params){
1274  .calc_looptri = false,
1275  .calc_normals = false,
1276  .is_destructive = false,
1277  });
1278  }
1279  }
1280 
1281  MEM_freeN(objects);
1282  BLI_kdtree_1d_free(tree_1d);
1283  BLI_kdtree_3d_free(tree_3d);
1284  if (gset != NULL) {
1285  BLI_gset_free(gset, NULL);
1286  }
1287 
1288  return OPERATOR_FINISHED;
1289 }
1290 
1293 /* -------------------------------------------------------------------- */
1298 {
1300  PropertyRNA *prop = RNA_struct_find_property(op->ptr, "threshold");
1301 
1302  const int type = RNA_enum_get(op->ptr, "type");
1303 
1304  if (!RNA_property_is_set(op->ptr, prop)) {
1305  RNA_property_float_set(op->ptr, prop, ts->select_thresh);
1306  }
1307  else {
1308  ts->select_thresh = RNA_property_float_get(op->ptr, prop);
1309  }
1310 
1311  if (type < 100) {
1312  return similar_vert_select_exec(C, op);
1313  }
1314  if (type < 200) {
1315  return similar_edge_select_exec(C, op);
1316  }
1317  return similar_face_select_exec(C, op);
1318 }
1319 
1321  PointerRNA *UNUSED(ptr),
1322  PropertyRNA *UNUSED(prop),
1323  bool *r_free)
1324 {
1325  Object *obedit;
1326 
1327  if (!C) { /* needed for docs and i18n tools */
1328  return prop_similar_types;
1329  }
1330 
1331  obedit = CTX_data_edit_object(C);
1332 
1333  if (obedit && obedit->type == OB_MESH) {
1334  EnumPropertyItem *item = NULL;
1335  int a, totitem = 0;
1336  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1337 
1338  if (em->selectmode & SCE_SELECT_VERTEX) {
1339  for (a = SIMVERT_NORMAL; a < SIMEDGE_LENGTH; a++) {
1340  RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
1341  }
1342  }
1343  else if (em->selectmode & SCE_SELECT_EDGE) {
1344  for (a = SIMEDGE_LENGTH; a < SIMFACE_MATERIAL; a++) {
1345  RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
1346  }
1347  }
1348  else if (em->selectmode & SCE_SELECT_FACE) {
1349 #ifdef WITH_FREESTYLE
1350  const int a_end = SIMFACE_FREESTYLE;
1351 #else
1352  const int a_end = SIMFACE_FACEMAP;
1353 #endif
1354  for (a = SIMFACE_MATERIAL; a <= a_end; a++) {
1355  RNA_enum_items_add_value(&item, &totitem, prop_similar_types, a);
1356  }
1357  }
1358  RNA_enum_item_end(&item, &totitem);
1359 
1360  *r_free = true;
1361 
1362  return item;
1363  }
1364 
1365  return prop_similar_types;
1366 }
1367 
1369  wmOperator *op,
1370  const PropertyRNA *prop)
1371 {
1372  const char *prop_id = RNA_property_identifier(prop);
1373  const int type = RNA_enum_get(op->ptr, "type");
1374 
1375  /* Only show compare when it is used. */
1376  if (STREQ(prop_id, "compare")) {
1377  if (type == SIMVERT_VGROUP) {
1378  return false;
1379  }
1380  }
1381  /* Only show threshold when it is used. */
1382  else if (STREQ(prop_id, "threshold")) {
1383  if (!ELEM(type,
1385  SIMEDGE_BEVEL,
1387  SIMEDGE_DIR,
1390  SIMFACE_AREA,
1393  SIMFACE_COPLANAR)) {
1394  return false;
1395  }
1396  }
1397 
1398  return true;
1399 }
1400 
1402 {
1403  PropertyRNA *prop;
1404 
1405  /* identifiers */
1406  ot->name = "Select Similar";
1407  ot->idname = "MESH_OT_select_similar";
1408  ot->description = "Select similar vertices, edges or faces by property types";
1409 
1410  /* api callbacks */
1415 
1416  /* flags */
1418 
1419  /* properties */
1420  prop = ot->prop = RNA_def_enum(ot->srna, "type", prop_similar_types, SIMVERT_NORMAL, "Type", "");
1422 
1423  RNA_def_enum(ot->srna, "compare", prop_similar_compare_types, SIM_CMP_EQ, "Compare", "");
1424 
1425  prop = RNA_def_float(ot->srna, "threshold", 0.0f, 0.0f, 1.0f, "Threshold", "", 0.0f, 1.0f);
1426  /* Very small values are needed sometimes, similar area of small faces for e.g: see T87823 */
1427  RNA_def_property_ui_range(prop, 0.0, 1.0, 0.01, 5);
1428 }
1429 
typedef float(TangentPoint)[2]
struct Object * CTX_data_edit_object(const bContext *C)
Definition: context.c:1370
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1100
struct View3D * CTX_wm_view3d(const bContext *C)
Definition: context.c:784
struct ToolSettings * CTX_data_tool_settings(const bContext *C)
Definition: context.c:1282
CustomData interface, see also DNA_customdata_types.h.
bool CustomData_has_layer(const struct CustomData *data, int type)
void * CustomData_bmesh_get(const struct CustomData *data, void *block, int type)
int CustomData_get_offset(const struct CustomData *data, int type)
support for deformation groups and hooks.
const struct ListBase * BKE_object_defgroup_list(const struct Object *ob)
int BKE_object_defgroup_count(const struct Object *ob)
BMEditMesh * BKE_editmesh_from_object(struct Object *ob)
Return the BMEditMesh for a given object.
Definition: editmesh.c:58
#define BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, v3d, r_len)
Definition: BKE_layer.h:542
General operations, lookup, etc. for materials.
struct Material *** BKE_object_material_array_p(struct Object *ob)
Definition: material.c:311
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition: report.c:83
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_BITMAP_NEW(_num, _alloc_string)
Definition: BLI_bitmap.h:40
#define BLI_BITMAP_TEST(_bitmap, _index)
Definition: BLI_bitmap.h:64
#define BLI_BITMAP_ENABLE(_bitmap, _index)
Definition: BLI_bitmap.h:81
unsigned int BLI_bitmap
Definition: BLI_bitmap.h:16
GSet * BLI_gset_str_new(const char *info)
struct GSet GSet
Definition: BLI_ghash.h:340
GSet * BLI_gset_ptr_new(const char *info)
unsigned int BLI_gset_len(const GSet *gs) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:957
#define GSET_ITER(gs_iter_, gset_)
Definition: BLI_ghash.h:471
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition: BLI_ghash.c:1037
BLI_INLINE void * BLI_gsetIterator_getKey(GSetIterator *gsi)
Definition: BLI_ghash.h:458
bool BLI_gset_add(GSet *gs, void *key)
Definition: BLI_ghash.c:969
A KD-tree for nearest neighbor search.
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
int BLI_findstringindex(const struct ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define M_PI
Definition: BLI_math_base.h:20
void plane_from_point_normal_v3(float r_plane[4], const float plane_co[3], const float plane_no[3])
Definition: math_geom.c:209
void copy_m3_m4(float m1[3][3], const float m2[4][4])
Definition: math_matrix.c:87
bool invert_m4_m4(float R[4][4], const float A[4][4])
Definition: math_matrix.c:1287
void mul_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:729
bool invert_m3_m3(float R[3][3], const float A[3][3])
Definition: math_matrix.c:1180
void mul_transposed_mat3_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:946
void mul_v3_m4v3(float r[3], const float M[4][4], const float v[3])
Definition: math_matrix.c:739
void mul_v3_mat3_m4v3(float r[3], const float M[4][4], const float v[3])
Definition: math_matrix.c:800
float angle_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
Definition: math_vector.c:385
MINLINE float normalize_v3(float r[3])
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
float angle_normalized_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT
Definition: math_vector.c:445
unsigned int uint
Definition: BLI_sys_types.h:67
#define POINTER_FROM_INT(i)
#define UNUSED(x)
#define POINTER_AS_INT(i)
#define ELEM(...)
#define STREQ(a, b)
#define LIKELY(x)
@ CD_FACEMAP
@ CD_MDEFORMVERT
@ CD_FREESTYLE_EDGE
@ CD_FREESTYLE_FACE
@ CD_BWEIGHT
@ FREESTYLE_EDGE_MARK
@ FREESTYLE_FACE_MARK
@ OB_MESH
#define SCE_SELECT_FACE
#define SCE_SELECT_VERTEX
#define SCE_SELECT_EDGE
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
void EDBM_update(struct Mesh *me, const struct EDBMUpdate_Params *params)
void EDBM_selectmode_flush(struct BMEditMesh *em)
bool ED_operator_editmesh(struct bContext *C)
Definition: screen_ops.c:433
@ SIM_CMP_LT
@ SIM_CMP_GT
@ SIM_CMP_EQ
bool ED_select_similar_compare_float_tree(const struct KDTree_1d *tree, float length, float thresh, eSimilarCmp compare)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble v1
Read Guarded memory(de)allocation.
#define C
Definition: RandGen.cpp:25
@ OPTYPE_UNDO
Definition: WM_types.h:148
@ OPTYPE_REGISTER
Definition: WM_types.h:146
__forceinline const avxb select(const avxb &m, const avxb &t, const avxb &f)
Definition: avxb.h:154
#define BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:622
@ BM_ELEM_HIDDEN
Definition: bmesh_class.h:472
@ BM_ELEM_SEAM
Definition: bmesh_class.h:473
@ BM_ELEM_SELECT
Definition: bmesh_class.h:471
@ BM_ELEM_SMOOTH
Definition: bmesh_class.h:477
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
Definition: bmesh_class.h:541
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:12
#define BM_ITER_MESH(ele, iter, bm, itype)
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_FACES_OF_MESH
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_face_select_set(BMesh *bm, BMFace *f, const bool select)
Select Face.
void BM_vert_select_set(BMesh *bm, BMVert *v, const bool select)
Select Vert.
void BM_edge_select_set(BMesh *bm, BMEdge *e, const bool select)
Select Edge.
@ SIMVERT_VGROUP
@ SIMVERT_FACE
@ SIMVERT_EDGE
@ SIMVERT_NORMAL
@ SIMVERT_CREASE
@ SIMEDGE_FACE_ANGLE
@ SIMEDGE_FACE
@ SIMEDGE_SHARP
@ SIMEDGE_DIR
@ SIMEDGE_BEVEL
@ SIMEDGE_FREESTYLE
@ SIMEDGE_CREASE
@ SIMEDGE_LENGTH
@ SIMEDGE_SEAM
@ SIMFACE_MATERIAL
@ SIMFACE_FREESTYLE
@ SIMFACE_AREA
@ SIMFACE_PERIMETER
@ SIMFACE_NORMAL
@ SIMFACE_SMOOTH
@ SIMFACE_COPLANAR
@ SIMFACE_FACEMAP
@ SIMFACE_SIDES
float BM_face_calc_area_with_mat3(const BMFace *f, const float mat3[3][3])
float BM_face_calc_perimeter_with_mat3(const BMFace *f, const float mat3[3][3])
int BM_edge_face_count_at_most(const BMEdge *e, const int count_max)
Definition: bmesh_query.c:645
int BM_vert_face_count(const BMVert *v)
Definition: bmesh_query.c:664
int BM_edge_face_count(const BMEdge *e)
Definition: bmesh_query.c:629
int BM_vert_edge_count(const BMVert *v)
Definition: bmesh_query.c:607
float BM_edge_calc_face_angle_with_imat3(const BMEdge *e, const float imat3[3][3])
Definition: bmesh_query.c:1364
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert * v
SIMD_FORCE_INLINE btScalar angle(const btVector3 &v) const
Return the angle between this and another vector.
Definition: btVector3.h:356
Material material
static int edbm_select_similar_exec(bContext *C, wmOperator *op)
static int mesh_select_similar_compare_int(const int delta, const int compare)
static int similar_edge_select_exec(bContext *C, wmOperator *op)
static int similar_vert_select_exec(bContext *C, wmOperator *op)
static const EnumPropertyItem prop_similar_types[]
@ SIMFACE_DATA_TRUE
@ SIMFACE_DATA_ALL
@ SIMFACE_DATA_NONE
@ SIMFACE_DATA_FALSE
static bool edge_data_value_set(BMEdge *edge, const int hflag, int *r_value)
static bool edbm_select_similar_poll_property(const bContext *UNUSED(C), wmOperator *op, const PropertyRNA *prop)
@ SIMEDGE_DATA_FALSE
@ SIMEDGE_DATA_NONE
@ SIMEDGE_DATA_ALL
@ SIMEDGE_DATA_TRUE
void MESH_OT_select_similar(wmOperatorType *ot)
static float edge_length_squared_worldspace_get(Object *ob, BMEdge *edge)
static int similar_face_select_exec(bContext *C, wmOperator *op)
static void face_to_plane(const Object *ob, BMFace *face, float r_plane[4])
static void edge_pos_direction_worldspace_get(Object *ob, BMEdge *edge, float *r_dir)
static const EnumPropertyItem prop_similar_compare_types[]
static const EnumPropertyItem * select_similar_type_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
static bool face_data_value_set(BMFace *face, const int hflag, int *r_value)
IconTextureDrawCall normal
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
ccl_device_inline float2 fabs(const float2 &a)
Definition: math_float2.h:222
#define fabsf(x)
Definition: metal/compat.h:219
static unsigned a[3]
Definition: RandGen.cpp:78
static void area(int d1, int d2, int e1, int e2, float weights[2])
T length(const vec_base< T, Size > &a)
float RNA_property_float_get(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:2767
const char * RNA_property_identifier(const PropertyRNA *prop)
Definition: rna_access.c:1000
bool RNA_property_is_set(PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:5271
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
Definition: rna_access.c:717
float RNA_float_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4957
void RNA_property_float_set(PointerRNA *ptr, PropertyRNA *prop, float value)
Definition: rna_access.c:2790
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:5004
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, float default_value, float hardmin, float hardmax, const char *ui_name, const char *ui_description, float softmin, float softmax)
Definition: rna_define.c:3836
void RNA_enum_item_end(EnumPropertyItem **items, int *totitem)
Definition: rna_define.c:4487
void RNA_def_enum_funcs(PropertyRNA *prop, EnumPropertyItemFunc itemfunc)
Definition: rna_define.c:3830
void RNA_enum_items_add_value(EnumPropertyItem **items, int *totitem, const EnumPropertyItem *item, int value)
Definition: rna_define.c:4472
void RNA_def_property_ui_range(PropertyRNA *prop, double min, double max, double step, int precision)
Definition: rna_define.c:1664
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, int default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3783
short selectmode
Definition: BKE_editmesh.h:52
struct BMesh * bm
Definition: BKE_editmesh.h:40
short mat_nr
Definition: bmesh_class.h:281
int len
Definition: bmesh_class.h:267
BMHeader head
Definition: bmesh_class.h:255
float no[3]
Definition: bmesh_class.h:271
void * data
Definition: bmesh_class.h:51
float co[3]
Definition: bmesh_class.h:87
float no[3]
Definition: bmesh_class.h:88
BMHeader head
Definition: bmesh_class.h:85
int totfacesel
Definition: bmesh_class.h:298
CustomData vdata
Definition: bmesh_class.h:337
CustomData edata
Definition: bmesh_class.h:337
int totvertsel
Definition: bmesh_class.h:298
int totedgesel
Definition: bmesh_class.h:298
CustomData pdata
Definition: bmesh_class.h:337
struct MDeformWeight * dw
unsigned int def_nr
float imat[4][4]
float obmat[4][4]
void * data
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:919
const char * name
Definition: WM_types.h:888
const char * idname
Definition: WM_types.h:890
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:943
bool(* poll_property)(const struct bContext *C, struct wmOperator *op, const PropertyRNA *prop) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:949
struct StructRNA * srna
Definition: WM_types.h:969
const char * description
Definition: WM_types.h:893
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:903
PropertyRNA * prop
Definition: WM_types.h:981
struct ReportList * reports
struct PointerRNA * ptr
PointerRNA * ptr
Definition: wm_files.c:3480
wmOperatorType * ot
Definition: wm_files.c:3479
int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))