forked from bartvdbraak/blender
vertex color rotation and reversing/shortest vertex path
This commit is contained in:
parent
f0ff8d665d
commit
c75e1598dd
@ -60,6 +60,12 @@ enum {
|
||||
DIRECTION_CCW
|
||||
};
|
||||
|
||||
/* vertex path selection values */
|
||||
enum {
|
||||
VPATH_SELECT_EDGE_LENGTH = 0,
|
||||
VPATH_SELECT_TOPOLOGICAL
|
||||
};
|
||||
|
||||
extern BMOpDefine *opdefines[];
|
||||
extern int bmesh_total_ops;
|
||||
|
||||
|
@ -761,6 +761,47 @@ BMOpDefine def_meshreverseuvs = {
|
||||
0
|
||||
};
|
||||
|
||||
/*
|
||||
** color rotation
|
||||
** cycle the colors
|
||||
*/
|
||||
BMOpDefine def_meshrotatecolors = {
|
||||
"meshrotatecolors",
|
||||
{{BMOP_OPSLOT_ELEMENT_BUF, "faces"}, /* input faces */
|
||||
{BMOP_OPSLOT_INT, "dir"}, /* direction */
|
||||
{0} /*null-terminating sentinel*/},
|
||||
bmesh_rotatecolors_exec,
|
||||
0
|
||||
};
|
||||
|
||||
/*
|
||||
** color reverse
|
||||
** reverse the colors
|
||||
*/
|
||||
BMOpDefine def_meshreversecolors = {
|
||||
"meshreversecolors",
|
||||
{{BMOP_OPSLOT_ELEMENT_BUF, "faces"}, /* input faces */
|
||||
{0} /*null-terminating sentinel*/},
|
||||
bmesh_reversecolors_exec,
|
||||
0
|
||||
};
|
||||
|
||||
/*
|
||||
Similar vertices select
|
||||
|
||||
Select similar vertices (normal, face, vertex group,....).
|
||||
*/
|
||||
BMOpDefine def_vertexshortestpath = {
|
||||
"vertexshortestpath",
|
||||
{{BMOP_OPSLOT_ELEMENT_BUF, "startv"}, /* start vertex */
|
||||
{BMOP_OPSLOT_ELEMENT_BUF, "endv"}, /* end vertex */
|
||||
{BMOP_OPSLOT_ELEMENT_BUF, "vertout"}, /* output vertices */
|
||||
{BMOP_OPSLOT_INT, "type"}, /* type of selection */
|
||||
{0} /*null-terminating sentinel*/},
|
||||
bmesh_vertexshortestpath_exec,
|
||||
0
|
||||
};
|
||||
|
||||
BMOpDefine *opdefines[] = {
|
||||
&def_splitop,
|
||||
&def_dupeop,
|
||||
@ -810,6 +851,9 @@ BMOpDefine *opdefines[] = {
|
||||
&def_bmesh_to_mesh,
|
||||
&def_meshreverseuvs,
|
||||
&def_edgenet_prepare,
|
||||
&def_meshrotatecolors,
|
||||
&def_meshreversecolors,
|
||||
&def_vertexshortestpath,
|
||||
&def_scale,
|
||||
};
|
||||
|
||||
|
@ -55,6 +55,8 @@ void bmesh_rotateuvs_exec(BMesh *bm, BMOperator *op);
|
||||
void object_load_bmesh_exec(BMesh *bm, BMOperator *op);
|
||||
void bmesh_reverseuvs_exec(BMesh *bm, BMOperator *op);
|
||||
void bmesh_edgenet_prepare(BMesh *bm, BMOperator *op);
|
||||
void bmesh_rotatecolors_exec(BMesh *bm, BMOperator *op);
|
||||
void bmesh_reversecolors_exec(BMesh *bm, BMOperator *op);
|
||||
void bmesh_vertexshortestpath_exec(BMesh *bm, BMOperator *op);
|
||||
void bmesh_scale_exec(BMesh *bm, BMOperator *op);
|
||||
|
||||
#endif
|
||||
|
@ -22,6 +22,8 @@
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_edgehash.h"
|
||||
|
||||
#include "BLI_heap.h"
|
||||
|
||||
#include "bmesh.h"
|
||||
|
||||
/*
|
||||
@ -1081,3 +1083,218 @@ void bmesh_reverseuvs_exec(BMesh *bm, BMOperator *op)
|
||||
|
||||
BLI_array_free(uvs);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
** Cycle colors for a face
|
||||
******************************************************************************/
|
||||
|
||||
void bmesh_rotatecolors_exec(BMesh *bm, BMOperator *op)
|
||||
{
|
||||
BMOIter fs_iter; /* selected faces iterator */
|
||||
BMFace *fs; /* current face */
|
||||
BMIter l_iter; /* iteration loop */
|
||||
int n;
|
||||
|
||||
int dir = BMO_Get_Int(op, "dir");
|
||||
|
||||
BMO_ITER(fs, &fs_iter, bm, op, "faces", BM_FACE) {
|
||||
if( CustomData_has_layer(&(bm->ldata), CD_MLOOPCOL) ) {
|
||||
if( dir == DIRECTION_CW ) { /* same loops direction */
|
||||
BMLoop *lf; /* current face loops */
|
||||
MLoopCol *f_lcol; /* first face loop color */
|
||||
MLoopCol p_col; /* previous color */
|
||||
MLoopCol t_col; /* tmp color */
|
||||
|
||||
int n = 0;
|
||||
BM_ITER(lf, &l_iter, bm, BM_LOOPS_OF_FACE, fs) {
|
||||
/* current loop color is the previous loop color */
|
||||
MLoopCol *luv = CustomData_bmesh_get(&bm->ldata, lf->head.data, CD_MLOOPCOL);
|
||||
if( n == 0 ) {
|
||||
f_lcol = luv;
|
||||
p_col = *luv;
|
||||
} else {
|
||||
t_col = *luv;
|
||||
*luv = p_col;
|
||||
p_col = t_col;
|
||||
}
|
||||
n++;
|
||||
}
|
||||
|
||||
*f_lcol = p_col;
|
||||
} else if( dir == DIRECTION_CCW ) { /* counter loop direction */
|
||||
BMLoop *lf; /* current face loops */
|
||||
MLoopCol *p_lcol; /*previous loop color */
|
||||
MLoopCol *lcol;
|
||||
MLoopCol t_col; /* current color */
|
||||
|
||||
int n = 0;
|
||||
BM_ITER(lf, &l_iter, bm, BM_LOOPS_OF_FACE, fs) {
|
||||
/* previous loop color is the current loop color */
|
||||
lcol = CustomData_bmesh_get(&bm->ldata, lf->head.data, CD_MLOOPCOL);
|
||||
if( n == 0 ) {
|
||||
p_lcol = lcol;
|
||||
t_col = *lcol;
|
||||
} else {
|
||||
*p_lcol = *lcol;
|
||||
p_lcol = lcol;
|
||||
}
|
||||
n++;
|
||||
}
|
||||
|
||||
*lcol = t_col;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
** Reverse colors for a face
|
||||
******************************************************************************/
|
||||
|
||||
void bmesh_reversecolors_exec(BMesh *bm, BMOperator *op)
|
||||
{
|
||||
BMOIter fs_iter; /* selected faces iterator */
|
||||
BMFace *fs; /* current face */
|
||||
BMIter l_iter; /* iteration loop */
|
||||
BLI_array_declare(cols);
|
||||
MLoopCol *cols = NULL;
|
||||
int max_vert_count = 0;
|
||||
|
||||
|
||||
BMO_ITER(fs, &fs_iter, bm, op, "faces", BM_FACE) {
|
||||
if( CustomData_has_layer(&(bm->ldata), CD_MLOOPCOL) ) {
|
||||
BMLoop *lf; /* current face loops */
|
||||
MLoopCol *f_lcol; /* first face loop color */
|
||||
int num_verts = fs->len;
|
||||
int i = 0;
|
||||
|
||||
BLI_array_empty(cols);
|
||||
BM_ITER(lf, &l_iter, bm, BM_LOOPS_OF_FACE, fs) {
|
||||
MLoopCol *lcol = CustomData_bmesh_get(&bm->ldata, lf->head.data, CD_MLOOPCOL);
|
||||
|
||||
/* current loop uv is the previous loop color */
|
||||
BLI_array_growone(cols);
|
||||
cols[i] = *lcol;
|
||||
i++;
|
||||
}
|
||||
|
||||
/* now that we have the uvs in the array, reverse! */
|
||||
i = 0;
|
||||
BM_ITER(lf, &l_iter, bm, BM_LOOPS_OF_FACE, fs) {
|
||||
/* current loop uv is the previous loop color */
|
||||
MLoopCol *lcol = CustomData_bmesh_get(&bm->ldata, lf->head.data, CD_MLOOPCOL);
|
||||
*lcol = cols[(fs->len - i - 1)];
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BLI_array_free(cols);
|
||||
}
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
** shortest vertex path select
|
||||
******************************************************************************/
|
||||
|
||||
typedef struct element_node {
|
||||
BMVert *v; /* vertex */
|
||||
BMVert *parent; /* node parent id */
|
||||
float weight; /* node weight */
|
||||
HeapNode *hn; /* heap node */
|
||||
} element_node;
|
||||
|
||||
void bmesh_vertexshortestpath_exec(BMesh *bm, BMOperator *op)
|
||||
{
|
||||
BMOIter vs_iter, vs2_iter; /* selected verts iterator */
|
||||
BMIter v_iter; /* mesh verts iterator */
|
||||
BMVert *vs, *sv, *ev; /* starting vertex, ending vertex */
|
||||
BMVert *v; /* mesh vertex */
|
||||
Heap *h = NULL;
|
||||
|
||||
element_node *vert_list = NULL;
|
||||
|
||||
int num_total = 0, num_sels = 0, i = 0;
|
||||
int type = BMO_Get_Int(op, "type");
|
||||
|
||||
BMO_ITER(vs, &vs_iter, bm, op, "startv", BM_VERT)
|
||||
sv = vs;
|
||||
BMO_ITER(vs, &vs_iter, bm, op, "endv", BM_VERT)
|
||||
ev = vs;
|
||||
|
||||
num_total = BM_Count_Element(bm, BM_VERT);
|
||||
|
||||
/* allocate memory for the nodes */
|
||||
vert_list = (element_node*)MEM_mallocN(sizeof(element_node) * num_total, "vertex nodes");
|
||||
|
||||
/* iterate through all the mesh vertices */
|
||||
/* loop through all the vertices and fill the vertices/indices structure */
|
||||
i = 0;
|
||||
BM_ITER(v, &v_iter, bm, BM_VERTS_OF_MESH, NULL) {
|
||||
vert_list[i].v = v;
|
||||
vert_list[i].parent = NULL;
|
||||
vert_list[i].weight = FLT_MAX;
|
||||
BMINDEX_SET(v, i);
|
||||
i++;
|
||||
}
|
||||
|
||||
/*
|
||||
** we now have everything we need, start Dijkstra path finding algorithm
|
||||
*/
|
||||
|
||||
/* set the distance/weight of the start vertex to 0 */
|
||||
vert_list[BMINDEX_GET(sv)].weight = 0.0f;
|
||||
|
||||
h = BLI_heap_new();
|
||||
|
||||
for( i = 0; i < num_total; i++ )
|
||||
vert_list[i].hn = BLI_heap_insert(h, vert_list[i].weight, vert_list[i].v);
|
||||
|
||||
while( !BLI_heap_empty(h) ) {
|
||||
BMEdge *e;
|
||||
BMIter e_i;
|
||||
float v_weight;
|
||||
|
||||
/* take the vertex with the lowest weight out of the heap */
|
||||
BMVert *v = (BMVert*)BLI_heap_popmin(h);
|
||||
|
||||
if( vert_list[BMINDEX_GET(v)].weight == FLT_MAX ) /* this means that there is no path */
|
||||
break;
|
||||
|
||||
v_weight = vert_list[BMINDEX_GET(v)].weight;
|
||||
|
||||
BM_ITER(e, &e_i, bm, BM_EDGES_OF_VERT, v) {
|
||||
BMVert *u;
|
||||
float e_weight = v_weight;
|
||||
|
||||
if( type == VPATH_SELECT_EDGE_LENGTH )
|
||||
e_weight += VecLenf(e->v1->co, e->v2->co);
|
||||
else e_weight += 1.0f;
|
||||
|
||||
u = ( e->v1 == v ) ? e->v2 : e->v1;
|
||||
|
||||
if( e_weight < vert_list[BMINDEX_GET(u)].weight ) { /* is this path shorter ? */
|
||||
/* add it if so */
|
||||
vert_list[BMINDEX_GET(u)].parent = v;
|
||||
vert_list[BMINDEX_GET(u)].weight = e_weight;
|
||||
|
||||
/* we should do a heap update node function!!! :-/ */
|
||||
BLI_heap_remove(h, vert_list[BMINDEX_GET(u)].hn);
|
||||
BLI_heap_insert(h, e_weight, u);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* now we trace the path (if it exists) */
|
||||
v = ev;
|
||||
|
||||
while( vert_list[BMINDEX_GET(v)].parent != NULL ) {
|
||||
BMO_SetFlag(bm, v, VERT_MARK);
|
||||
v = vert_list[BMINDEX_GET(v)].parent;
|
||||
}
|
||||
|
||||
BLI_heap_free(h, NULL);
|
||||
MEM_freeN(vert_list);
|
||||
|
||||
BMO_Flag_To_Slot(bm, op, "vertout", VERT_MARK, BM_VERT);
|
||||
}
|
||||
|
@ -2215,7 +2215,9 @@ static int mesh_rotate_uvs(bContext *C, wmOperator *op)
|
||||
/* dependencies graph and notification stuff */
|
||||
DAG_id_flush_update(ob->data, OB_RECALC_DATA);
|
||||
WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
|
||||
|
||||
/* DAG_id_flush_update(ob->data, OB_RECALC_DATA);
|
||||
WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
|
||||
*/
|
||||
/* we succeeded */
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
@ -2240,73 +2242,67 @@ static int mesh_reverse_uvs(bContext *C, wmOperator *op)
|
||||
/* dependencies graph and notification stuff */
|
||||
DAG_id_flush_update(ob->data, OB_RECALC_DATA);
|
||||
WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
|
||||
|
||||
/* DAG_id_flush_update(ob->data, OB_RECALC_DATA);
|
||||
WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
|
||||
*/
|
||||
/* we succeeded */
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static int mesh_rotate_colors(bContext *C, wmOperator *op)
|
||||
{
|
||||
#if 0
|
||||
Scene *scene= CTX_data_scene(C);
|
||||
Object *obedit= CTX_data_edit_object(C);
|
||||
EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
Object *ob = CTX_data_edit_object(C);
|
||||
BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
|
||||
BMOperator bmop;
|
||||
|
||||
EditFace *efa;
|
||||
short change = 0;
|
||||
MCol tmpcol, *mcol;
|
||||
int dir= RNA_enum_get(op->ptr, "direction");
|
||||
/* get the direction from RNA */
|
||||
int dir = RNA_enum_get(op->ptr, "direction");
|
||||
|
||||
if (!EM_vertColorCheck(em)) {
|
||||
BKE_report(op->reports, RPT_ERROR, "Mesh has no color layers.");
|
||||
BKE_mesh_end_editmesh(obedit->data, em);
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
/* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
|
||||
EDBM_InitOpf(em, &bmop, op, "meshrotatecolors faces=%hf dir=%d", BM_SELECT, dir);
|
||||
|
||||
for(efa=em->faces.first; efa; efa=efa->next) {
|
||||
if (efa->f & SELECT) {
|
||||
mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
|
||||
tmpcol= mcol[0];
|
||||
/* execute the operator */
|
||||
BMO_Exec_Op(em->bm, &bmop);
|
||||
|
||||
if (dir == DIRECTION_CCW) {
|
||||
if(efa->v4) {
|
||||
mcol[0]= mcol[3];
|
||||
mcol[3]= mcol[2];
|
||||
} else {
|
||||
mcol[0]= mcol[2];
|
||||
}
|
||||
mcol[2]= mcol[1];
|
||||
mcol[1]= tmpcol;
|
||||
} else {
|
||||
mcol[0]= mcol[1];
|
||||
mcol[1]= mcol[2];
|
||||
|
||||
if(efa->v4) {
|
||||
mcol[2]= mcol[3];
|
||||
mcol[3]= tmpcol;
|
||||
}
|
||||
else
|
||||
mcol[2]= tmpcol;
|
||||
}
|
||||
change = 1;
|
||||
}
|
||||
}
|
||||
|
||||
BKE_mesh_end_editmesh(obedit->data, em);
|
||||
|
||||
if(!change)
|
||||
/* finish the operator */
|
||||
if( !EDBM_FinishOp(em, &bmop, op, 1) )
|
||||
return OPERATOR_CANCELLED;
|
||||
|
||||
DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
|
||||
WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
|
||||
|
||||
/* dependencies graph and notification stuff */
|
||||
DAG_id_flush_update(ob->data, OB_RECALC_DATA);
|
||||
WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
|
||||
/* DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_GEOM_SELECT, ob);
|
||||
*/
|
||||
/* we succeeded */
|
||||
return OPERATOR_FINISHED;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static int mesh_mirror_colors(bContext *C, wmOperator *op)
|
||||
static int mesh_reverse_colors(bContext *C, wmOperator *op)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
Object *ob = CTX_data_edit_object(C);
|
||||
BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
|
||||
BMOperator bmop;
|
||||
|
||||
/* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
|
||||
EDBM_InitOpf(em, &bmop, op, "meshreversecolors faces=%hf", BM_SELECT);
|
||||
|
||||
/* execute the operator */
|
||||
BMO_Exec_Op(em->bm, &bmop);
|
||||
|
||||
/* finish the operator */
|
||||
if( !EDBM_FinishOp(em, &bmop, op, 1) )
|
||||
return OPERATOR_CANCELLED;
|
||||
|
||||
DAG_id_flush_update(ob->data, OB_RECALC_DATA);
|
||||
WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
|
||||
|
||||
/* we succeeded */
|
||||
return OPERATOR_FINISHED;
|
||||
#if 0
|
||||
Scene *scene= CTX_data_scene(C);
|
||||
Object *obedit= CTX_data_edit_object(C);
|
||||
@ -2415,21 +2411,21 @@ void MESH_OT_colors_rotate(wmOperatorType *ot)
|
||||
RNA_def_enum(ot->srna, "direction", direction_items, DIRECTION_CW, "Direction", "Direction to rotate edge around.");
|
||||
}
|
||||
|
||||
void MESH_OT_colors_mirror(wmOperatorType *ot)
|
||||
void MESH_OT_colors_reverse(wmOperatorType *ot)
|
||||
{
|
||||
/* identifiers */
|
||||
ot->name= "Mirror Colors";
|
||||
ot->idname= "MESH_OT_colors_mirror";
|
||||
ot->name= "Reverse Colors";
|
||||
ot->idname= "MESH_OT_colors_reverse";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec= mesh_mirror_colors;
|
||||
ot->exec= mesh_reverse_colors;
|
||||
ot->poll= ED_operator_editmesh;
|
||||
|
||||
/* flags */
|
||||
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
||||
|
||||
/* props */
|
||||
RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror colors around.");
|
||||
//RNA_def_enum(ot->srna, "axis", axis_items, DIRECTION_CW, "Axis", "Axis to mirror colors around.");
|
||||
}
|
||||
|
||||
|
||||
@ -2666,3 +2662,249 @@ void MESH_OT_remove_doubles(wmOperatorType *ot)
|
||||
"Merge Distance",
|
||||
"Minimum distance between elements to merge.", 0.00001, 10.0);
|
||||
}
|
||||
|
||||
/************************ Vertex Path Operator *************************/
|
||||
|
||||
typedef struct PathNode {
|
||||
int u;
|
||||
int visited;
|
||||
ListBase edges;
|
||||
} PathNode;
|
||||
|
||||
typedef struct PathEdge {
|
||||
struct PathEdge *next, *prev;
|
||||
int v;
|
||||
float w;
|
||||
} PathEdge;
|
||||
|
||||
|
||||
|
||||
int select_vertex_path_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Scene *scene = CTX_data_scene(C);
|
||||
Object *ob = CTX_data_edit_object(C);
|
||||
BMEditMesh *em = ((Mesh*)ob->data)->edit_btmesh;
|
||||
BMOperator bmop;
|
||||
BMEditSelection *sv, *ev;
|
||||
|
||||
/* get the type from RNA */
|
||||
int type = RNA_enum_get(op->ptr, "type");
|
||||
|
||||
sv = em->bm->selected.last;
|
||||
if( sv != NULL )
|
||||
ev = sv->prev;
|
||||
else return OPERATOR_CANCELLED;
|
||||
if( ev == NULL )
|
||||
return OPERATOR_CANCELLED;
|
||||
|
||||
if( sv->type != BM_VERT || ev->type != BM_VERT )
|
||||
return OPERATOR_CANCELLED;
|
||||
|
||||
/* initialize the bmop using EDBM api, which does various ui error reporting and other stuff */
|
||||
EDBM_InitOpf(em, &bmop, op, "vertexshortestpath startv=%e endv=%e type=%d", sv->data, ev->data, type);
|
||||
|
||||
/* execute the operator */
|
||||
BMO_Exec_Op(em->bm, &bmop);
|
||||
|
||||
/* DO NOT clear the existing selection */
|
||||
/* EDBM_clear_flag_all(em, BM_SELECT); */
|
||||
|
||||
/* select the output */
|
||||
BMO_HeaderFlag_Buffer(em->bm, &bmop, "vertout", BM_SELECT, BM_ALL);
|
||||
|
||||
/* finish the operator */
|
||||
if( !EDBM_FinishOp(em, &bmop, op, 1) )
|
||||
return OPERATOR_CANCELLED;
|
||||
|
||||
EDBM_selectmode_flush(em);
|
||||
|
||||
/* dependencies graph and notification stuff */
|
||||
/* DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_GEOM_SELECT, ob);
|
||||
*/
|
||||
DAG_id_flush_update(ob->data, OB_RECALC_DATA);
|
||||
WM_event_add_notifier(C, NC_GEOM|ND_DATA, ob->data);
|
||||
|
||||
|
||||
/* we succeeded */
|
||||
return OPERATOR_FINISHED;
|
||||
#if 0
|
||||
Object *obedit= CTX_data_edit_object(C);
|
||||
EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
|
||||
EditVert *eve, *s, *t;
|
||||
EditEdge *eed;
|
||||
EditSelection *ese;
|
||||
PathEdge *newpe, *currpe;
|
||||
PathNode *currpn;
|
||||
PathNode *Q;
|
||||
int v, *previous, pathvert, pnindex; /*pnindex redundant?*/
|
||||
int unbalanced, totnodes;
|
||||
short physical;
|
||||
float *cost;
|
||||
Heap *heap; /*binary heap for sorting pointers to PathNodes based upon a 'cost'*/
|
||||
|
||||
s = t = NULL;
|
||||
|
||||
ese = ((EditSelection*)em->selected.last);
|
||||
if(ese && ese->type == EDITVERT && ese->prev && ese->prev->type == EDITVERT){
|
||||
physical= pupmenu("Distance Method? %t|Edge Length%x1|Topological%x0");
|
||||
|
||||
t = (EditVert*)ese->data;
|
||||
s = (EditVert*)ese->prev->data;
|
||||
|
||||
/*need to find out if t is actually reachable by s....*/
|
||||
for(eve=em->verts.first; eve; eve=eve->next){
|
||||
eve->f1 = 0;
|
||||
}
|
||||
|
||||
s->f1 = 1;
|
||||
|
||||
unbalanced = 1;
|
||||
totnodes = 1;
|
||||
while(unbalanced){
|
||||
unbalanced = 0;
|
||||
for(eed=em->edges.first; eed; eed=eed->next){
|
||||
if(!eed->h){
|
||||
if(eed->v1->f1 && !eed->v2->f1){
|
||||
eed->v2->f1 = 1;
|
||||
totnodes++;
|
||||
unbalanced = 1;
|
||||
}
|
||||
else if(eed->v2->f1 && !eed->v1->f1){
|
||||
eed->v1->f1 = 1;
|
||||
totnodes++;
|
||||
unbalanced = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(s->f1 && t->f1){ /* t can be reached by s */
|
||||
Q = MEM_callocN(sizeof(PathNode)*totnodes, "Path Select Nodes");
|
||||
totnodes = 0;
|
||||
for(eve=em->verts.first; eve; eve=eve->next){
|
||||
if(eve->f1){
|
||||
Q[totnodes].u = totnodes;
|
||||
Q[totnodes].edges.first = 0;
|
||||
Q[totnodes].edges.last = 0;
|
||||
Q[totnodes].visited = 0;
|
||||
eve->tmp.p = &(Q[totnodes]);
|
||||
totnodes++;
|
||||
}
|
||||
else eve->tmp.p = NULL;
|
||||
}
|
||||
|
||||
for(eed=em->edges.first; eed; eed=eed->next){
|
||||
if(!eed->h){
|
||||
if(eed->v1->f1){
|
||||
currpn = ((PathNode*)eed->v1->tmp.p);
|
||||
|
||||
newpe = MEM_mallocN(sizeof(PathEdge), "Path Edge");
|
||||
newpe->v = ((PathNode*)eed->v2->tmp.p)->u;
|
||||
if(physical){
|
||||
newpe->w = VecLenf(eed->v1->co, eed->v2->co);
|
||||
}
|
||||
else newpe->w = 1;
|
||||
newpe->next = 0;
|
||||
newpe->prev = 0;
|
||||
BLI_addtail(&(currpn->edges), newpe);
|
||||
}
|
||||
if(eed->v2->f1){
|
||||
currpn = ((PathNode*)eed->v2->tmp.p);
|
||||
newpe = MEM_mallocN(sizeof(PathEdge), "Path Edge");
|
||||
newpe->v = ((PathNode*)eed->v1->tmp.p)->u;
|
||||
if(physical){
|
||||
newpe->w = VecLenf(eed->v1->co, eed->v2->co);
|
||||
}
|
||||
else newpe->w = 1;
|
||||
newpe->next = 0;
|
||||
newpe->prev = 0;
|
||||
BLI_addtail(&(currpn->edges), newpe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
heap = BLI_heap_new();
|
||||
cost = MEM_callocN(sizeof(float)*totnodes, "Path Select Costs");
|
||||
previous = MEM_callocN(sizeof(int)*totnodes, "PathNode indices");
|
||||
|
||||
for(v=0; v < totnodes; v++){
|
||||
cost[v] = 1000000;
|
||||
previous[v] = -1; /*array of indices*/
|
||||
}
|
||||
|
||||
pnindex = ((PathNode*)s->tmp.p)->u;
|
||||
cost[pnindex] = 0;
|
||||
BLI_heap_insert(heap, 0.0f, SET_INT_IN_POINTER(pnindex));
|
||||
|
||||
while( !BLI_heap_empty(heap) ){
|
||||
|
||||
pnindex = GET_INT_FROM_POINTER(BLI_heap_popmin(heap));
|
||||
currpn = &(Q[pnindex]);
|
||||
|
||||
if(currpn == (PathNode*)t->tmp.p) /*target has been reached....*/
|
||||
break;
|
||||
|
||||
for(currpe=currpn->edges.first; currpe; currpe=currpe->next){
|
||||
if(!Q[currpe->v].visited){
|
||||
if( cost[currpe->v] > (cost[currpn->u ] + currpe->w) ){
|
||||
cost[currpe->v] = cost[currpn->u] + currpe->w;
|
||||
previous[currpe->v] = currpn->u;
|
||||
Q[currpe->v].visited = 1;
|
||||
BLI_heap_insert(heap, cost[currpe->v], SET_INT_IN_POINTER(currpe->v));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pathvert = ((PathNode*)t->tmp.p)->u;
|
||||
while(pathvert != -1){
|
||||
for(eve=em->verts.first; eve; eve=eve->next){
|
||||
if(eve->f1){
|
||||
if( ((PathNode*)eve->tmp.p)->u == pathvert) eve->f |= SELECT;
|
||||
}
|
||||
}
|
||||
pathvert = previous[pathvert];
|
||||
}
|
||||
|
||||
for(v=0; v < totnodes; v++) BLI_freelistN(&(Q[v].edges));
|
||||
MEM_freeN(Q);
|
||||
MEM_freeN(cost);
|
||||
MEM_freeN(previous);
|
||||
BLI_heap_free(heap, NULL);
|
||||
EM_select_flush(em);
|
||||
}
|
||||
}
|
||||
else {
|
||||
BKE_mesh_end_editmesh(obedit->data, em);
|
||||
BKE_report(op->reports, RPT_ERROR, "Path Selection requires that exactly two vertices be selected");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
|
||||
BKE_mesh_end_editmesh(obedit->data, em);
|
||||
#endif
|
||||
}
|
||||
|
||||
void MESH_OT_select_vertex_path(wmOperatorType *ot)
|
||||
{
|
||||
static const EnumPropertyItem type_items[] = {
|
||||
{VPATH_SELECT_EDGE_LENGTH, "EDGE_LENGTH", 0, "Edge Length", NULL},
|
||||
{VPATH_SELECT_TOPOLOGICAL, "TOPOLOGICAL", 0, "Topological", NULL},
|
||||
{0, NULL, 0, NULL, NULL}};
|
||||
|
||||
/* identifiers */
|
||||
ot->name= "Select Vertex Path";
|
||||
ot->idname= "MESH_OT_select_vertex_path";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec= select_vertex_path_exec;
|
||||
ot->invoke= WM_menu_invoke;
|
||||
ot->poll= ED_operator_editmesh;
|
||||
|
||||
/* flags */
|
||||
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
||||
|
||||
/* properties */
|
||||
RNA_def_enum(ot->srna, "type", type_items, VPATH_SELECT_EDGE_LENGTH, "Type", "Method to compute distance.");
|
||||
}
|
||||
|
@ -5198,205 +5198,7 @@ int collapseEdges(EditMesh *em)
|
||||
return mergecount;
|
||||
}
|
||||
|
||||
/************************ Vertex Path Operator *************************/
|
||||
|
||||
typedef struct PathNode {
|
||||
int u;
|
||||
int visited;
|
||||
ListBase edges;
|
||||
} PathNode;
|
||||
|
||||
typedef struct PathEdge {
|
||||
struct PathEdge *next, *prev;
|
||||
int v;
|
||||
float w;
|
||||
} PathEdge;
|
||||
|
||||
#define PATH_SELECT_EDGE_LENGTH 0
|
||||
#define PATH_SELECT_TOPOLOGICAL 1
|
||||
|
||||
int select_vertex_path_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Object *obedit= CTX_data_edit_object(C);
|
||||
EditMesh *em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
|
||||
EditVert *eve, *s, *t;
|
||||
EditEdge *eed;
|
||||
EditSelection *ese;
|
||||
PathEdge *newpe, *currpe;
|
||||
PathNode *currpn;
|
||||
PathNode *Q;
|
||||
int v, *previous, pathvert, pnindex; /*pnindex redundant?*/
|
||||
int unbalanced, totnodes;
|
||||
short physical;
|
||||
float *cost;
|
||||
Heap *heap; /*binary heap for sorting pointers to PathNodes based upon a 'cost'*/
|
||||
|
||||
s = t = NULL;
|
||||
|
||||
ese = ((EditSelection*)em->selected.last);
|
||||
if(ese && ese->type == EDITVERT && ese->prev && ese->prev->type == EDITVERT){
|
||||
physical= pupmenu("Distance Method? %t|Edge Length%x1|Topological%x0");
|
||||
|
||||
t = (EditVert*)ese->data;
|
||||
s = (EditVert*)ese->prev->data;
|
||||
|
||||
/*need to find out if t is actually reachable by s....*/
|
||||
for(eve=em->verts.first; eve; eve=eve->next){
|
||||
eve->f1 = 0;
|
||||
}
|
||||
|
||||
s->f1 = 1;
|
||||
|
||||
unbalanced = 1;
|
||||
totnodes = 1;
|
||||
while(unbalanced){
|
||||
unbalanced = 0;
|
||||
for(eed=em->edges.first; eed; eed=eed->next){
|
||||
if(!eed->h){
|
||||
if(eed->v1->f1 && !eed->v2->f1){
|
||||
eed->v2->f1 = 1;
|
||||
totnodes++;
|
||||
unbalanced = 1;
|
||||
}
|
||||
else if(eed->v2->f1 && !eed->v1->f1){
|
||||
eed->v1->f1 = 1;
|
||||
totnodes++;
|
||||
unbalanced = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(s->f1 && t->f1){ /* t can be reached by s */
|
||||
Q = MEM_callocN(sizeof(PathNode)*totnodes, "Path Select Nodes");
|
||||
totnodes = 0;
|
||||
for(eve=em->verts.first; eve; eve=eve->next){
|
||||
if(eve->f1){
|
||||
Q[totnodes].u = totnodes;
|
||||
Q[totnodes].edges.first = 0;
|
||||
Q[totnodes].edges.last = 0;
|
||||
Q[totnodes].visited = 0;
|
||||
eve->tmp.p = &(Q[totnodes]);
|
||||
totnodes++;
|
||||
}
|
||||
else eve->tmp.p = NULL;
|
||||
}
|
||||
|
||||
for(eed=em->edges.first; eed; eed=eed->next){
|
||||
if(!eed->h){
|
||||
if(eed->v1->f1){
|
||||
currpn = ((PathNode*)eed->v1->tmp.p);
|
||||
|
||||
newpe = MEM_mallocN(sizeof(PathEdge), "Path Edge");
|
||||
newpe->v = ((PathNode*)eed->v2->tmp.p)->u;
|
||||
if(physical){
|
||||
newpe->w = VecLenf(eed->v1->co, eed->v2->co);
|
||||
}
|
||||
else newpe->w = 1;
|
||||
newpe->next = 0;
|
||||
newpe->prev = 0;
|
||||
BLI_addtail(&(currpn->edges), newpe);
|
||||
}
|
||||
if(eed->v2->f1){
|
||||
currpn = ((PathNode*)eed->v2->tmp.p);
|
||||
newpe = MEM_mallocN(sizeof(PathEdge), "Path Edge");
|
||||
newpe->v = ((PathNode*)eed->v1->tmp.p)->u;
|
||||
if(physical){
|
||||
newpe->w = VecLenf(eed->v1->co, eed->v2->co);
|
||||
}
|
||||
else newpe->w = 1;
|
||||
newpe->next = 0;
|
||||
newpe->prev = 0;
|
||||
BLI_addtail(&(currpn->edges), newpe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
heap = BLI_heap_new();
|
||||
cost = MEM_callocN(sizeof(float)*totnodes, "Path Select Costs");
|
||||
previous = MEM_callocN(sizeof(int)*totnodes, "PathNode indices");
|
||||
|
||||
for(v=0; v < totnodes; v++){
|
||||
cost[v] = 1000000;
|
||||
previous[v] = -1; /*array of indices*/
|
||||
}
|
||||
|
||||
pnindex = ((PathNode*)s->tmp.p)->u;
|
||||
cost[pnindex] = 0;
|
||||
BLI_heap_insert(heap, 0.0f, SET_INT_IN_POINTER(pnindex));
|
||||
|
||||
while( !BLI_heap_empty(heap) ){
|
||||
|
||||
pnindex = GET_INT_FROM_POINTER(BLI_heap_popmin(heap));
|
||||
currpn = &(Q[pnindex]);
|
||||
|
||||
if(currpn == (PathNode*)t->tmp.p) /*target has been reached....*/
|
||||
break;
|
||||
|
||||
for(currpe=currpn->edges.first; currpe; currpe=currpe->next){
|
||||
if(!Q[currpe->v].visited){
|
||||
if( cost[currpe->v] > (cost[currpn->u ] + currpe->w) ){
|
||||
cost[currpe->v] = cost[currpn->u] + currpe->w;
|
||||
previous[currpe->v] = currpn->u;
|
||||
Q[currpe->v].visited = 1;
|
||||
BLI_heap_insert(heap, cost[currpe->v], SET_INT_IN_POINTER(currpe->v));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pathvert = ((PathNode*)t->tmp.p)->u;
|
||||
while(pathvert != -1){
|
||||
for(eve=em->verts.first; eve; eve=eve->next){
|
||||
if(eve->f1){
|
||||
if( ((PathNode*)eve->tmp.p)->u == pathvert) eve->f |= SELECT;
|
||||
}
|
||||
}
|
||||
pathvert = previous[pathvert];
|
||||
}
|
||||
|
||||
for(v=0; v < totnodes; v++) BLI_freelistN(&(Q[v].edges));
|
||||
MEM_freeN(Q);
|
||||
MEM_freeN(cost);
|
||||
MEM_freeN(previous);
|
||||
BLI_heap_free(heap, NULL);
|
||||
EM_select_flush(em);
|
||||
}
|
||||
}
|
||||
else {
|
||||
BKE_mesh_end_editmesh(obedit->data, em);
|
||||
BKE_report(op->reports, RPT_ERROR, "Path Selection requires that exactly two vertices be selected");
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
|
||||
BKE_mesh_end_editmesh(obedit->data, em);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void MESH_OT_select_vertex_path(wmOperatorType *ot)
|
||||
{
|
||||
static const EnumPropertyItem type_items[] = {
|
||||
{PATH_SELECT_EDGE_LENGTH, "EDGE_LENGTH", 0, "Edge Length", NULL},
|
||||
{PATH_SELECT_TOPOLOGICAL, "TOPOLOGICAL", 0, "Topological", NULL},
|
||||
{0, NULL, 0, NULL, NULL}};
|
||||
|
||||
/* identifiers */
|
||||
ot->name= "Select Vertex Path";
|
||||
ot->idname= "MESH_OT_select_vertex_path";
|
||||
|
||||
/* api callbacks */
|
||||
ot->exec= select_vertex_path_exec;
|
||||
ot->invoke= WM_menu_invoke;
|
||||
ot->poll= ED_operator_editmesh;
|
||||
|
||||
/* flags */
|
||||
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
|
||||
|
||||
/* properties */
|
||||
RNA_def_enum(ot->srna, "type", type_items, PATH_SELECT_EDGE_LENGTH, "Type", "Method to compute distance.");
|
||||
}
|
||||
|
||||
/********************** Region/Loop Operators *************************/
|
||||
|
||||
|
@ -281,7 +281,9 @@ void MESH_OT_uvs_rotate(struct wmOperatorType *ot);
|
||||
//void MESH_OT_uvs_mirror(struct wmOperatorType *ot);
|
||||
void MESH_OT_uvs_reverse(struct wmOperatorType *ot);
|
||||
void MESH_OT_colors_rotate(struct wmOperatorType *ot);
|
||||
void MESH_OT_colors_mirror(struct wmOperatorType *ot);
|
||||
//void MESH_OT_colors_mirror(struct wmOperatorType *ot);
|
||||
|
||||
void MESH_OT_colors_reverse(struct wmOperatorType *ot);
|
||||
|
||||
void MESH_OT_delete(struct wmOperatorType *ot);
|
||||
void MESH_OT_rip(struct wmOperatorType *ot);
|
||||
|
@ -171,7 +171,8 @@ static int face_specials_invoke(bContext *C, wmOperator *op, wmEvent *event)
|
||||
//uiItemMenuEnumO(layout, NULL, 0, "MESH_OT_uvs_mirror", "axis");
|
||||
uiItemO(layout, NULL, 0, "MESH_OT_uvs_reverse");
|
||||
uiItemMenuEnumO(layout, NULL, 0, "MESH_OT_colors_rotate", "direction");
|
||||
uiItemMenuEnumO(layout, NULL, 0, "MESH_OT_colors_mirror", "axis");
|
||||
//uiItemMenuEnumO(layout, NULL, 0, "MESH_OT_colors_mirror", "axis");
|
||||
uiItemO(layout, NULL, 0, "MESH_OT_colors_reverse");
|
||||
|
||||
uiPupMenuEnd(C, pup);
|
||||
|
||||
@ -291,7 +292,8 @@ void ED_operatortypes_mesh(void)
|
||||
//WM_operatortype_append(MESH_OT_uvs_mirror);
|
||||
WM_operatortype_append(MESH_OT_uvs_reverse);
|
||||
WM_operatortype_append(MESH_OT_colors_rotate);
|
||||
WM_operatortype_append(MESH_OT_colors_mirror);
|
||||
//WM_operatortype_append(MESH_OT_colors_mirror);
|
||||
WM_operatortype_append(MESH_OT_colors_reverse);
|
||||
|
||||
WM_operatortype_append(MESH_OT_fill);
|
||||
WM_operatortype_append(MESH_OT_beauty_fill);
|
||||
@ -453,7 +455,8 @@ void ED_keymap_mesh(wmWindowManager *wm)
|
||||
//WM_keymap_add_item(keymap, "MESH_OT_uvs_mirror",SEVENKEY, KM_PRESS, KM_ALT, 0);
|
||||
WM_keymap_add_item(keymap, "MESH_OT_uvs_reverse",SEVENKEY, KM_PRESS, KM_ALT, 0);
|
||||
WM_keymap_add_item(keymap, "MESH_OT_colors_rotate",EIGHTKEY, KM_PRESS, KM_CTRL, 0);
|
||||
WM_keymap_add_item(keymap, "MESH_OT_colors_mirror",EIGHTKEY, KM_PRESS, KM_ALT, 0);
|
||||
//WM_keymap_add_item(keymap, "MESH_OT_colors_mirror",EIGHTKEY, KM_PRESS, KM_ALT, 0);
|
||||
WM_keymap_add_item(keymap, "MESH_OT_colors_reverse",EIGHTKEY, KM_PRESS, KM_ALT, 0);
|
||||
|
||||
WM_keymap_add_item(keymap, "MESH_OT_rip_move",VKEY, KM_PRESS, 0, 0);
|
||||
WM_keymap_add_item(keymap, "MESH_OT_merge", MKEY, KM_PRESS, KM_ALT, 0);
|
||||
|
Loading…
Reference in New Issue
Block a user