BMesh optimize face splitting by taking loops rather then verts

- add BM_vert_pair_share_face
- add BM_loop_is_adjacent
- remove BM_verts_connect
This commit is contained in:
Campbell Barton 2013-12-24 11:04:03 +11:00
parent d94db03ac8
commit 04a902965e
Notes: blender-bot 2023-02-14 11:26:25 +01:00
Referenced by issue #37938, GLSL alpha rendering bug in Texture Paint
Referenced by issue #37925, Dissolve Vertice causes segfault/assert/abort?
20 changed files with 232 additions and 180 deletions

View File

@ -1258,7 +1258,7 @@ static BMFace *bm_face_create__sfme(BMesh *bm, BMFace *UNUSED(example))
*
* \return A BMFace pointer
*/
BMFace *bmesh_sfme(BMesh *bm, BMFace *f, BMVert *v1, BMVert *v2,
BMFace *bmesh_sfme(BMesh *bm, BMFace *f, BMLoop *l_v1, BMLoop *l_v2,
BMLoop **r_l,
#ifdef USE_BMESH_HOLES
ListBase *holes,
@ -1275,21 +1275,12 @@ BMFace *bmesh_sfme(BMesh *bm, BMFace *f, BMVert *v1, BMVert *v2,
BMFace *f2;
BMLoop *l_iter, *l_first;
BMLoop *l_v1 = NULL, *l_v2 = NULL, *l_f1 = NULL, *l_f2 = NULL;
BMLoop *l_f1 = NULL, *l_f2 = NULL;
BMEdge *e;
int i, len, f1len, f2len;
BMVert *v1 = l_v1->v, *v2 = l_v2->v;
int f1len, f2len;
/* verify that v1 and v2 are in face */
len = f->len;
for (i = 0, l_iter = BM_FACE_FIRST_LOOP(f); i < len; i++, l_iter = l_iter->next) {
if (l_iter->v == v1) l_v1 = l_iter;
else if (l_iter->v == v2) l_v2 = l_iter;
}
if (!l_v1 || !l_v2) {
BLI_assert(0);
return NULL;
}
BLI_assert(f == l_v1->f && f == l_v2->f);
/* allocate new edge between v1 and v2 */
e = BM_edge_create(bm, v1, v2, example, no_double ? BM_CREATE_NO_DOUBLE : BM_CREATE_NOP);

View File

@ -72,14 +72,15 @@ void BM_vert_separate(BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len
BMEdge **e_in, int e_in_len);
/* EULER API - For modifying structure */
BMFace *bmesh_sfme(BMesh *bm, BMFace *f, BMVert *v1,
BMVert *v2, BMLoop **r_l,
BMFace *bmesh_sfme(BMesh *bm, BMFace *f,
BMLoop *l1, BMLoop *l2,
BMLoop **r_l,
#ifdef USE_BMESH_HOLES
ListBase *holes,
ListBase *holes,
#endif
BMEdge *example,
const bool no_double
);
BMEdge *example,
const bool no_double
);
BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e);
BMEdge *bmesh_jekv(BMesh *bm, BMEdge *e_kill, BMVert *v_kill, const bool check_edge_splice);

View File

@ -251,48 +251,6 @@ BMFace *BM_faces_join_pair(BMesh *bm, BMFace *f_a, BMFace *f_b, BMEdge *e, const
return BM_faces_join(bm, faces, 2, do_del);
}
/**
* \brief Connect Verts, Split Face
*
* connects two verts together, automatically (if very naively) finding the
* face they both share (if there is one) and splitting it. Use this at your
* own risk, as it doesn't handle the many complex cases it should (like zero-area faces,
* multiple faces, etc).
*
* this is really only meant for cases where you don't know before hand the face
* the two verts belong to for splitting (e.g. the subdivision operator).
*
* \return The newly created edge.
*/
BMEdge *BM_verts_connect(BMesh *bm, BMVert *v1, BMVert *v2, BMFace **r_f)
{
BMIter fiter;
BMIter viter;
BMVert *v_iter;
BMFace *f_iter;
/* be warned: this can do weird things in some ngon situation, see BM_face_legal_splits */
BM_ITER_ELEM (f_iter, &fiter, v1, BM_FACES_OF_VERT) {
BM_ITER_ELEM (v_iter, &viter, f_iter, BM_FACES_OF_VERT) {
if (v_iter == v2) {
BMLoop *l_new;
f_iter = BM_face_split(bm, f_iter, v1, v2, &l_new, NULL, false);
if (r_f) {
*r_f = f_iter;
}
return l_new->e;
}
}
}
if (r_f) {
*r_f = NULL;
}
return NULL;
}
/**
* \brief Face Split
*
@ -310,13 +268,26 @@ BMEdge *BM_verts_connect(BMesh *bm, BMVert *v1, BMVert *v2, BMFace **r_f)
* if the split is successful (and the original original face will be the
* other side). NULL if the split fails.
*/
BMFace *BM_face_split(BMesh *bm, BMFace *f, BMVert *v1, BMVert *v2, BMLoop **r_l,
BMEdge *example, const bool no_double)
BMFace *BM_face_split(BMesh *bm, BMFace *f,
BMLoop *l_a, BMLoop *l_b,
BMLoop **r_l, BMEdge *example,
const bool no_double)
{
const bool has_mdisp = CustomData_has_layer(&bm->ldata, CD_MDISPS);
BMFace *f_new, *f_tmp;
BLI_assert(v1 != v2);
BLI_assert(l_a != l_b);
BLI_assert(f == l_a->f && f == l_b->f);
BLI_assert(!BM_loop_is_adjacent(l_a, l_b));
/* could be an assert */
if (UNLIKELY(BM_loop_is_adjacent(l_a, l_b))) {
return NULL;
}
if (f != l_a->f || f != l_b->f) {
return NULL;
}
/* do we have a multires layer? */
if (has_mdisp) {
@ -324,9 +295,9 @@ BMFace *BM_face_split(BMesh *bm, BMFace *f, BMVert *v1, BMVert *v2, BMLoop **r_l
}
#ifdef USE_BMESH_HOLES
f_new = bmesh_sfme(bm, f, v1, v2, r_l, NULL, example, no_double);
f_new = bmesh_sfme(bm, f, l_a, l_b, r_l, NULL, example, no_double);
#else
f_new = bmesh_sfme(bm, f, v1, v2, r_l, example, no_double);
f_new = bmesh_sfme(bm, f, l_a, l_b, r_l, example, no_double);
#endif
if (f_new) {
@ -369,7 +340,7 @@ BMFace *BM_face_split(BMesh *bm, BMFace *f, BMVert *v1, BMVert *v2, BMLoop **r_l
*
* \param bm The bmesh
* \param f the original face
* \param v1, v2 vertices which define the split edge, must be different
* \param l_a, l_b vertices which define the split edge, must be different
* \param cos Array of coordinates for intermediate points
* \param n Length of \a cos (must be > 0)
* \param r_l pointer which will receive the BMLoop for the first split edge (from \a v1) in the new face
@ -379,16 +350,31 @@ BMFace *BM_face_split(BMesh *bm, BMFace *f, BMVert *v1, BMVert *v2, BMLoop **r_l
* if the split is successful (and the original original face will be the
* other side). NULL if the split fails.
*/
BMFace *BM_face_split_n(BMesh *bm, BMFace *f, BMVert *v1, BMVert *v2, float cos[][3], int n,
BMFace *BM_face_split_n(BMesh *bm, BMFace *f,
BMLoop *l_a, BMLoop *l_b,
float cos[][3], int n,
BMLoop **r_l, BMEdge *example)
{
BMFace *f_new, *f_tmp;
BMLoop *l_dummy;
BMEdge *e, *e_new;
BMVert *v_new;
// BMVert *v_a = l_a->v; /* UNUSED */
BMVert *v_b = l_b->v;
int i, j;
BLI_assert(v1 != v2);
BLI_assert(l_a != l_b);
BLI_assert(f == l_a->f && f == l_b->f);
BLI_assert(!BM_loop_is_adjacent(l_a, l_b));
/* could be an assert */
if (UNLIKELY(BM_loop_is_adjacent(l_a, l_b))) {
return NULL;
}
if (l_a->f != l_b->f) {
return NULL;
}
f_tmp = BM_face_copy(bm, bm, f, true, true);
@ -396,12 +382,12 @@ BMFace *BM_face_split_n(BMesh *bm, BMFace *f, BMVert *v1, BMVert *v2, float cos[
r_l = &l_dummy;
#ifdef USE_BMESH_HOLES
f_new = bmesh_sfme(bm, f, v1, v2, r_l, NULL, example, false);
f_new = bmesh_sfme(bm, f, l_a, l_b, r_l, NULL, example, false);
#else
f_new = bmesh_sfme(bm, f, v1, v2, r_l, example, false);
f_new = bmesh_sfme(bm, f, l_a, l_b, r_l, example, false);
#endif
/* bmesh_sfme returns in r_l a Loop for f_new going from v1 to v2.
* The radial_next is for f and goes from v2 to v1 */
/* bmesh_sfme returns in r_l a Loop for f_new going from v_a to v_b.
* The radial_next is for f and goes from v_b to v_a */
if (f_new) {
BM_elem_attrs_copy(bm, bm, f, f_new);
@ -409,7 +395,7 @@ BMFace *BM_face_split_n(BMesh *bm, BMFace *f, BMVert *v1, BMVert *v2, float cos[
e = (*r_l)->e;
for (i = 0; i < n; i++) {
v_new = bmesh_semv(bm, v2, e, &e_new);
v_new = bmesh_semv(bm, v_b, e, &e_new);
BLI_assert(v_new != NULL);
/* bmesh_semv returns in e_new the edge going from v_new to tv */
copy_v3_v3(v_new->co, cos[i]);
@ -510,8 +496,14 @@ BMEdge *BM_vert_collapse_faces(BMesh *bm, BMEdge *e_kill, BMVert *v_kill, float
BMFace *f2 = BM_faces_join(bm, faces, BLI_array_count(faces), true);
if (f2) {
BMLoop *l_new = NULL;
if (BM_face_split(bm, f2, tv, tv2, &l_new, NULL, false)) {
e_new = l_new->e;
BMLoop *l_a, *l_b;
if ((l_a = BM_face_vert_share_loop(f2, tv)) &&
(l_b = BM_face_vert_share_loop(f2, tv2)))
{
if (BM_face_split(bm, f2, l_a, l_b, &l_new, NULL, false)) {
e_new = l_new->e;
}
}
}
}
@ -1058,10 +1050,10 @@ BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_f
/* note, this assumes joining the faces _didnt_ also remove the verts.
* the #BM_edge_rotate_check will ensure this, but its possibly corrupt state or future edits
* break this */
if (!BM_face_split(bm, f, v1, v2, NULL, NULL, true)) {
return NULL;
}
else {
if ((l1 = BM_face_vert_share_loop(f, v1)) &&
(l2 = BM_face_vert_share_loop(f, v2)) &&
BM_face_split(bm, f, l1, l2, NULL, NULL, true))
{
/* we should really be able to know the faces some other way,
* rather then fetching them back from the edge, but this is predictable
* where using the return values from face split isn't. - campbell */
@ -1071,6 +1063,9 @@ BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_f
fb->head.hflag = f_hflag_prev_2;
}
}
else {
return NULL;
}
return e_new;
}

View File

@ -35,15 +35,13 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v);
BMFace *BM_faces_join_pair(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e, const bool do_del);
BMEdge *BM_verts_connect(BMesh *bm, BMVert *v1, BMVert *v2, BMFace **r_f);
BMFace *BM_face_split(BMesh *bm, BMFace *f,
BMVert *v1, BMVert *v2,
BMLoop *l_a, BMLoop *l_b,
BMLoop **r_l,
BMEdge *example, const bool no_double);
BMFace *BM_face_split_n(BMesh *bm, BMFace *f,
BMVert *v1, BMVert *v2,
BMLoop *l_a, BMLoop *l_b,
float cos[][3], int n,
BMLoop **r_l, BMEdge *example);

View File

@ -800,67 +800,67 @@ void BM_face_triangulate(BMesh *bm, BMFace *f,
BLI_assert((r_faces_new == NULL) == (r_faces_new_tot == NULL));
if (f->len == 4) {
BMVert *v1, *v2;
BMLoop *l_v1, *l_v2;
l_first = BM_FACE_FIRST_LOOP(f);
switch (quad_method) {
case MOD_TRIANGULATE_QUAD_FIXED:
{
v1 = l_first->v;
v2 = l_first->next->next->v;
l_v1 = l_first;
l_v2 = l_first->next->next;
break;
}
case MOD_TRIANGULATE_QUAD_ALTERNATE:
{
v1 = l_first->next->v;
v2 = l_first->prev->v;
l_v1 = l_first->next;
l_v2 = l_first->prev;
break;
}
case MOD_TRIANGULATE_QUAD_SHORTEDGE:
{
BMVert *v3, *v4;
BMLoop *l_v3, *l_v4;
float d1, d2;
v1 = l_first->v;
v2 = l_first->next->next->v;
v3 = l_first->next->v;
v4 = l_first->prev->v;
l_v1 = l_first;
l_v2 = l_first->next->next;
l_v3 = l_first->next;
l_v4 = l_first->prev;
d1 = len_squared_v3v3(v1->co, v2->co);
d2 = len_squared_v3v3(v3->co, v4->co);
d1 = len_squared_v3v3(l_v1->v->co, l_v2->v->co);
d2 = len_squared_v3v3(l_v3->v->co, l_v4->v->co);
if (d2 < d1) {
v1 = v3;
v2 = v4;
l_v1 = l_v3;
l_v2 = l_v4;
}
break;
}
case MOD_TRIANGULATE_QUAD_BEAUTY:
default:
{
BMVert *v3, *v4;
BMLoop *l_v3, *l_v4;
float cost;
v1 = l_first->next->v;
v2 = l_first->next->next->v;
v3 = l_first->prev->v;
v4 = l_first->v;
l_v1 = l_first->next;
l_v2 = l_first->next->next;
l_v3 = l_first->prev;
l_v4 = l_first;
cost = BM_verts_calc_rotate_beauty(v1, v2, v3, v4, 0, 0);
cost = BM_verts_calc_rotate_beauty(l_v1->v, l_v2->v, l_v3->v, l_v4->v, 0, 0);
if (cost < 0.0f) {
v1 = v4;
//v2 = v2;
l_v1 = l_v4;
//l_v2 = l_v2;
}
else {
//v1 = v1;
v2 = v3;
//l_v1 = l_v1;
l_v2 = l_v3;
}
break;
}
}
f_new = BM_face_split(bm, f, v1, v2, &l_new, NULL, false);
f_new = BM_face_split(bm, f, l_v1, l_v2, &l_new, NULL, false);
copy_v3_v3(f_new->no, f->no);
if (use_tag) {

View File

@ -181,6 +181,37 @@ BMLoop *BM_loop_other_vert_loop(BMLoop *l, BMVert *v)
#endif
}
/**
* Given 2 verts, find the smallest face they share and give back both loops.
*/
BMFace *BM_vert_pair_share_face(BMVert *v_a, BMVert *v_b,
BMLoop **r_l_a, BMLoop **r_l_b)
{
BMLoop *l_cur_a = NULL, *l_cur_b = NULL;
BMFace *f_cur = NULL;
if (v_a->e && v_b->e) {
BMIter iter;
BMLoop *l_a, *l_b;
BM_ITER_ELEM (l_a, &iter, v_a, BM_LOOPS_OF_VERT) {
if ((f_cur == NULL) || (l_a->f->len < f_cur->len)) {
l_b = BM_face_vert_share_loop(l_a->f, v_b);
if (l_b) {
f_cur = l_a->f;
l_cur_a = l_a;
l_cur_b = l_b;
}
}
}
}
if (r_l_a) *r_l_a = l_cur_a;
if (r_l_b) *r_l_b = l_cur_b;
return f_cur;
}
/**
* Get the first loop of a vert. Uses the same initialization code for the first loop of the
* iterator API

View File

@ -49,6 +49,8 @@ BMLoop *BM_face_other_vert_loop(BMFace *f, BMVert *v_prev, BMVert *v);
BMLoop *BM_loop_other_vert_loop(BMLoop *l, BMVert *v);
BMLoop *BM_vert_step_fan_loop(BMLoop *l, BMEdge **e_step);
BMLoop *BM_vert_find_first_loop(BMVert *v);
BMFace *BM_vert_pair_share_face(BMVert *v_a, BMVert *v_b,
BMLoop **r_l_a, BMLoop **r_l_b);
int BM_vert_edge_count_nonwire(BMVert *v);
int BM_vert_edge_count(BMVert *v);
@ -67,6 +69,7 @@ BLI_INLINE bool BM_edge_is_contiguous(const BMEdge *e);
bool BM_edge_is_convex(const BMEdge *e);
bool BM_loop_is_convex(const BMLoop *l);
BLI_INLINE bool BM_loop_is_adjacent(const BMLoop *l_a, const BMLoop *l_b);
float BM_loop_calc_face_angle(BMLoop *l);
void BM_loop_calc_face_normal(BMLoop *l, float r_normal[3]);

View File

@ -127,5 +127,14 @@ BLI_INLINE int BM_edge_is_boundary(BMEdge *e)
}
#endif
/**
* Tests whether one loop is next to another within the same face.
*/
BLI_INLINE bool BM_loop_is_adjacent(const BMLoop *l_a, const BMLoop *l_b)
{
BLI_assert(l_a->f == l_b->f);
BLI_assert(l_a != l_b);
return (ELEM(l_b, l_a->next, l_a->prev));
}
#endif /* __BMESH_QUERIES_INLINE_H__ */

View File

@ -63,7 +63,7 @@ static int bm_face_connect_verts(BMesh *bm, BMFace *f)
continue;
}
if (l_last != l->prev && l_last != l->next) {
if (!BM_loop_is_adjacent(l_last, l)) {
BMLoop **l_pair = STACK_PUSH_RET(loops_split);
l_pair[0] = l_last;
l_pair[1] = l;
@ -96,7 +96,17 @@ static int bm_face_connect_verts(BMesh *bm, BMFace *f)
}
for (i = 0; i < STACK_SIZE(verts_pair); i++) {
f_new = BM_face_split(bm, f, verts_pair[i][0], verts_pair[i][1], &l_new, NULL, false);
BMLoop *l_a, *l_b;
if ((l_a = BM_face_vert_share_loop(f, verts_pair[i][0])) &&
(l_b = BM_face_vert_share_loop(f, verts_pair[i][1])))
{
f_new = BM_face_split(bm, f, l_a, l_b, &l_new, NULL, false);
}
else {
f_new = NULL;
}
f = f_new;
if (!l_new || !f_new) {

View File

@ -86,7 +86,7 @@ static float bm_face_subset_calc_planar(BMLoop *l_first, BMLoop *l_last, const f
return delta_z;
}
static bool bm_face_split_find(BMFace *f, BMVert *v_pair[2], float *r_angle)
static bool bm_face_split_find(BMFace *f, BMLoop *l_pair[2], float *r_angle)
{
BMLoop *l_iter, *l_first;
BMLoop **l_arr = BLI_array_alloca(l_arr, f->len);
@ -111,9 +111,7 @@ static bool bm_face_split_find(BMFace *f, BMVert *v_pair[2], float *r_angle)
BMLoop *l_b = l_arr[i_b];
/* check these are not touching
* (we could be smarter here) */
if ((l_a->next != l_b) &&
(l_a->prev != l_b))
{
if (!BM_loop_is_adjacent(l_a, l_b)) {
/* first calculate normals */
float no_a[3], no_b[3];
@ -130,8 +128,8 @@ static bool bm_face_split_find(BMFace *f, BMVert *v_pair[2], float *r_angle)
BM_face_legal_splits(f, &l_split, 1);
if (l_split[0]) {
err_best = err_test;
v_pair[0] = l_a->v;
v_pair[1] = l_b->v;
l_pair[0] = l_a;
l_pair[1] = l_b;
angle_best = angle_normalized_v3v3(no_a, no_b);
found = true;
@ -151,13 +149,14 @@ static bool bm_face_split_find(BMFace *f, BMVert *v_pair[2], float *r_angle)
static bool bm_face_split_by_angle(BMesh *bm, BMFace *f, BMFace *r_f_pair[2], const float angle_limit)
{
BMVert *v_pair[2];
BMLoop *l_pair[2];
float angle;
if (bm_face_split_find(f, v_pair, &angle) && (angle > angle_limit)) {
if (bm_face_split_find(f, l_pair, &angle) && (angle > angle_limit)) {
BMFace *f_new;
BMLoop *l_new;
f_new = BM_face_split(bm, f, v_pair[0], v_pair[1], &l_new, NULL, false);
f_new = BM_face_split(bm, f, l_pair[0], l_pair[1], &l_new, NULL, false);
if (f_new) {
r_f_pair[0] = f;
r_f_pair[1] = f_new;

View File

@ -99,7 +99,7 @@ static void bm_face_split(BMesh *bm, const short oflag)
if (BMO_elem_flag_test(bm, l->next->v, oflag) == 0 &&
BMO_elem_flag_test(bm, l->prev->v, oflag) == 0)
{
BM_face_split(bm, l->f, l->next->v, l->prev->v, NULL, NULL, true);
BM_face_split(bm, l->f, l->next, l->prev, NULL, NULL, true);
}
}
}

View File

@ -40,30 +40,32 @@
static void remdoubles_splitface(BMFace *f, BMesh *bm, BMOperator *op, BMOpSlot *slot_targetmap)
{
BMIter liter;
BMLoop *l;
BMVert *v2, *v_double;
BMLoop *l, *l_tar, *l_double;
bool split = false;
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
v2 = BMO_slot_map_elem_get(slot_targetmap, l->v);
/* ok: if v2 is NULL (e.g. not in the map) then it's
BMVert *v_tar = BMO_slot_map_elem_get(slot_targetmap, l->v);
/* ok: if v_tar is NULL (e.g. not in the map) then it's
* a target vert, otherwise it's a double */
if ((v2 && BM_vert_in_face(f, v2)) &&
(v2 != l->prev->v) &&
(v2 != l->next->v))
{
v_double = l->v;
split = true;
break;
if (v_tar) {
BMLoop *l_tar = BM_face_vert_share_loop(f, v_tar);
if (l_tar && (l_tar != l) && !BM_loop_is_adjacent(l_tar, l)) {
l_double = l;
split = true;
break;
}
}
}
if (split && v_double != v2) {
if (split) {
BMLoop *l_new;
BMFace *f2 = BM_face_split(bm, f, v_double, v2, &l_new, NULL, false);
BMFace *f_new;
remdoubles_splitface(f, bm, op, slot_targetmap);
remdoubles_splitface(f2, bm, op, slot_targetmap);
f_new = BM_face_split(bm, f, l_double, l_tar, &l_new, NULL, false);
remdoubles_splitface(f, bm, op, slot_targetmap);
remdoubles_splitface(f_new, bm, op, slot_targetmap);
}
}

View File

@ -133,28 +133,23 @@ typedef struct SubDPattern {
/* connects face with smallest len, which I think should always be correct for
* edge subdivision */
static BMEdge *connect_smallest_face(BMesh *bm, BMVert *v1, BMVert *v2, BMFace **r_f_new)
static BMEdge *connect_smallest_face(BMesh *bm, BMVert *v_a, BMVert *v_b, BMFace **r_f_new)
{
BMIter iter, iter2;
BMVert *v;
BMLoop *l_new;
BMFace *f, *f_cur = NULL;
BMLoop *l_a, *l_b;
BMFace *f;
/* this isn't the best thing in the world. it doesn't handle cases where there's
* multiple faces yet. that might require a convexity test to figure out which
* face is "best" and who knows what for non-manifold conditions. */
for (f = BM_iter_new(&iter, bm, BM_FACES_OF_VERT, v1); f; f = BM_iter_step(&iter)) {
for (v = BM_iter_new(&iter2, bm, BM_VERTS_OF_FACE, f); v; v = BM_iter_step(&iter2)) {
if (v == v2) {
if (!f_cur || f->len < f_cur->len) f_cur = f;
}
}
}
f = BM_vert_pair_share_face(v_a, v_b, &l_a, &l_b);
if (f_cur) {
f = BM_face_split(bm, f_cur, v1, v2, &l_new, NULL, false);
if (f) {
BMFace *f_new;
f_new = BM_face_split(bm, f, l_a, l_b, &l_new, NULL, false);
if (r_f_new) *r_f_new = f;
if (r_f_new) *r_f_new = f_new;
return l_new ? l_new->e : NULL;
}
@ -1118,7 +1113,7 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op)
if (loops_split[j][0]) {
BMFace *f_new;
BLI_assert(BM_edge_exists(loops_split[j][0]->v, loops_split[j][1]->v) == NULL);
f_new = BM_face_split(bm, face, loops_split[j][0]->v, loops_split[j][1]->v, &l_new, NULL, false);
f_new = BM_face_split(bm, face, loops_split[j][0], loops_split[j][1], &l_new, NULL, false);
if (f_new) {
BMO_elem_flag_enable(bm, l_new->e, ELE_INNER);
}

View File

@ -828,7 +828,7 @@ static void bm_face_slice(BMesh *bm, BMLoop *l, const int cuts)
for (i = 0; i < cuts; i++) {
/* no chance of double */
BM_face_split(bm, l_new->f, l_new->prev->v, l_new->next->next->v, &l_new, NULL, false);
BM_face_split(bm, l_new->f, l_new->prev, l_new->next->next, &l_new, NULL, false);
if (l_new->f->len < l_new->radial_next->f->len) {
l_new = l_new->radial_next;
}

View File

@ -2095,7 +2095,7 @@ static void bevel_build_trifan(BMesh *bm, BevVert *bv)
BMLoop *l_new;
BMFace *f_new;
BLI_assert(v_fan == l_fan->v);
f_new = BM_face_split(bm, f, l_fan->v, l_fan->next->next->v, &l_new, NULL, FALSE);
f_new = BM_face_split(bm, f, l_fan, l_fan->next->next, &l_new, NULL, FALSE);
if (f_new->len > f->len) {
f = f_new;
@ -2140,7 +2140,7 @@ static void bevel_build_quadstrip(BMesh *bm, BevVert *bv)
l_b = l_b->next;
}
else {
BM_face_split(bm, f, l_a->v, l_b->v, &l_new, NULL, FALSE);
BM_face_split(bm, f, l_a, l_b, &l_new, NULL, FALSE);
f = l_new->f;
/* walk around the new face to get the next verts to split */

View File

@ -139,9 +139,14 @@ static void bm_face_bisect_verts(BMesh *bm, BMFace *f, const float plane[4], con
BMLoop *l_new;
if (LIKELY(STACK_SIZE(vert_split_arr) == 2)) {
BMLoop *l_a, *l_b;
l_a = BM_face_vert_share_loop(f, vert_split_arr[0]);
l_b = BM_face_vert_share_loop(f, vert_split_arr[1]);
/* common case, just cut the face once */
l_new = NULL;
BM_face_split(bm, f, vert_split_arr[0], vert_split_arr[1], &l_new, NULL, true);
BM_face_split(bm, f, l_a, l_b, &l_new, NULL, true);
if (l_new) {
if (oflag_center) {
BMO_elem_flag_enable(bm, l_new->e, oflag_center);
@ -254,9 +259,9 @@ static void bm_face_bisect_verts(BMesh *bm, BMFace *f, const float plane[4], con
/* in fact this simple test is good enough,
* test if the loops are adjacent */
if (found && (l_a->next != l_b && l_a->prev != l_b)) {
if (found && !BM_loop_is_adjacent(l_a, l_b)) {
BMFace *f_tmp;
f_tmp = BM_face_split(bm, face_split_arr[j], l_a->v, l_b->v, NULL, NULL, true);
f_tmp = BM_face_split(bm, face_split_arr[j], l_a, l_b, NULL, NULL, true);
if (f_tmp) {
if (f_tmp != face_split_arr[j]) {
STACK_PUSH(face_split_arr, f_tmp);

View File

@ -358,7 +358,7 @@ static bool bm_decim_triangulate_begin(BMesh *bm)
* - if there is a quad that has a free standing edge joining it along
* where we want to split the face, there isnt a good way we can handle this.
* currently that edge will get removed when joining the tris back into a quad. */
f_new = BM_face_split(bm, f, l_a->v, l_b->v, &l_new, NULL, false);
f_new = BM_face_split(bm, f, l_a, l_b, &l_new, NULL, false);
if (f_new) {
/* the value of this doesn't matter, only that the 2 loops match and have unique values */

View File

@ -144,7 +144,7 @@ static bool bm_vert_dissolve_fan(BMesh *bm, BMVert *v)
if (l->f->len > 3) {
BMLoop *l_new;
BLI_assert(l->prev->v != l->next->v);
BM_face_split(bm, l->f, l->prev->v, l->next->v, &l_new, NULL, true);
BM_face_split(bm, l->f, l->prev, l->next, &l_new, NULL, true);
BM_elem_flag_merge_into(l_new->e, l->e, l->prev->e);
}
}

View File

@ -2237,6 +2237,7 @@ static void knife_make_chain_cut(KnifeTool_OpData *kcd, BMFace *f, ListBase *cha
BMesh *bm = kcd->em->bm;
KnifeEdge *kfe, *kfelast;
BMVert *v1, *v2;
BMLoop *l_v1, *l_v2;
BMFace *f_new;
Ref *ref;
KnifeVert *kfv, *kfvprev;
@ -2262,27 +2263,35 @@ static void knife_make_chain_cut(KnifeTool_OpData *kcd, BMFace *f, ListBase *cha
}
BLI_assert(i == nco);
l_new = NULL;
if (nco == 0) {
/* Want to prevent creating two-sided polygons */
if (v1 == v2 || BM_edge_exists(v1, v2)) {
f_new = NULL;
if ((l_v1 = BM_face_vert_share_loop(f, v1)) &&
(l_v2 = BM_face_vert_share_loop(f, v2)))
{
if (nco == 0) {
/* Want to prevent creating two-sided polygons */
if (v1 == v2 || BM_edge_exists(v1, v2)) {
f_new = NULL;
}
else {
f_new = BM_face_split(bm, f, l_v1, l_v2, &l_new, NULL, true);
}
}
else {
f_new = BM_face_split(bm, f, v1, v2, &l_new, NULL, true);
f_new = BM_face_split_n(bm, f, l_v1, l_v2, cos, nco, &l_new, NULL);
if (f_new) {
/* Now go through lnew chain matching up chain kv's and assign real v's to them */
for (l_iter = l_new->next, i = 0; i < nco; l_iter = l_iter->next, i++) {
BLI_assert(equals_v3v3(cos[i], l_iter->v->co));
if (kcd->select_result) {
BM_edge_select_set(bm, l_iter->e, true);
}
kverts[i]->v = l_iter->v;
}
}
}
}
else {
f_new = BM_face_split_n(bm, f, v1, v2, cos, nco, &l_new, NULL);
if (f_new) {
/* Now go through lnew chain matching up chain kv's and assign real v's to them */
for (l_iter = l_new->next, i = 0; i < nco; l_iter = l_iter->next, i++) {
BLI_assert(equals_v3v3(cos[i], l_iter->v->co));
if (kcd->select_result) {
BM_edge_select_set(bm, l_iter->e, true);
}
kverts[i]->v = l_iter->v;
}
}
f_new = NULL;
}
/* the select chain above doesnt account for the first loop */

View File

@ -401,6 +401,7 @@ static PyObject *bpy_bm_utils_face_split(PyObject *UNUSED(self), PyObject *args,
BMesh *bm;
BMFace *f_new = NULL;
BMLoop *l_new = NULL;
BMLoop *l_a, *l_b;
if (!PyArg_ParseTupleAndKeywords(args, kw, "O!O!O!|OiO!:face_split", (char **)kwlist,
&BPy_BMFace_Type, &py_face,
@ -422,9 +423,12 @@ static PyObject *bpy_bm_utils_face_split(PyObject *UNUSED(self), PyObject *args,
}
/* this doubles for checking that the verts are in the same mesh */
if (BM_vert_in_face(py_face->f, py_vert_a->v) == false ||
BM_vert_in_face(py_face->f, py_vert_b->v) == false)
if ((l_a = BM_face_vert_share_loop(py_face->f, py_vert_a->v)) &&
(l_b = BM_face_vert_share_loop(py_face->f, py_vert_b->v)))
{
/* pass */
}
else {
PyErr_SetString(PyExc_ValueError,
"face_split(...): one of the verts passed is not found in the face");
return NULL;
@ -448,14 +452,14 @@ static PyObject *bpy_bm_utils_face_split(PyObject *UNUSED(self), PyObject *args,
if (ncoords) {
f_new = BM_face_split_n(bm, py_face->f,
py_vert_a->v, py_vert_b->v,
l_a, l_b,
(float (*)[3])coords, ncoords,
&l_new, py_edge_example ? py_edge_example->e : NULL);
PyMem_Free(coords);
}
else {
f_new = BM_face_split(bm, py_face->f,
py_vert_a->v, py_vert_b->v,
l_a, l_b,
&l_new, py_edge_example ? py_edge_example->e : NULL, edge_exists);
}