From 5bceb00a61f1cd98c049cc11931550acf08426c7 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 13 Mar 2014 01:36:24 +1100 Subject: [PATCH] Mesh API: replace octree mirror with kdtree --- source/blender/editors/include/ED_mesh.h | 3 +- source/blender/editors/mesh/meshtools.c | 283 +++++------------- .../bad_level_call_stubs/stubs.c | 2 +- 3 files changed, 77 insertions(+), 211 deletions(-) diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 04f8dfc2d1b..2d7e558ae70 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -300,7 +300,8 @@ void EDBM_redo_state_free(struct BMBackup *, struct BMEditMesh *em, int recalcte int join_mesh_exec(struct bContext *C, struct wmOperator *op); int join_mesh_shapes_exec(struct bContext *C, struct wmOperator *op); -intptr_t mesh_octree_table(struct Object *ob, struct BMEditMesh *em, const float co[3], char mode); +/* mirror lookup api */ +int mesh_octree_table(struct Object *ob, struct BMEditMesh *em, const float co[3], char mode); int mesh_mirrtopo_table(struct Object *ob, char mode); /* retrieves mirrored cache vert, or NULL if there isn't one. diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index 1d47d4c49df..8047959fb54 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -47,6 +47,7 @@ #include "BLI_blenlib.h" +#include "BLI_kdtree.h" #include "BKE_context.h" #include "BKE_depsgraph.h" #include "BKE_deform.h" @@ -657,245 +658,101 @@ int join_mesh_shapes_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -/* ********************* MESH VERTEX OCTREE LOOKUP ************* */ +/* -------------------------------------------------------------------- */ +/* Mesh Mirror (Spatial) */ -/* important note; this is unfinished, needs better API for editmode, and custom threshold */ +/** \name Mesh Spatial Mirror API + * \{ */ -#define MOC_RES 8 -#define MOC_NODE_RES 8 -#define MOC_THRESH 0.00002f +#define KD_THRESH 0.00002f -typedef struct MocNode { - struct MocNode *next; - intptr_t index[MOC_NODE_RES]; -} MocNode; - -static int mesh_octree_get_base_offs(const float co[3], const float offs[3], const float div[3]) -{ - int vx, vy, vz; - - vx = floor((co[0] - offs[0]) / div[0]); - vy = floor((co[1] - offs[1]) / div[1]); - vz = floor((co[2] - offs[2]) / div[2]); - - CLAMP(vx, 0, MOC_RES - 1); - CLAMP(vy, 0, MOC_RES - 1); - CLAMP(vz, 0, MOC_RES - 1); - - return (vx * MOC_RES * MOC_RES) + vy * MOC_RES + vz; -} - -static void mesh_octree_add_node(MocNode **bt, intptr_t index) -{ - if (*bt == NULL) { - *bt = MEM_callocN(sizeof(MocNode), "MocNode"); - (*bt)->index[0] = index; - } - else { - int a; - for (a = 0; a < MOC_NODE_RES; a++) { - if ((*bt)->index[a] == index) - return; - else if ((*bt)->index[a] == 0) { - (*bt)->index[a] = index; - return; - } - } - mesh_octree_add_node(&(*bt)->next, index); - } -} - -static void mesh_octree_free_node(MocNode **bt) -{ - if ( (*bt)->next) { - mesh_octree_free_node(&(*bt)->next); - } - MEM_freeN(*bt); -} - - -/* temporal define, just to make nicer code below */ -#define MOC_INDEX(vx, vy, vz) (((vx) * MOC_RES * MOC_RES) + (vy) * MOC_RES + (vz)) - -static void mesh_octree_add_nodes(MocNode **basetable, const float co[3], const float offs[3], - const float div[3], intptr_t index) -{ - float fx, fy, fz; - int vx, vy, vz; - - if ((finite(co[0]) == false) || - (finite(co[1]) == false) || - (finite(co[2]) == false)) - { - return; - } - - fx = (co[0] - offs[0]) / div[0]; - fy = (co[1] - offs[1]) / div[1]; - fz = (co[2] - offs[2]) / div[2]; - CLAMP(fx, 0.0f, MOC_RES - MOC_THRESH); - CLAMP(fy, 0.0f, MOC_RES - MOC_THRESH); - CLAMP(fz, 0.0f, MOC_RES - MOC_THRESH); - - vx = (int)floorf(fx); - vy = (int)floorf(fy); - vz = (int)floorf(fz); - - mesh_octree_add_node(basetable + MOC_INDEX(vx, vy, vz), index); - - if (vx > 0) - if (fx - ((float)vx) - MOC_THRESH < 0.0f) - mesh_octree_add_node(basetable + MOC_INDEX(vx - 1, vy, vz), index); - if (vx < MOC_RES - 2) - if (fx - ((float)vx) + MOC_THRESH > 1.0f) - mesh_octree_add_node(basetable + MOC_INDEX(vx + 1, vy, vz), index); - - if (vy > 0) - if (fy - ((float)vy) - MOC_THRESH < 0.0f) - mesh_octree_add_node(basetable + MOC_INDEX(vx, vy - 1, vz), index); - if (vy < MOC_RES - 2) - if (fy - ((float)vy) + MOC_THRESH > 1.0f) - mesh_octree_add_node(basetable + MOC_INDEX(vx, vy + 1, vz), index); - - if (vz > 0) - if (fz - ((float)vz) - MOC_THRESH < 0.0f) - mesh_octree_add_node(basetable + MOC_INDEX(vx, vy, vz - 1), index); - if (vz < MOC_RES - 2) - if (fz - ((float)vz) + MOC_THRESH > 1.0f) - mesh_octree_add_node(basetable + MOC_INDEX(vx, vy, vz + 1), index); - -} - -static intptr_t mesh_octree_find_index(MocNode **bt, MVert *mvert, const float co[3]) -{ - float *vec; - int a; - - if (*bt == NULL) - return -1; - - for (a = 0; a < MOC_NODE_RES; a++) { - if ((*bt)->index[a]) { - /* does mesh verts and editmode, code looks potential dangerous, octree should really be filled OK! */ - if (mvert) { - vec = (mvert + (*bt)->index[a] - 1)->co; - if (compare_v3v3(vec, co, MOC_THRESH)) - return (*bt)->index[a] - 1; - } - else { - BMVert *eve = (BMVert *)((*bt)->index[a]); - if (compare_v3v3(eve->co, co, MOC_THRESH)) - return (*bt)->index[a]; - } - } - else { - return -1; - } - } - if ( (*bt)->next) - return mesh_octree_find_index(&(*bt)->next, mvert, co); - - return -1; -} - -static struct { - MocNode **table; - float offs[3], div[3]; -} MeshOctree = {NULL, {0, 0, 0}, {0, 0, 0}}; +static struct { void *tree; } MirrKdStore = {NULL}; /* mode is 's' start, or 'e' end, or 'u' use */ /* if end, ob can be NULL */ -intptr_t mesh_octree_table(Object *ob, BMEditMesh *em, const float co[3], char mode) +int mesh_octree_table(Object *ob, BMEditMesh *em, const float co[3], char mode) { - MocNode **bt; - if (mode == 'u') { /* use table */ - if (MeshOctree.table == NULL) + if (MirrKdStore.tree == NULL) mesh_octree_table(ob, em, NULL, 's'); - if (MeshOctree.table) { - Mesh *me = ob->data; - bt = MeshOctree.table + mesh_octree_get_base_offs(co, MeshOctree.offs, MeshOctree.div); - if (em) - return mesh_octree_find_index(bt, NULL, co); - else - return mesh_octree_find_index(bt, me->mvert, co); + if (MirrKdStore.tree) { + KDTreeNearest nearest; + + int i; + + i = BLI_kdtree_find_nearest(MirrKdStore.tree, co, NULL, &nearest); + + if (i != -1) { + if (nearest.dist < KD_THRESH) { + return i; + } + } } return -1; } else if (mode == 's') { /* start table */ Mesh *me = ob->data; - float min[3], max[3]; + int totvert; - /* we compute own bounding box and don't reuse ob->bb because - * we are using the undeformed coordinates*/ - INIT_MINMAX(min, max); - - if (em && me->edit_btmesh == em) { - BMIter iter; - BMVert *eve; - - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - minmax_v3v3_v3(min, max, eve->co); - } - } - else { - MVert *mvert; - int a; - - for (a = 0, mvert = me->mvert; a < me->totvert; a++, mvert++) - minmax_v3v3_v3(min, max, mvert->co); - } - - /* for quick unit coordinate calculus */ - copy_v3_v3(MeshOctree.offs, min); - /* we offset it 1 threshold unit extra */ - add_v3_fl(MeshOctree.offs, -MOC_THRESH); - - sub_v3_v3v3(MeshOctree.div, max, min); - /* and divide with 2 threshold unit more extra (try 8x8 unit grid on paint) */ - add_v3_fl(MeshOctree.div, 2.0f * MOC_THRESH); - - mul_v3_fl(MeshOctree.div, 1.0f / MOC_RES); - if (MeshOctree.div[0] == 0.0f) MeshOctree.div[0] = 1.0f; - if (MeshOctree.div[1] == 0.0f) MeshOctree.div[1] = 1.0f; - if (MeshOctree.div[2] == 0.0f) MeshOctree.div[2] = 1.0f; - - if (MeshOctree.table) /* happens when entering this call without ending it */ + if (MirrKdStore.tree) /* happens when entering this call without ending it */ mesh_octree_table(ob, em, co, 'e'); - - MeshOctree.table = MEM_callocN(MOC_RES * MOC_RES * MOC_RES * sizeof(void *), "sym table"); - + if (em && me->edit_btmesh == em) { + totvert = em->bm->totvert; + } + else { + totvert = me->totvert; + } + + MirrKdStore.tree = BLI_kdtree_new(totvert); + + if (em && me->edit_btmesh == em) { + BMVert *eve; BMIter iter; + int i; - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { - mesh_octree_add_nodes(MeshOctree.table, eve->co, MeshOctree.offs, MeshOctree.div, (intptr_t)(eve)); + /* this needs to be valid for index lookups later (callers need) */ + BM_mesh_elem_table_ensure(em->bm, BM_VERT); + + BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) { + BLI_kdtree_insert(MirrKdStore.tree, i, eve->co, NULL); } } else { MVert *mvert; - int a; + int i; - for (a = 0, mvert = me->mvert; a < me->totvert; a++, mvert++) - mesh_octree_add_nodes(MeshOctree.table, mvert->co, MeshOctree.offs, MeshOctree.div, a + 1); + for (i = 0, mvert = me->mvert; i < me->totvert; i++, mvert++) { + BLI_kdtree_insert(MirrKdStore.tree, i, mvert->co, NULL); + } } + + BLI_kdtree_balance(MirrKdStore.tree); } else if (mode == 'e') { /* end table */ - if (MeshOctree.table) { - int a; - - for (a = 0, bt = MeshOctree.table; a < MOC_RES * MOC_RES * MOC_RES; a++, bt++) { - if (*bt) mesh_octree_free_node(bt); - } - MEM_freeN(MeshOctree.table); - MeshOctree.table = NULL; + if (MirrKdStore.tree) { + BLI_kdtree_free(MirrKdStore.tree); + MirrKdStore.tree = NULL; } } + else { + BLI_assert(0); + } + return 0; } +/** \} */ + + +/* -------------------------------------------------------------------- */ +/* Mesh Mirror (Topology) */ + +/** \name Mesh Topology Mirror API + * \{ */ + static MirrTopoStore_t mesh_topo_store = {NULL, -1. - 1, -1}; /* mode is 's' start, or 'e' end, or 'u' use */ @@ -914,9 +771,16 @@ int mesh_mirrtopo_table(Object *ob, char mode) else if (mode == 'e') { /* end table */ ED_mesh_mirrtopo_free(&mesh_topo_store); } + else { + BLI_assert(0); + } + return 0; } +/** \} */ + + static int mesh_get_x_mirror_vert_spatial(Object *ob, int index) { Mesh *me = ob->data; @@ -952,7 +816,7 @@ int mesh_get_x_mirror_vert(Object *ob, int index, const bool use_topology) static BMVert *editbmesh_get_x_mirror_vert_spatial(Object *ob, BMEditMesh *em, const float co[3]) { float vec[3]; - intptr_t poinval; + int i; /* ignore nan verts */ if ((finite(co[0]) == false) || @@ -966,9 +830,10 @@ static BMVert *editbmesh_get_x_mirror_vert_spatial(Object *ob, BMEditMesh *em, c vec[1] = co[1]; vec[2] = co[2]; - poinval = mesh_octree_table(ob, em, vec, 'u'); - if (poinval != -1) - return (BMVert *)(poinval); + i = mesh_octree_table(ob, em, vec, 'u'); + if (i != -1) { + return BM_vert_at_index(em->bm, i); + } return NULL; } diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index fd768f5a400..901724842f6 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -458,7 +458,7 @@ void ED_vgroup_delete(struct Object *ob, struct bDeformGroup *defgroup) RET_NONE void ED_vgroup_clear(struct Object *ob) RET_NONE bool ED_vgroup_object_is_edit_mode(struct Object *ob) RET_ZERO int mesh_mirrtopo_table(struct Object *ob, char mode) RET_ZERO -intptr_t mesh_octree_table(struct Object *ob, struct BMEditMesh *em, const float co[3], char mode) RET_ZERO +int mesh_octree_table(struct Object *ob, struct BMEditMesh *em, const float co[3], char mode) RET_ZERO float ED_rollBoneToVector(EditBone *bone, const float new_up_axis[3], const short axis_only) RET_ZERO void ED_space_image_get_size(struct SpaceImage *sima, int *width, int *height) RET_NONE