[Bf-blender-cvs] [fd1ea5e] master: Fix T44742. Bevel now avoids vertex meshes when only two edges are beveled.

Howard Trickey noreply at git.blender.org
Tue Jun 2 16:20:00 CEST 2015


Commit: fd1ea5e3db5a66848dc532423340dce2d08ab599
Author: Howard Trickey
Date:   Tue Jun 2 09:25:05 2015 -0400
Branches: master
https://developer.blender.org/rBfd1ea5e3db5a66848dc532423340dce2d08ab599

Fix T44742. Bevel now avoids vertex meshes when only two edges are beveled.

Also, changed the algorithm for generating the vertex meshes when not all
edges into a vertex are beveled. Now it tries to slide along edges that
form part of the silhouette when possible; when not possible, it tries
to snap to the best plane in between the beveled edges.

===================================================================

M	source/blender/bmesh/tools/bmesh_bevel.c

===================================================================

diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index 252c16e..1bbde6d 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -57,6 +57,9 @@
 /* happens far too often, uncomment for development */
 // #define BEVEL_ASSERT_PROJECT
 
+/* will likely remove the code enabled by this soon, when sure that it is not needed */
+// #define PRE_275_ALGORITHM
+
 /* for testing */
 // #pragma GCC diagnostic error "-Wpadded"
 
@@ -187,7 +190,7 @@ typedef struct BevelParams {
 	bool limit_offset;      /* should offsets be limited by collisions? */
 	const struct MDeformVert *dvert; /* vertex group array, maybe set if vertex_only */
 	int vertex_group;       /* vertex group index, maybe set if vertex_only */
-	int mat_nr;            /* if >= 0, material number for bevel; else material comes from adjacent faces */
+	int mat_nr;             /* if >= 0, material number for bevel; else material comes from adjacent faces */
 } BevelParams;
 
 // #pragma GCC diagnostic ignored "-Wpadded"
@@ -484,8 +487,7 @@ static bool contig_ldata_across_edge(BMesh *bm, BMEdge *e, BMFace *f1, BMFace *f
 }
 
 /**
- * Like #bev_create_quad_tri, but when verts straddle an old edge.
- *
+ * Like bev_create_quad_tri, but when verts straddle an old edge.
  * <pre>
  *        e
  *        |
@@ -593,10 +595,42 @@ static bool is_outside_edge(EdgeHalf *e, const float co[3], BMVert **ret_closer_
 	}
 }
 
+/* co should be approximately on the plane between e1 and e2, which share common vert v
+ * and common face f (which cannot be NULL).
+ * Is it between those edges, sweeping CCW? */
+static bool point_between_edges(float co[3], BMVert *v, BMFace *f, EdgeHalf *e1, EdgeHalf *e2)
+{
+	BMVert *v1, *v2;
+	float dir1[3], dir2[3], dirco[3], no[3];
+	float ang11, ang1co;
+
+	v1 = BM_edge_other_vert(e1->e, v);
+	v2 = BM_edge_other_vert(e2->e, v);
+	sub_v3_v3v3(dir1, v->co, v1->co);
+	sub_v3_v3v3(dir2, v->co, v2->co);
+	sub_v3_v3v3(dirco, v->co, co);
+	normalize_v3(dir1);
+	normalize_v3(dir2);
+	normalize_v3(dirco);
+	ang11 = angle_normalized_v3v3(dir1, dir2);
+	ang1co = angle_normalized_v3v3(dir1, dirco);
+	/* angles are in [0,pi]. need to compare cross product with normal to see if they are reflex */
+	cross_v3_v3v3(no, dir1, dir2);
+	if (dot_v3v3(no, f->no) < 0.0f)
+		ang11 = (float)(M_PI * 2.0) - ang11;
+	cross_v3_v3v3(no, dir1, dirco);
+	if (dot_v3v3(no, f->no) < 0.0f)
+		ang1co = (float)(M_PI * 2.0) - ang1co;
+	return (ang11 - ang1co > -BEVEL_EPSILON_BIG);
+}
+
 /*
  * Calculate the meeting point between the offset edges for e1 and e2, putting answer in meetco.
  * e1 and e2 share vertex v and face f (may be NULL) and viewed from the normal side of
  * the bevel vertex,  e1 precedes e2 in CCW order.
+ * Except: if edges_between is true, there are edges between e1 and e2 in CCW order so they
+ * don't share a common face. We want the meeting point to be on an existing face so it
+ * should be dropped onto one of the intermediate faces, if possible.
  * Offset edge is on right of both edges, where e1 enters v and e2 leave it.
  * When offsets are equal, the new point is on the edge bisector, with length offset/sin(angle/2),
  * but if the offsets are not equal (allowing for this, as bevel modifier has edge weights that may
@@ -605,16 +639,27 @@ static bool is_outside_edge(EdgeHalf *e, const float co[3], BMVert **ret_closer_
  * record the change in offset_l (or offset_r); later we can tell that a change has happened because
  * the offset will differ from its original value in offset_l_spec (or offset_r_spec).
  */
