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:
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?
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue