Fix Bevel bugs T39726 and T39108, bevels with wire edges.
authorHoward Trickey <howard.trickey@gmail.com>
Fri, 16 May 2014 14:28:15 +0000 (10:28 -0400)
committerHoward Trickey <howard.trickey@gmail.com>
Fri, 16 May 2014 14:28:15 +0000 (10:28 -0400)
This updates the fix in rB27db75363, which had to be undone
because it broke other bevels.
It also fixes cases where edges went away went doing vertex
bevel on vertices with some wire edges.

source/blender/bmesh/tools/bmesh_bevel.c

index 33ba4b9550ee1f87712b5f3a3b16f3e4551a20c6..0f7c3e2e3cf8156843cde7c23fdc797a82832bbc 100644 (file)
@@ -136,7 +136,7 @@ typedef struct BoundVert {
        Profile profile;    /* edge profile between this and next BoundVert */
        bool any_seam;      /* are any of the edges attached here seams? */
 //     int _pad;
-} BoundVert;
+} BoundVert;   
 
 /* Mesh structure replacing a vertex */
 typedef struct VMesh {
@@ -157,12 +157,14 @@ typedef struct VMesh {
 /* Data for a vertex involved in a bevel */
 typedef struct BevVert {
        BMVert *v;          /* original mesh vertex */
-       int edgecount;          /* total number of edges around the vertex */
+       int edgecount;          /* total number of edges around the vertex (excluding wire edges if edge beveling) */
        int selcount;           /* number of selected edges around the vertex */
+       int wirecount;                  /* count of wire edges */
        float offset;           /* offset for this vertex, if vertex_only bevel */
        bool any_seam;                  /* any seams on attached edges? */
        bool visited;           /* used in graph traversal */
        EdgeHalf *edges;        /* array of size edgecount; CCW order from vertex normal side */
+       BMEdge **wire_edges;    /* array of size wirecount of wire edges */
        VMesh *vmesh;           /* mesh structure for replacing vertex */
 } BevVert;
 
@@ -2680,6 +2682,25 @@ static void bevel_build_quadstrip(BMesh *bm, BevVert *bv)
        }
 }
 
+/* Special case: there is no vmesh pattern because this has only two boundary verts,
+ * and there are no faces in the original mesh at the original vertex.
+ * Since there will be no rebuilt face to make the edge between the boundary verts,
+ * we have to make it here. */
+static void bevel_build_one_wire(BMesh *bm, BevVert *bv)
+{
+       VMesh *vm = bv->vmesh;
+       BMVert *v1, *v2;
+       BMEdge *e_eg;
+
+       BLI_assert(vm->count == 2);
+
+       v1 = mesh_vert(vm, 0, 0, 0)->v;
+       v2 = mesh_vert(vm, 1, 0, 0)->v;
+       e_eg = bv->edges[0].e;
+       BLI_assert(v1 != NULL && v2 != NULL && e_eg != NULL);
+       BM_edge_create(bm, v1, v2, e_eg, BM_CREATE_NO_DOUBLE);
+}
+
 /* Given that the boundary is built, now make the actual BMVerts
  * for the boundary and the interior of the vertex mesh. */
 static void build_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv)
@@ -2763,7 +2784,8 @@ static void build_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv)
 
        switch (vm->mesh_kind) {
                case M_NONE:
-                       /* do nothing */
+                       if  (n == 2 && BM_vert_face_count(bv->v) == 0)
+                               bevel_build_one_wire(bm, bv);
                        break;
                case M_POLY:
                        bevel_build_poly(bm, bv);
@@ -2814,6 +2836,7 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v)
        int i, found_shared_face, ccw_test_sum;
        int nsel = 0;
        int ntot = 0;
+       int nwire = 0;
        int fcnt;
 
        /* Gather input selected edges.
@@ -2821,13 +2844,14 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v)
         * Want edges to be ordered so that they share faces.
         * There may be one or more chains of shared faces broken by
         * gaps where there are no faces.
-        * TODO: Want to ignore wire edges completely for edge beveling.
+        * Want to ignore wire edges completely for edge beveling.
         * TODO: make following work when more than one gap.
         */
 
        first_bme = NULL;
        BM_ITER_ELEM (bme, &iter, v, BM_EDGES_OF_VERT) {
                fcnt = BM_edge_face_count(bme);
+               BM_BEVEL_EDGE_TAG_DISABLE(bme);
                if (BM_elem_flag_test(bme, BM_ELEM_TAG) && !bp->vertex_only) {
                        BLI_assert(fcnt == 2);
                        nsel++;
@@ -2838,8 +2862,15 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v)
                        /* good to start face chain from this edge */
                        first_bme = bme;
                }
-               ntot++;
-               BM_BEVEL_EDGE_TAG_DISABLE(bme);
+               if (fcnt > 0 || bp->vertex_only)
+                       ntot++;
+               if (BM_edge_is_wire(bme)) {
+                       nwire++;
+                       /* If edge beveling, exclude wire edges from edges array.
+                        * Mark this edge as "chosen" so loop below won't choose it. */
+                        if (!bp->vertex_only)
+                               BM_BEVEL_EDGE_TAG_ENABLE(bme);
+               }
        }
        if (!first_bme)
                first_bme = v->e;
@@ -2854,8 +2885,13 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v)
        bv->v = v;
        bv->edgecount = ntot;
        bv->selcount = nsel;
+       bv->wirecount = nwire;
        bv->offset = bp->offset;
        bv->edges = (EdgeHalf *)BLI_memarena_alloc(bp->mem_arena, ntot * sizeof(EdgeHalf));
+       if (nwire)
+               bv->wire_edges = (BMEdge **)BLI_memarena_alloc(bp->mem_arena, nwire * sizeof(BMEdge *));
+       else
+               bv->wire_edges = NULL;
        bv->vmesh = (VMesh *)BLI_memarena_alloc(bp->mem_arena, sizeof(VMesh));
        bv->vmesh->seg = bp->seg;
 
@@ -3023,6 +3059,17 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v)
                        e->is_seam = true;
        }
 
+       if (nwire) {
+               i = 0;
+               BM_ITER_ELEM (bme, &iter, v, BM_EDGES_OF_VERT) {
+                       if (BM_edge_is_wire(bme)) {
+                               BLI_assert(i < bv->wirecount);
+                               bv->wire_edges[i++] = bme;
+                       }
+               }
+               BLI_assert(i == bv->wirecount);
+       }
+
        return bv;
 }
 
@@ -3128,6 +3175,61 @@ static void bevel_rebuild_existing_polygons(BMesh *bm, BevelParams *bp, BMVert *
        }
 }
 
+/* If there were any wire edges, they need to be reattached somewhere */
+static void bevel_reattach_wires(BMesh *bm, BevelParams *bp, BMVert *v)
+{
+       BMEdge *e;
+       BMVert *vclosest, *vother, *votherclosest;
+       BevVert *bv, *bvother;
+       BoundVert *bndv, *bndvother;
+       float d, dclosest;
+       int i;
+
+       bv = find_bevvert(bp, v);
+       if (!bv || bv->wirecount == 0 || !bv->vmesh)
+               return;
+
+       for (i = 0; i < bv->wirecount; i++) {
+               e = bv->wire_edges[i];
+               /* look for the new vertex closest to the other end of e */
+               vclosest = NULL;
+               dclosest = FLT_MAX;
+               votherclosest = NULL;
+               vother = BM_edge_other_vert(e, v);
+               bvother = NULL;
+               if (BM_elem_flag_test(vother, BM_ELEM_TAG)) {
+                       bvother = find_bevvert(bp, vother);
+                       if (!bvother || !bvother->vmesh)
+                               return;  /* shouldn't happen */
+               }
+               bndv = bv->vmesh->boundstart;
+               do {
+                       if (bvother) {
+                               bndvother = bvother->vmesh->boundstart;
+                               do {
+                                       d = len_squared_v3v3(bndvother->nv.co, bndv->nv.co);
+                                       if (d < dclosest) {
+                                               vclosest = bndv->nv.v;
+                                               votherclosest = bndvother->nv.v;
+                                               dclosest = d;
+                                               
+                                       }
+                               } while ((bndvother = bndvother->next) != bvother->vmesh->boundstart);
+                       }
+                       else {
+                               d = len_squared_v3v3(vother->co, bndv->nv.co);
+                               if (d < dclosest) {
+                                       vclosest = bndv->nv.v;
+                                       votherclosest = vother;
+                                       dclosest = d;
+                               }
+                       }
+               } while((bndv = bndv->next) != bv->vmesh->boundstart);
+               if (vclosest)
+                       BM_edge_create(bm, vclosest, votherclosest, e, BM_CREATE_NO_DOUBLE);
+       }
+}
+
 static void bev_merge_end_uvs(BMesh *bm, BevVert *bv, EdgeHalf *e)
 {
        VMesh *vm = bv->vmesh;
@@ -3504,6 +3606,7 @@ void BM_mesh_bevel(BMesh *bm, const float offset, const int offset_type,
                BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
                        if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
                                bevel_rebuild_existing_polygons(bm, &bp, v);
+                               bevel_reattach_wires(bm, &bp, v);
                        }
                }