-static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, float meetco[3])
+static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, bool edges_between, float meetco[3])
 {
-	float dir1[3], dir2[3], norm_v[3], norm_perp1[3], norm_perp2[3],
-	      off1a[3], off1b[3], off2a[3], off2b[3], isect2[3], ang, d;
+	float dir1[3], dir2[3], dir1n[3], dir2p[3], norm_v[3], norm_v1[3], norm_v2[3],
+		norm_perp1[3], norm_perp2[3], off1a[3], off1b[3], off2a[3], off2b[3],
+		isect2[3], dropco[3], plane[4], ang, d;
 	BMVert *closer_v;
+	EdgeHalf *e, *e1next, *e2prev;
+	BMFace *ff;
+	int isect_kind;
 
 	/* get direction vectors for two offset lines */
 	sub_v3_v3v3(dir1, v->co, BM_edge_other_vert(e1->e, v)->co);
 	sub_v3_v3v3(dir2, BM_edge_other_vert(e2->e, v)->co, v->co);
 
+	if (edges_between) {
+		e1next = e1->next;
+		e2prev = e2->prev;
+		sub_v3_v3v3(dir1n, BM_edge_other_vert(e1next->e, v)->co, v->co);
+		sub_v3_v3v3(dir2p, v->co, BM_edge_other_vert(e2prev->e, v)->co);
+	}
+
 	ang = angle_v3v3(dir1, dir2);
 	if (ang < BEVEL_EPSILON_BIG) {
 		/* special case: e1 and e2 are parallel; put offset point perp to both, from v.
@@ -654,14 +699,31 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, float
 		 * If e1-v-e2 is a reflex angle (viewed from vertex normal side), need to flip.
 		 * Use f->no to figure out which side to look at angle from, as even if
 		 * f is non-planar, will be more accurate than vertex normal */
-		cross_v3_v3v3(norm_v, dir2, dir1);
-		normalize_v3(norm_v);
-		if (dot_v3v3(norm_v, f ? f->no : v->no) < 0.0f)
-			negate_v3(norm_v);
+		if (!edges_between) {
+			cross_v3_v3v3(norm_v1, dir2, dir1);
+			normalize_v3(norm_v1);
+			if (dot_v3v3(norm_v1, f ? f->no : v->no) < 0.0f)
+				negate_v3(norm_v1);
+			copy_v3_v3(norm_v2, norm_v1);
+		}
+		else {
+			/* separate faces; get face norms at corners for each separately */
+			cross_v3_v3v3(norm_v1, dir1n, dir1);
+			normalize_v3(norm_v1);
+			f = e1->fnext;
+			if (dot_v3v3(norm_v1, f ? f->no : v->no) < 0.0f)
+				negate_v3(norm_v1);
+			cross_v3_v3v3(norm_v2, dir2, dir2p);
+			normalize_v3(norm_v2);
+			f = e2->fprev;
+			if (dot_v3v3(norm_v2, f ? f->no : v->no) < 0.0f)
+				negate_v3(norm_v2);
+		}
+
 
 		/* get vectors perp to each edge, perp to norm_v, and pointing into face */
-		cross_v3_v3v3(norm_perp1, dir1, norm_v);
-		cross_v3_v3v3(norm_perp2, dir2, norm_v);
+		cross_v3_v3v3(norm_perp1, dir1, norm_v1);
+		cross_v3_v3v3(norm_perp2, dir2, norm_v2);
 		normalize_v3(norm_perp1);
 		normalize_v3(norm_perp2);
 
@@ -673,11 +735,10 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, float
 		madd_v3_v3fl(off2a, norm_perp2, e2->offset_l);
 		add_v3_v3v3(off2b, off2a, dir2);
 
-		/* intersect the lines; by construction they should be on the same plane and not parallel */
-		if (!isect_line_line_v3(off1a, off1b, off2a, off2b, meetco, isect2)) {
-#ifdef BEVEL_ASSERT_PROJECT
-			BLI_assert(!"offset_meet failure");
-#endif
+		/* intersect the lines */
+		isect_kind = isect_line_line_v3(off1a, off1b, off2a, off2b, meetco, isect2);
+		if (isect_kind == 0) {
+			/* lines are colinear: we already tested for this, but this used a different epsilon */
 			copy_v3_v3(meetco, off1a);  /* just to do something */
 			d = dist_to_line_v3(meetco, v->co, BM_edge_other_vert(e2->e, v)->co);
 			if (fabsf(d - e2->offset_l) > BEVEL_EPSILON)
@@ -697,6 +758,26 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, float
 				copy_v3_v3(meetco, closer_v->co);
 				e1->offset_r = len_v3v3(meetco, v->co);
 			}
+			if (edges_between && e1->offset_r > 0.0 && e2->offset_l > 0.0) {
+				/* Try to drop meetco to a face between e1 and e2 */
+				if (isect_kind == 2) {
+					/* lines didn't meet in 3d: get average of meetco and isect2 */
+					mid_v3_v3v3(meetco, meetco, isect2);
+				}
+				for (e = e1; e != e2; e = e->next) {
+					ff = e->fnext;
+					if (!ff)
+						continue;
+					plane_from_point_normal_v3(plane, v->co, ff->no);
+					closest_to_plane_v3(dropco, plane, meetco);
+					if (point_between_edges(dropco, v, ff, e, e->next)) {
+						copy_v3_v3(meetco, dropco);
+						break;
+					}
+				}
+				e1->offset_r = dist_to_line_v3(meetco, v->co, BM_edge_other_vert(e1->e, v)->co);
+				e2->offset_l = dist_to_line_v3(meetco, v->co, BM_edge_other_vert(e2->e, v)->co);
+			}
 		}
 	}
 }
