[Bf-blender-cvs] [561d738eaa2] master: Fix T53459, inconsistent bevel on identical edges.

Howard Trickey noreply at git.blender.org
Mon Jan 29 01:38:45 CET 2018


Commit: 561d738eaa2f64044f5266a480d9bc822bd0296e
Author: Howard Trickey
Date:   Sun Jan 28 19:19:02 2018 -0500
Branches: master
https://developer.blender.org/rB561d738eaa2f64044f5266a480d9bc822bd0296e

Fix T53459, inconsistent bevel on identical edges.

The old algorithm depended on vertex order.
The new one uses a global least squares solution on chains
and cycles of edges where loop slide induces a dependency.

See https://wiki.blender.org/index.php/Dev:Source/Modeling/Bevel
in the "Consistent Widths for Even Bevels" for derivation of
the new algorithm.

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

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 18b2b4db2bf..35167835646 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -44,6 +44,8 @@
 #include "BKE_customdata.h"
 #include "BKE_deform.h"
 
+#include "eigen_capi.h"
+
 #include "bmesh.h"
 #include "bmesh_bevel.h"  /* own include */
 
@@ -58,6 +60,7 @@
 #define BEVEL_SMALL_ANG DEG2RADF(10.0f)
 #define BEVEL_MAX_ADJUST_PCT 10.0f
 #define BEVEL_MAX_AUTO_ADJUST_PCT 300.0f
+#define BEVEL_MATCH_SPEC_WEIGHT 0.2
 
 /* happens far too often, uncomment for development */
 // #define BEVEL_ASSERT_PROJECT
@@ -139,10 +142,14 @@ typedef struct BoundVert {
 	NewVert nv;
 	EdgeHalf *efirst;   /* first of edges attached here: in CCW order */
 	EdgeHalf *elast;
+	EdgeHalf *eon;      /* the "edge between" that this is on, in offset_on_edge_between case */
 	EdgeHalf *ebev;     /* beveled edge whose left side is attached here, if any */
 	int index;          /* used for vmesh indexing */
+	float sinratio;     /* when eon set, ratio of sines of angles to eon edge */
+	struct BoundVert *adjchain; /* adjustment chain or cycle link pointer */
 	Profile profile;    /* edge profile between this and next BoundVert */
 	bool any_seam;      /* are any of the edges attached here seams? */
+	bool visited;       /* used during delta adjust pass */
 //	int _pad;
 } BoundVert;	
 
@@ -192,6 +199,7 @@ typedef struct BevelParams {
 	bool use_weights;       /* bevel amount affected by weights on edges or verts */
 	bool loop_slide;	    /* should bevel prefer to slide along edges rather than keep widths spec? */
 	bool limit_offset;      /* should offsets be limited by collisions? */
+	bool offset_adjust;     /* should offsets be adjusted to try to get even widths? */
 	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 */
@@ -207,6 +215,7 @@ static int bev_debug_flags = 0;
 #define DEBUG_OLD_PROJ_TO_PERP_PLANE (bev_debug_flags & 2)
 #define DEBUG_OLD_FLAT_MID (bev_debug_flags & 4)
 
+
 /* this flag values will get set on geom we want to return in 'out' slots for edges and verts */
 #define EDGE_OUT 4
 #define VERT_OUT 8
@@ -260,6 +269,9 @@ static BoundVert *add_new_bound_vert(MemArena *mem_arena, VMesh *vm, const float
 		vm->boundstart->prev = ans;
 	}
 	ans->profile.super_r = PRO_LINE_R;
+	ans->adjchain = NULL;
+	ans->sinratio = 1.0f;
+	ans->visited = false;
 	vm->count++;
 	return ans;
 }
@@ -342,52 +354,6 @@ static EdgeHalf *find_other_end_edge_half(BevelParams *bp, EdgeHalf *e, BevVert
 	return NULL;
 }
 
