Blender  V2.93
bmesh_beautify.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 
32 #include "BLI_heap.h"
33 #include "BLI_math.h"
35 
36 #include "MEM_guardedalloc.h"
37 
38 #include "bmesh.h"
39 #include "bmesh_beautify.h" /* own include */
40 
41 // #define DEBUG_TIME
42 
43 #ifdef DEBUG_TIME
44 # include "PIL_time.h"
45 # include "PIL_time_utildefines.h"
46 #endif
47 
48 /* -------------------------------------------------------------------- */
49 /* GSet for edge rotation */
50 
51 typedef struct EdRotState {
52  int v1, v2; /* edge vert, small -> large */
53  int f1, f2; /* face vert, small -> large */
55 
56 #if 0
57 /* use BLI_ghashutil_inthash_v4 direct */
58 static uint erot_gsetutil_hash(const void *ptr)
59 {
60  const EdRotState *e_state = (const EdRotState *)ptr;
61  return BLI_ghashutil_inthash_v4(&e_state->v1);
62 }
63 #endif
64 #if 0
65 static int erot_gsetutil_cmp(const void *a, const void *b)
66 {
67  const EdRotState *e_state_a = (const EdRotState *)a;
68  const EdRotState *e_state_b = (const EdRotState *)b;
69  if (e_state_a->v1 < e_state_b->v1) {
70  return -1;
71  }
72  else if (e_state_a->v1 > e_state_b->v1) {
73  return 1;
74  }
75  else if (e_state_a->v2 < e_state_b->v2) {
76  return -1;
77  }
78  else if (e_state_a->v2 > e_state_b->v2) {
79  return 1;
80  }
81  else if (e_state_a->f1 < e_state_b->f1) {
82  return -1;
83  }
84  else if (e_state_a->f1 > e_state_b->f1) {
85  return 1;
86  }
87  else if (e_state_a->f2 < e_state_b->f2) {
88  return -1;
89  }
90  else if (e_state_a->f2 > e_state_b->f2) {
91  return 1;
92  }
93  else {
94  return 0;
95  }
96 }
97 #endif
98 static GSet *erot_gset_new(void)
99 {
101 }
102 
103 /* ensure v0 is smaller */
104 #define EDGE_ORD(v0, v1) \
105  if (v0 > v1) { \
106  SWAP(int, v0, v1); \
107  } \
108  (void)0
109 
110 static void erot_state_ex(const BMEdge *e, int v_index[2], int f_index[2])
111 {
113  BLI_assert(BM_vert_in_edge(e, e->l->prev->v) == false);
114  BLI_assert(BM_vert_in_edge(e, e->l->radial_next->prev->v) == false);
115 
116  /* verts of the edge */
117  v_index[0] = BM_elem_index_get(e->v1);
118  v_index[1] = BM_elem_index_get(e->v2);
119  EDGE_ORD(v_index[0], v_index[1]);
120 
121  /* verts of each of the 2 faces attached to this edge
122  * (that are not a part of this edge) */
123  f_index[0] = BM_elem_index_get(e->l->prev->v);
124  f_index[1] = BM_elem_index_get(e->l->radial_next->prev->v);
125  EDGE_ORD(f_index[0], f_index[1]);
126 }
127 
128 static void erot_state_current(const BMEdge *e, EdRotState *e_state)
129 {
130  erot_state_ex(e, &e_state->v1, &e_state->f1);
131 }
132 
133 static void erot_state_alternate(const BMEdge *e, EdRotState *e_state)
134 {
135  erot_state_ex(e, &e_state->f1, &e_state->v1);
136 }
137 
138 /* -------------------------------------------------------------------- */
139 /* Calculate the improvement of rotating the edge */
140 
141 static float bm_edge_calc_rotate_beauty__area(const float v1[3],
142  const float v2[3],
143  const float v3[3],
144  const float v4[3],
145  const bool lock_degenerate)
146 {
147  /* not a loop (only to be able to break out) */
148  do {
149  float v1_xy[2], v2_xy[2], v3_xy[2], v4_xy[2];
150 
151  /* first get the 2d values */
152  {
153  const float eps = 1e-5;
154  float no_a[3], no_b[3];
155  float no[3];
156  float axis_mat[3][3];
157  float no_scale;
158  cross_tri_v3(no_a, v2, v3, v4);
159  cross_tri_v3(no_b, v2, v4, v1);
160 
161  // printf("%p %p %p %p - %p %p\n", v1, v2, v3, v4, e->l->f, e->l->radial_next->f);
162  BLI_assert((ELEM(v1, v2, v3, v4) == false) && (ELEM(v2, v1, v3, v4) == false) &&
163  (ELEM(v3, v1, v2, v4) == false) && (ELEM(v4, v1, v2, v3) == false));
164 
165  add_v3_v3v3(no, no_a, no_b);
166  if (UNLIKELY((no_scale = normalize_v3(no)) == 0.0f)) {
167  break;
168  }
169 
170  axis_dominant_v3_to_m3(axis_mat, no);
171  mul_v2_m3v3(v1_xy, axis_mat, v1);
172  mul_v2_m3v3(v2_xy, axis_mat, v2);
173  mul_v2_m3v3(v3_xy, axis_mat, v3);
174  mul_v2_m3v3(v4_xy, axis_mat, v4);
175 
191  if (!(signum_i_ex(cross_tri_v2(v2_xy, v3_xy, v4_xy) / no_scale, eps) +
192  signum_i_ex(cross_tri_v2(v2_xy, v4_xy, v1_xy) / no_scale, eps))) {
193  break;
194  }
195  }
196 
204  v1_xy, v2_xy, v3_xy, v4_xy, lock_degenerate, NULL);
205  } while (false);
206 
207  return FLT_MAX;
208 }
209 
210 static float bm_edge_calc_rotate_beauty__angle(const float v1[3],
211  const float v2[3],
212  const float v3[3],
213  const float v4[3])
214 {
215  /* not a loop (only to be able to break out) */
216  do {
217  float no_a[3], no_b[3];
218  float angle_24, angle_13;
219 
220  /* edge (2-4), current state */
221  normal_tri_v3(no_a, v2, v3, v4);
222  normal_tri_v3(no_b, v2, v4, v1);
223  angle_24 = angle_normalized_v3v3(no_a, no_b);
224 
225  /* edge (1-3), new state */
226  /* only check new state for degenerate outcome */
227  if ((normal_tri_v3(no_a, v1, v2, v3) == 0.0f) || (normal_tri_v3(no_b, v1, v3, v4) == 0.0f)) {
228  break;
229  }
230  angle_13 = angle_normalized_v3v3(no_a, no_b);
231 
232  return angle_13 - angle_24;
233  } while (false);
234 
235  return FLT_MAX;
236 }
237 
245  const BMVert *v2,
246  const BMVert *v3,
247  const BMVert *v4,
248  const short flag,
249  const short method)
250 {
251  /* not a loop (only to be able to break out) */
252  do {
253  if (flag & VERT_RESTRICT_TAG) {
254  const BMVert *v_a = v1, *v_b = v3;
256  break;
257  }
258  }
259 
260  if (UNLIKELY(v1 == v3)) {
261  // printf("This should never happen, but does sometimes!\n");
262  break;
263  }
264 
265  switch (method) {
266  case 0:
268  v1->co, v2->co, v3->co, v4->co, flag & EDGE_RESTRICT_DEGENERATE);
269  default:
270  return bm_edge_calc_rotate_beauty__angle(v1->co, v2->co, v3->co, v4->co);
271  }
272  } while (false);
273 
274  return FLT_MAX;
275 }
276 
277 static float bm_edge_calc_rotate_beauty(const BMEdge *e, const short flag, const short method)
278 {
279  const BMVert *v1, *v2, *v3, *v4;
280  v1 = e->l->prev->v; /* first vert co */
281  v2 = e->l->v; /* e->v1 or e->v2*/
282  v3 = e->l->radial_next->prev->v; /* second vert co */
283  v4 = e->l->next->v; /* e->v1 or e->v2*/
284 
285  return BM_verts_calc_rotate_beauty(v1, v2, v3, v4, flag, method);
286 }
287 
288 /* -------------------------------------------------------------------- */
289 /* Update the edge cost of rotation in the heap */
290 
291 BLI_INLINE bool edge_in_array(const BMEdge *e, const BMEdge **edge_array, const int edge_array_len)
292 {
293  const int index = BM_elem_index_get(e);
294  return ((index >= 0) && (index < edge_array_len) && (e == edge_array[index]));
295 }
296 
297 /* recalc an edge in the heap (surrounding geometry has changed) */
299  Heap *eheap,
300  HeapNode **eheap_table,
301  GSet **edge_state_arr,
302  /* only for testing the edge is in the array */
303  const BMEdge **edge_array,
304  const int edge_array_len,
305 
306  const short flag,
307  const short method)
308 {
309  if (edge_in_array(e, edge_array, edge_array_len)) {
310  const int i = BM_elem_index_get(e);
311  GSet *e_state_set = edge_state_arr[i];
312 
313  if (eheap_table[i]) {
314  BLI_heap_remove(eheap, eheap_table[i]);
315  eheap_table[i] = NULL;
316  }
317 
318  /* check if we can add it back */
319  BLI_assert(BM_edge_is_manifold(e) == true);
320 
321  /* check we're not moving back into a state we have been in before */
322  if (e_state_set != NULL) {
323  EdRotState e_state_alt;
324  erot_state_alternate(e, &e_state_alt);
325  if (BLI_gset_haskey(e_state_set, (void *)&e_state_alt)) {
326  // printf(" skipping, we already have this state\n");
327  return;
328  }
329  }
330 
331  {
332  /* recalculate edge */
333  const float cost = bm_edge_calc_rotate_beauty(e, flag, method);
334  if (cost < 0.0f) {
335  eheap_table[i] = BLI_heap_insert(eheap, cost, e);
336  }
337  else {
338  eheap_table[i] = NULL;
339  }
340  }
341  }
342 }
343 
344 /* we have rotated an edge, tag other edges and clear this one */
346  Heap *eheap,
347  HeapNode **eheap_table,
348  GSet **edge_state_arr,
349  const BMEdge **edge_array,
350  const int edge_array_len,
351  /* only for testing the edge is in the array */
352  const short flag,
353  const short method)
354 {
355  int i;
356 
357  BMEdge *e_arr[4] = {
358  e->l->next->e,
359  e->l->prev->e,
360  e->l->radial_next->next->e,
361  e->l->radial_next->prev->e,
362  };
363 
364  BLI_assert(e->l->f->len == 3 && e->l->radial_next->f->len == 3);
365 
367 
368  for (i = 0; i < 4; i++) {
370  e_arr[i], eheap, eheap_table, edge_state_arr, edge_array, edge_array_len, flag, method);
371  }
372 }
373 
374 /* -------------------------------------------------------------------- */
375 /* Beautify Fill */
376 
381  BMEdge **edge_array,
382  const int edge_array_len,
383  const short flag,
384  const short method,
385  const short oflag_edge,
386  const short oflag_face)
387 {
388  Heap *eheap; /* edge heap */
389  HeapNode **eheap_table; /* edge index aligned table pointing to the eheap */
390 
391  GSet **edge_state_arr = MEM_callocN((size_t)edge_array_len * sizeof(GSet *), __func__);
392  BLI_mempool *edge_state_pool = BLI_mempool_create(sizeof(EdRotState), 0, 512, BLI_MEMPOOL_NOP);
393  int i;
394 
395 #ifdef DEBUG_TIME
396  TIMEIT_START(beautify_fill);
397 #endif
398 
399  eheap = BLI_heap_new_ex((uint)edge_array_len);
400  eheap_table = MEM_mallocN(sizeof(HeapNode *) * (size_t)edge_array_len, __func__);
401 
402  /* build heap */
403  for (i = 0; i < edge_array_len; i++) {
404  BMEdge *e = edge_array[i];
405  const float cost = bm_edge_calc_rotate_beauty(e, flag, method);
406  if (cost < 0.0f) {
407  eheap_table[i] = BLI_heap_insert(eheap, cost, e);
408  }
409  else {
410  eheap_table[i] = NULL;
411  }
412 
413  BM_elem_index_set(e, i); /* set_dirty */
414  }
416 
417  while (BLI_heap_is_empty(eheap) == false) {
418  BMEdge *e = BLI_heap_pop_min(eheap);
419  i = BM_elem_index_get(e);
420  eheap_table[i] = NULL;
421 
423 
425 
427 
428  if (LIKELY(e)) {
429  GSet *e_state_set = edge_state_arr[i];
430 
431  /* add the new state into the set so we don't move into this state again
432  * note: we could add the previous state too but this isn't essential)
433  * for avoiding eternal loops */
434  EdRotState *e_state = BLI_mempool_alloc(edge_state_pool);
435  erot_state_current(e, e_state);
436  if (UNLIKELY(e_state_set == NULL)) {
437  edge_state_arr[i] = e_state_set = erot_gset_new(); /* store previous state */
438  }
439  BLI_assert(BLI_gset_haskey(e_state_set, (void *)e_state) == false);
440  BLI_gset_insert(e_state_set, e_state);
441 
442  // printf(" %d -> %d, %d\n", i, BM_elem_index_get(e->v1), BM_elem_index_get(e->v2));
443 
444  /* maintain the index array */
445  edge_array[i] = e;
446  BM_elem_index_set(e, i);
447 
448  /* recalculate faces connected on the heap */
450  eheap,
451  eheap_table,
452  edge_state_arr,
453  (const BMEdge **)edge_array,
454  edge_array_len,
455  flag,
456  method);
457 
458  /* update flags */
459  if (oflag_edge) {
460  BMO_edge_flag_enable(bm, e, oflag_edge);
461  }
462 
463  if (oflag_face) {
464  BMO_face_flag_enable(bm, e->l->f, oflag_face);
465  BMO_face_flag_enable(bm, e->l->radial_next->f, oflag_face);
466  }
467  }
468  }
469 
470  BLI_heap_free(eheap, NULL);
471  MEM_freeN(eheap_table);
472 
473  for (i = 0; i < edge_array_len; i++) {
474  if (edge_state_arr[i]) {
475  BLI_gset_free(edge_state_arr[i], NULL);
476  }
477  }
478 
479  MEM_freeN(edge_state_arr);
480  BLI_mempool_destroy(edge_state_pool);
481 
482 #ifdef DEBUG_TIME
483  TIMEIT_END(beautify_fill);
484 #endif
485 }
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define BLI_INLINE
struct GSet GSet
Definition: BLI_ghash.h:189
#define BLI_ghashutil_inthash_v4_cmp
Definition: BLI_ghash.h:378
GSet * BLI_gset_new(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:1125
#define BLI_ghashutil_inthash_v4(key)
Definition: BLI_ghash.h:367
void BLI_gset_insert(GSet *gs, void *key)
Definition: BLI_ghash.c:1147
#define BLI_ghashutil_inthash_v4_p
Definition: BLI_ghash.h:369
bool BLI_gset_haskey(GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:1216
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition: BLI_ghash.c:1253
A min-heap / priority queue ADT.
void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp) ATTR_NONNULL(1)
Definition: BLI_heap.c:221
Heap * BLI_heap_new_ex(unsigned int tot_reserve) ATTR_WARN_UNUSED_RESULT
Definition: BLI_heap.c:201
void void bool BLI_heap_is_empty(const Heap *heap) ATTR_NONNULL(1)
Definition: BLI_heap.c:305
void * BLI_heap_pop_min(Heap *heap) ATTR_NONNULL(1)
Definition: BLI_heap.c:338
HeapNode * BLI_heap_insert(Heap *heap, float value, void *ptr) ATTR_NONNULL(1)
Definition: BLI_heap.c:268
void void BLI_heap_remove(Heap *heap, HeapNode *node) ATTR_NONNULL(1
MINLINE int signum_i_ex(float a, float eps)
MINLINE float cross_tri_v2(const float v1[2], const float v2[2], const float v3[2])
void cross_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
Definition: math_geom.c:36
void axis_dominant_v3_to_m3(float r_mat[3][3], const float normal[3])
Normal to x,y matrix.
Definition: math_geom.c:3752
float normal_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3])
Definition: math_geom.c:51
void mul_v2_m3v3(float r[2], const float M[3][3], const float a[3])
Definition: math_matrix.c:921
MINLINE float normalize_v3(float r[3])
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
float angle_normalized_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT
Definition: math_vector.c:505
@ BLI_MEMPOOL_NOP
Definition: BLI_mempool.h:77
BLI_mempool * BLI_mempool_create(unsigned int esize, unsigned int totelem, unsigned int pchunk, unsigned int flag) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition: BLI_mempool.c:268
void * BLI_mempool_alloc(BLI_mempool *pool) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition: BLI_mempool.c:334
void BLI_mempool_destroy(BLI_mempool *pool) ATTR_NONNULL(1)
Definition: BLI_mempool.c:757
float BLI_polyfill_beautify_quad_rotate_calc_ex(const float v1[2], const float v2[2], const float v3[2], const float v4[2], const bool lock_degenerate, float *r_area)
unsigned int uint
Definition: BLI_sys_types.h:83
#define UNLIKELY(x)
#define ELEM(...)
#define LIKELY(x)
_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.
Platform independent time functions.
Utility defines for timing/benchmarks.
#define TIMEIT_START(var)
#define TIMEIT_END(var)
static void erot_state_alternate(const BMEdge *e, EdRotState *e_state)
static GSet * erot_gset_new(void)
BLI_INLINE bool edge_in_array(const BMEdge *e, const BMEdge **edge_array, const int edge_array_len)
void BM_mesh_beautify_fill(BMesh *bm, BMEdge **edge_array, const int edge_array_len, const short flag, const short method, const short oflag_edge, const short oflag_face)
float BM_verts_calc_rotate_beauty(const BMVert *v1, const BMVert *v2, const BMVert *v3, const BMVert *v4, const short flag, const short method)
static void erot_state_current(const BMEdge *e, EdRotState *e_state)
#define EDGE_ORD(v0, v1)
static void bm_edge_update_beauty_cost_single(BMEdge *e, Heap *eheap, HeapNode **eheap_table, GSet **edge_state_arr, const BMEdge **edge_array, const int edge_array_len, const short flag, const short method)
static float bm_edge_calc_rotate_beauty__angle(const float v1[3], const float v2[3], const float v3[3], const float v4[3])
static void erot_state_ex(const BMEdge *e, int v_index[2], int f_index[2])
struct EdRotState EdRotState
static void bm_edge_update_beauty_cost(BMEdge *e, Heap *eheap, HeapNode **eheap_table, GSet **edge_state_arr, const BMEdge **edge_array, const int edge_array_len, const short flag, const short method)
static float bm_edge_calc_rotate_beauty__area(const float v1[3], const float v2[3], const float v3[3], const float v4[3], const bool lock_degenerate)
static float bm_edge_calc_rotate_beauty(const BMEdge *e, const short flag, const short method)
@ EDGE_RESTRICT_DEGENERATE
@ VERT_RESTRICT_TAG
@ BM_EDGE
Definition: bmesh_class.h:384
@ BM_ELEM_TAG
Definition: bmesh_class.h:484
#define BM_elem_index_get(ele)
Definition: bmesh_inline.h:124
#define BM_elem_index_set(ele, index)
Definition: bmesh_inline.h:125
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:26
ATTR_WARN_UNUSED_RESULT BMesh * bm
BMEdge * BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_flag)
Rotate Edge.
Definition: bmesh_mods.c:983
@ BM_EDGEROT_CHECK_EXISTS
Definition: bmesh_mods.h:86
#define BMO_edge_flag_enable(bm, e, oflag)
#define BMO_face_flag_enable(bm, e, oflag)
BLI_INLINE bool BM_edge_is_manifold(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
#define BM_edge_face_count_is_equal(e, n)
Definition: bmesh_query.h:96
BLI_INLINE bool BM_vert_in_edge(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
static unsigned a[3]
Definition: RandGen.cpp:92
const btScalar eps
Definition: poly34.cpp:11
float co[3]
Definition: bmesh_class.h:99
struct BMEdge * e
Definition: bmesh_class.h:109
char elem_index_dirty
Definition: bmesh_class.h:305
Definition: BLI_heap.c:57
PointerRNA * ptr
Definition: wm_files.c:3157