diff options
Diffstat (limited to 'source/blender/bmesh')
-rw-r--r-- | source/blender/bmesh/tools/bmesh_bevel.c | 419 | ||||
-rw-r--r-- | source/blender/bmesh/tools/bmesh_intersect_edges.c | 313 | ||||
-rw-r--r-- | source/blender/bmesh/tools/bmesh_intersect_edges.h | 6 |
3 files changed, 319 insertions, 419 deletions
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 07e159b3241..bc84c6872c4 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -60,16 +60,7 @@ #define BEVEL_MATCH_SPEC_WEIGHT 0.2 //#define DEBUG_CUSTOM_PROFILE_CUTOFF -//#define DEBUG_CUSTOM_PROFILE_SAMPLE - -#if defined(DEBUG_PROFILE_ORIENTATION_DRAW) || defined(DEBUG_CUSTOM_PROFILE_PIPE) -static float debug_color_red[4] = {1.0f, 0.0f, 0.0f, 1.0f}; -static float debug_color_blue[4] = {0.0f, 0.0f, 1.0f, 1.0f}; -extern void DRW_debug_sphere(const float center[3], const float radius, const float color[4]); -extern void DRW_debug_line_v3v3(const float v1[3], const float v2[3], const float color[4]); -#endif - -/* happens far too often, uncomment for development */ +/* Happens far too often, uncomment for development. */ // #define BEVEL_ASSERT_PROJECT /* for testing */ @@ -155,6 +146,8 @@ typedef struct Profile { float *prof_co; /** Like prof_co, but for seg power of 2 >= seg */ float *prof_co_2; + /** Mark a special case so the these parameters aren't reset with others. */ + bool special_params; } Profile; #define PRO_SQUARE_R 1e4f #define PRO_CIRCLE_R 2.0f @@ -266,7 +259,7 @@ typedef struct BevVert { VMesh *vmesh; } BevVert; -/* face classification: note depend on F_RECON > F_EDGE > F_VERT */ +/* Face classification. Note: depends on F_RECON > F_EDGE > F_VERT */ typedef enum { /** Used when there is no face at all */ F_NONE, @@ -290,10 +283,6 @@ enum { ANGLE_LARGER = 1, }; -#if 0 -static const char* fkind_names[] = {"F_NONE", "F_ORIG", "F_VERT", "F_EDGE", "F_RECON"}; /* DEBUG */ -#endif - /** Bevel parameters and state */ typedef struct BevelParams { /** Records BevVerts made: key BMVert*, value BevVert* */ @@ -359,12 +348,8 @@ typedef struct BevelParams { // #pragma GCC diagnostic ignored "-Wpadded" -/* Some flags to re-enable old behavior for a while, - * in case fixes broke things not caught by regression tests. */ -static int bev_debug_flags = 0; -#define DEBUG_OLD_PLANE_SPECIAL (bev_debug_flags & 1) -#define DEBUG_OLD_PROJ_TO_PERP_PLANE (bev_debug_flags & 2) -#define DEBUG_OLD_FLAT_MID (bev_debug_flags & 4) +/* Only for debugging, shouldn't be in blender repo. */ +// #include "bevdebug.c" /* use the unused _BM_ELEM_TAG_ALT flag to flag the 'long' loops (parallel to beveled edge) * of edge-polygons. */ @@ -1314,7 +1299,10 @@ static void offset_in_plane(EdgeHalf *e, const float plane_no[3], bool left, flo } /* 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]) +static void project_to_edge(const BMEdge *e, + const float co_a[3], + const float co_b[3], + float projco[3]) { float otherco[3]; @@ -1330,16 +1318,13 @@ static void project_to_edge(BMEdge *e, const float co_a[3], const float co_b[3], * 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 start[3], end[3], co3[3], d1[3], d2[3]; - bool do_linear_interp; + bool do_linear_interp = true; + EdgeHalf *e = bndv->ebev; + Profile *pro = &bndv->profile; 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; @@ -1350,23 +1335,8 @@ static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv) } normalize_v3(pro->proj_dir); 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, 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, 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, start); - copy_v3_v3(pro->end, end); - } + copy_v3_v3(pro->start, start); + copy_v3_v3(pro->end, end); /* 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); @@ -1384,69 +1354,55 @@ static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv) * If the profile is going to lead into unbeveled edges on each side * (that is, both BoundVerts are "on-edge" points on non-beveled edges) */ - if (DEBUG_OLD_PLANE_SPECIAL && (e->prev->is_bev || e->next->is_bev)) { - do_linear_interp = true; - } - else { - if (DEBUG_OLD_PROJ_TO_PERP_PLANE) { - 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); - } - 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. */ - float d3[3], d4[3], co4[3], meetco[3], isect2[3]; - int isect_kind; - - sub_v3_v3v3(d3, e->prev->e->v1->co, e->prev->e->v2->co); - sub_v3_v3v3(d4, e->next->e->v1->co, e->next->e->v2->co); - normalize_v3(d3); - normalize_v3(d4); - if (nearly_parallel(d3, d4)) { - /* Offset lines are collinear - want linear interpolation. */ - mid_v3_v3v3(pro->middle, start, end); - do_linear_interp = true; - } - else { - 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, start, end); - do_linear_interp = true; - } - } - } - } - copy_v3_v3(pro->end, end); - sub_v3_v3v3(d1, pro->middle, start); - normalize_v3(d1); - 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. */ + 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. */ + float d3[3], d4[3], co4[3], meetco[3], isect2[3]; + int isect_kind; + + sub_v3_v3v3(d3, e->prev->e->v1->co, e->prev->e->v2->co); + sub_v3_v3v3(d4, e->next->e->v1->co, e->next->e->v2->co); + normalize_v3(d3); + normalize_v3(d4); + if (nearly_parallel(d3, d4)) { + /* Offset lines are collinear - want linear interpolation. */ + mid_v3_v3v3(pro->middle, start, end); do_linear_interp = true; } else { - copy_v3_v3(pro->plane_co, bv->v->co); - copy_v3_v3(pro->proj_dir, pro->plane_no); + 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, start, end); + do_linear_interp = true; + } } } + copy_v3_v3(pro->end, end); + sub_v3_v3v3(d1, pro->middle, start); + normalize_v3(d1); + 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. */ + do_linear_interp = true; + } + else { + copy_v3_v3(pro->plane_co, bv->v->co); + copy_v3_v3(pro->proj_dir, pro->plane_no); + } } copy_v3_v3(pro->plane_co, start); } else if (bndv->is_arc_start) { - /* Assume pro->middle was alredy set. */ + /* Assume pro->middle was already set. */ copy_v3_v3(pro->start, start); copy_v3_v3(pro->end, end); pro->super_r = PRO_CIRCLE_R; @@ -1455,6 +1411,17 @@ static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv) zero_v3(pro->proj_dir); do_linear_interp = false; } + else if (bp->vertex_only) { + copy_v3_v3(pro->start, start); + copy_v3_v3(pro->middle, bv->v->co); + copy_v3_v3(pro->end, end); + pro->super_r = bp->pro_super_r; + zero_v3(pro->plane_co); + zero_v3(pro->plane_no); + zero_v3(pro->proj_dir); + do_linear_interp = false; + } + if (do_linear_interp) { pro->super_r = PRO_LINE_R; copy_v3_v3(pro->start, start); @@ -1467,11 +1434,11 @@ static void set_profile_params(BevelParams *bp, BevVert *bv, BoundVert *bndv) } } -/* Maybe move the profile plane for bndv->ebev to the plane its profile's start, and the +/* Maybe move the profile plane for bndv->ebev to the plane its profile's start, and the * original beveled vert, bmv. This will usually be the plane containing its adjacent * non-beveled edges, but sometimes the start and the end are not on those edges. * - * Currently just used in build boundary terminal edge */ + * Currently just used in #build_boundary_terminal_edge */ static void move_profile_plane(BoundVert *bndv, BMVert *bmvert) { float d1[3], d2[3], no[3], no2[3], no3[3], dot2, dot3; @@ -1496,6 +1463,9 @@ static void move_profile_plane(BoundVert *bndv, BMVert *bmvert) copy_v3_v3(bndv->profile.plane_no, no); } } + + /* We've changed the parameters from their defaults, so don't recalculate them later. */ + pro->special_params = true; } /* Move the profile plane for the two BoundVerts involved in a weld. @@ -1531,6 +1501,10 @@ static void move_weld_profile_planes(BevVert *bv, BoundVert *bndv1, BoundVert *b copy_v3_v3(bndv2->profile.plane_no, no); } } + + /* We've changed the parameters from their defaults, so don't recalculate them later. */ + bndv1->profile.special_params = true; + bndv2->profile.special_params = true; } /* return 1 if a and b are in CCW order on the normal side of f, @@ -1748,6 +1722,7 @@ static void calculate_profile(BevelParams *bp, BoundVert *bndv, bool reversed, b else { map_ok = make_unit_square_map(pro->start, pro->middle, pro->end, map); } + if (bp->vmesh_method == BEVEL_VMESH_CUTOFF && map_ok) { /* Calculate the "height" of the profile by putting the (0,0) and (1,1) corners of the * un-transformed profile throughout the 2D->3D map and calculating the distance between them. @@ -1759,6 +1734,7 @@ static void calculate_profile(BevelParams *bp, BoundVert *bndv, bool reversed, b mul_v3_m4v3(top_corner, map, p); pro->height = len_v3v3(bottom_corner, top_corner); } + /* The first iteration is the nseg case, the second is the seg_2 case (if it's needed) */ for (i = 0; i < 2; i++) { if (i == 0) { @@ -2321,15 +2297,20 @@ static bool eh_on_plane(EdgeHalf *e) /* Calculate the profiles for all the BoundVerts of VMesh vm */ static void calculate_vm_profiles(BevelParams *bp, BevVert *bv, VMesh *vm) { - BoundVert *bndv; - - bndv = vm->boundstart; + BoundVert *bndv = vm->boundstart; do { - set_profile_params(bp, bv, bndv); - /* Use the miter profile spacing struct if the default is filled with the custom profile. */ - bool miter_profile = bp->use_custom_profile && (bndv->is_arc_start || bndv->is_patch_start); - /* Don't bother reversing the profile if it's a miter profile */ - bool reverse_profile = !bndv->is_profile_start && !miter_profile; + /* In special cases the params will have already been set. */ + if (!bndv->profile.special_params) { + set_profile_params(bp, bv, bndv); + } + bool miter_profile = false; + bool reverse_profile = false; + if (bp->use_custom_profile) { + /* Use the miter profile spacing struct if the default is filled with the custom profile. */ + miter_profile = (bndv->is_arc_start || bndv->is_patch_start); + /* Don't bother reversing the profile if it's a miter profile */ + reverse_profile = !bndv->is_profile_start && !miter_profile; + } calculate_profile(bp, bndv, reverse_profile, miter_profile); } while ((bndv = bndv->next) != vm->boundstart); } @@ -2357,8 +2338,6 @@ static void build_boundary_vertex_only(BevelParams *bp, BevVert *bv, bool constr } } while ((e = e->next) != efirst); - calculate_vm_profiles(bp, bv, vm); - if (construct) { set_bound_vert_seams(bv, bp->mark_seam, bp->mark_sharp); if (vm->count == 2) { @@ -2471,15 +2450,13 @@ static void build_boundary_terminal_edge(BevelParams *bp, } } } - calculate_vm_profiles(bp, bv, vm); if (bv->edgecount >= 3) { /* Special case: snap profile to plane of adjacent two edges. */ bndv = vm->boundstart; BLI_assert(bndv->ebev != NULL); + set_profile_params(bp, bv, bndv); move_profile_plane(bndv, bv->v); - /* This step happens before the profile orientation pass so don't reverse the profile. */ - calculate_profile(bp, bndv, false, false); } if (construct) { @@ -2506,17 +2483,6 @@ static void build_boundary_terminal_edge(BevelParams *bp, vm->mesh_kind = M_POLY; } } -#ifdef DEBUG_CUSTOM_PROFILE_WELD - if (bp->seg > 1) { - printf("Terminal Edge Profile Coordinates:\n"); - for (int k = 0; k < bp->seg; k++) { - printf("%0.4f, %0.4f, %0.4f\n", - (double)vm->boundstart->profile.prof_co[3 * k], - (double)vm->boundstart->profile.prof_co[3 * k + 1], - (double)vm->boundstart->profile.prof_co[3 * k + 2]); - } - } -#endif } /* Helper for build_boundary to handle special miters */ @@ -2831,8 +2797,6 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) adjust_miter_coords(bp, bv, emiter); } - calculate_vm_profiles(bp, bv, vm); - if (construct) { set_bound_vert_seams(bv, bp->mark_seam, bp->mark_sharp); @@ -3185,53 +3149,6 @@ static void regularize_profile_orientation(BevelParams *bp, BMEdge *bme) } } -#ifdef DEBUG_PROFILE_ORIENTATION_DRAW -/** - * Draws markers on beveled edges showing the side that the profile starts on. A sphere shows - * the start side of the profile where it starts, and the lines connected to the sphere show which - * edge the orientation corresponds to. - * \note Only drawn while bevel is calculating, the debug geometry is not persistent. - */ -static void debug_draw_profile_orientation(BevelParams *bp, BMesh *bm) -{ - BMIter iter; - BMEdge *bmedge; - float middle[3]; - - BM_ITER_MESH (bmedge, &iter, bm, BM_EDGES_OF_MESH) { - if (BM_elem_flag_test(bmedge, BM_ELEM_TAG)) { - mid_v3_v3v3(middle, bmedge->v1->co, bmedge->v2->co); - - /* Draw the orientation for the first side of the edge. */ - EdgeHalf *edge_half = find_edge_half(find_bevvert(bp, bmedge->v1), bmedge); - if (edge_half->leftv->is_profile_start) { /* The left boundvert defines the profiles. */ - DRW_debug_sphere(edge_half->leftv->nv.co, 0.04f, debug_color_red); - DRW_debug_line_v3v3(middle, edge_half->leftv->nv.co, debug_color_red); - DRW_debug_line_v3v3(bmedge->v1->co, edge_half->leftv->nv.co, debug_color_red); - } - else { - DRW_debug_sphere(edge_half->rightv->nv.co, 0.04f, debug_color_red); - DRW_debug_line_v3v3(middle, edge_half->rightv->nv.co, debug_color_red); - DRW_debug_line_v3v3(bmedge->v1->co, edge_half->rightv->nv.co, debug_color_red); - } - - /* Draw the orientation for the second side of the edge. */ - edge_half = find_edge_half(find_bevvert(bp, bmedge->v2), bmedge); - if (edge_half->leftv->is_profile_start) { - DRW_debug_sphere(edge_half->leftv->nv.co, 0.05f, debug_color_blue); - DRW_debug_line_v3v3(middle, edge_half->leftv->nv.co, debug_color_blue); - DRW_debug_line_v3v3(bmedge->v2->co, edge_half->leftv->nv.co, debug_color_blue); - } - else { - DRW_debug_sphere(edge_half->rightv->nv.co, 0.05f, debug_color_blue); - DRW_debug_line_v3v3(middle, edge_half->rightv->nv.co, debug_color_blue); - DRW_debug_line_v3v3(bmedge->v2->co, edge_half->rightv->nv.co, debug_color_blue); - } - } - } -} -#endif - /* Adjust the offsets for a single cycle or chain. * For chains and some cycles, a fast solution exists. * Otherwise, we set up and solve a linear least squares problem @@ -3643,9 +3560,6 @@ static void vmesh_copy_equiv_verts(VMesh *vm) /* Calculate and return in r_cent the centroid of the center poly */ static void vmesh_center(VMesh *vm, float r_cent[3]) { -#ifdef DEBUG_CUSTOM_PROFILE_ADJ - printf("VMESH CENTER\n"); -#endif int n, ns2, i; n = vm->count; @@ -4157,9 +4071,8 @@ static VMesh *make_cube_corner_adj_vmesh(BevelParams *bp) copy_v3_v3(bndv->profile.plane_co, bndv->profile.start); cross_v3_v3v3(bndv->profile.plane_no, bndv->profile.start, bndv->profile.end); copy_v3_v3(bndv->profile.proj_dir, bndv->profile.plane_no); - /* No need to reverse the profile or use the miter profile spacing struct because this case - * isn't used with custom profiles. */ - calculate_profile(bp, bndv, false, false); + /* Calculate profiles again because we started over with new boundverts. */ + calculate_profile(bp, bndv, false, false); /* No custom profiles in this case. */ /* Just building the boundaries here, so sample the profile halfway through */ get_profile_point(bp, &bndv->profile, 1, 2, mesh_vert(vm0, i, 0, 1)->co); @@ -4394,14 +4307,6 @@ static void snap_to_pipe_profile(BoundVert *vpipe, bool midline, float co[3]) */ static VMesh *pipe_adj_vmesh(BevelParams *bp, BevVert *bv, BoundVert *vpipe) { -#ifdef DEBUG_CUSTOM_PROFILE_PIPE - printf("PIPE ADJ VMESH\n"); - float green[4] = {0.0f, 1.0f, 0.0f, 1.0f}; - float blue[4] = {0.0f, 0.0f, 1.0f, 1.0f}; - float red[4] = {1.0f, 0.0f, 0.0f, 1.0f}; - float white[4] = {1.0f, 1.0f, 1.0f, 1.0f}; - float *color; -#endif int i, j, k, n_bndv, ns, half_ns, ipipe1, ipipe2, ring; VMesh *vm; bool even, midline; @@ -4418,11 +4323,6 @@ static VMesh *pipe_adj_vmesh(BevelParams *bp, BevVert *bv, BoundVert *vpipe) ipipe1 = vpipe->index; ipipe2 = vpipe->next->next->index; -#ifdef DEBUG_CUSTOM_PROFILE_PIPE - printf("ipipe1: %d\n", ipipe1); - printf("ipipe2: %d\n", ipipe2); -#endif - for (i = 0; i < n_bndv; i++) { for (j = 1; j <= half_ns; j++) { for (k = 0; k <= half_ns; k++) { @@ -4456,18 +4356,6 @@ static VMesh *pipe_adj_vmesh(BevelParams *bp, BevVert *bv, BoundVert *vpipe) /* Place the vertex by interpolatin between the two profile points using the factor. */ interp_v3_v3v3(mesh_vert(vm, i, j, k)->co, profile_point_pipe1, profile_point_pipe2, f); -#ifdef DEBUG_CUSTOM_PROFILE_PIPE - printf("(%d, %d, %d)\n", i, j, k); - printf("f: %.3f\n", f); - printf("point 1: (%.3f, %.3f, %.3f)\n", - profile_point_pipe1[0], - profile_point_pipe1[1], - profile_point_pipe1[2]); - printf("point 2: (%.3f, %.3f, %.3f)\n", - profile_point_pipe2[0], - profile_point_pipe2[1], - profile_point_pipe2[2]); -#endif } else { /* A tricky case is for the 'square' profiles and an even nseg: we want certain @@ -4479,33 +4367,6 @@ static VMesh *pipe_adj_vmesh(BevelParams *bp, BevVert *bv, BoundVert *vpipe) } } } -#ifdef DEBUG_CUSTOM_PROFILE_PIPE - /* Draw the locations of all the vertices after the "snapping" process */ - for (i = 0; i < n_bndv; i++) { - for (j = 1; j <= half_ns; j++) { - for (k = 1; k <= ns; k++) { - if (!is_canon(vm, i, j, k)) { - continue; - } - switch (i) { - case 0: - color = red; - break; - case 1: - color = green; - break; - case 2: - color = blue; - break; - case 3: - color = white; - break; - } - DRW_debug_sphere(mesh_vert(vm, i, j, k)->co, 0.01f, color); - } - } - } -#endif return vm; } @@ -4922,20 +4783,6 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv, BoundVert odd = ns % 2; BLI_assert(n_bndv >= 3 && ns > 1); - /* Add support for profiles in vertex only in-plane bevels. */ - if (bp->vertex_only) { - bndv = bv->vmesh->boundstart; - do { - Profile *pro = &bndv->profile; - copy_v3_v3(pro->middle, bv->v->co); - pro->super_r = bp->pro_super_r; - bool miter_profile = bp->use_custom_profile && (bndv->is_arc_start || bndv->is_patch_start); - /* Orientation doesn't matter when only beveling vertices */ - calculate_profile(bp, bndv, false, miter_profile); - bndv = bndv->next; - } while (bndv != bv->vmesh->boundstart); - } - if (bp->pro_super_r == PRO_SQUARE_R && bv->selcount >= 3 && !odd && !bp->use_custom_profile) { vm1 = square_out_adj_vmesh(bp, bv); } @@ -5105,6 +4952,7 @@ static void bevel_build_cutoff(BevelParams *bp, BMesh *bm, BevVert *bv) { #ifdef DEBUG_CUSTOM_PROFILE_CUTOFF printf("BEVEL BUILD CUTOFF\n"); +# define F3(v) (v)[0], (v)[1], (v)[2] int j; #endif int i; @@ -5143,10 +4991,7 @@ static void bevel_build_cutoff(BevelParams *bp, BMesh *bm, BevVert *bv) #ifdef DEBUG_CUSTOM_PROFILE_CUTOFF printf("Corner vertices:\n"); for (j = 0; j < n_bndv; j++) { - printf(" (%.3f, %.3f, %.3f)\n", - (double)mesh_vert(bv->vmesh, j, 1, 0)->co[0], - (double)mesh_vert(bv->vmesh, j, 1, 0)->co[1], - (double)mesh_vert(bv->vmesh, j, 1, 0)->co[2]); + printf(" (%.3f, %.3f, %.3f)\n", F3(mesh_vert(bv->vmesh, j, 1, 0)->co)); } #endif @@ -5204,21 +5049,14 @@ static void bevel_build_cutoff(BevelParams *bp, BMesh *bm, BevVert *bv) if (bndv->is_patch_start || bndv->is_arc_start) { printf(" Miter profile\n"); } - printf(" Corner 1: (%0.3f, %0.3f, %0.3f)\n", - (double)mesh_vert(bv->vmesh, i, 1, 0)->co[0], - (double)mesh_vert(bv->vmesh, i, 1, 0)->co[1], - (double)mesh_vert(bv->vmesh, i, 1, 0)->co[2]); + printf(" Corner 1: (%0.3f, %0.3f, %0.3f)\n", F3(mesh_vert(bv->vmesh, i, 1, 0)->co)); #endif /* Add profile point vertices to the face, including the last one. */ for (int k = 0; k < bp->seg + 1; k++) { face_bmverts[k + 1] = mesh_vert(bv->vmesh, i, 0, k)->v; /* Leave room for first vert. */ #ifdef DEBUG_CUSTOM_PROFILE_CUTOFF - printf(" Profile %d: (%0.3f, %0.3f, %0.3f)\n", - k, - (double)mesh_vert(bv->vmesh, i, 0, k)->co[0], - (double)mesh_vert(bv->vmesh, i, 0, k)->co[1], - (double)mesh_vert(bv->vmesh, i, 0, k)->co[2]); + printf(" Profile %d: (%0.3f, %0.3f, %0.3f)\n", k, F3(mesh_vert(bv->vmesh, i, 0, k)->co)); #endif } @@ -5226,10 +5064,7 @@ static void bevel_build_cutoff(BevelParams *bp, BMesh *bm, BevVert *bv) if (build_center_face) { face_bmverts[bp->seg + 2] = mesh_vert(bv->vmesh, i, 1, 1)->v; #ifdef DEBUG_CUSTOM_PROFILE_CUTOFF - printf(" Corner 2: (%0.3f, %0.3f, %0.3f)\n", - (double)mesh_vert(bv->vmesh, i, 1, 1)->co[0], - (double)mesh_vert(bv->vmesh, i, 1, 1)->co[1], - (double)mesh_vert(bv->vmesh, i, 1, 1)->co[2]); + printf(" Corner 2: (%0.3f, %0.3f, %0.3f)\n", F3(mesh_vert(bv->vmesh, i, 1, 1)->co)); #endif } @@ -5428,7 +5263,6 @@ static void bevel_build_trifan(BevelParams *bp, BMesh *bm, BevVert *bv) * we have to make it here. */ static void bevel_vert_two_edges(BevelParams *bp, BMesh *bm, BevVert *bv) { - VMesh *vm = bv->vmesh; BMVert *v1, *v2; BMEdge *e_eg, *bme; @@ -5455,8 +5289,6 @@ static void bevel_vert_two_edges(BevelParams *bp, BMesh *bm, BevVert *bv) zero_v3(pro->plane_co); zero_v3(pro->plane_no); zero_v3(pro->proj_dir); - /* there's no orientation chain to continue so the orientation of the bevel doesn't matter. */ - calculate_profile(bp, bndv, false, false); for (k = 1; k < ns; k++) { get_profile_point(bp, pro, k, ns, co); @@ -5519,15 +5351,17 @@ static void build_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv) } else { /* Get the last of the two BoundVerts. */ weld2 = bndv; + set_profile_params(bp, bv, weld1); + set_profile_params(bp, bv, weld2); move_weld_profile_planes(bv, weld1, weld2); - if (!bp->use_custom_profile) { /* Else profile recalculated in next loop. */ - calculate_profile(bp, weld1, !weld1->is_profile_start, false); - calculate_profile(bp, weld2, !weld2->is_profile_start, false); - } } } } while ((bndv = bndv->next) != vm->boundstart); + /* It's simpler to calculate all profiles only once at a single moment, so keep just a single + * profile calculation here, the last point before actual mesh verts are created. */ + calculate_vm_profiles(bp, bv, vm); + /* Create new vertices and place them based on the profiles. */ /* Copy other ends to (i, 0, ns) for all i, and fill in profiles for edges. */ bndv = vm->boundstart; @@ -5536,10 +5370,6 @@ static void build_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv) /* bndv's last vert along the boundary arc is the first of the next BoundVert's arc. */ copy_mesh_vert(vm, i, 0, ns, bndv->next->index, 0, 0); - /* Fix the profile orientations if it's not a miter profile. */ - if (bp->use_custom_profile && !bndv->is_arc_start && !bndv->is_patch_start) { - calculate_profile(bp, bndv, !bndv->is_profile_start, false); - } if (vm->mesh_kind != M_ADJ) { for (k = 1; k < ns; k++) { if (bndv->ebev) { @@ -5589,24 +5419,6 @@ static void build_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv) copy_mesh_vert(bv->vmesh, weld2->index, 0, ns - k, weld1->index, 0, k); } } -#ifdef DEBUG_CUSTOM_PROFILE_WELD - if (weld && ns > 1) { - printf("Weld1 profile coordinates:\n"); - for (k = 0; k < ns; k++) { - printf("%0.4f, %0.4f, %0.4f\n", - (double)weld1->profile.prof_co[3 * k], - (double)weld1->profile.prof_co[3 * k + 1], - (double)weld1->profile.prof_co[3 * k + 2]); - } - printf("Weld2 profile coordinates\n"); - for (k = 0; k < ns; k++) { - printf("%0.4f, %0.4f, %0.4f\n", - (double)weld2->profile.prof_co[3 * k], - (double)weld2->profile.prof_co[3 * k + 1], - (double)weld2->profile.prof_co[3 * k + 2]); - } - } -#endif /* Make sure the pipe case ADJ mesh is used for both the "Grid Fill" (ADJ) and cutoff options. */ vpipe = NULL; @@ -7423,7 +7235,7 @@ void BM_mesh_bevel(BMesh *bm, adjust_offsets(&bp, bm); } - /* Maintain consistent orientations for the unsymmetrical custom profiles. */ + /* Maintain consistent orientations for the asymmetrical custom profiles. */ if (bp.use_custom_profile) { BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { if (BM_elem_flag_test(e, BM_ELEM_TAG)) { @@ -7431,11 +7243,6 @@ void BM_mesh_bevel(BMesh *bm, } } } -#ifdef DEBUG_PROFILE_ORIENTATION_DRAW - if (bp.use_custom_profile) { - debug_draw_profile_orientation(&bp, bm); - } -#endif /* Build the meshes around vertices, now that positions are final */ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { @@ -7511,22 +7318,6 @@ void BM_mesh_bevel(BMesh *bm, BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { BM_elem_flag_disable(l, BM_ELEM_LONG_TAG); } - -#ifdef DEBUG_CUSTOM_PROFILE_SAMPLE - printf("Profile spacing:\n"); - printf("Seg values:\n"); - if (bp.pro_spacing.xvals != NULL) { - for (int i = 0; i < bp.seg; i++) { - printf("(%.3f, %.3f)\n", bp.pro_spacing.xvals[i], bp.pro_spacing.yvals[i]); - } - } - if (bp.pro_spacing.seg_2 != bp.seg && bp.pro_spacing.seg_2 != 0) { - printf("Seg_2 values:\n"); - for (int i = 0; i < bp.pro_spacing.seg_2; i++) { - printf("(%0.2f, %0.2f)\n", bp.pro_spacing.xvals_2[i], bp.pro_spacing.yvals_2[i]); - } - } -#endif } /* primary free */ diff --git a/source/blender/bmesh/tools/bmesh_intersect_edges.c b/source/blender/bmesh/tools/bmesh_intersect_edges.c index c3687c5d477..b25dc82aac9 100644 --- a/source/blender/bmesh/tools/bmesh_intersect_edges.c +++ b/source/blender/bmesh/tools/bmesh_intersect_edges.c @@ -57,7 +57,7 @@ struct EDBMSplitBestFaceData { * Track the range of vertices in edgenet along the faces normal, * find the lowest since it's most likely to be most co-planar with the face. */ - float best_face_range_on_normal_axis; + float best_edgenet_range_on_face_normal; BMFace *r_best_face; }; @@ -76,11 +76,14 @@ static bool bm_vert_pair_share_best_splittable_face_cb(BMFace *f, SWAP(float, min, max); } - BMVert *v_test = l_b->v; BMEdge **e_iter = &data->edgenet[0]; + BMEdge *e_next = data->edgenet[1]; + BMVert *v_test = ELEM((*e_iter)->v1, e_next->v1, e_next->v2) ? (*e_iter)->v2 : (*e_iter)->v1; + int verts_len = data->edgenet_len - 1; for (int i = verts_len; i--; e_iter++) { v_test = BM_edge_other_vert(*e_iter, v_test); + BLI_assert(v_test != NULL); if (!BM_face_point_inside_test(f, v_test->co)) { return false; } @@ -93,9 +96,9 @@ static bool bm_vert_pair_share_best_splittable_face_cb(BMFace *f, } } - const float test_face_range_on_normal_axis = max - min; - if (test_face_range_on_normal_axis < data->best_face_range_on_normal_axis) { - data->best_face_range_on_normal_axis = test_face_range_on_normal_axis; + const float test_edgenet_range_on_face_normal = max - min; + if (test_edgenet_range_on_face_normal < data->best_edgenet_range_on_face_normal) { + data->best_edgenet_range_on_face_normal = test_edgenet_range_on_face_normal; data->r_best_face = f; } @@ -111,114 +114,79 @@ static bool bm_vert_pair_share_splittable_face_cb(BMFace *UNUSED(f), float(*data)[3] = userdata; float *v_a_co = data[0]; float *v_a_b_dir = data[1]; - - float lambda; - if (isect_ray_seg_v3(v_a_co, v_a_b_dir, l_a->prev->v->co, l_a->next->v->co, &lambda)) { - if (IN_RANGE(lambda, 0.0f, 1.0f)) { + const float range_min = -FLT_EPSILON; + const float range_max = 1.0f + FLT_EPSILON; + + float co[3]; + float dir[3]; + float lambda_a; + float lambda_b; + + copy_v3_v3(co, l_a->prev->v->co); + sub_v3_v3v3(dir, l_a->next->v->co, co); + if (isect_ray_ray_v3(v_a_co, v_a_b_dir, co, dir, &lambda_a, &lambda_b)) { + if (IN_RANGE(lambda_a, range_min, range_max) && IN_RANGE(lambda_b, range_min, range_max)) { return true; } - else if (isect_ray_seg_v3(v_a_co, v_a_b_dir, l_b->prev->v->co, l_b->next->v->co, &lambda)) { - return IN_RANGE(lambda, 0.0f, 1.0f); + else { + copy_v3_v3(co, l_b->prev->v->co); + sub_v3_v3v3(dir, l_b->next->v->co, co); + if (isect_ray_ray_v3(v_a_co, v_a_b_dir, co, dir, &lambda_a, &lambda_b)) { + return IN_RANGE(lambda_a, range_min, range_max) && + IN_RANGE(lambda_b, range_min, range_max); + } } } return false; } -void BM_vert_weld_linked_wire_edges_into_linked_faces( - BMesh *bm, BMVert *v, const float epsilon, BMEdge **r_edgenet[], int *r_edgenet_alloc_len) +static BMFace *bm_vert_pair_best_face_get( + BMVert *v_a, BMVert *v_b, BMEdge **edgenet, const int edgenet_len, const float epsilon) { - BMEdge **edgenet = *r_edgenet; - int edgenet_alloc_len = *r_edgenet_alloc_len; - - BMIter iter; - BMEdge *e; - BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { - int edgenet_len = 0; - BMVert *v_other = v; - while (BM_edge_is_wire(e)) { - if (edgenet_alloc_len == edgenet_len) { - edgenet_alloc_len = (edgenet_alloc_len + 1) * 2; - edgenet = MEM_reallocN(edgenet, (edgenet_alloc_len) * sizeof(*edgenet)); - } - edgenet[edgenet_len++] = e; - v_other = BM_edge_other_vert(e, v_other); - if (v_other == v) { - /* Endless loop. */ - break; - } - - BMEdge *e_next = BM_DISK_EDGE_NEXT(e, v_other); - if (e_next == e) { - /* Vert is wire_endpoint. */ - edgenet_len = 0; - break; - } - - BMEdge *e_test = e_next; - while ((e_test = BM_DISK_EDGE_NEXT(e_test, v_other)) != e) { - if (e_test->l) { - /* Vert is linked to a face. */ - goto l_break; - } - } - - e = e_next; - } - - BMLoop *dummy; - BMFace *best_face; + BMFace *r_best_face = NULL; - l_break: - if (edgenet_len == 0) { - /* Nothing to do. */ - continue; - } - if (edgenet_len == 1) { - float data[2][3]; - copy_v3_v3(data[0], v_other->co); - sub_v3_v3v3(data[1], v->co, data[0]); - best_face = BM_vert_pair_shared_face_cb( - v_other, v, true, bm_vert_pair_share_splittable_face_cb, &data, &dummy, &dummy); - } - else { - struct EDBMSplitBestFaceData data = { - .edgenet = edgenet, - .edgenet_len = edgenet_len, - .best_face_range_on_normal_axis = FLT_MAX, - .r_best_face = NULL, - }; - BM_vert_pair_shared_face_cb( - v_other, v, true, bm_vert_pair_share_best_splittable_face_cb, &data, &dummy, &dummy); - - if (data.r_best_face) { - float no[3], min = FLT_MAX, max = -FLT_MAX; - copy_v3_v3(no, data.r_best_face->no); - BMVert *v_test; - BMIter f_iter; - BM_ITER_ELEM (v_test, &f_iter, data.r_best_face, BM_VERTS_OF_FACE) { - float dot = dot_v3v3(v_test->co, no); - if (dot < min) { - min = dot; - } - if (dot > max) { - max = dot; - } + BMLoop *dummy; + if (edgenet_len == 1) { + float data[2][3]; + copy_v3_v3(data[0], v_b->co); + sub_v3_v3v3(data[1], v_a->co, data[0]); + r_best_face = BM_vert_pair_shared_face_cb( + v_a, v_b, false, bm_vert_pair_share_splittable_face_cb, &data, &dummy, &dummy); + } + else { + struct EDBMSplitBestFaceData data = { + .edgenet = edgenet, + .edgenet_len = edgenet_len, + .best_edgenet_range_on_face_normal = FLT_MAX, + .r_best_face = NULL, + }; + BM_vert_pair_shared_face_cb( + v_a, v_b, true, bm_vert_pair_share_best_splittable_face_cb, &data, &dummy, &dummy); + + if (data.r_best_face) { + /* Check if the edgenet's range is smaller than the face's range. */ + float no[3], min = FLT_MAX, max = -FLT_MAX; + copy_v3_v3(no, data.r_best_face->no); + BMVert *v_test; + BMIter f_iter; + BM_ITER_ELEM (v_test, &f_iter, data.r_best_face, BM_VERTS_OF_FACE) { + float dot = dot_v3v3(v_test->co, no); + if (dot < min) { + min = dot; } - float range = max - min + 2 * epsilon; - if (range < data.best_face_range_on_normal_axis) { - data.r_best_face = NULL; + if (dot > max) { + max = dot; } } - best_face = data.r_best_face; - } - - if (best_face) { - BM_face_split_edgenet(bm, best_face, edgenet, edgenet_len, NULL, NULL); + float face_range_on_normal = max - min + 2 * epsilon; + if (face_range_on_normal < data.best_edgenet_range_on_face_normal) { + data.r_best_face = NULL; + } } + r_best_face = data.r_best_face; } - *r_edgenet = edgenet; - *r_edgenet_alloc_len = edgenet_alloc_len; + return r_best_face; } /** \} */ @@ -517,7 +485,8 @@ static int sort_cmp_by_lambda_cb(const void *index1_v, const void *index2_v, voi #define INTERSECT_EDGES -bool BM_mesh_intersect_edges(BMesh *bm, const char hflag, const float dist, GHash *r_targetmap) +bool BM_mesh_intersect_edges( + BMesh *bm, const char hflag, const float dist, const bool split_faces, GHash *r_targetmap) { bool ok = false; @@ -560,6 +529,9 @@ bool BM_mesh_intersect_edges(BMesh *bm, const char hflag, const float dist, GHas verts_remain_len++; } } + + /* The index will indicate which cut in pair_array this vertex belongs to. */ + BM_elem_index_set(v, -1); } bm->elem_index_dirty |= BM_VERT; @@ -621,6 +593,10 @@ bool BM_mesh_intersect_edges(BMesh *bm, const char hflag, const float dist, GHas /* Don't test hidden edges or smaller than the minimum distance. * These have already been handled in the vertices overlap. */ BM_elem_index_set(e, 0); + if (split_faces) { + /* Tag to be ignored. */ + BM_elem_flag_enable(e, BM_ELEM_TAG); + } continue; } @@ -631,6 +607,10 @@ bool BM_mesh_intersect_edges(BMesh *bm, const char hflag, const float dist, GHas else { BM_elem_index_set(e, EDGE_REMAIN_TO_TEST); edges_remain_len++; + if (split_faces) { + /* Tag to be ignored. */ + BM_elem_flag_enable(e, BM_ELEM_TAG); + } } } @@ -823,6 +803,11 @@ bool BM_mesh_intersect_edges(BMesh *bm, const char hflag, const float dist, GHas lambda = (pair_elem->lambda - lambda_prev) / (1.0f - lambda_prev); lambda_prev = pair_elem->lambda; e = pair_elem->edge; + if (split_faces) { + /* Tagged edges are ignored when split faces. + /* Untag these. */ + BM_elem_flag_disable(e, BM_ELEM_TAG); + } BMVert *v_new = BM_edge_split(bm, e, e->v1, NULL, lambda); pair_elem->vert = v_new; @@ -856,10 +841,136 @@ bool BM_mesh_intersect_edges(BMesh *bm, const char hflag, const float dist, GHas BLI_assert((*pair_iter)[0].elem->head.htype == BM_VERT); BLI_assert((*pair_iter)[1].elem->head.htype == BM_VERT); BLI_assert((*pair_iter)[0].elem != (*pair_iter)[1].elem); - - BLI_ghash_insert(r_targetmap, (*pair_iter)[0].vert, (*pair_iter)[1].vert); + BMVert *v_key, *v_val; + v_key = (*pair_iter)[0].vert; + v_val = (*pair_iter)[1].vert; + BLI_ghash_insert(r_targetmap, v_key, v_val); + if (split_faces) { + BM_elem_index_set(v_key, i * 2); + BM_elem_index_set(v_val, i * 2 + 1); + } } + if (split_faces) { + BMEdge **edgenet = NULL; + int edgenet_alloc_len = 0; + + struct EDBMSplitElem *pair_flat = (struct EDBMSplitElem *)&pair_array[0]; + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + if (BM_elem_flag_test(e, BM_ELEM_TAG)) { + continue; + } + BM_elem_flag_enable(e, BM_ELEM_TAG); + + BMVert *va, *vb, *va_dest = NULL; + va = e->v1; + vb = e->v2; + + int v_cut = BM_elem_index_get(va); + int v_cut_other = BM_elem_index_get(vb); + if (v_cut == -1 && v_cut_other == -1) { + continue; + } + + if (v_cut == -1) { + SWAP(BMVert *, va, vb); + v_cut = v_cut_other; + v_cut_other = -1; + } + + v_cut += v_cut % 2 ? -1 : 1; + va_dest = pair_flat[v_cut].vert; + + BMFace *best_face = NULL; + int edgenet_len = 0; + BMVert *v_other_dest, *v_other = vb; + BMEdge *e_net = e; + while (true) { + if (edgenet_alloc_len == edgenet_len) { + edgenet_alloc_len = (edgenet_alloc_len + 1) * 2; + edgenet = MEM_reallocN(edgenet, (edgenet_alloc_len) * sizeof(*edgenet)); + } + edgenet[edgenet_len++] = e_net; + + if (v_cut_other != -1) { + v_cut_other += v_cut_other % 2 ? -1 : 1; + v_other_dest = pair_flat[v_cut_other].vert; + } + else { + v_other_dest = v_other; + } + + best_face = bm_vert_pair_best_face_get( + va_dest, v_other_dest, edgenet, edgenet_len, dist); + + if (best_face) { + if (va_dest != va) { + e_net = edgenet[0]; + if (edgenet_len > 1) { + vb = BM_edge_other_vert(e_net, va); + } + else { + vb = v_other_dest; + } + edgenet[0] = BM_edge_create(bm, va_dest, vb, e_net, BM_CREATE_NOP); + } + if ((edgenet_len > 1) && (v_other_dest != v_other)) { + e_net = edgenet[edgenet_len - 1]; + edgenet[edgenet_len - 1] = BM_edge_create( + bm, v_other_dest, BM_edge_other_vert(e_net, v_other), e_net, BM_CREATE_NOP); + } + break; + } + + BMEdge *e_test = e_net, *e_next = NULL; + while ((e_test = BM_DISK_EDGE_NEXT(e_test, v_other)) != (e_net)) { + if (!BM_edge_is_wire(e_test)) { + if (BM_elem_flag_test(e, BM_ELEM_TAG)) { + continue; + } + if (BM_elem_index_get(e_test->v1) == -1 && BM_elem_index_get(e_test->v2) == -1) { + continue; + } + } + else if (!BM_edge_is_wire(e_net)) { + continue; + } + e_next = e_test; + break; + } + + if (e_next == NULL) { + break; + } + + e_net = e_next; + v_other = BM_edge_other_vert(e_net, v_other); + if (v_other == va) { + /* Endless loop. */ + break; + } + v_cut_other = BM_elem_index_get(v_other); + } + + if (best_face) { + BMFace **face_arr = NULL; + int face_arr_len = 0; + BM_face_split_edgenet(bm, best_face, edgenet, edgenet_len, &face_arr, &face_arr_len); + if (face_arr) { + /* Update the new faces normal. + * Normal is necessary to obtain the best face for edgenet */ + while (face_arr_len--) { + BM_face_normal_update(face_arr[face_arr_len]); + } + MEM_freeN(face_arr); + } + } + } + + if (edgenet) { + MEM_freeN(edgenet); + } + } ok = true; } } diff --git a/source/blender/bmesh/tools/bmesh_intersect_edges.h b/source/blender/bmesh/tools/bmesh_intersect_edges.h index a22a1ca1e1d..7e2252250d6 100644 --- a/source/blender/bmesh/tools/bmesh_intersect_edges.h +++ b/source/blender/bmesh/tools/bmesh_intersect_edges.h @@ -21,9 +21,7 @@ #ifndef __BMESH_INTERSECT_EDGES_H__ #define __BMESH_INTERSECT_EDGES_H__ -void BM_vert_weld_linked_wire_edges_into_linked_faces( - BMesh *bm, BMVert *v, const float epsilon, BMEdge **r_edgenet[], int *r_edgenet_alloc_len); - -bool BM_mesh_intersect_edges(BMesh *bm, const char hflag, const float dist, GHash *r_targetmap); +bool BM_mesh_intersect_edges( + BMesh *bm, const char hflag, const float dist, const bool split_faces, GHash *r_targetmap); #endif /* __BMESH_INTERSECT_EDGES_H__ */ |