@@ -799,6 +880,7 @@ static void offset_on_edge_between(
 		e2->offset_l = d;
 }
 
+#ifdef PRE_275_ALGORITHM
 /* Calculate the best place for a meeting point for the offsets from edges e1 and e2
  * when there is an in-between edge emid, and we prefer to have a point that may not
  * be on emid if that does a better job of keeping offsets at the user spec.
@@ -874,6 +956,7 @@ static void offset_in_two_planes(
 		/* else iret == 1 and the lines are coplanar so meetco has the intersection */
 	}
 }
+#endif
 
 /* Offset by e->offset in plane with normal plane_no, on left if left==true,
  * else on right.  If no is NULL, choose an arbitrary plane different
@@ -1425,6 +1508,323 @@ static void set_bound_vert_seams(BevVert *bv)
 	} while ((v = v->next) != bv->vmesh->boundstart);
 }
 
+#ifndef PRE_275_ALGORITHM
+/* Is e between two planes where angle between is 180? */
+static bool eh_on_plane(EdgeHalf *e)
+{
+	float dot;
+
+	if (e->fprev && e->fnext) {
+		dot = dot_v3v3(e->fprev->no, e->fnext->no);
+		if (fabsf(dot) <= BEVEL_EPSILON ||
+			fabsf(dot - 1.0f) <= BEVEL_EPSILON)
+			return true;
+	}
+	return false;
+}
+
+/* Calculate the profiles for all the BoundVerts of VMesh vm */
+static void calculate_vm_profiles(BevelParams *bp, BevVert *bv, VMesh *vm)
+{
+	BoundVert *v;
+
+	v = vm->boundstart;
+	do {
+		set_profile_params(bp, bv, v);
+		calculate_profile(bp, v);
+	} while ((v = v->next) != vm->boundstart);
+}
+
+/* Implements build_boundary for vertex-only case */
+static void build_boundary_vertex_only(BevelParams *bp, BevVert *bv, bool construct)
+{
+	VMesh *vm = bv->vmesh;
+	EdgeHalf *efirst, *e;
+	BoundVert *v;
+	float co[3];
+
+	BLI_assert(bp->vertex_only);
+
+	e = efirst = &bv->edges[0];
+	do {
+		slide_dist(e, bv->v, e->offset_l, co);
+		if (construct) {
+			v = add_new_bound_vert(bp->mem_arena, vm, co);
+			v->efirst = v->elast = e;
+			e->leftv = v;
+		}
+		else {
+			adjust_bound_vert(e->leftv, co);
+		}
+	} while ((e = e->next) != efirst);
+
+	calculate_vm_profiles(bp, bv, vm);
+
+	if (construct) {
+		set_bound_vert_seams(bv);
+		if (vm->count == 2)
+			vm->mesh_kind = M_NONE;
+		else if (bp->seg == 1)
+			vm->mesh_kind = M_POLY;
+		else
+			vm->mesh_kind = M_ADJ;
+	}
+}
+

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list