[Bf-blender-cvs] [39202a5] master: Bevel: fix glitch in "pipe" case with square profile.

Howard Trickey noreply at git.blender.org
Tue Jan 28 19:25:36 CET 2014


Commit: 39202a53b559debb5ce1413c08f131173515c3cd
Author: Howard Trickey
Date:   Tue Jan 28 13:18:43 2014 -0500
https://developer.blender.org/rB39202a53b559debb5ce1413c08f131173515c3cd

Bevel: fix glitch in "pipe" case with square profile.

The "pipe" case -- where two beveled edges are in line
and there is at least one more beveled edge -- needed better
handling when profile parameter = 1.0 (square outward).

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

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 39e43db..460e3f4 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -1240,10 +1240,11 @@ static void calculate_profile(BevelParams *bp, BoundVert *bndv)
 	}
 }
 
-/* Snap a direction co to a superellipsoid with parameter super_r */
-static void snap_to_superellipsoid(float co[3], const float super_r)
+/* Snap a direction co to a superellipsoid with parameter super_r.
+ * For square profiles, midline says whether or not to snap to both planes. */
+static void snap_to_superellipsoid(float co[3], const float super_r, bool midline)
 {
-	float a, b, c, x, y, z, r, rinv;
+	float a, b, c, x, y, z, r, rinv, dx, dy;
 
 	r = super_r;
 	if (r == PRO_CIRCLE_R) {
@@ -1254,64 +1255,62 @@ static void snap_to_superellipsoid(float co[3], const float super_r)
 	x = a = max_ff(0.0f, co[0]);
 	y = b = max_ff(0.0f, co[1]);
 	z = c = max_ff(0.0f, co[2]);
-	if (r <= 0.0f)
-		r = 0.1f;
-	rinv = 1.0f / r;
-	if (a == 0.0f) {
-		if (b == 0.0f) {
-			x = 0.0f;
-			y = 0.0f;
-			z = powf(c, rinv);
+	if (r == PRO_SQUARE_R || r == PRO_SQUARE_IN_R) {
+		/* will only be called for 2d profile */
+		BLI_assert(fabsf(z) < BEVEL_EPSILON);
+		z = 0.0f;
+		x = min_ff(1.0f, x);
+		y = min_ff(1.0f, y);
+		if (r == PRO_SQUARE_R) {
+			/* snap to closer of x==1 and y==1 lines, or maybe both */
+			dx = 1.0f - x;
+			dy = 1.0f - y;
+			if (dx < dy) {
+				x = 1.0f;
+				y = midline ? 1.0f : y;
+			}
+			else {
+				y = 1.0f;
+				x = midline ? 1.0f : x;
+			}
 		}
 		else {
-			x = 0.0f;
-			y = powf(1.0f / (1.0f + powf(c / b, r)), rinv);
-			z = c * y / b;
+			/* snap to closer of x==0 and y==0 lines, or maybe both */
+			if (x < y) {
+				x = 0.0f;
+				y = midline ? 0.0f : y;
+			}
+			else {
+				y = 0.0f;
+				x = midline ? 0.0f : x;
+			}
 		}
 	}
 	else {
-		x = powf(1.0f / (1.0f + powf(b / a, r) + powf(c / a, r)), rinv);
-		y = b * x / a;
-		z = c * x / a;
+		rinv = 1.0f / r;
+		if (a == 0.0f) {
+			if (b == 0.0f) {
+				x = 0.0f;
+				y = 0.0f;
+				z = powf(c, rinv);
+			}
+			else {
+				x = 0.0f;
+				y = powf(1.0f / (1.0f + powf(c / b, r)), rinv);
+				z = c * y / b;
+			}
+		}
+		else {
+			x = powf(1.0f / (1.0f + powf(b / a, r) + powf(c / a, r)), rinv);
+			y = b * x / a;
+			z = c * x / a;
+		}
 	}
 	co[0] = x;
 	co[1] = y;
 	co[2] = z;
 }
 
-static void snap_to_profile(BoundVert *bndv, EdgeHalf *e, float co[3])
-{
-	float va[3], vb[3], edir[3], va0[3], vb0[3], vmid0[3];
-	float plane[4], m[4][4], minv[4][4], p[3], snap[3];
-
-	copy_v3_v3(va, bndv->nv.co);
-	copy_v3_v3(vb, bndv->next->nv.co);
-
-	sub_v3_v3v3(edir, e->e->v1->co, e->e->v2->co);
-
-	plane_from_point_normal_v3(plane, co, edir);
-	closest_to_plane_v3(va0, plane, va);
-	closest_to_plane_v3(vb0, plane, vb);
-	closest_to_plane_v3(vmid0, plane, bndv->profile.midco);
-	if (make_unit_square_map(va0, vmid0, vb0, m)) {
-		/* Transform co and project it onto superellipse */
-		if (!invert_m4_m4(minv, m)) {
-			/* shouldn't happen */
-			BLI_assert(!"failed inverse during profile snap");
-			return;
-		}
-		mul_v3_m4v3(p, minv, co);
-		snap_to_superellipsoid(p, bndv->profile.super_r);
-		mul_v3_m4v3(snap, m, p);
-		copy_v3_v3(co, snap);
-	}
-	else {
-		/* planar case: just snap to line va--vb */
-		closest_to_line_segment_v3(p, co, va, vb);
-		copy_v3_v3(co, p);
-	}
-}
-
 /* Set the any_seam property for a BevVert and all its BoundVerts */
 static void set_bound_vert_seams(BevVert *bv)
 {
@@ -1640,33 +1639,52 @@ static void adjust_offsets(BevelParams *bp)
 }
 
 /* Do the edges at bv form a "pipe"?
- * Current definition: at least three beveled edges,
- * two in line, and sharing a face. */
-static EdgeHalf *pipe_test(BevVert *bv)
-{
-	EdgeHalf *e1, *e2, *epipe;
+ * Current definition: 3 or 4 beveled edges, 2 in line with each other,
+ * with other edges on opposite sides of the pipe if there are 4.
+ * Also, the vertex boundary should have 3 or 4 vertices in it,
+ * and all of the faces involved should be parallel to the pipe edges.
+ * Return the boundary vert whose ebev is one of the pipe edges, and
+ * whose next boundary vert has a beveled, non-pipe edge. */
+static BoundVert *pipe_test(BevVert *bv)
+{
+	EdgeHalf *e, *epipe;
+	VMesh *vm;
+	BoundVert *v1, *v2, *v3;
+	float dir1[3], dir3[3];
+
+	vm = bv->vmesh;
+	if (vm->count < 3 || vm->count > 4 || bv->selcount < 3 || bv->selcount > 4)
+		return NULL;
 
+	/* find v1, v2, v3 all with beveled edges, where v1 and v3 have collinear edges */
 	epipe = NULL;
-	if (bv->selcount > 2) {
-		for (e1 = &bv->edges[0]; epipe == NULL && e1 != &bv->edges[bv->edgecount]; e1++) {
-			if (e1->is_bev) {
-				for (e2 = &bv->edges[0]; e2 != &bv->edges[bv->edgecount]; e2++) {
-					if (e1 != e2 && e2->is_bev) {
-						if ((e1->fnext == e2->fprev) || (e1->fprev == e2->fnext)) {
-							float dir1[3], dir2[3];
-							sub_v3_v3v3(dir1, bv->v->co, BM_edge_other_vert(e1->e, bv->v)->co);
-							sub_v3_v3v3(dir2, BM_edge_other_vert(e2->e, bv->v)->co, bv->v->co);
-							if (angle_v3v3(dir1, dir2) < 100.0f * BEVEL_EPSILON) {
-								epipe = e1;
-								break;
-							}
-						}
-					}
-				}
+	v1 = vm->boundstart;
+	do {
+		v2 = v1->next;
+		v3 = v2->next;
+		if (v1->ebev && v2->ebev && v3->ebev) {
+			sub_v3_v3v3(dir1, bv->v->co, BM_edge_other_vert(v1->ebev->e, bv->v)->co);
+			sub_v3_v3v3(dir3, BM_edge_other_vert(v3->ebev->e, bv->v)->co, bv->v->co);
+			normalize_v3(dir1);
+			normalize_v3(dir3);
+			if (angle_v3v3(dir1, dir3) < 100.0f * BEVEL_EPSILON) {
+				epipe =  v1->ebev;
+				break;
 			}
 		}
+	} while ((v1 = v1->next) != vm->boundstart);
+
+	if (!epipe)
+		return NULL;
+
+	/* check face planes: all should have normals perpendicular to epipe */
+	for (e = &bv->edges[0]; e != &bv->edges[bv->edgecount]; e++) {
+		if (e->fnext) {
+			if (dot_v3v3(dir1, e->fnext->no) > BEVEL_EPSILON)
+				return FALSE;
+		}
 	}
-	return epipe;
+	return v1;
 }
 
 static VMesh *new_adj_vmesh(MemArena *mem_arena, int count, int seg, BoundVert *bounds)
@@ -2214,7 +2232,7 @@ static VMesh *make_cube_corner_adj_vmesh(BevelParams *bp)
 	for (i = 0; i < 3; i++) {
 		for (j = 0; j <= ns2; j++) {
 			for (k = 0; k <= nseg; k++) {
-				snap_to_superellipsoid(mesh_vert(vm1, i, j, k)->co, r);
+				snap_to_superellipsoid(mesh_vert(vm1, i, j, k)->co, r, false);
 			}
 		}
 	}
@@ -2344,11 +2362,55 @@ static VMesh *adj_vmesh(BevelParams *bp, BevVert *bv)
 	return vm1;
 }
 
-static VMesh *pipe_adj_vmesh(BevelParams *bp, BevVert *bv, EdgeHalf *epipe)
+/* Snap co to the closest point on the profile for vpipe projected onto the plane
+ * containing co with normal in the direction of edge vpipe->ebev.
+ * For the square profiles, need to decide whether to snap to just one plane
+ * or to the midpoint of the profile; do so if midline is true. */
+static void snap_to_pipe_profile(BoundVert *vpipe, bool midline, float co[3])
+{
+	float va[3], vb[3], edir[3], va0[3], vb0[3], vmid0[3];
+	float plane[4], m[4][4], minv[4][4], p[3], snap[3];
+	Profile *pro = &vpipe->profile;
+	EdgeHalf *e = vpipe->ebev;
+
+	copy_v3_v3(va, pro->coa);
+	copy_v3_v3(vb, pro->cob);
+
+	sub_v3_v3v3(edir, e->e->v1->co, e->e->v2->co);
+
+	plane_from_point_normal_v3(plane, co, edir);
+	closest_to_plane_v3(va0, plane, va);
+	closest_to_plane_v3(vb0, plane, vb);
+	closest_to_plane_v3(vmid0, plane, pro->midco);
+	if (make_unit_square_map(va0, vmid0, vb0, m)) {
+		/* Transform co and project it onto superellipse */
+		if (!invert_m4_m4(minv, m)) {
+			/* shouldn't happen */
+			BLI_assert(!"failed inverse during pipe profile snap");
+			return;
+		}
+		mul_v3_m4v3(p, minv, co);
+		snap_to_superellipsoid(p, pro->super_r, midline);
+		mul_v3_m4v3(snap, m, p);
+		copy_v3_v3(co, snap);
+	}
+	else {
+		/* planar case: just snap to line va0--vb0 */
+		closest_to_line_segment_v3(p, co, va0, vb0);
+		copy_v3_v3(co, p);
+	}
+}
+
+/* See pipe_test for conditions that make 'pipe'; vpipe is the return value from that.
+ * We want to make an ADJ mesh but then snap the vertices to the profile in a plane
+ * perpendicular to the pipes.
+ * A tricky case is for the 'square' profiles and an even nseg: we want certain vertices
+ * to snap to the midline on the pipe, not just to one plane or the other. */
+static VMesh *pipe_adj_vmesh(BevelParams *bp, BevVert *bv, BoundVert *vpipe)
 {
-	int i, j, k, n, ns, ns2;
+	int i, j, k, n, ns, ns2, ipipe1, ipipe2;
 	VMesh *vm;
-	BoundVert *bndv;
+	bool even, midline;
 
 	vm = adj_vmesh(bp, bv);
 
@@ -2356,18 +2418,17 @@ static VMesh *pipe_adj_vmesh(BevelParams *bp, BevVert *bv, EdgeHalf *epipe)
 	n = bv->vmesh->count;
 	ns = bv->vmesh->seg;
 	ns2 = ns / 2;
-	bndv = vm->boundstart;
-	for (i = 0; i < n; i++) {
-		if (bndv->ebev == epipe)
-			break;
-		bndv = bndv->next;
-	}
+	even = (ns % 2) == 0;
+	ipipe1 = vpipe->index;
+	ipipe2 = vpipe->next->next->index;
 	for (i = 0; i < n; i++) {
 		for (j = 1; j <= ns2; j++) {
 			for (k = 0; k <= ns2; k++) {
 				if (!is_canon(vm, i, j, k))
 					continue;
-				snap_to_profile(bndv, epipe, mesh_vert(vm, i, j, k)->co);
+				midline = even && k == ns2 &&
+				          ((i == 0 && j == ns2) || (i == ipipe1 || i == ipipe2));
+				snap_to_pipe_profile(vpipe, midline, mesh_vert(vm, i, j, k)->co);
 			}
 		}
 	}
@@ -2386,7 +2447,7 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv)
 	BoundVert *v;
 	BMVert *bmv1, *bmv2, *bmv3, *bmv4;
 	BMFace *f, *f2, *f23;
-	EdgeHalf *epipe;
+	BoundVert *vpipe;
 
 	n = bv->vmesh->count;
 	ns = bv->vmesh->seg;
@@ -2394,10 +2455,10 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv)
 	odd = ns % 2;
 	BLI_assert(n >= 3 && ns > 1);
 
-	epipe = pipe_test(bv);
+	vpipe = pipe_test(bv);
 
-	if (epipe)
-		vm1 = pipe_adj_vmesh(bp, bv, epipe);
+	if (vpipe)
+		vm1 = pipe_adj_vmesh(bp, bv, vpipe);
 	else if (tri_corner_test(bp, bv))
 		vm1 = tri_corner_adj_vmesh(bp, bv);
 	else




More information about the Bf-blender-cvs mailing list