fix/workaround [#33281] script goes into not responding

scanfill remove-doubles pass assumes ordered edges (as with curves), otherwise it can hang.
workaround this problem by skipping removing-doubles for mesh ngons, since this isnt such a common case as it is with curves and we can just not support it.
This commit is contained in:
Campbell Barton 2012-11-26 23:18:04 +00:00
parent ceed3ef640
commit f9e339ef00
9 changed files with 99 additions and 73 deletions

View File

@ -487,7 +487,7 @@ void BKE_displist_fill(ListBase *dispbase, ListBase *to, int flipnormal)
}
/* XXX (obedit && obedit->actcol)?(obedit->actcol-1):0)) { */
if (totvert && (tot = BLI_scanfill_calc(&sf_ctx, FALSE))) {
if (totvert && (tot = BLI_scanfill_calc(&sf_ctx, BLI_SCANFILL_CALC_REMOVE_DOUBLES))) {
if (tot) {
dlnew = MEM_callocN(sizeof(DispList), "filldisplist");
dlnew->type = DL_INDEX3;

View File

@ -215,7 +215,7 @@ static void BMEdit_RecalcTessellation_intern(BMEditMesh *tm)
/* complete the loop */
BLI_scanfill_edge_add(&sf_ctx, sf_vert_first, sf_vert);
totfilltri = BLI_scanfill_calc_ex(&sf_ctx, FALSE, efa->no);
totfilltri = BLI_scanfill_calc_ex(&sf_ctx, 0, efa->no);
BLI_array_grow_items(looptris, totfilltri);
for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next) {

View File

@ -933,7 +933,7 @@ void BKE_maskrasterize_handle_init(MaskRasterHandle *mr_handle, struct Mask *mas
}
/* main scan-fill */
sf_tri_tot = BLI_scanfill_calc_ex(&sf_ctx, FALSE, zvec);
sf_tri_tot = BLI_scanfill_calc_ex(&sf_ctx, 0, zvec);
face_array = MEM_mallocN(sizeof(*face_array) * (sf_tri_tot + tot_feather_quads), "maskrast_face_index");
face_index = 0;

View File

@ -2607,7 +2607,7 @@ int BKE_mesh_recalc_tessellation(CustomData *fdata,
}
BLI_scanfill_edge_add(&sf_ctx, sf_vert_last, sf_vert_first);
totfilltri = BLI_scanfill_calc(&sf_ctx, FALSE);
totfilltri = BLI_scanfill_calc(&sf_ctx, 0);
if (totfilltri) {
BLI_array_grow_items(mface_to_poly_map, totfilltri);
BLI_array_grow_items(mface, totfilltri);

View File

@ -94,9 +94,18 @@ typedef struct ScanFillFace {
struct ScanFillVert *BLI_scanfill_vert_add(ScanFillContext *sf_ctx, const float vec[3]);
struct ScanFillEdge *BLI_scanfill_edge_add(ScanFillContext *sf_ctx, struct ScanFillVert *v1, struct ScanFillVert *v2);
enum {
BLI_SCANFILL_CALC_QUADTRI_FASTPATH = (1 << 0),
/* note: using BLI_SCANFILL_CALC_REMOVE_DOUBLES
* Assumes ordered edges, otherwise we risk an eternal loop
* removing double verts. - campbell */
BLI_SCANFILL_CALC_REMOVE_DOUBLES = (1 << 1),
};
int BLI_scanfill_begin(ScanFillContext *sf_ctx);
int BLI_scanfill_calc(ScanFillContext *sf_ctx, const short do_quad_tri_speedup);
int BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, const short do_quad_tri_speedup,
int BLI_scanfill_calc(ScanFillContext *sf_ctx, const int flag);
int BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, const int flag,
const float nor_proj[3]);
void BLI_scanfill_end(ScanFillContext *sf_ctx);

View File

@ -503,8 +503,7 @@ static void splitlist(ScanFillContext *sf_ctx, ListBase *tempve, ListBase *tempe
}
}
static int scanfill(ScanFillContext *sf_ctx, PolyFill *pf)
static int scanfill(ScanFillContext *sf_ctx, PolyFill *pf, const int flag)
{
ScanFillVertLink *sc = NULL, *sc1;
ScanFillVert *eve, *v1, *v2, *v3;
@ -530,26 +529,28 @@ static int scanfill(ScanFillContext *sf_ctx, PolyFill *pf)
#endif
/* STEP 0: remove zero sized edges */
eed = sf_ctx->filledgebase.first;
while (eed) {
if (equals_v2v2(eed->v1->xy, eed->v2->xy)) {
if (eed->v1->f == SF_VERT_ZERO_LEN && eed->v2->f != SF_VERT_ZERO_LEN) {
eed->v2->f = SF_VERT_ZERO_LEN;
eed->v2->tmp.v = eed->v1->tmp.v;
}
else if (eed->v2->f == SF_VERT_ZERO_LEN && eed->v1->f != SF_VERT_ZERO_LEN) {
eed->v1->f = SF_VERT_ZERO_LEN;
eed->v1->tmp.v = eed->v2->tmp.v;
}
else if (eed->v2->f == SF_VERT_ZERO_LEN && eed->v1->f == SF_VERT_ZERO_LEN) {
eed->v1->tmp.v = eed->v2->tmp.v;
}
else {
eed->v2->f = SF_VERT_ZERO_LEN;
eed->v2->tmp.v = eed->v1;
if (flag & BLI_SCANFILL_CALC_REMOVE_DOUBLES) {
eed = sf_ctx->filledgebase.first;
while (eed) {
if (equals_v2v2(eed->v1->xy, eed->v2->xy)) {
if (eed->v1->f == SF_VERT_ZERO_LEN && eed->v2->f != SF_VERT_ZERO_LEN) {
eed->v2->f = SF_VERT_ZERO_LEN;
eed->v2->tmp.v = eed->v1->tmp.v;
}
else if (eed->v2->f == SF_VERT_ZERO_LEN && eed->v1->f != SF_VERT_ZERO_LEN) {
eed->v1->f = SF_VERT_ZERO_LEN;
eed->v1->tmp.v = eed->v2->tmp.v;
}
else if (eed->v2->f == SF_VERT_ZERO_LEN && eed->v1->f == SF_VERT_ZERO_LEN) {
eed->v1->tmp.v = eed->v2->tmp.v;
}
else {
eed->v2->f = SF_VERT_ZERO_LEN;
eed->v2->tmp.v = eed->v1;
}
}
eed = eed->next;
}
eed = eed->next;
}
/* STEP 1: make using FillVert and FillEdge lists a sorted
@ -572,28 +573,42 @@ static int scanfill(ScanFillContext *sf_ctx, PolyFill *pf)
qsort(sf_ctx->_scdata, verts, sizeof(ScanFillVertLink), vergscdata);
eed = sf_ctx->filledgebase.first;
while (eed) {
nexted = eed->next;
BLI_remlink(&sf_ctx->filledgebase, eed);
/* This code is for handling zero-length edges that get
* collapsed in step 0. It was removed for some time to
* fix trunk bug #4544, so if that comes back, this code
* may need some work, or there will have to be a better
* fix to #4544. */
if (eed->v1->f == SF_VERT_ZERO_LEN) {
v1 = eed->v1;
while ((eed->v1->f == SF_VERT_ZERO_LEN) && (eed->v1->tmp.v != v1) && (eed->v1 != eed->v1->tmp.v))
eed->v1 = eed->v1->tmp.v;
if (flag & BLI_SCANFILL_CALC_REMOVE_DOUBLES) {
for (eed = sf_ctx->filledgebase.first; eed; eed = nexted) {
nexted = eed->next;
BLI_remlink(&sf_ctx->filledgebase, eed);
/* This code is for handling zero-length edges that get
* collapsed in step 0. It was removed for some time to
* fix trunk bug #4544, so if that comes back, this code
* may need some work, or there will have to be a better
* fix to #4544.
*
* warning, this can hang on un-ordered edges, see: [#33281]
* for now disable 'BLI_SCANFILL_CALC_REMOVE_DOUBLES' for ngons.
*/
if (eed->v1->f == SF_VERT_ZERO_LEN) {
v1 = eed->v1;
while ((eed->v1->f == SF_VERT_ZERO_LEN) && (eed->v1->tmp.v != v1) && (eed->v1 != eed->v1->tmp.v))
eed->v1 = eed->v1->tmp.v;
}
if (eed->v2->f == SF_VERT_ZERO_LEN) {
v2 = eed->v2;
while ((eed->v2->f == SF_VERT_ZERO_LEN) && (eed->v2->tmp.v != v2) && (eed->v2 != eed->v2->tmp.v))
eed->v2 = eed->v2->tmp.v;
}
if (eed->v1 != eed->v2) {
addedgetoscanlist(sf_ctx, eed, verts);
}
}
if (eed->v2->f == SF_VERT_ZERO_LEN) {
v2 = eed->v2;
while ((eed->v2->f == SF_VERT_ZERO_LEN) && (eed->v2->tmp.v != v2) && (eed->v2 != eed->v2->tmp.v))
eed->v2 = eed->v2->tmp.v;
}
else {
for (eed = sf_ctx->filledgebase.first; eed; eed = nexted) {
nexted = eed->next;
BLI_remlink(&sf_ctx->filledgebase, eed);
if (eed->v1 != eed->v2) {
addedgetoscanlist(sf_ctx, eed, verts);
}
}
if (eed->v1 != eed->v2) addedgetoscanlist(sf_ctx, eed, verts);
eed = nexted;
}
#if 0
sc = scdata;
@ -775,12 +790,12 @@ int BLI_scanfill_begin(ScanFillContext *sf_ctx)
return 1;
}
int BLI_scanfill_calc(ScanFillContext *sf_ctx, const short do_quad_tri_speedup)
int BLI_scanfill_calc(ScanFillContext *sf_ctx, const int flag)
{
return BLI_scanfill_calc_ex(sf_ctx, do_quad_tri_speedup, NULL);
return BLI_scanfill_calc_ex(sf_ctx, flag, NULL);
}
int BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, const short do_quad_tri_speedup, const float nor_proj[3])
int BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, const int flag, const float nor_proj[3])
{
/*
* - fill works with its own lists, so create that first (no faces!)
@ -810,30 +825,32 @@ int BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, const short do_quad_tri_speedu
a += 1;
}
if (do_quad_tri_speedup && (a == 3)) {
eve = sf_ctx->fillvertbase.first;
if (flag & BLI_SCANFILL_CALC_QUADTRI_FASTPATH) {
if (a == 3) {
eve = sf_ctx->fillvertbase.first;
addfillface(sf_ctx, eve, eve->next, eve->next->next);
return 1;
}
else if (do_quad_tri_speedup && (a == 4)) {
float vec1[3], vec2[3];
eve = sf_ctx->fillvertbase.first;
/* no need to check 'eve->next->next->next' is valid, already counted */
/* use shortest diagonal for quad */
sub_v3_v3v3(vec1, eve->co, eve->next->next->co);
sub_v3_v3v3(vec2, eve->next->co, eve->next->next->next->co);
if (dot_v3v3(vec1, vec1) < dot_v3v3(vec2, vec2)) {
addfillface(sf_ctx, eve, eve->next, eve->next->next);
addfillface(sf_ctx, eve->next->next, eve->next->next->next, eve);
return 1;
}
else {
addfillface(sf_ctx, eve->next, eve->next->next, eve->next->next->next);
addfillface(sf_ctx, eve->next->next->next, eve, eve->next);
else if (a == 4) {
float vec1[3], vec2[3];
eve = sf_ctx->fillvertbase.first;
/* no need to check 'eve->next->next->next' is valid, already counted */
/* use shortest diagonal for quad */
sub_v3_v3v3(vec1, eve->co, eve->next->next->co);
sub_v3_v3v3(vec2, eve->next->co, eve->next->next->next->co);
if (dot_v3v3(vec1, vec1) < dot_v3v3(vec2, vec2)) {
addfillface(sf_ctx, eve, eve->next, eve->next->next);
addfillface(sf_ctx, eve->next->next, eve->next->next->next, eve);
}
else {
addfillface(sf_ctx, eve->next, eve->next->next, eve->next->next->next);
addfillface(sf_ctx, eve->next->next->next, eve, eve->next);
}
return 2;
}
return 2;
}
/* first test vertices if they are in edges */
@ -1091,7 +1108,7 @@ int BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, const short do_quad_tri_speedu
for (a = 0; a < poly; a++) {
if (pf->edges > 1) {
splitlist(sf_ctx, &tempve, &temped, pf->nr);
totfaces += scanfill(sf_ctx, pf);
totfaces += scanfill(sf_ctx, pf, flag);
}
pf++;
}

View File

@ -190,7 +190,7 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op)
/* sf_edge->tmp.p = e; */ /* UNUSED */
}
BLI_scanfill_calc(&sf_ctx, FALSE);
BLI_scanfill_calc(&sf_ctx, 0);
for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next) {
BMFace *f = BM_face_create_quad_tri(bm,

View File

@ -306,7 +306,7 @@ static ParamHandle *construct_param_handle(Scene *scene, Object *ob, BMEditMesh
BLI_scanfill_edge_add(&sf_ctx, sf_vert_first, sf_vert);
BLI_scanfill_calc_ex(&sf_ctx, TRUE, efa->no);
BLI_scanfill_calc_ex(&sf_ctx, 0, efa->no);
for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next) {
int i;
ls[0] = sf_tri->v1->tmp.p;

View File

@ -255,7 +255,7 @@ static void draw_filled_lasso(wmGesture *gt)
if (sf_vert_first) {
const float zvec[3] = {0.0f, 0.0f, 1.0f};
BLI_scanfill_edge_add(&sf_ctx, sf_vert_first, sf_vert);
BLI_scanfill_calc_ex(&sf_ctx, FALSE, zvec);
BLI_scanfill_calc_ex(&sf_ctx, BLI_SCANFILL_CALC_REMOVE_DOUBLES, zvec);
glEnable(GL_BLEND);
glColor4f(1.0, 1.0, 1.0, 0.05);