Add mesh tool to split faces by wire edges (face menu)

This can be used in a similar way to the knife tool, but the edges are manually setup first.
This commit is contained in:
Campbell Barton 2014-07-11 10:32:33 +10:00
parent 48abc65c39
commit dd9a33dc83
5 changed files with 282 additions and 0 deletions

View File

@ -2278,6 +2278,7 @@ class VIEW3D_MT_edit_mesh_faces(Menu):
layout.operator("mesh.poke")
layout.operator("mesh.quads_convert_to_tris")
layout.operator("mesh.tris_convert_to_quads")
layout.operator("mesh.face_split_by_edges")
layout.separator()

View File

@ -45,6 +45,7 @@ set(SRC
editmesh_bisect.c
editmesh_extrude.c
editmesh_inset.c
editmesh_intersect.c
editmesh_knife.c
editmesh_knife_project.c
editmesh_loopcut.c

View File

@ -0,0 +1,276 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/editors/mesh/editmesh_intersect.c
* \ingroup edmesh
*/
#include "MEM_guardedalloc.h"
#include "DNA_object_types.h"
#include "BLI_math.h"
#include "BLI_array.h"
#include "BLI_linklist_stack.h"
#include "BKE_context.h"
#include "BKE_editmesh.h"
#include "WM_api.h"
#include "WM_types.h"
#include "ED_mesh.h"
#include "ED_screen.h"
#include "intern/bmesh_private.h"
#include "mesh_intern.h" /* own include */
/* -------------------------------------------------------------------- */
/* Face Split by Edges */
/** \name Face/Edge Split
* \{ */
static void bm_face_split_by_edges(BMesh *bm, BMFace *f, const char hflag)
{
BMEdge **edge_net = NULL;
BLI_array_declare(edge_net);
const int f_index = BM_elem_index_get(f);
BMLoop *l_iter;
BMLoop *l_first;
BMVert *v;
BMFace **face_arr;
int face_arr_len;
/* likely this will stay very small
* all verts pushed into this stack _must_ have their previous edges set! */
BLI_SMALLSTACK_DECLARE(vert_stack, BMVert *);
BLI_SMALLSTACK_DECLARE(vert_stack_next, BMVert *);
/* collect all edges */
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
BMIter iter;
BMEdge *e;
BM_ITER_ELEM (e, &iter, l_iter->v, BM_EDGES_OF_VERT) {
if (BM_elem_flag_test(e, hflag) &&
(BM_elem_index_get(e) == f_index))
{
BMVert *v;
v = BM_edge_other_vert(e, l_iter->v);
v->e = e;
BLI_SMALLSTACK_PUSH(vert_stack, v);
BLI_array_append(edge_net, e);
}
}
} while ((l_iter = l_iter->next) != l_first);
/* now assign all */
/* pop free values into the next stack */
while ((v = BLI_SMALLSTACK_POP_EX(vert_stack, vert_stack_next))) {
BMIter eiter;
BMEdge *e_next;
BM_ITER_ELEM (e_next, &eiter, v, BM_EDGES_OF_VERT) {
if (BM_elem_flag_test(e_next, hflag) &&
(BM_elem_index_get(e_next) == -1))
{
BMVert *v_next;
v_next = BM_edge_other_vert(e_next, v);
BM_elem_index_set(e_next, f_index);
BLI_SMALLSTACK_PUSH(vert_stack_next, v_next);
BLI_array_append(edge_net, e_next);
}
}
if (BLI_SMALLSTACK_IS_EMPTY(vert_stack)) {
BLI_SMALLSTACK_SWAP(vert_stack, vert_stack_next);
}
}
BM_face_split_edgenet(bm, f, edge_net, BLI_array_count(edge_net), &face_arr, &face_arr_len);
BLI_array_free(edge_net);
if (face_arr_len) {
int i;
for (i = 0; i < face_arr_len; i++) {
BM_face_select_set(bm, face_arr[i], true);
BM_elem_flag_disable(face_arr[i], hflag);
}
}
if (face_arr) {
MEM_freeN(face_arr);
}
}
static int edbm_face_split_by_edges_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMesh *bm = em->bm;
const char hflag = BM_ELEM_TAG;
BMVert *v;
BMEdge *e;
BMFace *f;
BMIter iter;
BLI_SMALLSTACK_DECLARE(loop_stack, BMLoop *);
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
BM_elem_flag_disable(v, hflag);
}
/* edge index is set to -1 then used to assosiate them with faces */
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
if (BM_elem_flag_test(e, BM_ELEM_SELECT) && BM_edge_is_wire(e)) {
BM_elem_flag_enable(e, hflag);
BM_elem_flag_enable(e->v1, hflag);
BM_elem_flag_enable(e->v2, hflag);
}
else {
BM_elem_flag_disable(e, hflag);
}
BM_elem_index_set(e, -1); /* set_dirty */
}
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
BM_elem_flag_enable(f, hflag);
}
else {
BM_elem_flag_disable(f, hflag);
}
}
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
if (BM_elem_flag_test(e, hflag)) {
BMIter viter;
BMVert *v;
BM_ITER_ELEM (v, &viter, e, BM_VERTS_OF_EDGE) {
BMIter liter;
BMLoop *l;
unsigned int loop_stack_len;
BMLoop *l_best = NULL;
BLI_assert(BLI_SMALLSTACK_IS_EMPTY(loop_stack));
loop_stack_len = 0;
BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
if (BM_elem_flag_test(l->f, hflag)) {
BLI_SMALLSTACK_PUSH(loop_stack, l);
loop_stack_len++;
}
}
if (loop_stack_len == 0) {
/* pass */
}
else if (loop_stack_len == 1) {
l_best = BLI_SMALLSTACK_POP(loop_stack);
}
else {
/* complicated case, match the edge with a face-loop */
BMVert *v_other = BM_edge_other_vert(e, v);
float e_dir[3];
/* we wan't closest to zero */
float dot_best = FLT_MAX;
sub_v3_v3v3(e_dir, v_other->co, v->co);
normalize_v3(e_dir);
while ((l = BLI_SMALLSTACK_POP(loop_stack))) {
float dot_test;
/* Check dot first to save on expensive angle-comparison.
* ideal case is 90d difference == 0.0 dot */
dot_test = fabsf(dot_v3v3(e_dir, l->f->no));
if (dot_test < dot_best) {
/* check we're in the correct corner (works with convex loops too) */
if (angle_signed_on_axis_v3v3v3_v3(l->prev->v->co, l->v->co, v_other->co, l->f->no) <
angle_signed_on_axis_v3v3v3_v3(l->prev->v->co, l->v->co, l->next->v->co, l->f->no))
{
dot_best = dot_test;
l_best = l;
}
}
}
}
if (l_best) {
BM_elem_index_set(e, BM_elem_index_get(l_best->f)); /* set_dirty */
}
}
}
}
bm->elem_index_dirty |= BM_EDGE;
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
if (BM_elem_flag_test(f, hflag)) {
bm_face_split_by_edges(bm, f, hflag);
}
}
EDBM_mesh_normals_update(em);
EDBM_update_generic(em, true, true);
return OPERATOR_FINISHED;
}
void MESH_OT_face_split_by_edges(struct wmOperatorType *ot)
{
/* identifiers */
ot->name = "Split by Edges";
ot->description = "Split faces by loose edges";
ot->idname = "MESH_OT_face_split_by_edges";
/* api callbacks */
ot->exec = edbm_face_split_by_edges_exec;
ot->poll = ED_operator_editmesh;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/** \} */

View File

@ -112,6 +112,9 @@ void MESH_OT_screw(struct wmOperatorType *ot);
/* *** editmesh_inset.c *** */
void MESH_OT_inset(struct wmOperatorType *ot);
/* *** editmesh_intersect.c *** */
void MESH_OT_face_split_by_edges(struct wmOperatorType *ot);
/* *** editmesh_knife.c *** */
void MESH_OT_knife_tool(struct wmOperatorType *ot);

View File

@ -170,6 +170,7 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_bridge_edge_loops);
WM_operatortype_append(MESH_OT_inset);
WM_operatortype_append(MESH_OT_face_split_by_edges);
WM_operatortype_append(MESH_OT_poke);
WM_operatortype_append(MESH_OT_wireframe);
WM_operatortype_append(MESH_OT_edge_split);