Blender  V2.93
bmesh_structure.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) 2007 Blender Foundation.
17  * All rights reserved.
18  */
19 
26 #include "BLI_utildefines.h"
27 
28 #include "bmesh.h"
29 #include "intern/bmesh_private.h"
30 
35 void bmesh_disk_vert_swap(BMEdge *e, BMVert *v_dst, BMVert *v_src)
36 {
37  if (e->v1 == v_src) {
38  e->v1 = v_dst;
39  e->v1_disk_link.next = e->v1_disk_link.prev = NULL;
40  }
41  else if (e->v2 == v_src) {
42  e->v2 = v_dst;
43  e->v2_disk_link.next = e->v2_disk_link.prev = NULL;
44  }
45  else {
46  BLI_assert(0);
47  }
48 }
49 
55 void bmesh_edge_vert_swap(BMEdge *e, BMVert *v_dst, BMVert *v_src)
56 {
57  /* swap out loops */
58  if (e->l) {
59  BMLoop *l_iter, *l_first;
60  l_iter = l_first = e->l;
61  do {
62  if (l_iter->v == v_src) {
63  l_iter->v = v_dst;
64  }
65  else if (l_iter->next->v == v_src) {
66  l_iter->next->v = v_dst;
67  }
68  else {
69  BLI_assert(l_iter->prev->v != v_src);
70  }
71  } while ((l_iter = l_iter->radial_next) != l_first);
72  }
73 
74  /* swap out edges */
75  bmesh_disk_vert_replace(e, v_dst, v_src);
76 }
77 
79 {
80  BLI_assert(e->v1 == v_src || e->v2 == v_src);
81  bmesh_disk_edge_remove(e, v_src); /* remove e from tv's disk cycle */
82  bmesh_disk_vert_swap(e, v_dst, v_src); /* swap out tv for v_new in e */
83  bmesh_disk_edge_append(e, v_dst); /* add e to v_dst's disk cycle */
84  BLI_assert(e->v1 != e->v2);
85 }
86 
157 {
158  if (!v->e) {
159  BMDiskLink *dl1 = bmesh_disk_edge_link_from_vert(e, v);
160 
161  v->e = e;
162  dl1->next = dl1->prev = e;
163  }
164  else {
165  BMDiskLink *dl1, *dl2, *dl3;
166 
167  dl1 = bmesh_disk_edge_link_from_vert(e, v);
168  dl2 = bmesh_disk_edge_link_from_vert(v->e, v);
169  dl3 = dl2->prev ? bmesh_disk_edge_link_from_vert(dl2->prev, v) : NULL;
170 
171  dl1->next = v->e;
172  dl1->prev = dl2->prev;
173 
174  dl2->prev = e;
175  if (dl3) {
176  dl3->next = e;
177  }
178  }
179 }
180 
182 {
183  BMDiskLink *dl1, *dl2;
184 
185  dl1 = bmesh_disk_edge_link_from_vert(e, v);
186  if (dl1->prev) {
187  dl2 = bmesh_disk_edge_link_from_vert(dl1->prev, v);
188  dl2->next = dl1->next;
189  }
190 
191  if (dl1->next) {
192  dl2 = bmesh_disk_edge_link_from_vert(dl1->next, v);
193  dl2->prev = dl1->prev;
194  }
195 
196  if (v->e == e) {
197  v->e = (e != dl1->next) ? dl1->next : NULL;
198  }
199 
200  dl1->next = dl1->prev = NULL;
201 }
202 
204 {
205  BMEdge *e_iter, *e_first;
206 
207  if (v1->e) {
208  e_first = e_iter = v1->e;
209 
210  do {
211  if (BM_verts_in_edge(v1, v2, e_iter)) {
212  return e_iter;
213  }
214  } while ((e_iter = bmesh_disk_edge_next(e_iter, v1)) != e_first);
215  }
216 
217  return NULL;
218 }
219 
221 {
222  int count = 0;
223  if (v->e) {
224  BMEdge *e_first, *e_iter;
225  e_iter = e_first = v->e;
226  do {
227  count++;
228  } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
229  }
230  return count;
231 }
232 
233 int bmesh_disk_count_at_most(const BMVert *v, const int count_max)
234 {
235  int count = 0;
236  if (v->e) {
237  BMEdge *e_first, *e_iter;
238  e_iter = e_first = v->e;
239  do {
240  count++;
241  if (count == count_max) {
242  break;
243  }
244  } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
245  }
246  return count;
247 }
248 
250 {
251  BMEdge *e_iter;
252 
253  if (!BM_vert_in_edge(e, v)) {
254  return false;
255  }
256  if (len == 0 || bmesh_disk_count_at_most(v, len + 1) != len) {
257  return false;
258  }
259 
260  e_iter = e;
261  do {
262  if (len != 1 && bmesh_disk_edge_prev(e_iter, v) == e_iter) {
263  return false;
264  }
265  } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e);
266 
267  return true;
268 }
269 
279 {
280  /* is there an edge on this vert at all */
281  int count = 0;
282  if (v->e) {
283  BMEdge *e_first, *e_iter;
284 
285  /* first, loop around edge */
286  e_first = e_iter = v->e;
287  do {
288  if (e_iter->l) {
289  count += bmesh_radial_facevert_count(e_iter->l, v);
290  }
291  } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
292  }
293  return count;
294 }
295 
296 int bmesh_disk_facevert_count_at_most(const BMVert *v, const int count_max)
297 {
298  /* is there an edge on this vert at all */
299  int count = 0;
300  if (v->e) {
301  BMEdge *e_first, *e_iter;
302 
303  /* first, loop around edge */
304  e_first = e_iter = v->e;
305  do {
306  if (e_iter->l) {
307  count += bmesh_radial_facevert_count_at_most(e_iter->l, v, count_max - count);
308  if (count == count_max) {
309  break;
310  }
311  }
312  } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
313  }
314  return count;
315 }
316 
326 {
327  const BMEdge *e_iter = e;
328  do {
329  if (e_iter->l != NULL) {
330  return (BMEdge *)((e_iter->l->v == v) ? e_iter : e_iter->l->next->e);
331  }
332  } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e);
333  return NULL;
334 }
335 
342 {
343  const BMEdge *e_iter = e;
344  do {
345  if (e_iter->l != NULL) {
346  return (e_iter->l->v == v) ? e_iter->l : e_iter->l->next;
347  }
348  } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e);
349  return NULL;
350 }
351 
356 {
357  const BMEdge *e_iter = e;
358  do {
359  if (!BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN)) {
360  if (e_iter->l != NULL) {
361  BMLoop *l_iter, *l_first;
362  l_iter = l_first = e_iter->l;
363  do {
364  if (!BM_elem_flag_test(l_iter->f, BM_ELEM_HIDDEN)) {
365  return (l_iter->v == v) ? l_iter : l_iter->next;
366  }
367  } while ((l_iter = l_iter->radial_next) != l_first);
368  }
369  }
370  } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e);
371  return NULL;
372 }
373 
375 {
376  BMEdge *e_find;
377  e_find = bmesh_disk_edge_next(e, v);
378  do {
379  if (e_find->l && bmesh_radial_facevert_check(e_find->l, v)) {
380  return e_find;
381  }
382  } while ((e_find = bmesh_disk_edge_next(e_find, v)) != e);
383  return (BMEdge *)e;
384 }
385 
386 /*****radial cycle functions, e.g. loops surrounding edges**** */
387 bool bmesh_radial_validate(int radlen, BMLoop *l)
388 {
389  BMLoop *l_iter = l;
390  int i = 0;
391 
392  if (bmesh_radial_length(l) != radlen) {
393  return false;
394  }
395 
396  do {
397  if (UNLIKELY(!l_iter)) {
398  BMESH_ASSERT(0);
399  return false;
400  }
401 
402  if (l_iter->e != l->e) {
403  return false;
404  }
405  if (!ELEM(l_iter->v, l->e->v1, l->e->v2)) {
406  return false;
407  }
408 
409  if (UNLIKELY(i > BM_LOOP_RADIAL_MAX)) {
410  BMESH_ASSERT(0);
411  return false;
412  }
413 
414  i++;
415  } while ((l_iter = l_iter->radial_next) != l);
416 
417  return true;
418 }
419 
421 {
422  if (e->l == NULL) {
423  e->l = l;
424  l->radial_next = l->radial_prev = l;
425  }
426  else {
427  l->radial_prev = e->l;
428  l->radial_next = e->l->radial_next;
429 
430  e->l->radial_next->radial_prev = l;
431  e->l->radial_next = l;
432 
433  e->l = l;
434  }
435 
436  if (UNLIKELY(l->e && l->e != e)) {
437  /* l is already in a radial cycle for a different edge */
438  BMESH_ASSERT(0);
439  }
440 
441  l->e = e;
442 }
443 
453 {
454  /* if e is non-NULL, l must be in the radial cycle of e */
455  if (UNLIKELY(e != l->e)) {
456  BMESH_ASSERT(0);
457  }
458 
459  if (l->radial_next != l) {
460  if (l == e->l) {
461  e->l = l->radial_next;
462  }
463 
466  }
467  else {
468  if (l == e->l) {
469  e->l = NULL;
470  }
471  else {
472  BMESH_ASSERT(0);
473  }
474  }
475 
476  /* l is no longer in a radial cycle; empty the links
477  * to the cycle and the link back to an edge */
479  l->e = NULL;
480 }
481 
487 {
488  if (l->radial_next != l) {
491  }
492 
493  /* l is no longer in a radial cycle; empty the links
494  * to the cycle and the link back to an edge */
496  l->e = NULL;
497 }
498 
506 {
507  const BMLoop *l_iter;
508  l_iter = l;
509  do {
510  if (l_iter->v == v) {
511  return (BMLoop *)l_iter;
512  }
513  } while ((l_iter = l_iter->radial_next) != l);
514  return NULL;
515 }
516 
518 {
519  BMLoop *l_iter;
520  l_iter = l->radial_next;
521  do {
522  if (l_iter->v == v) {
523  return l_iter;
524  }
525  } while ((l_iter = l_iter->radial_next) != l);
526  return (BMLoop *)l;
527 }
528 
530 {
531  const BMLoop *l_iter = l;
532  int i = 0;
533 
534  if (!l) {
535  return 0;
536  }
537 
538  do {
539  if (UNLIKELY(!l_iter)) {
540  /* Radial cycle is broken (not a circular loop). */
541  BMESH_ASSERT(0);
542  return 0;
543  }
544 
545  i++;
546  if (UNLIKELY(i >= BM_LOOP_RADIAL_MAX)) {
547  BMESH_ASSERT(0);
548  return -1;
549  }
550  } while ((l_iter = l_iter->radial_next) != l);
551 
552  return i;
553 }
554 
562 {
563  const BMLoop *l_iter;
564  int count = 0;
565  l_iter = l;
566  do {
567  if (l_iter->v == v) {
568  count++;
569  }
570  } while ((l_iter = l_iter->radial_next) != l);
571 
572  return count;
573 }
574 
575 int bmesh_radial_facevert_count_at_most(const BMLoop *l, const BMVert *v, const int count_max)
576 {
577  const BMLoop *l_iter;
578  int count = 0;
579  l_iter = l;
580  do {
581  if (l_iter->v == v) {
582  count++;
583  if (count == count_max) {
584  break;
585  }
586  }
587  } while ((l_iter = l_iter->radial_next) != l);
588 
589  return count;
590 }
591 
598 {
599  const BMLoop *l_iter;
600  l_iter = l;
601  do {
602  if (l_iter->v == v) {
603  return true;
604  }
605  } while ((l_iter = l_iter->radial_next) != l);
606 
607  return false;
608 }
609 
610 /*****loop cycle functions, e.g. loops surrounding a face**** */
612 {
613  int i;
614  int len = f->len;
615  BMLoop *l_iter, *l_first;
616 
617  l_first = BM_FACE_FIRST_LOOP(f);
618 
619  if (l_first == NULL) {
620  return false;
621  }
622 
623  /* Validate that the face loop cycle is the length specified by f->len */
624  for (i = 1, l_iter = l_first->next; i < len; i++, l_iter = l_iter->next) {
625  if ((l_iter->f != f) || (l_iter == l_first)) {
626  return false;
627  }
628  }
629  if (l_iter != l_first) {
630  return false;
631  }
632 
633  /* Validate the loop->prev links also form a cycle of length f->len */
634  for (i = 1, l_iter = l_first->prev; i < len; i++, l_iter = l_iter->prev) {
635  if (l_iter == l_first) {
636  return false;
637  }
638  }
639  if (l_iter != l_first) {
640  return false;
641  }
642 
643  return true;
644 }
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define UNLIKELY(x)
#define ELEM(...)
_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
#define BM_LOOP_RADIAL_MAX
Definition: bmesh_class.h:580
@ BM_ELEM_HIDDEN
Definition: bmesh_class.h:472
#define BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:553
#define BMESH_ASSERT(a)
Definition: bmesh_error.h:76
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:26
BLI_INLINE bool BM_verts_in_edge(const BMVert *v1, const BMVert *v2, const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
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 BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
void bmesh_disk_edge_remove(BMEdge *e, BMVert *v)
bool bmesh_loop_validate(BMFace *f)
void bmesh_disk_edge_append(BMEdge *e, BMVert *v)
BMLoop * bmesh_disk_faceloop_find_first_visible(const BMEdge *e, const BMVert *v)
int bmesh_radial_facevert_count_at_most(const BMLoop *l, const BMVert *v, const int count_max)
void bmesh_edge_vert_swap(BMEdge *e, BMVert *v_dst, BMVert *v_src)
BMLoop * bmesh_disk_faceloop_find_first(const BMEdge *e, const BMVert *v)
void bmesh_disk_vert_replace(BMEdge *e, BMVert *v_dst, BMVert *v_src)
BMEdge * bmesh_disk_faceedge_find_next(const BMEdge *e, const BMVert *v)
void bmesh_radial_loop_unlink(BMLoop *l)
BMLoop * bmesh_radial_faceloop_find_next(const BMLoop *l, const BMVert *v)
int bmesh_radial_length(const BMLoop *l)
int bmesh_disk_count_at_most(const BMVert *v, const int count_max)
bool bmesh_radial_facevert_check(const BMLoop *l, const BMVert *v)
RADIAL CHECK FACE VERT.
BMLoop * bmesh_radial_faceloop_find_first(const BMLoop *l, const BMVert *v)
BME RADIAL FIND FIRST FACE VERT.
void bmesh_radial_loop_append(BMEdge *e, BMLoop *l)
void bmesh_disk_vert_swap(BMEdge *e, BMVert *v_dst, BMVert *v_src)
BMEdge * bmesh_disk_faceedge_find_first(const BMEdge *e, const BMVert *v)
FIND FIRST FACE EDGE.
void bmesh_radial_loop_remove(BMEdge *e, BMLoop *l)
BMESH RADIAL REMOVE LOOP.
int bmesh_radial_facevert_count(const BMLoop *l, const BMVert *v)
RADIAL COUNT FACE VERT.
BMEdge * bmesh_disk_edge_exists(const BMVert *v1, const BMVert *v2)
bool bmesh_disk_validate(int len, BMEdge *e, BMVert *v)
bool bmesh_radial_validate(int radlen, BMLoop *l)
int bmesh_disk_facevert_count(const BMVert *v)
DISK COUNT FACE VERT.
int bmesh_disk_facevert_count_at_most(const BMVert *v, const int count_max)
int bmesh_disk_count(const BMVert *v)
BLI_INLINE BMEdge * bmesh_disk_edge_next(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE BMEdge * bmesh_disk_edge_prev(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
int count
static ulong * next
BMVert * v1
Definition: bmesh_class.h:134
BMVert * v2
Definition: bmesh_class.h:134
struct BMLoop * l
Definition: bmesh_class.h:140
int len
Definition: bmesh_class.h:279
struct BMVert * v
Definition: bmesh_class.h:165
struct BMEdge * e
Definition: bmesh_class.h:176
struct BMLoop * radial_prev
Definition: bmesh_class.h:216
struct BMLoop * radial_next
Definition: bmesh_class.h:216
struct BMLoop * prev
Definition: bmesh_class.h:245
struct BMFace * f
Definition: bmesh_class.h:183
struct BMLoop * next
Definition: bmesh_class.h:245
struct BMEdge * e
Definition: bmesh_class.h:109
uint len