[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [39954] branches/bmesh/blender/source/ blender/editors/mesh: patch [#28518] BMesh: fix 28491 ( implement edge tag shortest path)
Campbell Barton
ideasman42 at gmail.com
Tue Sep 6 05:32:59 CEST 2011
Revision: 39954
http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=39954
Author: campbellbarton
Date: 2011-09-06 03:32:58 +0000 (Tue, 06 Sep 2011)
Log Message:
-----------
patch [#28518] BMesh: fix 28491 (implement edge tag shortest path)
from Andrew Wiggin (ender79)
Modified Paths:
--------------
branches/bmesh/blender/source/blender/editors/mesh/bmesh_select.c
branches/bmesh/blender/source/blender/editors/mesh/editface.c
branches/bmesh/blender/source/blender/editors/mesh/mesh_intern.h
Modified: branches/bmesh/blender/source/blender/editors/mesh/bmesh_select.c
===================================================================
--- branches/bmesh/blender/source/blender/editors/mesh/bmesh_select.c 2011-09-06 03:21:55 UTC (rev 39953)
+++ branches/bmesh/blender/source/blender/editors/mesh/bmesh_select.c 2011-09-06 03:32:58 UTC (rev 39954)
@@ -56,6 +56,7 @@
#include "BLI_rand.h"
#include "BLI_array.h"
#include "BLI_smallhash.h"
+#include "BLI_heap.h"
#include "BKE_context.h"
#include "BKE_displist.h"
@@ -1053,15 +1054,267 @@
RNA_def_boolean(ot->srna, "ring", 0, "Select Ring", "");
}
+/* ******************* edgetag_shortest_path and helpers ****************** */
+
+static float edgetag_cut_cost(BMEditMesh *UNUSED(em), BMEdge *e1, BMEdge *e2, BMVert* v)
+{
+ BMVert *v1 = (e1->v1 == v) ? e1->v2 : e1->v1;
+ BMVert *v2 = (e2->v1 == v) ? e2->v2 : e2->v1;
+ float cost, d1[3], d2[3];
+
+ /*The cost is based on the simple sum of the length of the two edgees...*/
+ sub_v3_v3v3(d1, v->co, v1->co);
+ sub_v3_v3v3(d2, v2->co, v->co);
+ cost = len_v3(d1);
+ cost += len_v3(d2);
+
+ /*...but is biased to give higher values to sharp turns, so that it will take
+ paths with fewer "turns" when selecting between equal-weighted paths between
+ the two edges*/
+ cost = cost + 0.5f*cost*(2.0f - sqrt(fabs(dot_v3v3(d1, d2))));
+
+ return cost;
+}
+
+static void edgetag_add_adjacent(BMEditMesh *em, SmallHash *visithash, Heap *heap, int mednum, int vertnum,
+ int *nedges, int *edges, int *prevedge, float *cost)
+{
+ BMEdge *e1 = EDBM_get_edge_for_index(em, mednum);
+ BMVert *v = EDBM_get_vert_for_index(em, vertnum);
+ int startadj, endadj = nedges[vertnum+1];
+
+ for (startadj = nedges[vertnum]; startadj < endadj; startadj++) {
+ int adjnum = edges[startadj];
+ BMEdge *e2 = EDBM_get_edge_for_index(em, adjnum);
+ float newcost;
+ float cutcost;
+
+ if (BLI_smallhash_haskey(visithash, (uintptr_t)e2))
+ continue;
+
+ cutcost = edgetag_cut_cost(em, e1, e2, v);
+ newcost = cost[mednum] + cutcost;
+
+ if (cost[adjnum] > newcost) {
+ cost[adjnum] = newcost;
+ prevedge[adjnum] = mednum;
+ BLI_heap_insert(heap, newcost, SET_INT_IN_POINTER(adjnum));
+ }
+ }
+}
+
+static void edgetag_context_set(BMEditMesh *em, Scene *scene, BMEdge *e, int val)
+{
+
+ switch (scene->toolsettings->edge_mode) {
+ case EDGE_MODE_SELECT:
+ BM_Select(em->bm, e, val);
+ break;
+ case EDGE_MODE_TAG_SEAM:
+ if (val) {BM_SetHFlag(e, BM_SEAM);}
+ else {BM_ClearHFlag(e, BM_SEAM);}
+ break;
+ case EDGE_MODE_TAG_SHARP:
+ if (val) {BM_SetHFlag(e, BM_SEAM);}
+ else {BM_ClearHFlag(e, BM_SEAM);}
+ break;
+ case EDGE_MODE_TAG_CREASE:
+ {
+ float *crease = CustomData_bmesh_get(&em->bm->edata, e->head.data, CD_CREASE);
+
+ if (val) {*crease = 1.0f;}
+ else {*crease = 0.0f;}
+ break;
+ }
+ case EDGE_MODE_TAG_BEVEL:
+ {
+ float *bweight = CustomData_bmesh_get(&em->bm->edata, e->head.data, CD_BWEIGHT);
+
+ if (val) {*bweight = 1.0f;}
+ else {*bweight = 0.0f;}
+ break;
+ }
+ }
+}
+
+static float bm_cdata_get_single_float(BMesh *UNUSED(bm), CustomData *cdata, void *element, int type)
+{
+ BMHeader *ele = element;
+ float *f;
+
+ if (!CustomData_has_layer(cdata, type))
+ return 0.0f;
+
+ f = CustomData_bmesh_get(cdata, ele->data, type);
+
+ return *f;
+}
+
+static int edgetag_context_check(Scene *scene, BMEditMesh *em, BMEdge *e)
+{
+ switch (scene->toolsettings->edge_mode) {
+ case EDGE_MODE_SELECT:
+ return BM_TestHFlag(e, BM_SELECT) ? 1 : 0;
+ case EDGE_MODE_TAG_SEAM:
+ return BM_TestHFlag(e, BM_SEAM);
+ case EDGE_MODE_TAG_SHARP:
+ return BM_TestHFlag(e, BM_SHARP);
+ case EDGE_MODE_TAG_CREASE:
+ return bm_cdata_get_single_float(em->bm, &em->bm->edata, e, CD_CREASE) ? 1 : 0;
+ case EDGE_MODE_TAG_BEVEL:
+ return bm_cdata_get_single_float(em->bm, &em->bm->edata, e, CD_BWEIGHT) ? 1 : 0;
+ }
+ return 0;
+}
+
+static int edgetag_shortest_path(Scene *scene, BMEditMesh *em, BMEdge *source, BMEdge *target)
+{
+ BMEdge *e;
+ BMVert *v;
+ BMIter iter;
+ Heap *heap;
+ SmallHash visithash;
+ float *cost;
+ int i, totvert=0, totedge=0, *nedges, *edges, *prevedge, mednum = -1, nedgeswap = 0;
+ int targetnum;
+
+ BLI_smallhash_init(&visithash);
+
+ /* we need the vert */
+ BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
+ BM_SetIndex(v, totvert);
+ totvert++;
+ }
+
+ BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ e->head.flags[0].f = 0;
+ if (BM_TestHFlag(e, BM_HIDDEN)) {
+ BLI_smallhash_insert(&visithash, (uintptr_t)e, NULL);
+ }
+ BM_SetIndex(e, totedge);
+ totedge++;
+ }
+
+ /* alloc */
+ nedges = MEM_callocN(sizeof(*nedges)*totvert+1, "SeamPathNEdges");
+ edges = MEM_mallocN(sizeof(*edges)*totedge*2, "SeamPathEdges");
+ prevedge = MEM_mallocN(sizeof(*prevedge)*totedge, "SeamPathPrevious");
+ cost = MEM_mallocN(sizeof(*cost)*totedge, "SeamPathCost");
+
+ /* count edges, compute adjacent edges offsets and fill adjacent */
+ BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ nedges[BM_GetIndex(e->v1)+1]++;
+ nedges[BM_GetIndex(e->v2)+1]++;
+ }
+
+ for (i = 1; i < totvert; i++) {
+ int newswap = nedges[i+1];
+ nedges[i+1] = nedgeswap + nedges[i];
+ nedgeswap = newswap;
+ }
+ nedges[0] = nedges[1] = 0;
+
+ i = 0;
+ BM_ITER(e, &iter, em->bm, BM_EDGES_OF_MESH, NULL) {
+ edges[nedges[BM_GetIndex(e->v1)+1]++] = i;
+ edges[nedges[BM_GetIndex(e->v2)+1]++] = i;
+
+ cost[i] = 1e20f;
+ prevedge[i] = -1;
+ i++;
+ }
+
+ /*
+ * Arrays are now filled as follows:
+ *
+ * nedges[n] = sum of the # of edges incident to all vertices numbered 0 thru n-1
+ * edges[edges[n]..edges[n-1]] = the indices of of the edges incident to vertex n
+ *
+ * As the search continues, prevedge[n] will be the previous edge on the shortest
+ * path found so far to edge n. The visitedhash will of course contain entries
+ * for edges that have been visited, cost[n] will contain the length of the shortest
+ * path to edge n found so far, Finally, heap is a priority heap which is built on the
+ * the same data as the cost arry, but inverted: it is a worklist of edges prioritized
+ * by the shortest path found so far to the edge.
+ */
+
+ for (i = 0; i < totvert; i++) {
+ int start = nedges[i], end = nedges[i+1], cur;
+ for (cur = start; cur < end; cur++) {
+ BMEdge* e = EDBM_get_edge_for_index(em, edges[cur]);
+ }
+ }
+
+ /* regular dijkstra shortest path, but over edges instead of vertices */
+ heap = BLI_heap_new();
+ BLI_heap_insert(heap, 0.0f, SET_INT_IN_POINTER(BM_GetIndex(source)));
+ cost[BM_GetIndex(source)] = 0.0f;
+ EDBM_init_index_arrays(em, 1, 1, 0);
+ targetnum = BM_GetIndex(target);
+
+ while (!BLI_heap_empty(heap)) {
+ mednum = GET_INT_FROM_POINTER(BLI_heap_popmin(heap));
+ e = EDBM_get_edge_for_index(em, mednum);
+
+ if (mednum == targetnum)
+ break;
+
+ if (BLI_smallhash_haskey(&visithash, (uintptr_t)e))
+ continue;
+
+ BLI_smallhash_insert(&visithash, (uintptr_t)e, NULL);
+
+ edgetag_add_adjacent(em, &visithash, heap, mednum, BM_GetIndex(e->v1), nedges, edges, prevedge, cost);
+ edgetag_add_adjacent(em, &visithash, heap, mednum, BM_GetIndex(e->v2), nedges, edges, prevedge, cost);
+ }
+
+ if (mednum == targetnum) {
+ short allseams = 1;
+
+ /*Check whether the path is already completely tagged.
+ if it is, the tags will be cleared instead of set.*/
+ mednum = targetnum;
+ do {
+ e = EDBM_get_edge_for_index(em, mednum);
+ if (!edgetag_context_check(scene, em, e)) {
+ allseams = 0;
+ break;
+ }
+ mednum = prevedge[mednum];
+ } while (mednum != BM_GetIndex(source));
+
+ /*Follow path back and source and add or remove tags*/
+ mednum = targetnum;
+ do {
+ e = EDBM_get_edge_for_index(em, mednum);
+ if (allseams)
+ edgetag_context_set(em, scene, e, 0);
+ else
+ edgetag_context_set(em, scene, e, 1);
+ mednum = prevedge[mednum];
+ } while (mednum != -1);
+ }
+
+ EDBM_free_index_arrays(em);
+ MEM_freeN(nedges);
+ MEM_freeN(edges);
+ MEM_freeN(prevedge);
+ MEM_freeN(cost);
+ BLI_heap_free(heap, NULL);
+ BLI_smallhash_release(&visithash);
+
+ return 1;
+}
+
/* ******************* mesh shortest path select, uses prev-selected edge ****************** */
/* since you want to create paths with multiple selects, it doesn't have extend option */
-static void mouse_mesh_shortest_path(bContext *UNUSED(C), int UNUSED(mval[2]))
+static void mouse_mesh_shortest_path(bContext *C, int mval[2])
{
-#if 0 //BMESH_TODO
+ Object *ob = CTX_data_edit_object(C);
ViewContext vc;
BMEditMesh *em;
- BMEdge *eed;
+ BMEdge *e;
int dist= 50;
em_setup_viewcontext(C, &vc);
@@ -1069,37 +1322,37 @@
vc.mval[1]= mval[1];
em= vc.em;
- eed= findnearestedge(&vc, &dist);
- if(eed) {
+ e= EDBM_findnearestedge(&vc, &dist);
+ if(e) {
Mesh *me= vc.obedit->data;
int path = 0;
if (em->bm->selected.last) {
EditSelection *ese = em->bm->selected.last;
- if(ese && ese->type == BMEdge) {
- BMEdge *eed_act;
- eed_act = (BMEdge*)ese->data;
- if (eed_act != eed) {
- if (edgetag_shortest_path(vc.scene, em, eed_act, eed)) {
- EM_remove_selection(em, eed_act, BMEdge);
+ if(ese && ese->type == BM_EDGE) {
+ BMEdge *e_act;
+ e_act = (BMEdge*)ese->data;
+ if (e_act != e) {
+ if (edgetag_shortest_path(vc.scene, em, e_act, e)) {
+ EDBM_remove_selection(em, e_act);
path = 1;
}
}
}
}
if (path==0) {
- int act = (edgetag_context_check(vc.scene, eed)==0);
- edgetag_context_set(em, vc.scene, eed, act); /* switch the edge option */
+ int act = (edgetag_context_check(vc.scene, em, e)==0);
+ edgetag_context_set(em, vc.scene, e, act); /* switch the edge option */
}
- EM_selectmode_flush(em);
+ EDBM_selectmode_flush(em);
/* even if this is selected it may not be in the selection list */
- if(edgetag_context_check(vc.scene, eed)==0)
- EDBM_remove_selection(em, eed);
+ if(edgetag_context_check(vc.scene, em, e)==0)
+ EDBM_remove_selection(em, e);
else
- EDBM_store_selection(em, eed);
+ EDBM_store_selection(em, e);
/* force drawmode for mesh */
switch (CTX_data_tool_settings(C)->edge_mode) {
@@ -1121,7 +1374,6 @@
DAG_id_tag_update(ob->data, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_GEOM|ND_SELECT, ob->data);
}
-#endif
}
Modified: branches/bmesh/blender/source/blender/editors/mesh/editface.c
===================================================================
--- branches/bmesh/blender/source/blender/editors/mesh/editface.c 2011-09-06 03:21:55 UTC (rev 39953)
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list