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