Changeset View
Standalone View
source/blender/editors/mesh/editmesh_select.c
| Show First 20 Lines • Show All 187 Lines • ▼ Show 20 Lines | ok = BMO_op_callf(em->bm, | ||||
| hflag, | hflag, | ||||
| scene->toolsettings->doublimit); | scene->toolsettings->doublimit); | ||||
| if (LIKELY(ok) && update) { | if (LIKELY(ok) && update) { | ||||
| EDBM_update_generic(em, true, true); | EDBM_update_generic(em, true, true); | ||||
| } | } | ||||
| } | } | ||||
| static void min_max_from_seg( | |||||
| float v1[3], float v2[3], float epsilon, float r_min[3], float r_max[3]) | |||||
| { | |||||
| copy_v3_v3(r_min, v1); | |||||
| copy_v3_v3(r_max, v2); | |||||
| if (r_min[0] > r_max[0]) { | |||||
| SWAP(float, r_min[0], r_max[0]); | |||||
| } | |||||
campbellbarton: Could use `BM_vert_pair_share_face_check_cb`. | |||||
| if (r_min[1] > r_max[1]) { | |||||
| SWAP(float, r_min[1], r_max[1]); | |||||
| } | |||||
| if (r_min[2] > r_max[2]) { | |||||
Done Inline ActionsThis isn't checking if the face is hidden. campbellbarton: This isn't checking if the face is hidden. | |||||
| SWAP(float, r_min[2], r_max[2]); | |||||
Done Inline Actionsthis can be made into a utility function similar to BM_vert_pair_share_face_check_cb Would also pick the *best* face since this will cause an error with edges between concave faces, which may also be joined by an adjacent face which the edge crosses. There are a few ways this could be tested, one would be to calculate two normals on either side of the vertices with BM_face_calc_normal_subset, if they're flipped - the edge runs between concave part of a face and can be skipped, we could also check that this edge doesn't cross any edges of the face - although not sure that's needed. campbellbarton: this can be made into a utility function similar to `BM_vert_pair_share_face_check_cb`
Would… | |||||
Done Inline ActionsThis is no longer used. campbellbarton: This is no longer used. | |||||
| } | |||||
| add_v3_fl(r_min, -epsilon); | |||||
| add_v3_fl(r_max, epsilon); | |||||
| } | |||||
| static bool embm_face_split_vert_pair(BMesh *bm, BMVert *v_a, BMVert *v_b) | |||||
| { | |||||
| if (v_a->e && v_b->e) { | |||||
| BMIter iter; | |||||
| BMLoop *l1, *l2; | |||||
| BM_ITER_ELEM (l1, &iter, v_a, BM_LOOPS_OF_VERT) { | |||||
| BMIter iter2; | |||||
| BM_ITER_ELEM (l2, &iter2, v_b, BM_LOOPS_OF_VERT) { | |||||
| if (l1->f == l2->f) { | |||||
| BM_face_split(bm, l1->f, l1, l2, NULL, NULL, true); | |||||
| return true; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
Done Inline Actionsshould be static. campbellbarton: should be static. | |||||
Done Inline Actionsf isn't used,. use UNUSED(f) campbellbarton: f isn't used,. use `UNUSED(f)` | |||||
| return false; | |||||
| } | |||||
| static bool edbm_automerge_check_and_split_faces(BMesh *bm, BMVert *v_src, BMVert *v_dst) | |||||
| { | |||||
| BMIter iter; | |||||
| BMEdge *e_iter; | |||||
| BM_ITER_ELEM (e_iter, &iter, v_src, BM_EDGES_OF_VERT) { | |||||
| BMVert *vert_other = BM_edge_other_vert(e_iter, v_src); | |||||
| if (!BM_edge_exists(vert_other, v_dst) && embm_face_split_vert_pair(bm, vert_other, v_dst)) { | |||||
| return true; | |||||
| } | |||||
| } | |||||
| return false; | |||||
| } | |||||
| void EDBM_automerge_and_split_edges( | |||||
| Scene *scene, Object *obedit, bool split_edges, bool update, const char hflag) | |||||
| { | |||||
| //#define COMPARE_TIME | |||||
| #ifdef COMPARE_TIME | |||||
| # include "PIL_time.h" | |||||
| BMesh *bm_copy = BM_mesh_copy(em->bm); | |||||
| double t1 = PIL_check_seconds_timer(); | |||||
| BMO_op_callf(bm_copy, | |||||
| BMO_FLAG_DEFAULTS, | |||||
| "automerge verts=%hv dist=%f", | |||||
| hflag, | |||||
| scene->toolsettings->doublimit); | |||||
| t1 = PIL_check_seconds_timer() - t1; | |||||
| BM_mesh_free(bm_copy); | |||||
| double t2 = PIL_check_seconds_timer(); | |||||
| #endif | |||||
| bool ok = false; | |||||
| BMOperator findop, weldop; | |||||
| BMOpSlot *slot_targetmap; | |||||
| BMEditMesh *em = BKE_editmesh_from_object(obedit); | |||||
| BMesh *bm = em->bm; | |||||
| float dist = scene->toolsettings->doublimit; | |||||
| BMIter iter; | |||||
| BMVert *v; | |||||
| /* tag and count the verts to be tested. */ | |||||
| int verts_len = 0; | |||||
| BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { | |||||
| if (BM_elem_flag_test(v, hflag)) { | |||||
| BM_elem_flag_enable(v, BM_ELEM_TAG); | |||||
| BMO_vert_flag_enable(bm, v, BMO_ELE_TAG); | |||||
| verts_len++; | |||||
| } | |||||
| else { | |||||
| BM_elem_flag_disable(v, BM_ELEM_TAG); | |||||
| } | |||||
| } | |||||
Done Inline ActionsWould call this DEBUG_TIME (typically used elsewhere). campbellbarton: Would call this `DEBUG_TIME` (typically used elsewhere). | |||||
| /* Search for doubles among all vertices, but only merge non-BMO_ELE_TAG | |||||
Done Inline ActionsEven with ifdef's like this, they should be outside the function otherwise adding inline function could cause an error - for eg. campbellbarton: Even with ifdef's like this, they should be outside the function otherwise adding inline… | |||||
| * vertices into BMO_ELE_TAG vertices. */ | |||||
| BMO_op_initf(bm, &findop, 0, "find_doubles verts=%av keep_verts=%Fv dist=%f", BMO_ELE_TAG, dist); | |||||
| BMO_op_exec(bm, &findop); | |||||
| /* Init weld_verts operator to later fill the targetmap. */ | |||||
| BMO_op_init(bm, &weldop, 0, "weld_verts"); | |||||
| BMO_slot_copy(&findop, slots_out, "targetmap.out", &weldop, slots_in, "targetmap"); | |||||
| slot_targetmap = BMO_slot_get(weldop.slots_in, "targetmap"); | |||||
| GHash *ghash_targetmap = BMO_SLOT_AS_GHASH(slot_targetmap); | |||||
| GHashIterator gh_iter; | |||||
| GHASH_ITER (gh_iter, ghash_targetmap) { | |||||
| v = BLI_ghashIterator_getKey(&gh_iter); | |||||
| BMVert *v_dst = BLI_ghashIterator_getValue(&gh_iter); | |||||
| if (!BM_elem_flag_test(v, BM_ELEM_TAG)) { | |||||
| /* Should this happen? */ | |||||
| SWAP(BMVert *, v, v_dst); | |||||
| } | |||||
| BLI_assert(BM_elem_flag_test(v, BM_ELEM_TAG)); | |||||
| BM_elem_flag_disable(v, BM_ELEM_TAG); | |||||
| edbm_automerge_check_and_split_faces(bm, v, v_dst); | |||||
| ok = true; | |||||
| verts_len--; | |||||
| } | |||||
| int totedge = bm->totedge; | |||||
| if (totedge == 0 || verts_len == 0) { | |||||
| split_edges = false; | |||||
| } | |||||
| if (split_edges) { | |||||
| BMEdge *e; | |||||
| float dist_sq = SQUARE(dist); | |||||
| struct { | |||||
| float min[3]; | |||||
| float max[3]; | |||||
| BMEdge *e; | |||||
| } * bv_iter, *bv; | |||||
| /* Create a bound volume for each edge. | |||||
| * Add a margin for new edges. | |||||
| * TODO: Optimize using a cached BVHTree of edges. */ | |||||
| bv = MEM_mallocN((totedge + verts_len) * sizeof(*bv), __func__); | |||||
| bv_iter = &bv[0]; | |||||
| int bv_count = 0; | |||||
| BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { | |||||
| if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN) && !BM_elem_flag_test(e->v1, BM_ELEM_TAG) && | |||||
| !BM_elem_flag_test(e->v2, BM_ELEM_TAG)) { | |||||
| min_max_from_seg(e->v1->co, e->v2->co, dist, bv_iter->min, bv_iter->max); | |||||
| bv_iter->e = e; | |||||
| bv_iter++; | |||||
| bv_count++; | |||||
| } | |||||
| } | |||||
| /* Search for intersections and fill in new pairs for the targetmaps. */ | |||||
| BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { | |||||
| if (BM_elem_flag_test(v, BM_ELEM_TAG)) { | |||||
| float co[3]; | |||||
| copy_v3_v3(co, v->co); | |||||
| bv_iter = &bv[0]; | |||||
| for (int i = bv_count; i--; bv_iter++) { | |||||
| if (co[0] > bv_iter->min[0] && co[1] > bv_iter->min[1] && co[2] > bv_iter->min[2] && | |||||
| co[0] < bv_iter->max[0] && co[1] < bv_iter->max[1] && co[2] < bv_iter->max[2]) { | |||||
| e = bv_iter->e; | |||||
| BLI_assert(!ELEM(v, e->v1, e->v2)); | |||||
| float lambda = line_point_factor_v3_ex(co, e->v2->co, e->v1->co, 0.0f, -1.0f); | |||||
| BLI_assert(IN_RANGE(lambda, 0.0f, 1.0f)); | |||||
| float near_co[3]; | |||||
| interp_v3_v3v3(near_co, e->v2->co, e->v1->co, lambda); | |||||
| if (len_squared_v3v3(near_co, co) < dist_sq) { | |||||
| BMEdge *e_new; | |||||
| BMVert *v_new = BM_edge_split(bm, e, e->v2, &e_new, lambda); | |||||
| /* Add and update edges bound volume. */ | |||||
| min_max_from_seg(e->v1->co, e->v2->co, dist, bv_iter->min, bv_iter->max); | |||||
| min_max_from_seg( | |||||
Done Inline ActionsPrefer to avoid adding numbers onto variable names and instead name them in a way that tells us how it's different. eg: cuts_iter_other or cuts_iter_adjacent. campbellbarton: Prefer to avoid adding numbers onto variable names and instead name them in a way that tells us… | |||||
| e_new->v1->co, e_new->v2->co, dist, bv[bv_count].min, bv[bv_count].max); | |||||
| bv[bv_count].e = e_new; | |||||
| bv_count++; | |||||
| edbm_automerge_check_and_split_faces(bm, v, v_new); | |||||
| BMO_slot_map_elem_insert(&weldop, slot_targetmap, v_new, v); | |||||
| ok = true; | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| MEM_freeN(bv); | |||||
| } | |||||
| BMO_op_exec(bm, &weldop); | |||||
| BMO_op_finish(bm, &findop); | |||||
| BMO_op_finish(bm, &weldop); | |||||
| #ifdef COMPARE_TIME | |||||
| t2 = PIL_check_seconds_timer() - t2; | |||||
| printf("t1: %lf; t2: %lf; fac: %lf\n", t1, t2, t1 / t2); | |||||
| #endif | |||||
| if (LIKELY(ok) && update) { | |||||
| EDBM_update_generic(em, true, true); | |||||
| } | |||||
| } | |||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Back-Buffer OpenGL Selection | /** \name Back-Buffer OpenGL Selection | ||||
| * \{ */ | * \{ */ | ||||
| static BMElem *edbm_select_id_bm_elem_get(Base **bases, const uint sel_id, uint *r_base_index) | static BMElem *edbm_select_id_bm_elem_get(Base **bases, const uint sel_id, uint *r_base_index) | ||||
| { | { | ||||
| Show All 22 Lines | |||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Find Nearest Vert/Edge/Face | /** \name Find Nearest Vert/Edge/Face | ||||
| * | * | ||||
| * \note Screen-space manhatten distances are used here, | * \note Screen-space manhatten distances are used here, | ||||
| * since its faster and good enough for the purpose of selection. | * since its faster and good enough for the purpose of selection. | ||||
Done Inline ActionsSingle . campbellbarton: Single `.` | |||||
| * | * | ||||
| * \note \a dist_bias is used so we can bias against selected items. | * \note \a dist_bias is used so we can bias against selected items. | ||||
| * when choosing between elements of a single type, but return the real distance | * when choosing between elements of a single type, but return the real distance | ||||
| * to avoid the bias interfering with distance comparisons when mixing types. | * to avoid the bias interfering with distance comparisons when mixing types. | ||||
| * \{ */ | * \{ */ | ||||
| #define FIND_NEAR_SELECT_BIAS 5 | #define FIND_NEAR_SELECT_BIAS 5 | ||||
Done Inline ActionsThis gives me: /src/blender/source/blender/editors/mesh/editmesh_select.c: In function ‘EDBM_automerge_and_split’: /src/blender/source/blender/editors/mesh/editmesh_select.c:456:15: error: flexible array member in union 456 | int as_int[]; use int as_int[0]; campbellbarton: This gives me:
```
/src/blender/source/blender/editors/mesh/editmesh_select.c: In function… | |||||
| #define FIND_NEAR_CYCLE_THRESHOLD_MIN 3 | #define FIND_NEAR_CYCLE_THRESHOLD_MIN 3 | ||||
| struct NearestVertUserData_Hit { | struct NearestVertUserData_Hit { | ||||
| float dist; | float dist; | ||||
| float dist_bias; | float dist_bias; | ||||
| int index; | int index; | ||||
| BMVert *vert; | BMVert *vert; | ||||
| }; | }; | ||||
| struct NearestVertUserData { | struct NearestVertUserData { | ||||
| float mval_fl[2]; | float mval_fl[2]; | ||||
| bool use_select_bias; | bool use_select_bias; | ||||
| bool use_cycle; | bool use_cycle; | ||||
Done Inline ActionsShadows previous value, needs to be named differently. campbellbarton: Shadows previous value, needs to be named differently. | |||||
| int cycle_index_prev; | int cycle_index_prev; | ||||
| struct NearestVertUserData_Hit hit; | struct NearestVertUserData_Hit hit; | ||||
| struct NearestVertUserData_Hit hit_cycle; | struct NearestVertUserData_Hit hit_cycle; | ||||
| }; | }; | ||||
| static void findnearestvert__doClosest(void *userData, | static void findnearestvert__doClosest(void *userData, | ||||
| BMVert *eve, | BMVert *eve, | ||||
| ▲ Show 20 Lines • Show All 4,548 Lines • Show Last 20 Lines | |||||
Could use BM_vert_pair_share_face_check_cb.