Partial fix for array modifier vertex merge (bug 30195).

Two fixes:

* The find-doubles operator was overriding the "dirty" element
  indices, so vertices were not being mapped correctly.

* In some cases a vertex can be set to merge with a vertex that is
  also set to be merged, so added a loop to find the first unmerged
  vert in this case.

Not yet working is the "First Last" merge option.

Also made some cleanups and added comments in the array/remove doubles
code.
This commit is contained in:
Nicholas Bishop 2012-03-28 22:03:46 +00:00
parent 9391e4c4a3
commit b8bb3f2e3c
2 changed files with 77 additions and 56 deletions

View File

@ -103,6 +103,7 @@ void bmo_weldverts_exec(BMesh *bm, BMOperator *op)
BMFace *f, *f2;
int a, b;
/* mark merge verts for deletion */
BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
if ((v2 = BMO_slot_map_ptr_get(bm, op, "targetmap", v))) {
BMO_elem_flag_enable(bm, v, ELE_DEL);
@ -112,10 +113,12 @@ void bmo_weldverts_exec(BMesh *bm, BMOperator *op)
}
}
/* check if any faces are getting their own corners merged
together, split face if so */
BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
remdoubles_splitface(f, bm, op);
}
BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
if (BMO_elem_flag_test(bm, e->v1, ELE_DEL) || BMO_elem_flag_test(bm, e->v2, ELE_DEL)) {
v = BMO_slot_map_ptr_get(bm, op, "targetmap", e->v1);
@ -149,6 +152,8 @@ void bmo_weldverts_exec(BMesh *bm, BMOperator *op)
}
bm->elem_index_dirty |= BM_FACE;
/* faces get "modified" by creating new faces here, then at the
end the old faces are deleted */
BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
if (!BMO_elem_flag_test(bm, f, FACE_MARK))
continue;

View File

