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
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.c159
1 files changed, 106 insertions, 53 deletions
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index 7293e400951..a1f08583e2c 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -133,6 +133,7 @@ typedef struct BevelParams {
int seg; /* number of segments in beveled edge profile */
bool vertex_only; /* bevel vertices only */
bool use_weights; /* bevel amount affected by weights on edges or verts */
+ bool preserve_widths; /* should bevel prefer widths over angles, if forced to choose? */
const struct MDeformVert *dvert; /* vertex group array, maybe set if vertex_only */
int vertex_group; /* vertex group index, maybe set if vertex_only */
} BevelParams;
@@ -208,6 +209,28 @@ static EdgeHalf *find_edge_half(BevVert *bv, BMEdge *bme)
return NULL;
}
+/* find the BevVert corresponding to BMVert bmv */
+static BevVert *find_bevvert(BevelParams *bp, BMVert *bmv)
+{
+ return BLI_ghash_lookup(bp->vert_hash, bmv);
+}
+
+/* Find the EdgeHalf representing the other end of e->e.
+ * That may not have been constructed yet, in which case return NULL. */
+static EdgeHalf *find_other_end_edge_half(BevelParams *bp, EdgeHalf *e)
+{
+ BevVert *bvother;
+ EdgeHalf *eother;
+
+ bvother = find_bevvert(bp, e->is_rev ? e->e->v1 : e->e->v2);
+ if (bvother) {
+ eother = find_edge_half(bvother, e->e);
+ BLI_assert(eother != NULL);
+ return eother;
+ }
+ return NULL;
+}
+
/* 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)
@@ -225,12 +248,6 @@ static EdgeHalf *next_bev(BevVert *bv, EdgeHalf *from_e)
return NULL;
}
-/* find the BevVert corresponding to BMVert bmv */
-static BevVert *find_bevvert(BevelParams *bp, BMVert *bmv)
-{
- return BLI_ghash_lookup(bp->vert_hash, bmv);
-}
-
/* Return a good representative face (for materials, etc.) for faces
* created around/near BoundVert v */
static BMFace *boundvert_rep_face(BoundVert *v)
@@ -522,19 +539,40 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f,
}
}
+/* Like offset_in_two planes, but for the case where we prefer to solve the problem
+ * of not meeting at the same point by choosing to change the bevel offset on one
+ * of the appropriate side of either e1 or e2, in order that the lines can meet on emid. */
+static void offset_on_edge_between(BevelParams *bp, EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *emid,
+ BMVert *v, float meetco[3])
+{
+ BLI_assert(e1->is_bev && e2->is_bev && !emid->is_bev);
+
+ /* If have to change offset of e1 or e2, which one?
+ * Prefer the one whose other end hasn't been constructed yet.
+ * Following will choose to change e2 if both have already been constructed. */
+ if (find_other_end_edge_half(bp, e1)) {
+ offset_meet(e1, emid, v, e1->fnext, TRUE, meetco);
+ /* now e2's left offset is probably different */
+ e2->offset_l = dist_to_line_v3(meetco, v->co, BM_edge_other_vert(e2->e, v)->co);
+ }
+ else {
+ offset_meet(emid, e2, v, emid->fnext, TRUE, meetco);
+ /* now e1's right offset is probably different */
+ e1->offset_r = dist_to_line_v3(meetco, v->co, BM_edge_other_vert(e1->e, v)->co);
+ }
+}
+
/* Like offset_meet, but with a mid edge between them that is used
* to calculate the planes in which to run the offset lines.
- * They may not meet exactly: the offsets for the edges may be different
- * or both the planes and the lines may be angled so that they can't meet.
+ * They may not meet exactly: the lines may be angled so that they can't meet,
+ * probably because one or both faces is non-planar.
* In that case, pick a close point on emid, which should be the dividing
- * edge between the two planes.
- * TODO: should have a global 'offset consistency' prepass to adjust offset
- * widths so that all edges have the same offset at both ends. */
-static void offset_in_two_planes(EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *emid,
+ * edge between the two planes. */
+static void offset_in_two_planes(BevelParams *bp, EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *emid,
BMVert *v, float meetco[3])
{
float dir1[3], dir2[3], dirmid[3], norm_perp1[3], norm_perp2[3],
- off1a[3], off1b[3], off2a[3], off2b[3], isect2[3], co[3],
+ off1a[3], off1b[3], off2a[3], off2b[3], isect2[3],
f1no[3], f2no[3], ang;
int iret;
@@ -562,8 +600,8 @@ static void offset_in_two_planes(EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *emid,
ang = angle_v3v3(dir1, dir2);
if (ang < 100.0f * BEVEL_EPSILON) {
- /* lines are parallel; off1a is a good meet point */
- copy_v3_v3(meetco, off1a);
+ /* lines are parallel; put intersection on emid */
+ offset_on_edge_between(bp, e1, e2, emid, v, meetco);
}
else if (fabsf(ang - (float)M_PI) < 100.0f * BEVEL_EPSILON) {
slide_dist(e2, v, e2->offset_l, meetco);
@@ -575,11 +613,10 @@ static void offset_in_two_planes(EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *emid,
copy_v3_v3(meetco, off1a);
}
else if (iret == 2) {
- /* lines are not coplanar; meetco and isect2 are nearest to first and second lines */
+ /* lines are not coplanar and don't meet; meetco and isect2 are nearest to first and second lines */
if (len_v3v3(meetco, isect2) > 100.0f * BEVEL_EPSILON) {
- /* offset lines don't meet: project average onto emid; this is not ideal (see TODO above) */
- mid_v3_v3v3(co, meetco, isect2);
- closest_to_line_v3(meetco, co, v->co, BM_edge_other_vert(emid->e, v)->co);
+ /* offset lines don't meet so can't preserve widths; fallback on sliding along edge between */
+ offset_on_edge_between(bp, e1, e2, emid, v, meetco);
}
}
/* else iret == 1 and the lines are coplanar so meetco has the intersection */
@@ -849,7 +886,10 @@ static void build_boundary(BevelParams *bp, BevVert *bv)
if (e->prev->prev->is_bev) {
BLI_assert(e->prev->prev != e); /* see: edgecount 2, selcount 1 case */
/* find meet point between e->prev->prev and e and attach e->prev there */
- offset_in_two_planes(e->prev->prev, e, e->prev, bv->v, co);
+ if (bp->preserve_widths)
+ offset_in_two_planes(bp, e->prev->prev, e, e->prev, bv->v, co);
+ else
+ offset_on_edge_between(bp, e->prev->prev, e, e->prev, bv->v, co);
v = add_new_bound_vert(mem_arena, vm, co);
v->efirst = e->prev->prev;
v->elast = v->ebev = e;
@@ -1950,7 +1990,7 @@ static void bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v)
BMEdge *bme2, *unflagged_bme, *first_bme;
BMFace *f;
BMIter iter, iter2;
- EdgeHalf *e;
+ EdgeHalf *e, *eother;
float weight, z;
int i, found_shared_face, ccw_test_sum;
int nsel = 0;
@@ -2107,39 +2147,51 @@ static void bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v)
if (e->is_bev) {
/* Convert distance as specified by user into offsets along
* faces on left side and right side of this edgehalf.
- * Except for percent method, offset will be same on each side. */
- switch (bp->offset_type) {
- case BEVEL_AMT_OFFSET:
- e->offset_l = bp->offset;
- break;
- case BEVEL_AMT_WIDTH:
- z = fabs(2.0f * sinf(edge_face_angle(e) / 2.0f));
- if (z < BEVEL_EPSILON)
- e->offset_l = 0.01f * bp->offset; /* undefined behavior, so tiny bevel */
- else
- e->offset_l = bp->offset / z;
- break;
- case BEVEL_AMT_DEPTH:
- z = fabs(cosf(edge_face_angle(e) / 2.0f));
- if (z < BEVEL_EPSILON)
- e->offset_l = 0.01f * bp->offset; /* undefined behavior, so tiny bevel */
- else
- e->offset_l = bp->offset / z;
- break;
- case BEVEL_AMT_PERCENT:
- e->offset_l = BM_edge_calc_length(e->prev->e) * bp->offset / 100.0f;
- e->offset_r = BM_edge_calc_length(e->next->e) * bp->offset / 100.0f;
- break;
- default:
- BLI_assert(!"bad bevel offset kind");
- e->offset_l = bp->offset;
+ * Except for percent method, offset will be same on each side.
+ *
+ * First check to see if other end has had construction made,
+ * because offset may have been forced to another number
+ * (but for percent method all 4 widths can be different). */
+
+ eother = find_other_end_edge_half(bp, e);
+ if (eother && bp->offset_type != BEVEL_AMT_PERCENT) {
+ e->offset_l = eother->offset_r;
+ e->offset_r = eother->offset_l;
}
- if (bp->offset_type != BEVEL_AMT_PERCENT)
- e->offset_r = e->offset_l;
- if (bp->use_weights) {
- weight = BM_elem_float_data_get(&bm->edata, bme, CD_BWEIGHT);
- e->offset_l *= weight;
- e->offset_r *= weight;
+ else {
+ switch (bp->offset_type) {
+ case BEVEL_AMT_OFFSET:
+ e->offset_l = bp->offset;
+ break;
+ case BEVEL_AMT_WIDTH:
+ z = fabs(2.0f * sinf(edge_face_angle(e) / 2.0f));
+ if (z < BEVEL_EPSILON)
+ e->offset_l = 0.01f * bp->offset; /* undefined behavior, so tiny bevel */
+ else
+ e->offset_l = bp->offset / z;
+ break;
+ case BEVEL_AMT_DEPTH:
+ z = fabs(cosf(edge_face_angle(e) / 2.0f));
+ if (z < BEVEL_EPSILON)
+ e->offset_l = 0.01f * bp->offset; /* undefined behavior, so tiny bevel */
+ else
+ e->offset_l = bp->offset / z;
+ break;
+ case BEVEL_AMT_PERCENT:
+ e->offset_l = BM_edge_calc_length(e->prev->e) * bp->offset / 100.0f;
+ e->offset_r = BM_edge_calc_length(e->next->e) * bp->offset / 100.0f;
+ break;
+ default:
+ BLI_assert(!"bad bevel offset kind");
+ e->offset_l = bp->offset;
+ }
+ if (bp->offset_type != BEVEL_AMT_PERCENT)
+ e->offset_r = e->offset_l;
+ if (bp->use_weights) {
+ weight = BM_elem_float_data_get(&bm->edata, bme, CD_BWEIGHT);
+ e->offset_l *= weight;
+ e->offset_r *= weight;
+ }
}
}
else {
@@ -2432,6 +2484,7 @@ void BM_mesh_bevel(BMesh *bm, const float offset, const int offset_type, const f
bp.seg = segments;
bp.vertex_only = vertex_only;
bp.use_weights = use_weights;
+ bp.preserve_widths = false;
bp.dvert = dvert;
bp.vertex_group = vertex_group;