-static bool other_edge_half_visited(BevelParams *bp, EdgeHalf *e)
-{
-	BevVert *bvo;
-
-	bvo = find_bevvert(bp, e->is_rev ? e->e->v1 : e->e->v2);
-	if (bvo)
-		return bvo->visited;
-	else
-		return false;
-}
-
-static bool edge_half_offset_changed(EdgeHalf *e)
-{
-	return e->offset_l != e->offset_l_spec ||
-	       e->offset_r != e->offset_r_spec;
-}
-
-static float adjusted_rel_change(float val, float spec)
-{
-	float relchg;
-
-	relchg = 0.0f;
-	if (val != spec) {
-		if (spec == 0)
-			relchg = 1000.0f;  /* arbitrary large value */
-		else
-			relchg = fabsf((val - spec) / spec);
-	}
-	return relchg;
-}
-
-static float max_edge_half_offset_rel_change(BevVert *bv)
-{
-	int i;
-	float max_rel_change;
-	EdgeHalf *e;
-
-	max_rel_change = 0.0f;
-	for (i = 0; i < bv->edgecount; i++) {
-		e = &bv->edges[i];
-		max_rel_change = max_ff(max_rel_change, adjusted_rel_change(e->offset_l, e->offset_l_spec));
-		max_rel_change = max_ff(max_rel_change, adjusted_rel_change(e->offset_r, e->offset_r_spec));
-	}
-	return max_rel_change;
-}
-
 /* Return the next EdgeHalf after from_e that is beveled.
  * If from_e is NULL, find the first beveled edge. */
 static EdgeHalf *next_bev(BevVert *bv, EdgeHalf *from_e)
@@ -818,10 +784,6 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, bool e
 		copy_v3_v3(off1a, v->co);
 		d = max_ff(e1->offset_r, e2->offset_l);
 		madd_v3_v3fl(off1a, norm_perp1, d);
-		if (e1->offset_r != d)
-			e1->offset_r = d;
-		else if (e2->offset_l != d)
-			e2->offset_l = d;
 		copy_v3_v3(meetco, off1a);
 	}
 	else if (fabsf(ang - (float)M_PI) < BEVEL_EPSILON_ANG) {
@@ -830,10 +792,6 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, bool e
 		 * common line, at offset distance from v. */
 		d = max_ff(e1->offset_r, e2->offset_l);
 		slide_dist(e2, v, d, meetco);
-		if (e1->offset_r != d)
-			e1->offset_r = d;
-		else if (e2->offset_l != d)
-			e2->offset_l = d;
 	}
 	else {
 		/* Get normal to plane where meet point should be,
@@ -871,7 +829,6 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, bool e
 				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_v1);
 		cross_v3_v3v3(norm_perp2, dir2, norm_v2);
@@ -891,9 +848,6 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, bool e
 		if (isect_kind == 0) {
 			/* lines are collinear: 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)
-				e2->offset_l = d;
 		}
 		else {
 			/* The lines intersect, but is it at a reasonable place?
@@ -903,11 +857,9 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, bool e
 			 * or if the offset amount is > the edge length*/
 			if (e1->offset_r == 0.0f && is_outside_edge(e1, meetco, &closer_v)) {
 				copy_v3_v3(meetco, closer_v->co);
-				e2->offset_l = len_v3v3(meetco, v->co);
 			}
 			if (e2->offset_l == 0.0f && is_outside_edge(e2, meetco, &closer_v)) {
 				copy_v3_v3(meetco, closer_v->co);
-				e1->offset_r = len_v3v3(meetco, v->co);
 			}
 			if (edges_between && e1->offset_r > 0.0f && e2->offset_l > 0.0f) {
 				/* Try to drop meetco to a face between e1 and e2 */
@@ -926,8 +878,6 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, bool e
 						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);
 			}
 		}
 	}
