27#define KD_THRESH 0.00002f
36 const bool use_em = (!mesh_eval && em && mesh->
runtime->edit_mesh.get() == em);
37 const int totvert = use_em ? em->
bm->
totvert :
61 mesh->vert_positions();
62 for (
int i = 0;
i < totvert;
i++) {
80 KDTreeNearest_3d nearest;
81 const int i = BLI_kdtree_3d_find_nearest(
MirrKdStore.tree, co, &nearest);
138 const bool is_editmode = em !=
nullptr;
163 const bool skip_em_vert_array_init)
168 const bool is_editmode = (em !=
nullptr);
175 int totvert, totedge;
176 int tot_unique = -1, tot_unique_prev = -1;
177 int tot_unique_edges = 0, tot_unique_edges_prev;
210 topo_hash[edge[0]]++;
211 topo_hash[edge[1]]++;
217 tot_unique_prev = -1;
218 tot_unique_edges_prev = -1;
222 tot_unique_edges = 0;
228 topo_hash[i1] += topo_hash_prev[i2] * topo_pass;
229 topo_hash[i2] += topo_hash_prev[i1] * topo_pass;
230 tot_unique_edges += (topo_hash[i1] != topo_hash[i2]);
235 const int i1 = edge[0], i2 = edge[1];
236 topo_hash[i1] += topo_hash_prev[i2] * topo_pass;
237 topo_hash[i2] += topo_hash_prev[i1] * topo_pass;
238 tot_unique_edges += (topo_hash[i1] != topo_hash[i2]);
241 memcpy(topo_hash_prev, topo_hash,
sizeof(
MirrTopoHash_t) * totvert);
247 for (a = 1; a < totvert; a++) {
248 if (topo_hash_prev[a - 1] != topo_hash_prev[a]) {
253 if ((tot_unique <= tot_unique_prev) && (tot_unique_edges <= tot_unique_edges_prev)) {
258 tot_unique_prev = tot_unique;
259 tot_unique_edges_prev = tot_unique_edges;
261 memcpy(topo_hash_prev, topo_hash,
sizeof(
MirrTopoHash_t) * totvert);
270 intptr_t *index_lookup =
static_cast<intptr_t *
>(
271 MEM_mallocN(totvert *
sizeof(*index_lookup),
"mesh_topo_lookup"));
274 if (skip_em_vert_array_init ==
false) {
279 for (a = 0; a < totvert; a++) {
280 topo_pairs[a].
hash = topo_hash[a];
284 index_lookup[a] = -1;
296 for (a = 1; a <= totvert; a++) {
299 if ((a == totvert) || (topo_pairs[a - 1].
hash != topo_pairs[a].
hash)) {
300 const int match_count = a - last;
301 if (match_count == 2) {
302 const int j = topo_pairs[a - 1].
v_index, k = topo_pairs[a - 2].
v_index;
303 index_lookup[j] = intptr_t(vtable[k]);
304 index_lookup[k] = intptr_t(vtable[j]);
306 else if (match_count == 1) {
308 const int j = topo_pairs[a - 1].
v_index;
309 index_lookup[j] = intptr_t(vtable[j]);
317 for (a = 1; a <= totvert; a++) {
318 if ((a == totvert) || (topo_pairs[a - 1].
hash != topo_pairs[a].
hash)) {
319 const int match_count = a - last;
320 if (match_count == 2) {
321 const int j = topo_pairs[a - 1].
v_index, k = topo_pairs[a - 2].
v_index;
325 else if (match_count == 1) {
327 const int j = topo_pairs[a - 1].
v_index;
336 topo_pairs =
nullptr;
365 if (!ob || !ob->
data) {
374 return EditMeshSymmetryHelper(ob, htype);
377EditMeshSymmetryHelper::EditMeshSymmetryHelper(
Object *ob,
uchar htype)
389 for (
int axis = 0; axis < 3; axis++) {
396 use_topology_mirror_);
401 if (processed_verts.
contains(v_curr)) {
405 if (v_mirr && v_mirr != v_curr) {
407 if (v_mirr_check == v_curr) {
408 vert_to_mirror_map_.lookup_or_add(v_curr, {}).append(v_mirr);
409 vert_to_mirror_map_.lookup_or_add(v_mirr, {}).append(v_curr);
410 processed_verts.
add(v_curr);
411 processed_verts.
add(v_mirr);
420 if (processed_edges.
contains(e_curr)) {
424 if (e_mirr && e_mirr != e_curr) {
426 if (e_mirr_check == e_curr) {
427 edge_to_mirror_map_.lookup_or_add(e_curr, {}).append(e_mirr);
428 edge_to_mirror_map_.lookup_or_add(e_mirr, {}).append(e_curr);
429 processed_edges.
add(e_curr);
430 processed_edges.
add(e_mirr);
439 if (processed_faces.
contains(f_curr)) {
443 if (f_mirr && f_mirr != f_curr) {
445 if (f_mirr_check == f_curr) {
446 face_to_mirror_map_.lookup_or_add(f_curr, {}).append(f_mirr);
447 face_to_mirror_map_.lookup_or_add(f_mirr, {}).append(f_curr);
448 processed_faces.
add(f_curr);
449 processed_faces.
add(f_mirr);
465 for (
BMVert *v_mirr : *mirrors) {
477 for (
BMEdge *e_mirr : *mirrors) {
489 for (
BMFace *f_mirr : *mirrors) {
500 for (
BMVert *v_mirr : *mirrors) {
514 for (
BMEdge *e_mirr : *mirrors) {
528 for (
BMFace *f_mirr : *mirrors) {
539 const bool value)
const
554 const bool value)
const
569 const bool value)
const
BMEditMesh * BKE_editmesh_from_object(Object *ob)
Return the BMEditMesh for a given object.
A KD-tree for nearest neighbor search.
Object is a sort of wrapper for general info.
BMVert * EDBM_verts_mirror_get(BMEditMesh *em, BMVert *v)
void EDBM_verts_mirror_cache_begin(BMEditMesh *em, int axis, bool use_self, bool use_select, bool respecthide, bool use_topology)
void EDBM_verts_mirror_cache_end(BMEditMesh *em)
BMEdge * EDBM_verts_mirror_get_edge(BMEditMesh *em, BMEdge *e)
BMFace * EDBM_verts_mirror_get_face(BMEditMesh *em, BMFace *f)
Read Guarded memory(de)allocation.
#define BM_elem_index_get(ele)
#define BM_elem_flag_set(ele, hflag, val)
#define BM_elem_flag_test(ele, hflag)
#define BM_ITER_MESH(ele, iter, bm, itype)
#define BM_ITER_MESH_INDEX(ele, iter, bm, itype, indexvar)
BMesh const char void * data
void BM_face_select_set(BMesh *bm, BMFace *f, const bool select)
Select Face.
void BM_vert_select_set(BMesh *bm, BMVert *v, const bool select)
Select Vert.
void BM_edge_select_set(BMesh *bm, BMEdge *e, const bool select)
Select Edge.
void BM_mesh_elem_table_ensure(BMesh *bm, const char htype)
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
static std::optional< EditMeshSymmetryHelper > create_if_needed(Object *ob, uchar htype)
void set_hflag_on_mirror_edges(BMEdge *e, char hflag, bool value) const
void set_hflag_on_mirror_verts(BMVert *v, char hflag, bool value) const
void set_hflag_on_mirror_faces(BMFace *f, char hflag, bool value) const
bool any_mirror_edge_selected(BMEdge *e, char hflag) const
bool any_mirror_face_selected(BMFace *f, char hflag) const
void apply_on_mirror_faces(BMFace *f, blender::FunctionRef< void(BMFace *)> op) const
bool any_mirror_vert_selected(BMVert *v, char hflag) const
void apply_on_mirror_verts(BMVert *v, blender::FunctionRef< void(BMVert *)> op) const
void apply_on_mirror_edges(BMEdge *e, blender::FunctionRef< void(BMEdge *)> op) const
bool contains(const Key &key) const
void ED_mesh_mirror_spatial_table_end(Object *)
int ED_mesh_mirror_spatial_table_lookup(Object *ob, BMEditMesh *em, Mesh *mesh_eval, const float co[3])
static int mirrtopo_vert_sort(const void *v1, const void *v2)
static int mirrtopo_hash_sort(const void *l1, const void *l2)
void ED_mesh_mirror_spatial_table_begin(Object *ob, BMEditMesh *em, Mesh *mesh_eval)
void ED_mesh_mirrtopo_init(BMEditMesh *em, Mesh *mesh, MirrTopoStore_t *mesh_topo_store, const bool skip_em_vert_array_init)
void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store)
static struct @373065230156164077010030262226042245223102312262 MirrKdStore
bool ED_mesh_mirrtopo_recalc_check(BMEditMesh *em, Mesh *mesh, MirrTopoStore_t *mesh_topo_store)
void * MEM_mallocN(size_t len, const char *str)
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
void * MEM_dupallocN(const void *vmemh)
void MEM_freeN(void *vmemh)
VecBase< int32_t, 2 > int2
MeshRuntimeHandle * runtime