diff options
author | Campbell Barton <ideasman42@gmail.com> | 2013-09-05 15:07:49 +0400 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2013-09-05 15:07:49 +0400 |
commit | 8f49054b77f4006779a45b4d6977af383662722a (patch) | |
tree | 3bd0422b74aff8cbe3086ac3db7ca7e27ef4266b /source/blender/editors/mesh/editmesh_tools.c | |
parent | 4228463caada293d7de02d18b630c11a8b0c5479 (diff) |
grid-fill can now fill a single, closed edge loop.
the active vertex is used when possible, else the corner vertex is detected.
this should replace the grid-fill-manager addon by Alexander Nedovizin.
Diffstat (limited to 'source/blender/editors/mesh/editmesh_tools.c')
-rw-r--r-- | source/blender/editors/mesh/editmesh_tools.c | 134 |
1 files changed, 133 insertions, 1 deletions
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 1f5ea9f7b0f..fe9da4b4f1d 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -29,6 +29,8 @@ * \ingroup edmesh */ +#include <stddef.h> + #include "MEM_guardedalloc.h" #include "DNA_key_types.h" @@ -2832,6 +2834,101 @@ void MESH_OT_fill(wmOperatorType *ot) RNA_def_boolean(ot->srna, "use_beauty", true, "Beauty", "Use best triangulation division"); } +/* -------------------------------------------------------------------- */ +/* Grid Fill (and helper functions) */ + +static bool bm_edge_test_fill_grid_cb(BMEdge *e, void *UNUSED(bm_v)) +{ + return BM_elem_flag_test_bool(e, BM_ELEM_TAG); +} + +static float edbm_fill_grid_vert_tag_angle(BMVert *v) +{ + BMIter iter; + BMEdge *e_iter; + BMVert *v_pair[2]; + int i = 0; + BM_ITER_ELEM (e_iter, &iter, v, BM_EDGES_OF_VERT) { + if (BM_elem_flag_test(e_iter, BM_ELEM_TAG)) { + v_pair[i++] = BM_edge_other_vert(e_iter, v); + } + } + BLI_assert(i == 2); + + return fabsf((float)M_PI - angle_v3v3v3(v_pair[0]->co, v->co, v_pair[1]->co)); +} + +/** + * non-essential utility function to select 2 open edge loops from a closed loop. + */ +static void edbm_fill_grid_prepare(BMesh *bm, int span, int offset) +{ + BMEdge *e; + BMIter iter; + int count; + + ListBase eloops = {NULL}; + struct BMEdgeLoopStore *el_store; + // LinkData *el_store; + + /* select -> tag */ + BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { + BM_elem_flag_set(e, BM_ELEM_TAG, BM_elem_flag_test(e, BM_ELEM_SELECT)); + } + + count = BM_mesh_edgeloops_find(bm, &eloops, bm_edge_test_fill_grid_cb, bm); + el_store = eloops.first; + + if (count == 1 && BM_edgeloop_is_closed(el_store) && (BM_edgeloop_length_get(el_store) & 1) == 0) { + /* be clever! detect 2 edge loops from one closed edge loop */ + const int verts_len = BM_edgeloop_length_get(el_store); + ListBase *verts = BM_edgeloop_verts_get(el_store); + BMVert *v_act = BM_mesh_active_vert_get(bm); + LinkData *v_act_link; + BMEdge **edges = MEM_mallocN(sizeof(*edges) * verts_len, __func__); + int i; + + if (v_act && (v_act_link = BLI_findptr(verts, v_act, offsetof(LinkData, data)))) { + /* pass */ + } + else { + /* find the vertex with the best angle (a corner vertex) */ + LinkData *v_link, *v_link_best = NULL; + float angle_best = -1.0f; + for (v_link = verts->first; v_link; v_link = v_link->next) { + const float angle = edbm_fill_grid_vert_tag_angle(v_link->data); + if ((angle > angle_best) || (v_link_best == NULL)) { + angle_best = angle; + v_link_best = v_link; + } + } + + v_act_link = v_link_best; + v_act = v_act_link->data; + } + + if (offset != 0) { + v_act_link = BLI_findlink(verts, offset); + v_act = v_act_link->data; + } + + /* set this vertex first */ + BLI_rotatelist(verts, v_act_link); + BM_edgeloop_edges_get(el_store, edges); + + /* un-flag 'rails' */ + for (i = 0; i < span; i++) { + BM_elem_flag_disable(edges[i], BM_ELEM_TAG); + BM_elem_flag_disable(edges[(verts_len / 2) + i], BM_ELEM_TAG); + } + + MEM_freeN(edges); + } + /* else let the bmesh-operator handle it */ + + BM_mesh_edgeloops_free(&eloops); +} + static int edbm_fill_grid_exec(bContext *C, wmOperator *op) { BMOperator bmop; @@ -2841,9 +2938,36 @@ static int edbm_fill_grid_exec(bContext *C, wmOperator *op) const int totedge_orig = em->bm->totedge; const int totface_orig = em->bm->totface; + const bool use_prepare = true; + + if (use_prepare) { + /* use when we have a single loop selected */ + PropertyRNA *prop_span = RNA_struct_find_property(op->ptr, "span"); + PropertyRNA *prop_offset = RNA_struct_find_property(op->ptr, "offset"); + + const int clamp = em->bm->totvertsel; + int span; + int offset; + + if (RNA_property_is_set(op->ptr, prop_span)) { + span = RNA_property_int_get(op->ptr, prop_span); + span = min_ii(span, (clamp / 2) - 1); + } + else { + span = clamp / 4; + } + RNA_property_int_set(op->ptr, prop_span, span); + + offset = RNA_property_int_get(op->ptr, prop_offset); + offset = positive_mod(offset, clamp); + + /* in simple cases, move selection for tags, but also support more advanced cases */ + edbm_fill_grid_prepare(em->bm, span, offset); + } + if (!EDBM_op_init(em, &bmop, op, "grid_fill edges=%he mat_nr=%i use_smooth=%b", - BM_ELEM_SELECT, em->mat_nr, use_smooth)) + use_prepare ? BM_ELEM_TAG : BM_ELEM_SELECT, em->mat_nr, use_smooth)) { return OPERATOR_CANCELLED; } @@ -2871,6 +2995,8 @@ static int edbm_fill_grid_exec(bContext *C, wmOperator *op) void MESH_OT_fill_grid(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Grid Fill"; ot->description = "Fill grid from two loops"; @@ -2882,6 +3008,12 @@ void MESH_OT_fill_grid(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + prop = RNA_def_int(ot->srna, "span", 1, 1, INT_MAX, "Span", "Number of sides (zero disables)", 1, 100); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_int(ot->srna, "offset", 0, INT_MIN, INT_MAX, "Offset", "Number of sides (zero disables)", -100, 100); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } static int edbm_fill_holes_exec(bContext *C, wmOperator *op) |