@@ -994,40 +944,27 @@ static bool good_offset_on_edge_between(EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *em
 /* Calculate the best place for a meeting point for the offsets from edges e1 and e2
  * on the in-between edge emid.  Viewed from the vertex normal side, the CCW
  * order of these edges is e1, emid, e2.
- * The offsets probably do not meet at a common point on emid, so need to pick
- * one that causes the least problems. If the other end of one of e1 or e2 has been visited
- * already, prefer to keep the offset the same on this end.
- * Otherwise, pick a point between the two intersection points on emid that minimizes
- * the sum of squares of errors from desired offset. */
-static void offset_on_edge_between(
-        BevelParams *bp, EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *emid,
-        BMVert *v, float meetco[3])
+ * Return true if we placed meetco as compromise between where two edges met.
+ * If we did, put ration of sines of angles in *r_sinratio too */
+static bool offset_on_edge_between(
+        EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *emid,
+        BMVert *v, float meetco[3], float *r_sinratio)
 {
-	float d, ang1, ang2, sina1, sina2, lambda;
+	float ang1, ang2;
 	float meet1[3], meet2[3];
-	bool visited1, visited2, ok1, ok2;
+	bool ok1, ok2;
+	bool retval = false;
 
 	BLI_assert(e1->is_bev && e2->is_bev && !emid->is_bev);
 
-	visited1 = other_edge_half_visited(bp, e1);
-	visited2 = other_edge_half_visited(bp, e2);
-
 	ok1 = offset_meet_edge(e1, emid, v, meet1, &ang1);
 	ok2 = offset_meet_edge(emid, e2, v, meet2, &ang2);
 	if (ok1 && ok2) {
-		if (visited1 && !visited2) {
-			copy_v3_v3(meetco, meet1);
-		}
-		else if (!visited1 && visited2) {
-			copy_v3_v3(meetco, meet2);
-		}
-		else {
-			/* find best compromise meet point */
-			sina1 = sinf(ang1);
-			sina2 = sinf(ang2);
-			lambda = sina2 * sina2 / (sina1 * sina1 + sina2 * sina2);
-			interp_v3_v3v3(meetco, meet1, meet2, lambda);
-		}
+		mid_v3_v3v3(meetco, meet1, meet2);
+		if (r_sinratio)
+			/* ang1 should not be 0, but be paranoid */
+			*r_sinratio = (ang1 == 0.0f) ? 1.0f : sinf(ang2) / sinf(ang1);
+		retval = true;
 	}
 	else if (ok1 && !ok2) {
 		copy_v3_v3(meetco, meet1);
@@ -1041,13 +978,7 @@ static void offset_on_edge_between(
 		slide_dist(emid, v, e1->offset_r, meetco);
 	}
 
-	/* offsets may have changed now */
-	d = dist_to_line_v3(meetco, v->co, BM_edge_other_vert(e1->e, v)->co);
-	if (fabsf(d - e1->offset_r) > BEVEL_EPSILON)
-		e1->offset_r = d;
-	d = dist_to_line_v3(meetco, v->co, BM_edge_other_vert(e2->e, v)->co);
-	if (fabsf(d - e2->offset_l) > BEVEL_EPSILON)
-		e2->offset_l = d;
+	return retval;
 }
 
 /* Offset by e->offset in plane with normal plane_no, on left if left==true,
@@ -1806,6 +1737,7 @@ static void build_boundary_terminal_edge(BevelParams *bp, BevVert *bv, EdgeHalf
 	}
 }
 
+#if 0
 /* Return a value that is v if v is within BEVEL_MAX_ADJUST_PCT of the spec (assumed positive),
  * else clamp to make it at most that far away from spec */
 static float clamp_adjust(float v, float spec)
@@ -1819,6 +1751,7 @@ static float clamp_adjust(float v, float spec)
 	else
 		return v;
 }
+#endif
 
 /* Make a circular list of BoundVerts for bv, each of which has the coordinates
  * of a vertex on the boundary of the beveled vertex bv->v.
@@ -1835,11 +1768,10 @@ static float clamp_adjust(float v, float spec)
 static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
 {
 	MemArena *mem_arena = bp->mem_arena;
-	EdgeHalf *efirst, *e, *e2, *e3, *enip, *eip, *eother;
+	EdgeHalf *efirst, *e, *e2, *e3, *enip, *eip, *eon;
 	BoundVert *v;
-	BevVert *bvother;
 	VMesh *vm;
-	float co[3];
+	float co[3], r;
 	int nip, nnip;
 
 	/* Current bevel 

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list