knife projection feature,

apart of 3d printing tools - use to cookie-cut text into a mesh.
This commit is contained in:
Campbell Barton
2013-03-15 13:06:31 +00:00
parent 6dc4ea34e4
commit 03f02019f2
5 changed files with 335 additions and 0 deletions

View File

@@ -43,6 +43,7 @@ set(SRC
editmesh_add.c
editmesh_bvh.c
editmesh_knife.c
editmesh_knife_project.c
editmesh_loopcut.c
editmesh_rip.c
editmesh_select.c

View File

@@ -37,6 +37,7 @@
#include "BLI_blenlib.h"
#include "BLI_array.h"
#include "BLI_linklist.h"
#include "BLI_math.h"
#include "BLI_smallhash.h"
#include "BLI_memarena.h"
@@ -3270,3 +3271,167 @@ void MESH_OT_knife_tool(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "use_occlude_geometry", TRUE, "Occlude Geometry", "Only cut the front most geometry");
RNA_def_boolean(ot->srna, "only_selected", FALSE, "Only Selected", "Only cut selected geometry");
}
/* -------------------------------------------------------------------- */
/* Knife tool as a utility function
* that can be used for internal slicing operations */
static bool edbm_mesh_knife_face_isect(ARegion *ar, LinkNode *polys, BMFace *f, float projmat[4][4])
{
float co[3];
float co_ss[2];
{
BMLoop *l;
float tangent[3];
l = BM_FACE_FIRST_LOOP(f);
BM_loop_calc_face_tangent(l, tangent);
/* get a point inside the face (tiny offset) - we could be more clever here */
mul_v3_fl(tangent, 0.02f);
add_v3_v3v3(co, l->v->co, tangent);
}
ED_view3d_project_float_v3_m4(ar, co, co_ss, projmat);
/* check */
{
LinkNode *p = polys;
int isect = 0;
while (p) {
const float (*mval_fl)[2] = p->link;
const int mval_tot = MEM_allocN_len(mval_fl) / sizeof(*mval_fl);
isect += (int)isect_point_poly_v2(co_ss, mval_fl, mval_tot - 1);
p = p->next;
}
if (isect % 2) {
return true;
}
}
return false;
}
/**
* \param use_tag When set, tag all faces inside the polylines.
*/
void EDBM_mesh_knife(bContext *C, LinkNode *polys, bool use_tag)
{
KnifeTool_OpData *kcd;
view3d_operator_needs_opengl(C);
/* init */
{
const bool only_select = false;
const bool cut_through = false;
kcd = MEM_callocN(sizeof(KnifeTool_OpData), __func__);
knifetool_init(C, kcd, only_select, cut_through);
kcd->ignore_edge_snapping = true;
kcd->ignore_vert_snapping = true;
if (use_tag) {
BM_mesh_elem_hflag_enable_all(kcd->em->bm, BM_EDGE, BM_ELEM_TAG, false);
}
}
/* execute */
{
LinkNode *p = polys;
knife_recalc_projmat(kcd);
while (p) {
const float (*mval_fl)[2] = p->link;
const int mval_tot = MEM_allocN_len(mval_fl) / sizeof(*mval_fl);
int i;
for (i = 0; i < mval_tot; i++) {
knifetool_update_mval(kcd, mval_fl[i]);
if (i == 0) {
knife_start_cut(kcd);
kcd->mode = MODE_DRAGGING;
}
else {
knife_add_cut(kcd);
}
}
knife_finish_cut(kcd);
kcd->mode = MODE_IDLE;
p = p->next;
}
}
/* finish */
{
knifetool_finish_ex(kcd);
/* tag faces inside! */
if (use_tag) {
BMesh *bm = kcd->em->bm;
float projmat[4][4];
BMEdge *e;
BMIter iter;
bool keep_search;
ED_view3d_ob_project_mat_get(kcd->ar->regiondata, kcd->ob, projmat);
BM_mesh_elem_hflag_disable_all(kcd->em->bm, BM_FACE, BM_ELEM_TAG, false);
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
/* check are we tagged?, then we are an original face */
if (BM_elem_flag_test(e, BM_ELEM_TAG) == false) {
BMFace *f;
BMIter fiter;
BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) {
/* if we trusy b*/
if (edbm_mesh_knife_face_isect(kcd->ar, polys, f, projmat)) {
BM_elem_flag_enable(f, BM_ELEM_TAG);
}
}
}
}
do {
BMFace *f;
keep_search = false;
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
if (BM_elem_flag_test(f, BM_ELEM_TAG) == false) {
/* am I connected to a tagged face via a tagged edge (ie, not across a cut) */
BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
BMLoop *l_iter = l_first;
int found = false;
do {
if (BM_elem_flag_test(l_iter, BM_ELEM_TAG) != false) {
found = true;
break;
}
} while ((l_iter = l_iter->next) != l_first);
if (found) {
// if (edbm_mesh_knife_face_isect(kcd->ar, polys, f, projmat))
{
BM_elem_flag_enable(f, BM_ELEM_TAG);
keep_search = true;
}
}
}
}
} while (keep_search);
}
knifetool_exit_ex(C, kcd);
kcd = NULL;
}
}

View File