@ -185,13 +185,60 @@ static void bm_merge_dm_transform(BMesh* bm, DerivedMesh *dm, float mat[4][4])
}
}
static int *find_doubles_index_map(BMesh *bm, BMOperator *dupe_op,
const ArrayModifierData *amd,
int *index_map_length)
{
BMOperator find_op;
BMOIter oiter;
BMVert *v, *v2;
BMElem *ele;
int *index_map, i;
BMO_op_initf(bm, &find_op,
"finddoubles verts=%av dist=%f keepverts=%s",
amd->merge_dist, dupe_op, "geom");
BMO_op_exec(bm, &find_op);
i = 0;
BMO_ITER(ele, &oiter, bm, dupe_op, "geom", BM_ALL) {
BM_elem_index_set(ele, i); /* set_dirty */
i++;
}
BMO_ITER(ele, &oiter, bm, dupe_op, "newout", BM_ALL) {
BM_elem_index_set(ele, i); /* set_dirty */
i++;
}
/* above loops over all, so set all to dirty, if this is somehow
* setting valid values, this line can be remvoed - campbell */
bm->elem_index_dirty |= BM_VERT | BM_EDGE | BM_FACE;
(*index_map_length) = i;
index_map = MEM_callocN(sizeof(int) * (*index_map_length), "index_map");
/*element type argument doesn't do anything here*/
BMO_ITER(v, &oiter, bm, &find_op, "targetmapout", 0) {
v2 = BMO_iter_map_value_p(&oiter);
index_map[BM_elem_index_get(v)] = BM_elem_index_get(v2) + 1;
}
BMO_op_finish(bm, &find_op);
return index_map;
}
static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
Scene *scene, Object *ob, DerivedMesh *dm,
int UNUSED(initFlags))
{
DerivedMesh *result;
BMEditMesh *em = DM_to_editbmesh(dm, NULL, FALSE);
BMOperator op, oldop, weldop;
BMOperator dupe_op, old_dupe_op, weld_op;
int i, j, indexLen;
/* offset matrix */
float offset[4][4];
@ -290,65 +337,29 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
BMO_push(em->bm, NULL);
bmesh_edit_begin(em->bm, 0);
BMO_op_init(em->bm, &weldop, "weldverts");
BMO_op_initf(em->bm, &op, "dupe geom=%avef");
oldop = op;
BMO_op_init(em->bm, &weld_op, "weldverts");
BMO_op_initf(em->bm, &dupe_op, "dupe geom=%avef");
old_dupe_op = dupe_op;
for (j=0; j < count - 1; j++) {
BMVert *v, *v2;
BMVert *v, *v2, *v3;
BMOpSlot *s1;
BMOpSlot *s2;
BMO_op_initf(em->bm, &op, "dupe geom=%s", &oldop, j==0 ? "geom" : "newout");
BMO_op_exec(em->bm, &op);
BMO_op_initf(em->bm, &dupe_op, "dupe geom=%s", &old_dupe_op, j==0 ? "geom" : "newout");
BMO_op_exec(em->bm, &dupe_op);
s1 = BMO_slot_get(&op, "geom");
s2 = BMO_slot_get(&op, "newout");
s1 = BMO_slot_get(&dupe_op, "geom");
s2 = BMO_slot_get(&dupe_op, "newout");
BMO_op_callf(em->bm, "transform mat=%m4 verts=%s", offset, &op, "newout");
#define _E(s, i) ((BMVert **)(s)->data.buf)[i]
BMO_op_callf(em->bm, "transform mat=%m4 verts=%s", offset, &dupe_op, "newout");
/*calculate merge mapping*/
if (j == 0) {
BMOperator findop;
BMOIter oiter;
BMVert *v, *v2;
BMElem *ele;
BMO_op_initf(em->bm, &findop,
"finddoubles verts=%av dist=%f keepverts=%s",
amd->merge_dist, &op, "geom");
i = 0;
BMO_ITER(ele, &oiter, em->bm, &op, "geom", BM_ALL) {
BM_elem_index_set(ele, i); /* set_dirty */
i++;
}
BMO_ITER(ele, &oiter, em->bm, &op, "newout", BM_ALL) {
BM_elem_index_set(ele, i); /* set_dirty */
i++;
}
/* above loops over all, so set all to dirty, if this is somehow
* setting valid values, this line can be remvoed - campbell */
em->bm->elem_index_dirty |= BM_VERT | BM_EDGE | BM_FACE;
BMO_op_exec(em->bm, &findop);
indexLen = i;
indexMap = MEM_callocN(sizeof(int)*indexLen, "indexMap");
/*element type argument doesn't do anything here*/
BMO_ITER(v, &oiter, em->bm, &findop, "targetmapout", 0) {
v2 = BMO_iter_map_value_p(&oiter);
indexMap[BM_elem_index_get(v)] = BM_elem_index_get(v2)+1;
}
BMO_op_finish(em->bm, &findop);
indexMap = find_doubles_index_map(em->bm, &dupe_op,
amd, &indexLen);
}
#define _E(s, i) ((BMVert **)(s)->data.buf)[i]
/* generate merge mapping using index map. we do this by using the
* operator slots as lookup arrays.*/
#define E(i) (i) < s1->len ? _E(s1, i) : _E(s2, (i)-s1->len)
@ -359,17 +370,22 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
v = E(i);
v2 = E(indexMap[i]-1);
BMO_slot_map_ptr_insert(em->bm, &weldop, "targetmap", v, v2);
/* check in case the target vertex (v2) is already marked
for merging */
while((v3 = BMO_slot_map_ptr_get(em->bm, &weld_op, "targetmap", v2)))
v2 = v3;
BMO_slot_map_ptr_insert(em->bm, &weld_op, "targetmap", v, v2);
}
#undef E
#undef _E
BMO_op_finish(em->bm, &oldop);
oldop = op;
BMO_op_finish(em->bm, &old_dupe_op);
old_dupe_op = dupe_op;
}
if (j > 0) BMO_op_finish(em->bm, &op);
if (j > 0) BMO_op_finish(em->bm, &dupe_op);
/* BMESH_TODO - cap ends are not welded, even though weld is called after */
@ -399,9 +415,9 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
/* done capping */
if (amd->flags & MOD_ARR_MERGE)
BMO_op_exec(em->bm, &weldop);
BMO_op_exec(em->bm, &weld_op);
BMO_op_finish(em->bm, &weldop);
BMO_op_finish(em->bm, &weld_op);
/* Bump the stack level back down to match the adjustment up above */
BMO_pop(em->bm);