diff options
Diffstat (limited to 'source/blender/bmesh/tools/bmesh_bevel.c')
-rw-r--r-- | source/blender/bmesh/tools/bmesh_bevel.c | 270 |
1 files changed, 141 insertions, 129 deletions
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 9cc645f7a3a..07e159b3241 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -994,23 +994,31 @@ static bool point_between_edges(float co[3], BMVert *v, BMFace *f, EdgeHalf *e1, return (ang11 - ang1co > -BEVEL_EPSILON_ANG); } -/* +/** * 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 * the bevel vertex, e1 precedes e2 in CCW order. - * Except: if edges_between is true, there are edges between e1 and e2 in CCW order so they - * don't share a common face. We want the meeting point to be on an existing face so it - * should be dropped onto one of the intermediate faces, if possible. * Offset edge is on right of both edges, where e1 enters v and e2 leave it. * When offsets are equal, the new point is on the edge bisector, with length offset/sin(angle/2), - * but if the offsets are not equal (allowing for this, as bevel modifier has edge weights that may - * lead to different offsets) then meeting point can be found be intersecting offset lines. + * but if the offsets are not equal (we allow for because the bevel modifier has edge weights that + * may lead to different offsets) then the meeting point can be found by intersecting offset lines. * If making the meeting point significantly changes the left or right offset from the user spec, * record the change in offset_l (or offset_r); later we can tell that a change has happened * because the offset will differ from its original value in offset_l_spec (or offset_r_spec). + * + * \param edges_between If this is true, there are edges between e1 and e2 in CCW order so they + * don't share a common face. We want the meeting point to be on an existing face so it + * should be dropped onto one of the intermediate faces, if possible. + * \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, EdgeHalf *e2, BMVert *v, BMFace *f, bool edges_between, float meetco[3]) +static void offset_meet(EdgeHalf *e1, + EdgeHalf *e2, + BMVert *v, + BMFace *f, + bool edges_between, + float meetco[3], + const EdgeHalf *e_in_plane) { float dir1[3], dir2[3], dir1n[3], dir2p[3], norm_v[3], norm_v1[3], norm_v2[3]; float norm_perp1[3], norm_perp2[3], off1a[3], off1b[3], off2a[3], off2b[3]; @@ -1018,10 +1026,10 @@ static void offset_meet( float ang, d; BMVert *closer_v; EdgeHalf *e, *e1next, *e2prev; - BMFace *ff; + BMFace *fnext; int isect_kind; - /* get direction vectors for two offset lines */ + /* Get direction vectors for two offset lines. */ sub_v3_v3v3(dir1, v->co, BM_edge_other_vert(e1->e, v)->co); sub_v3_v3v3(dir2, BM_edge_other_vert(e2->e, v)->co, v->co); @@ -1032,20 +1040,20 @@ static void offset_meet( sub_v3_v3v3(dir2p, v->co, BM_edge_other_vert(e2prev->e, v)->co); } else { - /* shup up 'maybe unused' warnings */ + /* Shut up 'maybe unused' warnings. */ zero_v3(dir1n); zero_v3(dir2p); } ang = angle_v3v3(dir1, dir2); if (ang < BEVEL_EPSILON_ANG) { - /* special case: e1 and e2 are parallel; put offset point perp to both, from v. + /* Special case: e1 and e2 are parallel; put offset point perp to both, from v. * need to find a suitable plane. - * this code used to just use offset and dir1, but that makes for visible errors + * This code used to just use offset and dir1, but that makes for visible errors * on a circle with > 200 sides, which trips this "nearly perp" code (see T61214). * so use the average of the two, and the offset formula for angle bisector. - * if offsets are different, we're out of luck: - * use the max of the two (so get consistent looking results if the same situation + * If offsets are different, we're out of luck: + * Use the max of the two (so get consistent looking results if the same situation * arises elsewhere in the object but with opposite roles for e1 and e2 */ if (f) { copy_v3_v3(norm_v, f->no); @@ -1063,23 +1071,21 @@ static void offset_meet( copy_v3_v3(meetco, off1a); } else if (fabsf(ang - (float)M_PI) < BEVEL_EPSILON_ANG) { - /* special case e1 and e2 are antiparallel, so bevel is into - * a zero-area face. Just make the offset point on the - * common line, at offset distance from v. */ + /* Special case: e1 and e2 are antiparallel, so bevel is into a zero-area face. + * Just make the offset point on the common line, at offset distance from v. */ d = max_ff(e1->offset_r, e2->offset_l); slide_dist(e2, v, d, meetco); } else { - /* Get normal to plane where meet point should be, - * using cross product instead of f->no in case f is non-planar. - * Except: sometimes locally there can be a small angle - * between dir1 and dir2 that leads to a normal that is actually almost - * perpendicular to the face normal; in this case it looks wrong to use - * the local (cross-product) normal, so use the face normal if the angle - * between dir1 and dir2 is smallish. + /* Get normal to plane where meet point should be, using cross product instead of f->no + * in case f is non-planar. + * Except: sometimes locally there can be a small angle between dir1 and dir2 that leads + * to a normal that is actually almost perpendicular to the face normal; + * in this case it looks wrong to use the local (cross-product) normal, + * so use the face normal if the angle between dir1 and dir2 is smallish. * If e1-v-e2 is a reflex angle (viewed from vertex normal side), need to flip. - * Use f->no to figure out which side to look at angle from, as even if - * f is non-planar, will be more accurate than vertex normal */ + * Use f->no to figure out which side to look at angle from, as even if f is non-planar, + * will be more accurate than vertex normal. */ if (f && ang < BEVEL_SMALL_ANG) { copy_v3_v3(norm_v1, f->no); copy_v3_v3(norm_v2, f->no); @@ -1093,7 +1099,7 @@ static void offset_meet( copy_v3_v3(norm_v2, norm_v1); } else { - /* separate faces; get face norms at corners for each separately */ + /* Separate faces; get face norms at corners for each separately. */ cross_v3_v3v3(norm_v1, dir1n, dir1); normalize_v3(norm_v1); f = e1->fnext; @@ -1108,13 +1114,13 @@ static void offset_meet( } } - /* get vectors perp to each edge, perp to norm_v, and pointing into face */ + /* 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); normalize_v3(norm_perp1); normalize_v3(norm_perp2); - /* get points that are offset distances from each line, then another point on each line */ + /* 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); @@ -1122,18 +1128,17 @@ static void offset_meet( madd_v3_v3fl(off2a, norm_perp2, e2->offset_l); add_v3_v3v3(off2b, off2a, dir2); - /* intersect the lines */ + /* Intersect the offset lines. */ isect_kind = isect_line_line_v3(off1a, off1b, off2a, off2b, meetco, isect2); 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 */ + /* Lines are collinear: we already tested for this, but this used a different epsilon. */ + copy_v3_v3(meetco, off1a); /* Just to do something. */ } else { /* The lines intersect, but is it at a reasonable place? - * One problem to check: if one of the offsets is 0, then don't - * want an intersection that is outside that edge itself. - * This can happen if angle between them is > 180 degrees, - * or if the offset amount is > the edge length*/ + * One problem to check: if one of the offsets is 0, then don't want an intersection + * that is outside that edge itself. This can happen if angle between them is > 180 degrees, + * 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); } @@ -1141,19 +1146,26 @@ static void offset_meet( copy_v3_v3(meetco, closer_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 */ + /* Try to drop meetco to a face between e1 and e2. */ if (isect_kind == 2) { - /* lines didn't meet in 3d: get average of meetco and isect2 */ + /* Lines didn't meet in 3d: get average of meetco and isect2. */ mid_v3_v3v3(meetco, meetco, isect2); } for (e = e1; e != e2; e = e->next) { - ff = e->fnext; - if (!ff) { + fnext = e->fnext; + if (!fnext) { continue; } - plane_from_point_normal_v3(plane, v->co, ff->no); + plane_from_point_normal_v3(plane, v->co, fnext->no); closest_to_plane_normalized_v3(dropco, plane, meetco); - if (point_between_edges(dropco, v, ff, e, e->next)) { + /* Don't drop to the faces next to the in plane edge. */ + if (e_in_plane) { + ang = angle_v3v3(fnext->no, e_in_plane->fnext->no); + if ((fabsf(ang) < BEVEL_SMALL_ANG) || (fabsf(ang - (float)M_PI) < BEVEL_SMALL_ANG)) { + continue; + } + } + if (point_between_edges(dropco, v, fnext, e, e->next)) { copy_v3_v3(meetco, dropco); break; } @@ -1163,8 +1175,7 @@ static void offset_meet( } } -/* Chosen so that 1/sin(BEVEL_GOOD_ANGLE) is about 4, - * giving that expansion factor to bevel width. */ +/* Chosen so 1/sin(BEVEL_GOOD_ANGLE) is about 4, giving that expansion factor to bevel width. */ #define BEVEL_GOOD_ANGLE 0.25f /* Calculate the meeting point between e1 and e2 (one of which should have zero offsets), @@ -1182,7 +1193,7 @@ static bool offset_meet_edge( normalize_v3(dir1); normalize_v3(dir2); - /* find angle from dir1 to dir2 as viewed from vertex normal side */ + /* Find angle from dir1 to dir2 as viewed from vertex normal side. */ ang = angle_normalized_v3v3(dir1, dir2); if (fabsf(ang) < BEVEL_GOOD_ANGLE) { if (r_angle) { @@ -1192,7 +1203,7 @@ static bool offset_meet_edge( } cross_v3_v3v3(fno, dir1, dir2); if (dot_v3v3(fno, v->no) < 0.0f) { - ang = 2.0f * (float)M_PI - ang; /* angle is reflex */ + ang = 2.0f * (float)M_PI - ang; /* Angle is reflex. */ if (r_angle) { *r_angle = ang; } @@ -1219,7 +1230,7 @@ static bool offset_meet_edge( } /* Return true if it will look good to put the meeting point where offset_on_edge_between - * would put it. This means that neither side sees a reflex angle */ + * would put it. This means that neither side sees a reflex angle. */ static bool good_offset_on_edge_between(EdgeHalf *e1, EdgeHalf *e2, EdgeHalf *emid, BMVert *v) { float ang; @@ -1248,7 +1259,7 @@ static bool offset_on_edge_between( if (ok1 && ok2) { mid_v3_v3v3(meetco, meet1, meet2); if (r_sinratio) { - /* ang1 should not be 0, but be paranoid */ + /* ang1 should not be 0, but be paranoid. */ *r_sinratio = (ang1 == 0.0f) ? 1.0f : sinf(ang2) / sinf(ang1); } retval = true; @@ -1261,7 +1272,7 @@ static bool offset_on_edge_between( } else { /* Neither offset line met emid. - * This should only happen if all three lines are on top of each other */ + * This should only happen if all three lines are on top of each other. */ slide_dist(emid, v, e1->offset_r, meetco); } @@ -1269,8 +1280,7 @@ static bool offset_on_edge_between( } /* Offset by e->offset in plane with normal plane_no, on left if left==true, - * else on right. If no is NULL, choose an arbitrary plane different - * from eh's direction. */ + * else on right. If no is NULL, choose an arbitrary plane different from eh's direction. */ static void offset_in_plane(EdgeHalf *e, const float plane_no[3], bool left, float r[3]) { float dir[3], no[3], fdir[3]; @@ -1303,7 +1313,7 @@ static void offset_in_plane(EdgeHalf *e, const float plane_no[3], bool left, flo madd_v3_v3fl(r, fdir, left ? e->offset_l : e->offset_r); } -/* Calculate the point on e where line (co_a, co_b) comes closest to and return it in projco */ +/* Calculate the point on e where line (co_a, co_b) comes closest to and return it in projco. */ static void project_to_edge(BMEdge *e, const float co_a[3], const float co_b[3], float projco[3]) { float otherco[3]; @@ -1317,56 +1327,55 @@ static void project_to_edge(BMEdge *e, const float co_a[3], const float co_b[3], } /* If there is a bndv->ebev edge, find the mid control point if necessary. - * It is the closest point on the beveled edge to the line segment between - * bndv and bndv->next. */ + * It is the closest point on the beveled edge to the line segment between bndv and bndv->next. */ static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv) { EdgeHalf *e; Profile *pro; - float co1[3], co2[3], co3[3], d1[3], d2[3]; + float start[3], end[3], co3[3], d1[3], d2[3]; bool do_linear_interp; - copy_v3_v3(co1, bndv->nv.co); - copy_v3_v3(co2, bndv->next->nv.co); + copy_v3_v3(start, bndv->nv.co); + copy_v3_v3(end, bndv->next->nv.co); pro = &bndv->profile; e = bndv->ebev; do_linear_interp = true; if (e) { do_linear_interp = false; pro->super_r = bp->pro_super_r; - /* projection direction is direction of the edge */ + /* projection direction is direction of the edge. */ sub_v3_v3v3(pro->proj_dir, e->e->v1->co, e->e->v2->co); if (e->is_rev) { negate_v3(pro->proj_dir); } normalize_v3(pro->proj_dir); - project_to_edge(e->e, co1, co2, pro->middle); + project_to_edge(e->e, start, end, pro->middle); if (DEBUG_OLD_PROJ_TO_PERP_PLANE) { - /* put arc endpoints on plane with normal proj_dir, containing middle */ - add_v3_v3v3(co3, co1, pro->proj_dir); - if (!isect_line_plane_v3(pro->start, co1, co3, pro->middle, pro->proj_dir)) { - /* shouldn't happen */ - copy_v3_v3(pro->start, co1); + /* Put arc endpoints on plane with normal proj_dir, containing middle. */ + add_v3_v3v3(co3, start, pro->proj_dir); + if (!isect_line_plane_v3(pro->start, start, co3, pro->middle, pro->proj_dir)) { + /* Shouldn't happen. */ + copy_v3_v3(pro->start, start); } - add_v3_v3v3(co3, co2, pro->proj_dir); - if (!isect_line_plane_v3(pro->end, co2, co3, pro->middle, pro->proj_dir)) { - /* shouldn't happen */ - copy_v3_v3(pro->end, co2); + add_v3_v3v3(co3, end, pro->proj_dir); + if (!isect_line_plane_v3(pro->end, end, co3, pro->middle, pro->proj_dir)) { + /* Shouldn't happen. */ + copy_v3_v3(pro->end, end); } } else { - copy_v3_v3(pro->start, co1); - copy_v3_v3(pro->end, co2); + copy_v3_v3(pro->start, start); + copy_v3_v3(pro->end, end); } - /* default plane to project onto is the one with triangle co1 - middle - co2 in it */ - sub_v3_v3v3(d1, pro->middle, co1); - sub_v3_v3v3(d2, pro->middle, co2); + /* Default plane to project onto is the one with triangle start - middle - end in it. */ + sub_v3_v3v3(d1, pro->middle, start); + sub_v3_v3v3(d2, pro->middle, end); normalize_v3(d1); normalize_v3(d2); cross_v3_v3v3(pro->plane_no, d1, d2); normalize_v3(pro->plane_no); if (nearly_parallel(d1, d2)) { - /* co1 - middle -co2 are collinear. + /* Start - middle - end are collinear. * Should be case that beveled edge is coplanar with two boundary verts. * We want to move the profile to that common plane, if possible. * That makes the multi-segment bevels curve nicely in that plane, as users expect. @@ -1380,8 +1389,8 @@ static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv) } else { if (DEBUG_OLD_PROJ_TO_PERP_PLANE) { - copy_v3_v3(pro->start, co1); - copy_v3_v3(pro->end, co2); + copy_v3_v3(pro->start, start); + copy_v3_v3(pro->end, end); } if (DEBUG_OLD_FLAT_MID) { copy_v3_v3(pro->middle, bv->v->co); @@ -1389,7 +1398,7 @@ static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv) else { copy_v3_v3(pro->middle, bv->v->co); if (e->prev->is_bev && e->next->is_bev && bv->selcount >= 3) { - /* want mid at the meet point of next and prev offset edges */ + /* Want mid at the meet point of next and prev offset edges. */ float d3[3], d4[3], co4[3], meetco[3], isect2[3]; int isect_kind; @@ -1398,34 +1407,34 @@ static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv) normalize_v3(d3); normalize_v3(d4); if (nearly_parallel(d3, d4)) { - /* offset lines are collinear - want linear interpolation */ - mid_v3_v3v3(pro->middle, co1, co2); + /* Offset lines are collinear - want linear interpolation. */ + mid_v3_v3v3(pro->middle, start, end); do_linear_interp = true; } else { - add_v3_v3v3(co3, co1, d3); - add_v3_v3v3(co4, co2, d4); - isect_kind = isect_line_line_v3(co1, co3, co2, co4, meetco, isect2); + add_v3_v3v3(co3, start, d3); + add_v3_v3v3(co4, end, d4); + isect_kind = isect_line_line_v3(start, co3, end, co4, meetco, isect2); if (isect_kind != 0) { copy_v3_v3(pro->middle, meetco); } else { - /* offset lines don't intersect - want linear interpolation */ - mid_v3_v3v3(pro->middle, co1, co2); + /* Offset lines don't intersect - want linear interpolation. */ + mid_v3_v3v3(pro->middle, start, end); do_linear_interp = true; } } } } - copy_v3_v3(pro->end, co2); - sub_v3_v3v3(d1, pro->middle, co1); + copy_v3_v3(pro->end, end); + sub_v3_v3v3(d1, pro->middle, start); normalize_v3(d1); - sub_v3_v3v3(d2, pro->middle, co2); + sub_v3_v3v3(d2, pro->middle, end); normalize_v3(d2); cross_v3_v3v3(pro->plane_no, d1, d2); normalize_v3(pro->plane_no); if (nearly_parallel(d1, d2)) { - /* whole profile is collinear with edge: just interpolate */ + /* Whole profile is collinear with edge: just interpolate. */ do_linear_interp = true; } else { @@ -1434,12 +1443,12 @@ static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv) } } } - copy_v3_v3(pro->plane_co, co1); + copy_v3_v3(pro->plane_co, start); } else if (bndv->is_arc_start) { - /* assume pro->middle was alredy set */ - copy_v3_v3(pro->start, co1); - copy_v3_v3(pro->end, co2); + /* Assume pro->middle was alredy set. */ + copy_v3_v3(pro->start, start); + copy_v3_v3(pro->end, end); pro->super_r = PRO_CIRCLE_R; zero_v3(pro->plane_co); zero_v3(pro->plane_no); @@ -1448,10 +1457,10 @@ static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv) } if (do_linear_interp) { pro->super_r = PRO_LINE_R; - copy_v3_v3(pro->start, co1); - copy_v3_v3(pro->end, co2); - mid_v3_v3v3(pro->middle, co1, co2); - /* won't use projection for this line profile */ + copy_v3_v3(pro->start, start); + copy_v3_v3(pro->end, end); + mid_v3_v3v3(pro->middle, start, end); + /* Won't use projection for this line profile. */ zero_v3(pro->plane_co); zero_v3(pro->plane_no); zero_v3(pro->proj_dir); @@ -2295,14 +2304,14 @@ static int count_bound_vert_seams(BevVert *bv) return ans; } -/* Is e between two planes where angle between is 180? */ +/* Is e between two faces with a 180 degree angle between their normals? */ static bool eh_on_plane(EdgeHalf *e) { float dot; if (e->fprev && e->fnext) { dot = dot_v3v3(e->fprev->no, e->fnext->no); - if (fabsf(dot) <= BEVEL_EPSILON_BIG || fabsf(dot - 1.0f) <= BEVEL_EPSILON_BIG) { + if (fabsf(dot + 1.0f) <= BEVEL_EPSILON_BIG || fabsf(dot - 1.0f) <= BEVEL_EPSILON_BIG) { return true; } } @@ -2422,7 +2431,7 @@ static void build_boundary_terminal_edge(BevelParams *bp, * and join with the beveled 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); + offset_meet(e->prev, e, bv->v, e->fprev, false, co, NULL); if (construct) { bndv = add_new_bound_vert(mem_arena, vm, co); bndv->efirst = e->prev; @@ -2434,7 +2443,7 @@ 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); + offset_meet(e->prev, e, bv->v, e->fprev, false, co, NULL); if (construct) { bndv = add_new_bound_vert(mem_arena, vm, co); bndv->efirst = e->prev; @@ -2592,18 +2601,20 @@ static void adjust_miter_inner_coords(BevelParams *bp, BevVert *bv, EdgeHalf *em } while (v != vstart); } -/* 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. - * This may adjust some EdgeHalf widths, and there might have to be - * a subsequent pass to make the widths as consistent as possible. - * The first time through, construct will be true and we are making the BoundVerts - * and setting up the BoundVert and EdgeHalf pointers appropriately. - * For a width consistency path, we just recalculate the coordinates of the - * BoundVerts. If the other ends have been (re)built already, then we - * copy the offsets from there to match, else we use the ideal (user-specified) - * widths. - * Also, if construct, decide on the mesh pattern that will be used inside the boundary. - * Doesn't make the actual BMVerts */ +/** + * 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. This may adjust some EdgeHalf widths, and there might have + * to be a subsequent pass to make the widths as consistent as possible. + * Doesn't make the actual BMVerts. + * + * For a width consistency pass, we just recalculate the coordinates of the BoundVerts. If the + * other ends have been (re)built already, then we copy the offsets from there to match, else we + * use the ideal (user-specified) widths. + * + * \param construct The first time through, construct will be true and we are making the BoundVerts + * and setting up the BoundVert and EdgeHalf pointers appropriately. Also, if construct, decide on + * the mesh pattern that will be used inside the boundary. + */ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) { MemArena *mem_arena = bp->mem_arena; @@ -2614,7 +2625,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) int in_plane, not_in_plane, miter_outer, miter_inner; int ang_kind; - /* Current bevel does nothing if only one edge into a vertex */ + /* Current bevel does nothing if only one edge into a vertex. */ if (bv->edgecount <= 1) { return; } @@ -2626,21 +2637,21 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) vm = bv->vmesh; - /* Find a beveled edge to be efirst */ + /* Find a beveled edge to be efirst. */ e = efirst = next_bev(bv, NULL); BLI_assert(e->is_bev); if (bv->selcount == 1) { - /* Special case: only one beveled edge in */ + /* Special case: only one beveled edge in. */ build_boundary_terminal_edge(bp, bv, efirst, construct); return; } - /* Special miters outside only for 3 or more beveled edges */ + /* Special miters outside only for 3 or more beveled edges. */ miter_outer = (bv->selcount >= 3) ? bp->miter_outer : BEVEL_MITER_SHARP; miter_inner = bp->miter_inner; - /* keep track of the first beveled edge of an outside miter (there can be at most 1 per bv */ + /* Keep track of the first beveled edge of an outside miter (there can be at most 1 per bv). */ emiter = NULL; /* There is more than one beveled edge. @@ -2650,14 +2661,13 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) do { BLI_assert(e->is_bev); eon = NULL; - /* Make the BoundVert for the right side of e; other side will be made - * when the beveled edge to the left of e is handled. - * Analyze edges until next beveled edge. - * They are either "in plane" (preceding and subsequent faces are coplanar) or not. - * The "non-in-plane" edges affect the silhouette and we prefer to slide along one of those if - * possible. */ - in_plane = not_in_plane = 0; /* Counts of in-plane / not-in-plane */ - enip = eip = NULL; /* representatives of each */ + /* Make the BoundVert for the right side of e; the other side will be made when the beveled + * edge to the left of e is handled. + * Analyze edges until next beveled edge: They are either "in plane" (preceding and subsequent + * faces are coplanar) or not. The "non-in-plane" edges affect the silhouette and we prefer to + * slide along one of those if possible. */ + in_plane = not_in_plane = 0; /* Counts of in-plane / not-in-plane. */ + enip = eip = NULL; /* Representatives of each type. */ for (e2 = e->next; !e2->is_bev; e2 = e2->next) { if (eh_on_plane(e2)) { in_plane++; @@ -2668,8 +2678,9 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) enip = e2; } } + if (in_plane == 0 && not_in_plane == 0) { - offset_meet(e, e2, bv->v, e->fnext, false, co); + offset_meet(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)) { @@ -2678,7 +2689,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) } } else { - offset_meet(e, e2, bv->v, NULL, true, co); + offset_meet(e, e2, bv->v, NULL, true, co, eip); } } else { @@ -2689,9 +2700,10 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) } } else { - offset_meet(e, e2, bv->v, e->fnext, true, co); + offset_meet(e, e2, bv->v, e->fnext, true, co, eip); } } + if (construct) { v = add_new_bound_vert(mem_arena, vm, co); v->efirst = e; |