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:
Diffstat (limited to 'source/blender/bmesh/tools')
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.c194
1 files changed, 163 insertions, 31 deletions
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index b9c9aa3aec8..f45457085dc 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -1149,6 +1149,112 @@ static bool point_between_edges(
return (ang11 - ang1co > -BEVEL_EPSILON_ANG);
}
+/* Is the angle swept from e1 to e2, CCW when viewed from the normal side of f,
+ * not a reflex angle or a straight angle? Assume e1 and e2 share a vert. */
+static bool edge_edge_angle_less_than_180(const BMEdge *e1, const BMEdge *e2, const BMFace *f)
+{
+ float dir1[3], dir2[3], cross[3];
+ BLI_assert(f != NULL);
+ BMVert *v, *v1, *v2;
+ if (e1->v1 == e2->v1) {
+ v = e1->v1;
+ v1 = e1->v2;
+ v2 = e2->v2;
+ }
+ else if (e1->v1 == e2->v2) {
+ v = e1->v1;
+ v1 = e1->v2;
+ v2 = e2->v1;
+ }
+ else if (e1->v2 == e2->v1) {
+ v = e1->v2;
+ v1 = e1->v1;
+ v2 = e2->v2;
+ }
+ else if (e1->v2 == e2->v2) {
+ v = e1->v2;
+ v1 = e1->v1;
+ v2 = e2->v1;
+ }
+ else {
+ BLI_assert(false);
+ }
+ sub_v3_v3v3(dir1, v1->co, v->co);
+ sub_v3_v3v3(dir2, v2->co, v->co);
+ cross_v3_v3v3(cross, dir1, dir2);
+ return dot_v3v3(cross, f->no) > 0.0f;
+}
+
+/* When the offset_type is BEVEL_AMT_PERCENT or BEVEL_AMT_ABSOLUTE, fill in the coordinates
+ * of the lines whose intersection defines the boundary point between e1 and e2 with common
+ * vert v, as defined in the parameters of offset_meet.
+ */
+static void offset_meet_lines_percent_or_absolute(BevelParams *bp,
+ EdgeHalf *e1,
+ EdgeHalf *e2,
+ BMVert *v,
+ float r_l1a[3],
+ float r_l1b[3],
+ float r_l2a[3],
+ float r_l2b[3])
+{
+ /* Get points the specified distance along each leg.
+ * Note: not all BevVerts and EdgeHalfs have been made yet, so we have
+ * to find required edges by moving around faces and use fake EdgeHalfs for
+ * some of the edges. If there aren't faces to move around, we have to give up.
+ * The legs we need are:
+ * e0 : the next edge around e1->fnext (==f1) after e1.
+ * e3 : the prev edge around e2->fprev (==f2) before e2.
+ * e4 : the previous edge around f1 before e1 (may be e2).
+ * e5 : the next edge around f2 after e2 (may be e1).
+ */
+ BMVert *v1, *v2;
+ EdgeHalf e0, e3, e4, e5;
+ BMFace *f1, *f2;
+ float d0, d3, d4, d5;
+ v1 = BM_edge_other_vert(e1->e, v);
+ v2 = BM_edge_other_vert(e2->e, v);
+ f1 = e1->fnext;
+ f2 = e2->fprev;
+ bool no_offsets = f1 == NULL || f2 == NULL;
+ if (!no_offsets) {
+ BMLoop *l = BM_face_vert_share_loop(f1, v1);
+ e0.e = l->e;
+ l = BM_face_vert_share_loop(f2, v2);
+ e3.e = l->prev->e;
+ l = BM_face_vert_share_loop(f1, v);
+ e4.e = l->prev->e;
+ l = BM_face_vert_share_loop(f2, v);
+ e5.e = l->e;
+ /* All the legs must be visible from their opposite legs. */
+ no_offsets = !edge_edge_angle_less_than_180(e0.e, e1->e, f1) ||
+ !edge_edge_angle_less_than_180(e1->e, e4.e, f1) ||
+ !edge_edge_angle_less_than_180(e2->e, e3.e, f2) ||
+ !edge_edge_angle_less_than_180(e5.e, e2->e, f1);
+ if (!no_offsets) {
+ if (bp->offset_type == BEVEL_AMT_ABSOLUTE) {
+ d0 = d3 = d4 = d5 = bp->offset;
+ }
+ else {
+ d0 = bp->offset * BM_edge_calc_length(e0.e) / 100.0f;
+ d3 = bp->offset * BM_edge_calc_length(e3.e) / 100.0f;
+ d4 = bp->offset * BM_edge_calc_length(e4.e) / 100.0f;
+ d5 = bp->offset * BM_edge_calc_length(e5.e) / 100.0f;
+ }
+ slide_dist(&e4, v, d4, r_l1a);
+ slide_dist(&e0, v1, d0, r_l1b);
+ slide_dist(&e5, v, d5, r_l2a);
+ slide_dist(&e3, v2, d3, r_l2b);
+ }
+ }
+ if (no_offsets) {
+ copy_v3_v3(r_l1a, v->co);
+ copy_v3_v3(r_l1b, v1->co);
+ copy_v3_v3(r_l2a, v->co);
+ copy_v3_v3(r_l2b, v2->co);
+ }
+}
+
/**
* 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
@@ -1167,7 +1273,8 @@ static bool point_between_edges(
* \param e_in_plane: If we need to drop from the calculated offset lines to one of the faces,
* we don't want to drop onto the 'in plane' face, so if this is not null skip this edge's faces.
*/
-static void offset_meet(EdgeHalf *e1,
+static void offset_meet(BevelParams *bp,
+ EdgeHalf *e1,
EdgeHalf *e2,
BMVert *v,
BMFace *f,
@@ -1273,14 +1380,19 @@ static void offset_meet(EdgeHalf *e1,
normalize_v3(norm_perp1);
normalize_v3(norm_perp2);
- /* Get points that are offset distances from each line, then another point on each line. */
float off1a[3], off1b[3], off2a[3], off2b[3];
- copy_v3_v3(off1a, v->co);
- madd_v3_v3fl(off1a, norm_perp1, e1->offset_r);
- add_v3_v3v3(off1b, off1a, dir1);
- copy_v3_v3(off2a, v->co);
- madd_v3_v3fl(off2a, norm_perp2, e2->offset_l);
- add_v3_v3v3(off2b, off2a, dir2);
+ if (bp->offset_type == BEVEL_AMT_PERCENT || bp->offset_type == BEVEL_AMT_ABSOLUTE) {
+ offset_meet_lines_percent_or_absolute(bp, e1, e2, v, off1a, off1b, off2a, off2b);
+ }
+ else {
+ /* Get points that are offset distances from each line, then another point on each line. */
+ copy_v3_v3(off1a, v->co);
+ madd_v3_v3fl(off1a, norm_perp1, e1->offset_r);
+ add_v3_v3v3(off1b, off1a, dir1);
+ copy_v3_v3(off2a, v->co);
+ madd_v3_v3fl(off2a, norm_perp2, e2->offset_l);
+ add_v3_v3v3(off2b, off2a, dir2);
+ }
/* Intersect the offset lines. */
float isect2[3];
@@ -2554,7 +2666,9 @@ static void build_boundary_terminal_edge(BevelParams *bp,
EdgeHalf *e = efirst;
float co[3];
if (bv->edgecount == 2) {
- /* Only 2 edges in, so terminate the edge with an artificial vertex on the unbeveled edge. */
+ /* Only 2 edges in, so terminate the edge with an artificial vertex on the unbeveled edge.
+ * If the offset type is BEVEL_AMT_PERCENT or BEVEL_AMT_ABSOLUTE, what to do is a bit
+ * undefined (there aren't two "legs"), so just let the code do what it does. */
const float *no = e->fprev ? e->fprev->no : (e->fnext ? e->fnext->no : NULL);
offset_in_plane(e, no, true, co);
if (construct) {
@@ -2592,7 +2706,13 @@ static void build_boundary_terminal_edge(BevelParams *bp,
* edge to make a poly or adj mesh, because e->prev has offset 0, offset_meet will put co on
* that edge. */
/* TODO: should do something else if angle between e and e->prev > 180 */
- offset_meet(e->prev, e, bv->v, e->fprev, false, co, NULL);
+ bool leg_slide = bp->offset_type == BEVEL_AMT_PERCENT || bp->offset_type == BEVEL_AMT_ABSOLUTE;
+ if (leg_slide) {
+ slide_dist(e->prev, bv->v, e->offset_l, co);
+ }
+ else {
+ offset_meet(bp, e->prev, e, bv->v, e->fprev, false, co, NULL);
+ }
if (construct) {
BoundVert *bndv = add_new_bound_vert(mem_arena, vm, co);
bndv->efirst = e->prev;
@@ -2604,7 +2724,12 @@ static void build_boundary_terminal_edge(BevelParams *bp,
adjust_bound_vert(e->leftv, co);
}
e = e->next;
- offset_meet(e->prev, e, bv->v, e->fprev, false, co, NULL);
+ if (leg_slide) {
+ slide_dist(e, bv->v, e->prev->offset_r, co);
+ }
+ else {
+ offset_meet(bp, e->prev, e, bv->v, e->fprev, false, co, NULL);
+ }
if (construct) {
BoundVert *bndv = add_new_bound_vert(mem_arena, vm, co);
bndv->efirst = e->prev;
@@ -2823,7 +2948,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
float r, co[3];
if (in_plane == 0 && not_in_plane == 0) {
- offset_meet(e, e2, bv->v, e->fnext, false, co, NULL);
+ offset_meet(bp, e, e2, bv->v, e->fnext, false, co, NULL);
}
else if (not_in_plane > 0) {
if (bp->loop_slide && not_in_plane == 1 && good_offset_on_edge_between(e, e2, enip, bv->v)) {
@@ -2832,7 +2957,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
}
}
else {
- offset_meet(e, e2, bv->v, NULL, true, co, eip);
+ offset_meet(bp, e, e2, bv->v, NULL, true, co, eip);
}
}
else {
@@ -2843,7 +2968,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
}
}
else {
- offset_meet(e, e2, bv->v, e->fnext, true, co, eip);
+ offset_meet(bp, e, e2, bv->v, e->fnext, true, co, eip);
}
}
@@ -6040,27 +6165,21 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v)
break;
}
case BEVEL_AMT_PERCENT: {
- /* Offset needs to meet adjacent edges at percentage of their lengths. */
- BMVert *v1 = BM_edge_other_vert(e->prev->e, v);
- BMVert *v2 = BM_edge_other_vert(e->e, v);
- float z = sinf(angle_v3v3v3(v1->co, v->co, v2->co));
- e->offset_l_spec = BM_edge_calc_length(e->prev->e) * bp->offset * z / 100.0f;
- v1 = BM_edge_other_vert(e->e, v);
- v2 = BM_edge_other_vert(e->next->e, v);
- z = sinf(angle_v3v3v3(v1->co, v->co, v2->co));
- e->offset_r_spec = BM_edge_calc_length(e->next->e) * bp->offset * z / 100.0f;
+ /* Offset needs to meet adjacent edges at percentage of their lengths.
+ * Since the width isn't constant, we don't store a width at all, but
+ * rather the distance along the adjacent edge that we need to go
+ * at this end of the edge.
+ */
+
+ e->offset_l_spec = BM_edge_calc_length(e->prev->e) * bp->offset / 100.0f;
+ e->offset_r_spec = BM_edge_calc_length(e->next->e) * bp->offset / 100.0f;
+
break;
}
case BEVEL_AMT_ABSOLUTE: {
/* Like Percent, but the amount gives the absolute distance along adjacent edges. */
- BMVert *v1 = BM_edge_other_vert(e->prev->e, v);
- BMVert *v2 = BM_edge_other_vert(e->e, v);
- float z = sinf(angle_v3v3v3(v1->co, v->co, v2->co));
- e->offset_l_spec = bp->offset * z;
- v1 = BM_edge_other_vert(e->e, v);
- v2 = BM_edge_other_vert(e->next->e, v);
- z = sinf(angle_v3v3v3(v1->co, v->co, v2->co));
- e->offset_r_spec = bp->offset * z;
+ e->offset_l_spec = bp->offset;
+ e->offset_r_spec = bp->offset;
break;
}
default: {
@@ -7072,6 +7191,19 @@ static float geometry_collide_offset(BevelParams *bp, EdgeHalf *eb)
EdgeHalf *ec;
BMVert *vd;
float kc;
+ if (bp->offset_type == BEVEL_AMT_PERCENT || bp->offset_type == BEVEL_AMT_ABSOLUTE) {
+ if (ea->is_bev && ebother != NULL && ebother->prev->is_bev) {
+ if (bp->offset_type == BEVEL_AMT_PERCENT) {
+ return bp->offset > 50.0f ? 50.0f : 100.f;
+ }
+ else {
+ /* This is only right sometimes. The exact answer is very hard to calculate. */
+ float blen = BM_edge_calc_length(eb->e);
+ return bp->offset > blen / 2.0f ? blen / 2.0f : blen;
+ }
+ }
+ return no_collide_offset;
+ }
if (ebother != NULL) {
ec = ebother->prev; /* Note: this is in direction c --> d. */
vc = bvc->v;