[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [40949] branches/bmesh/blender/source/ blender: implementation of bmesh_urmv (unglue region make vert) and use of it to fix ripping corners joining just two faces, which wasn' t working before
Andrew Wiggin
ender79bl at gmail.com
Wed Oct 12 08:11:21 CEST 2011
Revision: 40949
http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=40949
Author: ender79
Date: 2011-10-12 06:11:21 +0000 (Wed, 12 Oct 2011)
Log Message:
-----------
implementation of bmesh_urmv (unglue region make vert) and use of it to fix ripping corners joining just two faces, which wasn't working before
Modified Paths:
--------------
branches/bmesh/blender/source/blender/bmesh/bmesh.h
branches/bmesh/blender/source/blender/bmesh/intern/bmesh_mods.c
branches/bmesh/blender/source/blender/bmesh/intern/bmesh_newcore.c
branches/bmesh/blender/source/blender/bmesh/intern/bmesh_structure.c
branches/bmesh/blender/source/blender/bmesh/intern/bmesh_structure.h
branches/bmesh/blender/source/blender/bmesh/operators/createops.c
branches/bmesh/blender/source/blender/editors/mesh/bmesh_tools.c
Modified: branches/bmesh/blender/source/blender/bmesh/bmesh.h
===================================================================
--- branches/bmesh/blender/source/blender/bmesh/bmesh.h 2011-10-12 03:46:38 UTC (rev 40948)
+++ branches/bmesh/blender/source/blender/bmesh/bmesh.h 2011-10-12 06:11:21 UTC (rev 40949)
@@ -201,6 +201,9 @@
(if ccw is 1).*/
BMEdge *BM_Rotate_Edge ( BMesh *bm, BMEdge *e, int ccw );
+/* Rip a single face from a vertex fan */
+BMVert *BM_Rip_Vertex ( BMesh *bm, BMFace *sf, BMVert *sv);
+
/*updates a face normal*/
void BM_Face_UpdateNormal ( BMesh *bm, BMFace *f );
Modified: branches/bmesh/blender/source/blender/bmesh/intern/bmesh_mods.c
===================================================================
--- branches/bmesh/blender/source/blender/bmesh/intern/bmesh_mods.c 2011-10-12 03:46:38 UTC (rev 40948)
+++ branches/bmesh/blender/source/blender/bmesh/intern/bmesh_mods.c 2011-10-12 06:11:21 UTC (rev 40949)
@@ -499,7 +499,6 @@
}
BLI_array_free(faces);
-
return ne;
}
@@ -563,7 +562,7 @@
if (CustomData_has_layer(&bm->ldata, CD_MDISPS) && e->l && nv) {
int i, j;
-
+
/*interpolate new/changed loop data from copied old faces*/
for (j=0; j<2; j++) {
for (i=0; i<BLI_array_count(oldfaces); i++) {
@@ -723,3 +722,8 @@
return nl->e;
}
+
+BMVert *BM_Rip_Vertex ( BMesh *bm, BMFace *sf, BMVert *sv)
+{
+ return bmesh_urmv(bm, sf, sv);
+}
Modified: branches/bmesh/blender/source/blender/bmesh/intern/bmesh_newcore.c
===================================================================
--- branches/bmesh/blender/source/blender/bmesh/intern/bmesh_newcore.c 2011-10-12 03:46:38 UTC (rev 40948)
+++ branches/bmesh/blender/source/blender/bmesh/intern/bmesh_newcore.c 2011-10-12 06:11:21 UTC (rev 40949)
@@ -203,7 +203,7 @@
/*just return NULL for now*/
return NULL;
}
-
+
f = BLI_mempool_calloc(bm->fpool);
bm->totface += 1;
f->head.type = BM_FACE;
@@ -531,10 +531,9 @@
len = bmesh_loop_length(l);
for(i=0, curloop = l; i< len; i++, curloop= curloop->next) {
- bmesh_radial_remove_loop(curloop, curloop->e);
- /*in case of border edges we HAVE to zero out curloop->radial Next/Prev*/
- curloop->radial_next = curloop->radial_prev = NULL;
- BLI_array_append(edar, curloop->e);
+ BMEdge *curedge = curloop->e;
+ bmesh_radial_remove_loop(curloop, curedge);
+ BLI_array_append(edar, curedge);
}
/*actually reverse the loop.*/
@@ -1398,7 +1397,7 @@
/*validate direction of f2's loop cycle is compatible.*/
if(f1loop->v == f2loop->v) return NULL;
-
+
/*
validate that for each face, each vertex has another edge in its disk cycle that is
not e, and not shared.
@@ -1480,3 +1479,295 @@
return f1;
}
+
+/*
+ * BMESH SPLICE VERT
+ *
+ * merges two verts into one (v into vtarget).
+ */
+static int bmesh_splicevert(BMesh *bm, BMVert *v, BMVert *vtarget)
+{
+ BMEdge *e;
+ BMLoop *l;
+ BMIter liter;
+
+ /* verts already spliced */
+ if (v == vtarget) {
+ return 0;
+ }
+
+ /* retarget all the loops of v to vtarget */
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_VERT, v) {
+ l->v = vtarget;
+ }
+
+ /* move all the edges from v's disk to vtarget's disk */
+ e = v->e;
+ while (e != NULL) {
+ bmesh_disk_remove_edge(e, v);
+ bmesh_edge_swapverts(e, v, vtarget);
+ bmesh_disk_append_edge(e, vtarget);
+ e = v->e;
+ }
+
+ /* v is unused now, and can be killed */
+ BM_Kill_Vert(bm, v);
+
+ return 1;
+}
+
+/* BMESH CUT VERT
+ *
+ * cut all disjoint fans that meet at a vertex, making a unique
+ * vertex for each region. returns an array of all resulting
+ * vertices.
+ */
+static int bmesh_cutvert(BMesh *bm, BMVert *v, BMVert ***vout, int *len)
+{
+ BMEdge **stack = NULL;
+ BLI_array_declare(stack);
+ BMVert **verts = NULL;
+ GHash *visithash;
+ BMIter eiter, liter;
+ BMLoop *l;
+ BMEdge *e;
+ int i, maxindex;
+ BMLoop *nl;
+
+ visithash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh_cutvert visithash");
+
+ maxindex = 0;
+ BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, v) {
+ if (BLI_ghash_haskey(visithash, e)) {
+ continue;
+ }
+
+ /* Prime the stack with this unvisited edge */
+ BLI_array_append(stack, e);
+
+ /* Walk over edges that:
+ 1) have v as one of the vertices
+ 2) are connected to e through face loop cycles
+ assigning a unique index to that group of edges */
+ while (e = BLI_array_pop(stack)) {
+ BLI_ghash_insert(visithash, e, SET_INT_IN_POINTER(maxindex));
+ BM_SetIndex(e, maxindex);
+
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_EDGE, e) {
+ nl = (l->v == v) ? l->prev : l->next;
+ if (!BLI_ghash_haskey(visithash, nl->e)) {
+ BLI_array_append(stack, nl->e);
+ }
+ }
+ }
+
+ maxindex++;
+ }
+
+ /* Make enough verts to split v for each group */
+ verts = MEM_callocN(sizeof(BMVert *) * maxindex, "bmesh_cutvert");
+ verts[0] = v;
+ for (i = 1; i < maxindex; i++) {
+ verts[i] = BM_Make_Vert(bm, v->co, v);
+ }
+
+ /* Replace v with the new verts in each group */
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_VERT, v) {
+ i = GET_INT_FROM_POINTER(BLI_ghash_lookup(visithash, l->e));
+ if (i == 0) {
+ continue;
+ }
+
+ if (l->v == v) {
+ l->v = verts[i];
+ }
+ if (l->next->v == v) {
+ l->next->v = verts[i];
+ }
+ }
+
+ BM_ITER(e, &eiter, bm, BM_EDGES_OF_VERT, v) {
+ i = GET_INT_FROM_POINTER(BLI_ghash_lookup(visithash, e));
+ if (i == 0) {
+ continue;
+ }
+
+ BM_ITER(l, &liter, bm, BM_LOOPS_OF_EDGE, e) {
+ if (l->v == v) {
+ l->v = verts[i];
+ }
+ if (l->next->v == v) {
+ l->next->v = verts[i];
+ }
+ }
+
+ if (e->v1 == v || e->v2 == v) {
+ bmesh_disk_remove_edge(e, v);
+ bmesh_edge_swapverts(e, v, verts[i]);
+ bmesh_disk_append_edge(e, verts[i]);
+ }
+ }
+
+ BLI_ghash_free(visithash, NULL, NULL);
+ BLI_array_free(stack);
+
+ *vout = verts;
+ *len = maxindex;
+
+ return 1;
+}
+
+/* BMESH SPLICE EDGE
+ *
+ * splice two unique edges which share the same two vertices into one edge.
+ *
+ * edges must already have the same vertices
+ */
+static int bmesh_spliceedge(BMesh *bm, BMEdge *e, BMEdge *etarget)
+{
+ BMLoop *l;
+
+ if (!BM_Vert_In_Edge(e, etarget->v1) || !BM_Vert_In_Edge(e, etarget->v2)) {
+ /* not the same vertices can't splice */
+ return 0;
+ }
+
+ while (e->l) {
+ l = e->l;
+ bmesh_radial_remove_loop(l, e);
+ bmesh_radial_append(etarget, l);
+ }
+
+ BM_Kill_Edge(bm, e);
+
+ return 1;
+}
+
+/*
+ * BMESH CUT EDGE
+ *
+ * Cuts a single edge into two edge: the original edge and
+ * a new edge that has only "cutl" in its radial.
+ *
+ * Does nothing if cutl is already the only loop in the
+ * edge radial.
+ */
+static int bmesh_cutedge(BMesh *bm, BMEdge *e, BMLoop *cutl)
+{
+ BMEdge *ne;
+
+ BLI_assert(cutl->e == e);
+ BLI_assert(e->l);
+
+ if (bmesh_radial_length(e->l) < 2) {
+ /* no cut required */
+ return 1;
+ }
+
+ if (cutl == e->l) {
+ e->l = cutl->radial_next;
+ }
+
+ ne = BM_Make_Edge(bm, e->v1, e->v2, e, 0);
+ bmesh_radial_remove_loop(cutl, e);
+ bmesh_radial_append(ne, cutl);
+ cutl->e = ne;
+
+ return 1;
+}
+
+/*
+ * BMESH UNGLUE REGION MAKE VERT
+ *
+ * Disconnects a face from its vertex fan at loop sl.
+ */
+static BMVert *bmesh_urmv_loop(BMesh *bm, BMLoop *sl)
+{
+ BMVert **vtar;
+ int len, i;
+ BMVert *nv = NULL;
+ BMVert *sv = sl->v;
+
+ /* peel the face from the edge radials on both sides of the
+ loop vert, disconnecting the face from its fan */
+ bmesh_cutedge(bm, sl->e, sl);
+ bmesh_cutedge(bm, sl->prev->e, sl->prev);
+
+ if (bmesh_disk_count(sv) == 2) {
+ /* If there are still only two edges out of sv, then
+ this whole URMV was just a no-op, so exit now. */
+ return sv;
+ }
+
+ /* Update the disk start, so that v->e points to an edge
+ not touching the split loop. This is so that bmesh_cutvert
+ will leave the original sv on some *other* fan (not the
+ one-face fan that holds the unglue face). */
+ while (sv->e == sl->e || sv->e == sl->prev->e) {
+ sv->e = bmesh_disk_nextedge(sv->e, sv);
+ }
+
+ /* Split all fans connected to the vert, duplicating it for
+ each fans. */
+ bmesh_cutvert(bm, sv, &vtar, &len);
+
+ /* There should have been at least two fans cut apart here,
+ otherwise the early exit would have kicked in. */
+ BLI_assert(len >= 2);
+
+ nv = sl->v;
+
+ /* Desired result here is that a new vert should always be
+ created for the unglue face. This is so we can glue any
+ extras back into the original vert. */
+ BLI_assert(nv != sv);
+ BLI_assert(sv == vtar[0]);
+
+ /* If there are more than two verts as a result, glue together
+ all the verts except the one this URMV intended to create */
+ if (len > 2) {
+ for (i = 0; i < len; i++) {
+ if (vtar[i] == nv) {
+ break;
+ }
+ }
+
+ if (i != len) {
+ /* Swap the single vert that was needed for the
+ unglue into the last array slot */
+ SWAP(BMVert *, vtar[i], vtar[len - 1]);
+
+ /* And then glue the rest back together */
+ for (i = 1; i < len - 1; i++) {
+ bmesh_splicevert(bm, vtar[i], vtar[0]);
+ }
+ }
+ }
+
+ MEM_freeN(vtar);
+
+ return nv;
+}
+
+/*
+ * BMESH UNGLUE REGION MAKE VERT
+ *
+ * Disconnects a face from its vertex fan at loop sl.
+ */
+BMVert *bmesh_urmv(BMesh *bm, BMFace *sf, BMVert *sv)
+{
+ BMLoop *hl, *sl;
+
+ hl = sl = bm_firstfaceloop(sf);
+ do {
+ if (sl->v == sv) break;
+ sl = sl->next;
+ } while (sl != hl);
+
+ if (sl->v != sv) {
+ /* sv is not part of sf */
+ return NULL;
+ }
+
+ return bmesh_urmv_loop(bm, sl);
+}
Modified: branches/bmesh/blender/source/blender/bmesh/intern/bmesh_structure.c
===================================================================
--- branches/bmesh/blender/source/blender/bmesh/intern/bmesh_structure.c 2011-10-12 03:46:38 UTC (rev 40948)
+++ branches/bmesh/blender/source/blender/bmesh/intern/bmesh_structure.c 2011-10-12 06:11:21 UTC (rev 40949)
@@ -361,8 +361,21 @@
return 1;
}
+/*
+ * BMESH RADIAL REMOVE LOOP
+ *
+ * Removes a loop from an radial cycle. If edge e is non-NULL
+ * it should contain the radial cycle, and it will also get
+ * updated (in the case that the edge's link into the radial
+ * cycle was the loop which is being removed from the cycle).
+ */
void bmesh_radial_remove_loop(BMLoop *l, BMEdge *e)
{
+ /* if e is non-NULL, l must be in the radial cycle of e */
+ if (e && e != l->e) {
+ bmesh_error();
+ }
+
if (l->radial_next != l) {
if (e && l == e->l)
e->l = l->radial_next;
@@ -370,12 +383,20 @@
l->radial_next->radial_prev = l->radial_prev;
l->radial_prev->radial_next = l->radial_next;
} else {
- l->radial_next = l->radial_prev = NULL;
- if (e && l == e->l)
- e->l = NULL;
- else if (e)
- bmesh_error();
+ if (e) {
+ if (l == e->l) {
+ e->l = NULL;
+ }
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list