vertex color rotation and reversing/shortest vertex path

This commit is contained in:
Wael El Oraiby 2009-09-20 18:18:40 +00:00
parent f0ff8d665d
commit c75e1598dd
8 changed files with 576 additions and 258 deletions

@ -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);