2013-06-04 01:23:51 +00:00
|
|
|
/*
|
|
|
|
* ***** 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) 2004 Blender Foundation.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* The Original Code is: all of this file.
|
|
|
|
*
|
|
|
|
* Contributor(s): none yet.
|
|
|
|
*
|
|
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
|
|
*/
|
|
|
|
|
|
|
|
/** \file blender/editors/mesh/editmesh_path.c
|
|
|
|
* \ingroup edmesh
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "DNA_scene_types.h"
|
|
|
|
#include "DNA_object_types.h"
|
|
|
|
#include "DNA_mesh_types.h"
|
|
|
|
#include "DNA_meshdata_types.h"
|
|
|
|
#include "DNA_windowmanager_types.h"
|
|
|
|
|
|
|
|
#include "BLI_math.h"
|
|
|
|
#include "BLI_linklist.h"
|
|
|
|
|
|
|
|
#include "BKE_context.h"
|
|
|
|
#include "BKE_editmesh.h"
|
|
|
|
#include "BKE_report.h"
|
|
|
|
|
|
|
|
#include "ED_mesh.h"
|
|
|
|
#include "ED_screen.h"
|
|
|
|
#include "ED_uvedit.h"
|
|
|
|
#include "ED_view3d.h"
|
|
|
|
|
|
|
|
#include "RNA_access.h"
|
|
|
|
#include "RNA_define.h"
|
|
|
|
|
|
|
|
#include "WM_types.h"
|
|
|
|
|
2013-08-23 04:22:07 +00:00
|
|
|
#include "bmesh.h"
|
|
|
|
#include "bmesh_tools.h"
|
|
|
|
|
2013-06-04 01:23:51 +00:00
|
|
|
#include "mesh_intern.h" /* own include */
|
|
|
|
|
|
|
|
struct UserData {
|
|
|
|
BMesh *bm;
|
|
|
|
Mesh *me;
|
|
|
|
Scene *scene;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/* Vert Path */
|
|
|
|
|
|
|
|
/* callbacks */
|
|
|
|
static bool verttag_filter_cb(BMVert *v, void *UNUSED(user_data_v))
|
|
|
|
{
|
|
|
|
return !BM_elem_flag_test(v, BM_ELEM_HIDDEN);
|
|
|
|
}
|
|
|
|
static bool verttag_test_cb(BMVert *v, void *UNUSED(user_data_v))
|
|
|
|
{
|
|
|
|
return BM_elem_flag_test_bool(v, BM_ELEM_SELECT);
|
|
|
|
}
|
|
|
|
static void verttag_set_cb(BMVert *v, bool val, void *user_data_v)
|
|
|
|
{
|
|
|
|
struct UserData *user_data = user_data_v;
|
|
|
|
BM_vert_select_set(user_data->bm, v, val);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool mouse_mesh_shortest_path_vert(ViewContext *vc)
|
|
|
|
{
|
|
|
|
/* unlike edge/face versions, this uses a bmesh operator */
|
|
|
|
|
|
|
|
BMEditMesh *em = vc->em;
|
2013-06-24 04:51:56 +00:00
|
|
|
BMesh *bm = em->bm;
|
2013-06-04 01:23:51 +00:00
|
|
|
BMVert *v_dst;
|
2014-03-11 15:34:19 +11:00
|
|
|
float dist = ED_view3d_select_dist_px();
|
2013-06-04 01:23:51 +00:00
|
|
|
const bool use_length = true;
|
|
|
|
|
|
|
|
v_dst = EDBM_vert_find_nearest(vc, &dist, false, false);
|
|
|
|
if (v_dst) {
|
2013-06-24 04:51:56 +00:00
|
|
|
struct UserData user_data = {bm, vc->obedit->data, vc->scene};
|
2013-06-04 01:23:51 +00:00
|
|
|
LinkNode *path = NULL;
|
2013-06-24 04:51:56 +00:00
|
|
|
BMVert *v_act = BM_mesh_active_vert_get(bm);
|
2013-06-04 01:23:51 +00:00
|
|
|
|
2013-06-24 04:51:56 +00:00
|
|
|
if (v_act && (v_act != v_dst)) {
|
|
|
|
if ((path = BM_mesh_calc_path_vert(bm, v_act, v_dst, use_length,
|
2014-11-03 08:30:33 +01:00
|
|
|
verttag_filter_cb, &user_data)))
|
2013-06-24 04:51:56 +00:00
|
|
|
{
|
|
|
|
BM_select_history_remove(bm, v_act);
|
2013-06-04 01:23:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (path) {
|
|
|
|
/* toggle the flag */
|
|
|
|
bool all_set = true;
|
|
|
|
LinkNode *node;
|
|
|
|
|
|
|
|
node = path;
|
|
|
|
do {
|
|
|
|
if (!verttag_test_cb((BMVert *)node->link, &user_data)) {
|
|
|
|
all_set = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while ((node = node->next));
|
|
|
|
|
|
|
|
node = path;
|
|
|
|
do {
|
|
|
|
verttag_set_cb((BMVert *)node->link, !all_set, &user_data);
|
|
|
|
} while ((node = node->next));
|
|
|
|
|
|
|
|
BLI_linklist_free(path, NULL);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
const bool is_act = !verttag_test_cb(v_dst, &user_data);
|
|
|
|
verttag_set_cb(v_dst, is_act, &user_data); /* switch the face option */
|
|
|
|
}
|
|
|
|
|
|
|
|
EDBM_selectmode_flush(em);
|
|
|
|
|
|
|
|
/* even if this is selected it may not be in the selection list */
|
|
|
|
if (BM_elem_flag_test(v_dst, BM_ELEM_SELECT) == 0)
|
2013-06-24 04:51:56 +00:00
|
|
|
BM_select_history_remove(bm, v_dst);
|
2013-06-04 01:23:51 +00:00
|
|
|
else
|
2013-06-24 04:51:56 +00:00
|
|
|
BM_select_history_store(bm, v_dst);
|
2013-06-04 01:23:51 +00:00
|
|
|
|
|
|
|
EDBM_update_generic(em, false, false);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/* Edge Path */
|
|
|
|
|
|
|
|
/* callbacks */
|
|
|
|
static bool edgetag_filter_cb(BMEdge *e, void *UNUSED(user_data_v))
|
|
|
|
{
|
|
|
|
return !BM_elem_flag_test(e, BM_ELEM_HIDDEN);
|
|
|
|
}
|
|
|
|
static bool edgetag_test_cb(BMEdge *e, void *user_data_v)
|
|
|
|
{
|
|
|
|
struct UserData *user_data = user_data_v;
|
|
|
|
Scene *scene = user_data->scene;
|
|
|
|
BMesh *bm = user_data->bm;
|
|
|
|
|
|
|
|
switch (scene->toolsettings->edge_mode) {
|
|
|
|
case EDGE_MODE_SELECT:
|
|
|
|
return BM_elem_flag_test(e, BM_ELEM_SELECT) ? true : false;
|
|
|
|
case EDGE_MODE_TAG_SEAM:
|
2013-06-24 05:26:42 +00:00
|
|
|
return BM_elem_flag_test(e, BM_ELEM_SEAM) ? true : false;
|
2013-06-04 01:23:51 +00:00
|
|
|
case EDGE_MODE_TAG_SHARP:
|
|
|
|
return BM_elem_flag_test(e, BM_ELEM_SMOOTH) ? false : true;
|
|
|
|
case EDGE_MODE_TAG_CREASE:
|
|
|
|
return BM_elem_float_data_get(&bm->edata, e, CD_CREASE) ? true : false;
|
|
|
|
case EDGE_MODE_TAG_BEVEL:
|
|
|
|
return BM_elem_float_data_get(&bm->edata, e, CD_BWEIGHT) ? true : false;
|
|
|
|
#ifdef WITH_FREESTYLE
|
|
|
|
case EDGE_MODE_TAG_FREESTYLE:
|
2014-03-19 12:46:33 +11:00
|
|
|
{
|
|
|
|
FreestyleEdge *fed = CustomData_bmesh_get(&bm->edata, e->head.data, CD_FREESTYLE_EDGE);
|
2014-04-01 11:34:00 +11:00
|
|
|
return (!fed) ? false : (fed->flag & FREESTYLE_EDGE_MARK) ? true : false;
|
2014-03-19 12:46:33 +11:00
|
|
|
}
|
2013-06-04 01:23:51 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
static void edgetag_set_cb(BMEdge *e, bool val, void *user_data_v)
|
|
|
|
{
|
|
|
|
struct UserData *user_data = user_data_v;
|
|
|
|
Scene *scene = user_data->scene;
|
|
|
|
BMesh *bm = user_data->bm;
|
|
|
|
|
|
|
|
switch (scene->toolsettings->edge_mode) {
|
|
|
|
case EDGE_MODE_SELECT:
|
|
|
|
BM_edge_select_set(bm, e, val);
|
|
|
|
break;
|
|
|
|
case EDGE_MODE_TAG_SEAM:
|
|
|
|
BM_elem_flag_set(e, BM_ELEM_SEAM, val);
|
|
|
|
break;
|
|
|
|
case EDGE_MODE_TAG_SHARP:
|
|
|
|
BM_elem_flag_set(e, BM_ELEM_SMOOTH, !val);
|
|
|
|
break;
|
|
|
|
case EDGE_MODE_TAG_CREASE:
|
|
|
|
BM_elem_float_data_set(&bm->edata, e, CD_CREASE, (val) ? 1.0f : 0.0f);
|
|
|
|
break;
|
|
|
|
case EDGE_MODE_TAG_BEVEL:
|
|
|
|
BM_elem_float_data_set(&bm->edata, e, CD_BWEIGHT, (val) ? 1.0f : 0.0f);
|
|
|
|
break;
|
|
|
|
#ifdef WITH_FREESTYLE
|
|
|
|
case EDGE_MODE_TAG_FREESTYLE:
|
|
|
|
{
|
|
|
|
FreestyleEdge *fed;
|
|
|
|
fed = CustomData_bmesh_get(&bm->edata, e->head.data, CD_FREESTYLE_EDGE);
|
|
|
|
if (!val)
|
|
|
|
fed->flag &= ~FREESTYLE_EDGE_MARK;
|
|
|
|
else
|
|
|
|
fed->flag |= FREESTYLE_EDGE_MARK;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void edgetag_ensure_cd_flag(Scene *scene, Mesh *me)
|
|
|
|
{
|
|
|
|
BMesh *bm = me->edit_btmesh->bm;
|
|
|
|
|
|
|
|
switch (scene->toolsettings->edge_mode) {
|
|
|
|
case EDGE_MODE_TAG_CREASE:
|
|
|
|
BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_CREASE);
|
|
|
|
break;
|
|
|
|
case EDGE_MODE_TAG_BEVEL:
|
|
|
|
BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_BWEIGHT);
|
|
|
|
break;
|
|
|
|
#ifdef WITH_FREESTYLE
|
|
|
|
case EDGE_MODE_TAG_FREESTYLE:
|
|
|
|
if (!CustomData_has_layer(&bm->edata, CD_FREESTYLE_EDGE)) {
|
|
|
|
BM_data_layer_add(bm, &bm->edata, CD_FREESTYLE_EDGE);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* mesh shortest path select, uses prev-selected edge */
|
|
|
|
|
|
|
|
/* since you want to create paths with multiple selects, it doesn't have extend option */
|
|
|
|
static bool mouse_mesh_shortest_path_edge(ViewContext *vc)
|
|
|
|
{
|
|
|
|
BMEditMesh *em = vc->em;
|
2013-06-24 04:51:56 +00:00
|
|
|
BMesh *bm = em->bm;
|
2013-06-04 01:23:51 +00:00
|
|
|
BMEdge *e_dst;
|
2014-03-11 15:34:19 +11:00
|
|
|
float dist = ED_view3d_select_dist_px();
|
2013-06-04 01:23:51 +00:00
|
|
|
const bool use_length = true;
|
|
|
|
|
|
|
|
e_dst = EDBM_edge_find_nearest(vc, &dist);
|
|
|
|
if (e_dst) {
|
2013-06-24 05:24:27 +00:00
|
|
|
const char edge_mode = vc->scene->toolsettings->edge_mode;
|
2013-06-24 04:51:56 +00:00
|
|
|
struct UserData user_data = {bm, vc->obedit->data, vc->scene};
|
2013-06-04 01:23:51 +00:00
|
|
|
LinkNode *path = NULL;
|
|
|
|
Mesh *me = vc->obedit->data;
|
2013-06-24 04:51:56 +00:00
|
|
|
BMEdge *e_act = BM_mesh_active_edge_get(bm);
|
2013-06-04 01:23:51 +00:00
|
|
|
|
|
|
|
edgetag_ensure_cd_flag(vc->scene, em->ob->data);
|
|
|
|
|
2013-06-24 04:51:56 +00:00
|
|
|
if (e_act && (e_act != e_dst)) {
|
|
|
|
if ((path = BM_mesh_calc_path_edge(bm, e_act, e_dst, use_length,
|
2014-11-03 08:30:33 +01:00
|
|
|
edgetag_filter_cb, &user_data)))
|
2013-06-24 04:51:56 +00:00
|
|
|
{
|
|
|
|
BM_select_history_remove(bm, e_act);
|
2013-06-04 01:23:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (path) {
|
|
|
|
/* toggle the flag */
|
|
|
|
bool all_set = true;
|
|
|
|
LinkNode *node;
|
|
|
|
|
|
|
|
node = path;
|
|
|
|
do {
|
|
|
|
if (!edgetag_test_cb((BMEdge *)node->link, &user_data)) {
|
|
|
|
all_set = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while ((node = node->next));
|
|
|
|
|
|
|
|
node = path;
|
|
|
|
do {
|
|
|
|
edgetag_set_cb((BMEdge *)node->link, !all_set, &user_data);
|
|
|
|
} while ((node = node->next));
|
|
|
|
|
|
|
|
BLI_linklist_free(path, NULL);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
const bool is_act = !edgetag_test_cb(e_dst, &user_data);
|
|
|
|
edgetag_ensure_cd_flag(vc->scene, vc->obedit->data);
|
|
|
|
edgetag_set_cb(e_dst, is_act, &user_data); /* switch the edge option */
|
|
|
|
}
|
|
|
|
|
2013-06-24 05:24:27 +00:00
|
|
|
if (edge_mode != EDGE_MODE_SELECT) {
|
|
|
|
/* simple rules - last edge is _always_ active and selected */
|
|
|
|
if (e_act)
|
|
|
|
BM_edge_select_set(bm, e_act, false);
|
|
|
|
BM_edge_select_set(bm, e_dst, true);
|
|
|
|
BM_select_history_store(bm, e_dst);
|
|
|
|
}
|
|
|
|
|
2013-06-04 01:23:51 +00:00
|
|
|
EDBM_selectmode_flush(em);
|
|
|
|
|
|
|
|
/* even if this is selected it may not be in the selection list */
|
2013-06-24 05:24:27 +00:00
|
|
|
if (edge_mode == EDGE_MODE_SELECT) {
|
|
|
|
if (edgetag_test_cb(e_dst, &user_data) == 0)
|
|
|
|
BM_select_history_remove(bm, e_dst);
|
|
|
|
else
|
|
|
|
BM_select_history_store(bm, e_dst);
|
|
|
|
}
|
2013-06-04 01:23:51 +00:00
|
|
|
|
|
|
|
/* force drawmode for mesh */
|
2013-06-24 05:24:27 +00:00
|
|
|
switch (edge_mode) {
|
2013-06-04 01:23:51 +00:00
|
|
|
|
|
|
|
case EDGE_MODE_TAG_SEAM:
|
|
|
|
me->drawflag |= ME_DRAWSEAMS;
|
|
|
|
ED_uvedit_live_unwrap(vc->scene, vc->obedit);
|
|
|
|
break;
|
|
|
|
case EDGE_MODE_TAG_SHARP:
|
|
|
|
me->drawflag |= ME_DRAWSHARP;
|
|
|
|
break;
|
|
|
|
case EDGE_MODE_TAG_CREASE:
|
|
|
|
me->drawflag |= ME_DRAWCREASES;
|
|
|
|
break;
|
|
|
|
case EDGE_MODE_TAG_BEVEL:
|
|
|
|
me->drawflag |= ME_DRAWBWEIGHTS;
|
|
|
|
break;
|
|
|
|
#ifdef WITH_FREESTYLE
|
|
|
|
case EDGE_MODE_TAG_FREESTYLE:
|
|
|
|
me->drawflag |= ME_DRAW_FREESTYLE_EDGE;
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
EDBM_update_generic(em, false, false);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/* Face Path */
|
|
|
|
|
|
|
|
/* callbacks */
|
|
|
|
static bool facetag_filter_cb(BMFace *f, void *UNUSED(user_data_v))
|
|
|
|
{
|
|
|
|
return !BM_elem_flag_test(f, BM_ELEM_HIDDEN);
|
|
|
|
}
|
|
|
|
//static bool facetag_test_cb(Scene *UNUSED(scene), BMesh *UNUSED(bm), BMFace *f)
|
|
|
|
static bool facetag_test_cb(BMFace *f, void *UNUSED(user_data_v))
|
|
|
|
{
|
|
|
|
return BM_elem_flag_test_bool(f, BM_ELEM_SELECT);
|
|
|
|
}
|
|
|
|
//static void facetag_set_cb(BMesh *bm, Scene *UNUSED(scene), BMFace *f, const bool val)
|
|
|
|
static void facetag_set_cb(BMFace *f, bool val, void *user_data_v)
|
|
|
|
{
|
|
|
|
struct UserData *user_data = user_data_v;
|
|
|
|
BM_face_select_set(user_data->bm, f, val);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool mouse_mesh_shortest_path_face(ViewContext *vc)
|
|
|
|
{
|
|
|
|
BMEditMesh *em = vc->em;
|
2013-06-24 04:51:56 +00:00
|
|
|
BMesh *bm = em->bm;
|
2013-06-04 01:23:51 +00:00
|
|
|
BMFace *f_dst;
|
2014-03-11 15:34:19 +11:00
|
|
|
float dist = ED_view3d_select_dist_px();
|
2013-06-04 01:23:51 +00:00
|
|
|
const bool use_length = true;
|
|
|
|
|
|
|
|
f_dst = EDBM_face_find_nearest(vc, &dist);
|
|
|
|
if (f_dst) {
|
2013-06-24 04:51:56 +00:00
|
|
|
struct UserData user_data = {bm, vc->obedit->data, vc->scene};
|
2013-06-04 01:23:51 +00:00
|
|
|
LinkNode *path = NULL;
|
2013-06-24 04:51:56 +00:00
|
|
|
BMFace *f_act = BM_mesh_active_face_get(bm, false, true);
|
2013-06-04 01:23:51 +00:00
|
|
|
|
|
|
|
if (f_act) {
|
|
|
|
if (f_act != f_dst) {
|
2013-06-24 04:51:56 +00:00
|
|
|
if ((path = BM_mesh_calc_path_face(bm, f_act, f_dst, use_length,
|
2014-11-03 08:30:33 +01:00
|
|
|
facetag_filter_cb, &user_data)))
|
2013-06-04 01:23:51 +00:00
|
|
|
{
|
2013-06-24 04:51:56 +00:00
|
|
|
BM_select_history_remove(bm, f_act);
|
2013-06-04 01:23:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (path) {
|
|
|
|
/* toggle the flag */
|
|
|
|
bool all_set = true;
|
|
|
|
LinkNode *node;
|
|
|
|
|
|
|
|
node = path;
|
|
|
|
do {
|
|
|
|
if (!facetag_test_cb((BMFace *)node->link, &user_data)) {
|
|
|
|
all_set = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while ((node = node->next));
|
|
|
|
|
|
|
|
node = path;
|
|
|
|
do {
|
|
|
|
facetag_set_cb((BMFace *)node->link, !all_set, &user_data);
|
|
|
|
} while ((node = node->next));
|
|
|
|
|
|
|
|
BLI_linklist_free(path, NULL);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
const bool is_act = !facetag_test_cb(f_dst, &user_data);
|
|
|
|
facetag_set_cb(f_dst, is_act, &user_data); /* switch the face option */
|
|
|
|
}
|
|
|
|
|
|
|
|
EDBM_selectmode_flush(em);
|
|
|
|
|
|
|
|
/* even if this is selected it may not be in the selection list */
|
|
|
|
if (facetag_test_cb(f_dst, &user_data) == 0)
|
2013-06-24 04:51:56 +00:00
|
|
|
BM_select_history_remove(bm, f_dst);
|
2013-06-04 01:23:51 +00:00
|
|
|
else
|
2013-06-24 04:51:56 +00:00
|
|
|
BM_select_history_store(bm, f_dst);
|
2013-06-04 01:23:51 +00:00
|
|
|
|
2013-06-24 04:51:56 +00:00
|
|
|
BM_mesh_active_face_set(bm, f_dst);
|
2013-06-04 01:23:51 +00:00
|
|
|
|
|
|
|
EDBM_update_generic(em, false, false);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/* Main Operator for vert/edge/face tag */
|
|
|
|
|
|
|
|
static int edbm_shortest_path_pick_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
|
|
|
|
{
|
|
|
|
ViewContext vc;
|
|
|
|
BMEditMesh *em;
|
2014-02-18 08:21:19 +11:00
|
|
|
BMElem *ele;
|
2013-06-04 01:23:51 +00:00
|
|
|
|
|
|
|
|
|
|
|
em_setup_viewcontext(C, &vc);
|
|
|
|
copy_v2_v2_int(vc.mval, event->mval);
|
|
|
|
em = vc.em;
|
|
|
|
|
2014-02-18 08:21:19 +11:00
|
|
|
ele = BM_mesh_active_elem_get(em->bm);
|
|
|
|
if (ele == NULL) {
|
|
|
|
return OPERATOR_PASS_THROUGH;
|
|
|
|
}
|
|
|
|
|
|
|
|
view3d_operator_needs_opengl(C);
|
|
|
|
|
|
|
|
if ((em->selectmode & SCE_SELECT_VERTEX) && (ele->head.htype == BM_VERT)) {
|
2013-06-04 01:23:51 +00:00
|
|
|
if (mouse_mesh_shortest_path_vert(&vc)) {
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return OPERATOR_PASS_THROUGH;
|
|
|
|
}
|
|
|
|
}
|
2014-02-18 08:21:19 +11:00
|
|
|
else if ((em->selectmode & SCE_SELECT_EDGE) && (ele->head.htype == BM_EDGE)) {
|
2013-06-04 01:23:51 +00:00
|
|
|
if (mouse_mesh_shortest_path_edge(&vc)) {
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return OPERATOR_PASS_THROUGH;
|
|
|
|
}
|
|
|
|
}
|
2014-02-18 08:21:19 +11:00
|
|
|
else if ((em->selectmode & SCE_SELECT_FACE) && (ele->head.htype == BM_FACE)) {
|
2013-06-04 01:23:51 +00:00
|
|
|
if (mouse_mesh_shortest_path_face(&vc)) {
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return OPERATOR_PASS_THROUGH;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return OPERATOR_PASS_THROUGH;
|
|
|
|
}
|
|
|
|
|
|
|
|
void MESH_OT_shortest_path_pick(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Pick Shortest Path";
|
|
|
|
ot->idname = "MESH_OT_shortest_path_pick";
|
|
|
|
ot->description = "Select shortest path between two selections";
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
ot->invoke = edbm_shortest_path_pick_invoke;
|
|
|
|
ot->poll = ED_operator_editmesh_region_view3d;
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
|
|
|
|
|
|
|
/* properties */
|
|
|
|
RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/* Select path between existing selection */
|
|
|
|
|
|
|
|
static int edbm_shortest_path_select_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
|
|
|
Object *ob = CTX_data_edit_object(C);
|
|
|
|
BMEditMesh *em = BKE_editmesh_from_object(ob);
|
2013-06-24 04:51:56 +00:00
|
|
|
BMesh *bm = em->bm;
|
2013-06-04 01:23:51 +00:00
|
|
|
BMIter iter;
|
|
|
|
BMEditSelection *ese_src, *ese_dst;
|
|
|
|
BMElem *ele_src = NULL, *ele_dst = NULL, *ele;
|
|
|
|
|
|
|
|
const bool use_length = RNA_boolean_get(op->ptr, "use_length");
|
|
|
|
|
|
|
|
/* first try to find vertices in edit selection */
|
2013-06-24 04:51:56 +00:00
|
|
|
ese_src = bm->selected.last;
|
2013-06-04 01:23:51 +00:00
|
|
|
if (ese_src && (ese_dst = ese_src->prev) && (ese_src->htype == ese_dst->htype)) {
|
|
|
|
ele_src = ese_src->ele;
|
|
|
|
ele_dst = ese_dst->ele;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* if selection history isn't available, find two selected elements */
|
2013-06-04 05:03:36 +00:00
|
|
|
ele_src = ele_dst = NULL;
|
2013-06-24 04:51:56 +00:00
|
|
|
if ((em->selectmode & SCE_SELECT_VERTEX) && (bm->totvertsel >= 2)) {
|
|
|
|
BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) {
|
2013-06-04 01:23:51 +00:00
|
|
|
if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
|
|
|
|
if (ele_src == NULL) ele_src = ele;
|
|
|
|
else if (ele_dst == NULL) ele_dst = ele;
|
|
|
|
else break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-24 04:51:56 +00:00
|
|
|
if ((ele_dst == NULL) && (em->selectmode & SCE_SELECT_EDGE) && (bm->totedgesel >= 2)) {
|
2013-06-04 05:03:36 +00:00
|
|
|
ele_src = NULL;
|
2013-06-24 04:51:56 +00:00
|
|
|
BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) {
|
2013-06-04 01:23:51 +00:00
|
|
|
if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
|
|
|
|
if (ele_src == NULL) ele_src = ele;
|
|
|
|
else if (ele_dst == NULL) ele_dst = ele;
|
|
|
|
else break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-24 04:51:56 +00:00
|
|
|
if ((ele_dst == NULL) && (em->selectmode & SCE_SELECT_FACE) && (bm->totfacesel >= 2)) {
|
2013-06-04 05:03:36 +00:00
|
|
|
ele_src = NULL;
|
2013-06-24 04:51:56 +00:00
|
|
|
BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) {
|
2013-06-04 01:23:51 +00:00
|
|
|
if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
|
|
|
|
if (ele_src == NULL) ele_src = ele;
|
|
|
|
else if (ele_dst == NULL) ele_dst = ele;
|
|
|
|
else break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ele_src && ele_dst) {
|
|
|
|
LinkNode *path = NULL;
|
|
|
|
switch (ele_src->head.htype) {
|
|
|
|
case BM_VERT:
|
|
|
|
path = BM_mesh_calc_path_vert(
|
2013-06-24 04:51:56 +00:00
|
|
|
bm, (BMVert *)ele_src, (BMVert *)ele_dst, use_length,
|
2014-11-06 11:47:08 +01:00
|
|
|
BM_elem_cb_check_hflag_disabled_simple(BMVert *, BM_ELEM_HIDDEN));
|
2013-06-04 01:23:51 +00:00
|
|
|
break;
|
|
|
|
case BM_EDGE:
|
|
|
|
path = BM_mesh_calc_path_edge(
|
2013-06-24 04:51:56 +00:00
|
|
|
bm, (BMEdge *)ele_src, (BMEdge *)ele_dst, use_length,
|
2014-11-06 11:47:08 +01:00
|
|
|
BM_elem_cb_check_hflag_disabled_simple(BMEdge *, BM_ELEM_HIDDEN));
|
2013-06-04 01:23:51 +00:00
|
|
|
break;
|
|
|
|
case BM_FACE:
|
|
|
|
path = BM_mesh_calc_path_face(
|
2013-06-24 04:51:56 +00:00
|
|
|
bm, (BMFace *)ele_src, (BMFace *)ele_dst, use_length,
|
2014-11-06 11:47:08 +01:00
|
|
|
BM_elem_cb_check_hflag_disabled_simple(BMFace *, BM_ELEM_HIDDEN));
|
2013-06-04 01:23:51 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (path) {
|
|
|
|
LinkNode *node = path;
|
|
|
|
|
|
|
|
do {
|
2013-06-24 04:51:56 +00:00
|
|
|
BM_elem_select_set(bm, node->link, true);
|
2013-06-04 01:23:51 +00:00
|
|
|
} while ((node = node->next));
|
|
|
|
|
|
|
|
BLI_linklist_free(path, NULL);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BKE_report(op->reports, RPT_WARNING, "Path can't be found");
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
|
|
|
|
|
|
|
EDBM_selectmode_flush(em);
|
|
|
|
EDBM_update_generic(em, false, false);
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BKE_report(op->reports, RPT_WARNING, "Path selection requires two matching elements to be selected");
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void MESH_OT_shortest_path_select(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Select Shortest Path";
|
|
|
|
ot->idname = "MESH_OT_shortest_path_select";
|
|
|
|
ot->description = "Selected vertex path between two vertices";
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
ot->exec = edbm_shortest_path_select_exec;
|
|
|
|
ot->poll = ED_operator_editmesh;
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
|
|
|
|
|
|
|
/* properties */
|
|
|
|
RNA_def_boolean(ot->srna, "use_length", true, "Length", "Use length when measuring distance");
|
|
|
|
}
|