@@ -0,0 +1,163 @@
/*
* ***** 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.
*
* The Original Code is Copyright (C) 2007 Blender Foundation.
* All rights reserved.
*
*
* Contributor(s): Campbell Barton
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/editors/mesh/editmesh_knife_project.c
* \ingroup edmesh
*/
#include "DNA_curve_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
#include "DNA_screen_types.h"
#include "DNA_windowmanager_types.h"
#include "BLI_utildefines.h"
#include "BLI_math.h"
#include "BLI_linklist.h"
#include "BLI_listbase.h"
#include "BKE_library.h"
#include "BKE_mesh.h"
#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_tessmesh.h"
#include "BKE_report.h"
#include "MEM_guardedalloc.h"
#include "WM_types.h"
#include "ED_screen.h"
#include "ED_view3d.h"
#include "mesh_intern.h"
static LinkNode *knifeproject_poly_from_object(ARegion *ar, Scene *scene, Object *ob, LinkNode *polys)
{
DerivedMesh *dm;
bool dm_needsFree;
if (ob->type == OB_MESH || ob->derivedFinal) {
dm = ob->derivedFinal ? ob->derivedFinal : mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
dm_needsFree = false;
}
else if (ELEM3(ob->type, OB_FONT, OB_CURVE, OB_SURF)) {
dm = CDDM_from_curve(ob);
dm_needsFree = true;
}
if (dm) {
ListBase nurbslist = {NULL, NULL};
float projmat[4][4];
BKE_mesh_to_curve_nurblist(dm, &nurbslist, 0); /* wire */
BKE_mesh_to_curve_nurblist(dm, &nurbslist, 1); /* boundary */
ED_view3d_ob_project_mat_get(ar->regiondata, ob, projmat);
if (nurbslist.first) {
Nurb *nu;
for (nu = nurbslist.first; nu; nu = nu->next) {
if (nu->bp) {
int a;
BPoint *bp;
bool is_cyclic = (nu->flagu & CU_NURB_CYCLIC) != 0;
float (*mval)[2] = MEM_mallocN(sizeof(*mval) * (nu->pntsu + is_cyclic), __func__);
for (bp = nu->bp, a = 0; a < nu->pntsu; a++, bp++) {
ED_view3d_project_float_v3_m4(ar, bp->vec, mval[a], projmat);
}
if (is_cyclic) {
copy_v2_v2(mval[a], mval[0]);
}
BLI_linklist_prepend(&polys, mval);
}
}
}
BKE_nurbList_free(&nurbslist);
if (dm_needsFree) {
dm->release(dm);
}
}
return polys;
}
static int knifeproject_exec(bContext *C, wmOperator *op)
{
ARegion *ar = CTX_wm_region(C);
Scene *scene = CTX_data_scene(C);
Object *obedit = CTX_data_edit_object(C);
BMEditMesh *em = BMEdit_FromObject(obedit);
LinkNode *polys = NULL;
CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
{
if (ob != obedit) {
polys = knifeproject_poly_from_object(ar, scene, ob, polys);
}
}
CTX_DATA_END;
if (polys) {
EDBM_mesh_knife(C, polys, true);
/* select only tagged faces */
BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
BM_mesh_elem_hflag_enable_test(em->bm, BM_FACE, BM_ELEM_SELECT, true, BM_ELEM_TAG);
BLI_linklist_freeN(polys);
return OPERATOR_FINISHED;
}
else {
BKE_report(op->reports, RPT_ERROR, "No other selected objects found to use for projection");
return OPERATOR_CANCELLED;
}
}
void MESH_OT_knife_project(wmOperatorType *ot)
{
/* description */
ot->name = "Knife Project";
ot->idname = "MESH_OT_knife_project";
ot->description = "Use other objects outlines & boundaries to project knife cuts";
/* callbacks */
ot->exec = knifeproject_exec;
ot->poll = ED_operator_editmesh_view3d;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
}

View File

@@ -48,6 +48,7 @@ struct wmKeyConfig;
struct wmKeyMap;
struct wmOperator;
struct wmOperatorType;
struct LinkNode;
/* ******************** editmesh_utils.c */
@@ -204,6 +205,8 @@ void MESH_OT_edgering_select(struct wmOperatorType *ot);
void MESH_OT_loopcut(struct wmOperatorType *ot);
void MESH_OT_knife_tool(struct wmOperatorType *ot);
void MESH_OT_knife_project(wmOperatorType *ot);
void MESH_OT_bevel(struct wmOperatorType *ot);
void MESH_OT_bridge_edge_loops(struct wmOperatorType *ot);
@@ -221,4 +224,6 @@ void MESH_OT_navmesh_face_add(struct wmOperatorType *ot);
void MESH_OT_navmesh_reset(struct wmOperatorType *ot);
void MESH_OT_navmesh_clear(struct wmOperatorType *ot);
void EDBM_mesh_knife(struct bContext *C, struct LinkNode *polys, bool use_tag);
#endif /* __MESH_INTERN_H__ */

View File

@@ -149,6 +149,7 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_select_nth);
WM_operatortype_append(MESH_OT_vert_connect);
WM_operatortype_append(MESH_OT_knife_tool);
WM_operatortype_append(MESH_OT_knife_project);
WM_operatortype_append(MESH_OT_bevel);