Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHoward Trickey <howard.trickey@gmail.com>2012-12-03 05:46:37 +0400
committerHoward Trickey <howard.trickey@gmail.com>2012-12-03 05:46:37 +0400
commit11e87d118ee157537fb3f107227563c279ffaea6 (patch)
treeadf5eff7e01fcb4f546bf6c5ecad3220bebf253c /source/blender/bmesh/tools
parent4e7a4960f701ffef5665872e0e6ace6bb25e68a9 (diff)
Bevel: fix for bulging part of bug 33280.
Bulging still happens, but fixed the cases where it was obvious because it destroys an otherwise straight 'pipe' by snapping the vertex mesh points to that pipe.
Diffstat (limited to 'source/blender/bmesh/tools')
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.c241
1 files changed, 126 insertions, 115 deletions
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index b52525c1780..aafba124c92 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -571,100 +571,11 @@ static void get_point_on_round_edge(const float uv[2],
#else /* USE_ALTERNATE_ADJ */
-#ifdef OLD_ROUND_EDGE
-/*
- * calculation of points on the round profile
- * r - result, coordinate of point on round profile
- * method:
- * Inscribe a circle in angle va - v -vb
- * such that it touches the arms at offset from v.
- * Rotate the center-va segment by (i/n) of the
- * angle va - center -vb, and put the endpoint
- * of that segment in r.
- */
-static void get_point_on_round_profile(float r_co[3], float offset, int k, int count,
- const float va[3], const float v[3], const float vb[3])
-{
- float vva[3], vvb[3], angle, center[3], rv[3], axis[3], co[3];
-
- sub_v3_v3v3(vva, va, v);
- sub_v3_v3v3(vvb, vb, v);
- normalize_v3(vva);
- normalize_v3(vvb);
- angle = angle_normalized_v3v3(vva, vvb);
-
- add_v3_v3v3(center, vva, vvb);
- normalize_v3(center);
- mul_v3_fl(center, offset * (1.0f / cosf(0.5f * angle)));
- add_v3_v3(center, v); /* coordinates of the center of the inscribed circle */
-
-
- sub_v3_v3v3(rv, va, center); /* radius vector */
-
-
- sub_v3_v3v3(co, v, center);
- cross_v3_v3v3(axis, rv, co); /* calculate axis */
-
- sub_v3_v3v3(vva, va, center);
- sub_v3_v3v3(vvb, vb, center);
- angle = angle_v3v3(vva, vvb);
-
- rotate_v3_v3v3fl(co, rv, axis, angle * (float)k / (float)count);
-
- add_v3_v3(co, center);
- copy_v3_v3(r_co, co);
-}
-
-/*
- * Find the point (/n) of the way around the round profile for e,
- * where start point is va, midarc point is vmid, and end point is vb.
- * Return the answer in profileco.
- * Method:
- * Adjust va and vb (along edge direction) so that they are perpendicular
- * to edge at v, then use get_point_on_round_profile, then project
- * back onto original va - vmid - vb plane.
- * If va, vmid, and vb are all on the same plane, just interpolate between va and vb.
- */
-static void get_point_on_round_edge(EdgeHalf *e, int k,
- const float va[3], const float vmid[3], const float vb[3],
- float r_co[3])
-{
- float vva[3], vvb[3], point[3], dir[3], vaadj[3], vbadj[3], p2[3], pn[3];
- int n = e->seg;
-
- sub_v3_v3v3(vva, va, vmid);
- sub_v3_v3v3(vvb, vb, vmid);
- if (e->is_rev)
- sub_v3_v3v3(dir, e->e->v1->co, e->e->v2->co);
- else
- sub_v3_v3v3(dir, e->e->v2->co, e->e->v1->co);
- normalize_v3(dir);
- if (fabsf(angle_v3v3(vva, vvb) - (float)M_PI) > 100.f *(float)BEVEL_EPSILON) {
- copy_v3_v3(vaadj, va);
- madd_v3_v3fl(vaadj, dir, -len_v3(vva) * cosf(angle_v3v3(vva, dir)));
- copy_v3_v3(vbadj, vb);
- madd_v3_v3fl(vbadj, dir, -len_v3(vvb) * cosf(angle_v3v3(vvb, dir)));
-
- get_point_on_round_profile(point, e->offset, k, n, vaadj, vmid, vbadj);
-
- add_v3_v3v3(p2, point, dir);
- cross_v3_v3v3(pn, vva, vvb);
- if (!isect_line_plane_v3(r_co, point, p2, vmid, pn, 0)) {
- /* TODO: track down why this sometimes fails */
- copy_v3_v3(r_co, point);
- }
- }
- else {
- /* planar case */
- interp_v3_v3v3(r_co, va, vb, (float)k / (float)n);
- }
-}
-#else
-
-/*
- * Find the point (/n) of the way around the round profile for e,
- * where start point is va, midarc point is vmid, and end point is vb.
- * Return the answer in profileco.
+/* Fill matrix r_mat so that a point in the sheared parallelogram with corners
+ * va, vmid, vb (and the 4th that is implied by it being a parallelogram)
+ * is transformed to the unit square by multiplication with r_mat.
+ * If it can't be done because the parallelogram is degenerate, return FALSE
+ * else return TRUE.
* Method:
* Find vo, the origin of the parallelogram with other three points va, vmid, vb.
* Also find vd, which is in direction normal to parallelogram and 1 unit away
@@ -676,16 +587,14 @@ static void get_point_on_round_edge(EdgeHalf *e, int k,
* (1,1,0) -> vmid
* (1,0,0) -> vb
* (0,1,1) -> vd
- * However if va -- vmid -- vb is approximately a straight line, just
- * interpolate along the line.
- */
-static void get_point_on_round_edge(EdgeHalf *e, int k,
- const float va[3], const float vmid[3], const float vb[3],
- float r_co[3])
+ * We want M to make M*A=B where A has the left side above, as columns
+ * and B has the right side as columns - both extended into homogeneous coords.
+ * So M = B*(Ainverse). Doing Ainverse by hand gives the code below.
+*/
+static int make_unit_square_map(const float va[3], const float vmid[3], const float vb[3],
+ float r_mat[4][4])
{
- float vo[3], vd[3], vb_vmid[3], va_vmid[3], vddir[3], p[3], angle;
- float m[4][4] = MAT4_UNITY;
- int n = e->seg;
+ float vo[3], vd[3], vb_vmid[3], va_vmid[3], vddir[3];
sub_v3_v3v3(va_vmid, vmid, va);
sub_v3_v3v3(vb_vmid, vmid, vb);
@@ -698,15 +607,41 @@ static void get_point_on_round_edge(EdgeHalf *e, int k,
/* The cols of m are: {vmid - va, vmid - vb, vmid + vd - va -vb, va + vb - vmid;
* blender transform matrices are stored such that m[i][*] is ith column;
* the last elements of each col remain as they are in unity matrix */
- sub_v3_v3v3(&m[0][0], vmid, va);
- sub_v3_v3v3(&m[1][0], vmid, vb);
- add_v3_v3v3(&m[2][0], vmid, vd);
- sub_v3_v3(&m[2][0], va);
- sub_v3_v3(&m[2][0], vb);
- add_v3_v3v3(&m[3][0], va, vb);
- sub_v3_v3(&m[3][0], vmid);
-
- /* Now find point k/(e->seg) along quarter circle from (0,1,0) to (1,0,0) */
+ sub_v3_v3v3(&r_mat[0][0], vmid, va);
+ r_mat[0][3] = 0.0f;
+ sub_v3_v3v3(&r_mat[1][0], vmid, vb);
+ r_mat[1][3] = 0.0f;
+ add_v3_v3v3(&r_mat[2][0], vmid, vd);
+ sub_v3_v3(&r_mat[2][0], va);
+ sub_v3_v3(&r_mat[2][0], vb);
+ r_mat[2][3] = 0.0f;
+ add_v3_v3v3(&r_mat[3][0], va, vb);
+ sub_v3_v3(&r_mat[3][0], vmid);
+ r_mat[3][3] = 1.0f;
+
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+/*
+ * Find the point (/n) of the way around the round profile for e,
+ * where start point is va, midarc point is vmid, and end point is vb.
+ * Return the answer in profileco.
+ * If va -- vmid -- vb is approximately a straight line, just
+ * interpolate along the line.
+ */
+static void get_point_on_round_edge(EdgeHalf *e, int k,
+ const float va[3], const float vmid[3], const float vb[3],
+ float r_co[3])
+{
+ float p[3], angle;
+ float m[4][4];
+ int n = e->seg;
+
+ if (make_unit_square_map(va, vmid, vb, m)) {
+ /* Find point k/(e->seg) along quarter circle from (0,1,0) to (1,0,0) */
angle = (float)M_PI * (float)k / (2.0f * (float)n); /* angle from y axis */
p[0] = sinf(angle);
p[1] = cosf(angle);
@@ -714,11 +649,47 @@ static void get_point_on_round_edge(EdgeHalf *e, int k,
mul_v3_m4v3(r_co, m, p);
}
else {
- /* planar case */
+ /* degenerate case: profile is a line */
interp_v3_v3v3(r_co, va, vb, (float)k / (float)n);
}
}
-#endif /* ! OLD_ROUND_EDGE */
+
+/* Calculate a snapped point to the transformed profile of edge e, extended as
+ * in a cylinder-like surface in the direction of e.
+ * co is the point to snap and is modified in place.
+ * va and vb are the limits of the profile (with peak on e). */
+static void snap_to_edge_profile(EdgeHalf *e, const float va[3], const float vb[3],
+ float co[3])
+{
+ float m[4][4], minv[4][4];
+ float edir[3], va0[3], vb0[3], vmid0[3], p[3], snap[3];
+
+ sub_v3_v3v3(edir, e->e->v1->co, e->e->v2->co);
+ normalize_v3(edir);
+
+ /* project va and vb onto plane P, with normal edir and containing co */
+ closest_to_plane_v3(va0, co, edir, va);
+ closest_to_plane_v3(vb0, co, edir, vb);
+ project_to_edge(e->e, va0, vb0, vmid0);
+ if (make_unit_square_map(va0, vmid0, vb0, m)) {
+ /* Transform co and project it onto the unit circle.
+ * Projecting is in fact just normalizing the transformed co */
+ if (!invert_m4_m4(minv, m)) {
+ /* shouldn't happen, by angle test and construction of vd */
+ BLI_assert(!"failed inverse during profile snap");
+ return;
+ }
+ mul_v3_m4v3(p, minv, co);
+ normalize_v3(p);
+ 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);
+ }
+}
#endif /* !USE_ALTERNATE_ADJ */
@@ -860,9 +831,11 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv)
VMesh *vm = bv->vmesh;
BoundVert *v, *vprev, *vnext;
NewVert *nv, *nvprev, *nvnext;
+ EdgeHalf *e1, *e2, *epipe;
BMVert *bmv, *bmv1, *bmv2, *bmv3, *bmv4;
BMFace *f;
- float co[3], coa[3], cob[3], midco[3];
+ float co[3], coa[3], cob[3], midco[3], dir1[3], dir2[3];
+ float va_pipe[3], vb_pipe[3];
#ifdef USE_ALTERNATE_ADJ
/* ordered as follows (orig, prev, center, next)*/
@@ -882,6 +855,27 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv)
ns2 = ns / 2;
BLI_assert(n > 2 && ns > 1);
(void)n;
+
+ /* special case: two beveled edges are in line and share a face, making a "pipe" */
+ 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) {
+ 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 * (float)BEVEL_EPSILON &&
+ (e1->fnext == e2->fprev || e1->fprev == e2->fnext)) {
+ epipe = e1;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
/* Make initial rings, going between points on neighbors.
* After this loop, will have coords for all (i, r, k) where
* BoundVert for i has a bevel, 0 <= r <= ns2, 0 <= k <= ns */
@@ -952,6 +946,12 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv)
get_point_on_round_edge(v->ebev, k, coa, midco, cob, co);
copy_v3_v3(mesh_vert(vm, i, ring, k)->co, co);
}
+
+ if (v->ebev == epipe) {
+ /* save profile extremes for later snapping */
+ copy_v3_v3(va_pipe, mesh_vert(vm, i, 0, 0)->co);
+ copy_v3_v3(vb_pipe, mesh_vert(vm, i, 0, ns)->co);
+ }
#endif
}
} while ((v = v->next) != vm->boundstart);
@@ -977,6 +977,9 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv)
nv = mesh_vert(vm, i, ring, k);
nvprev = mesh_vert(vm, vprev->index, k, ns - ring);
mid_v3_v3v3(co, nv->co, nvprev->co);
+ if (epipe)
+ snap_to_edge_profile(epipe, va_pipe, vb_pipe, co);
+
#ifndef USE_ALTERNATE_ADJ
copy_v3_v3(nv->co, co);
#endif
@@ -1026,6 +1029,8 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv)
nvnext = mesh_vert(vm, vnext->index, ns2, k);
if (vprev->ebev && vnext->ebev) {
mid_v3_v3v3v3(co, nvprev->co, nv->co, nvnext->co);
+ if (epipe)
+ snap_to_edge_profile(epipe, va_pipe, vb_pipe, co);
#ifndef USE_ALTERNATE_ADJ
copy_v3_v3(nv->co, co);
#endif
@@ -1036,6 +1041,8 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv)
}
else if (vprev->ebev) {
mid_v3_v3v3(co, nvprev->co, nv->co);
+ if (epipe)
+ snap_to_edge_profile(epipe, va_pipe, vb_pipe, co);
#ifndef USE_ALTERNATE_ADJ
copy_v3_v3(nv->co, co);
#endif
@@ -1046,6 +1053,8 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv)
}
else if (vnext->ebev) {
mid_v3_v3v3(co, nv->co, nvnext->co);
+ if (epipe)
+ snap_to_edge_profile(epipe, va_pipe, vb_pipe, co);
#ifndef USE_ALTERNATE_ADJ
copy_v3_v3(nv->co, co);
#endif
@@ -1073,6 +1082,8 @@ static void bevel_build_rings(BMesh *bm, BevVert *bv)
}
} while ((v = v->next) != vm->boundstart);
mul_v3_fl(midco, 1.0f / nn);
+ if (epipe)
+ snap_to_edge_profile(epipe, va_pipe, vb_pipe, midco);
bmv = BM_vert_create(bm, midco, NULL, 0);
v = vm->boundstart;
do {