Changeset View
Changeset View
Standalone View
Standalone View
source/blender/bmesh/intern/bmesh_polygon.c
| Show First 20 Lines • Show All 280 Lines • ▼ Show 20 Lines | float BM_face_calc_perimeter(const BMFace *f) | ||||
| l_iter = l_first = BM_FACE_FIRST_LOOP(f); | l_iter = l_first = BM_FACE_FIRST_LOOP(f); | ||||
| do { | do { | ||||
| perimeter += len_v3v3(l_iter->v->co, l_iter->next->v->co); | perimeter += len_v3v3(l_iter->v->co, l_iter->next->v->co); | ||||
| } while ((l_iter = l_iter->next) != l_first); | } while ((l_iter = l_iter->next) != l_first); | ||||
| return perimeter; | return perimeter; | ||||
| } | } | ||||
| void BM_vert_tri_calc_plane(BMVert *verts[3], float r_plane[3]) | /** | ||||
| * Calculate a tangent from any 3 vertices. | |||||
| * | |||||
| * The tangent aligns to the most *unique* edge | |||||
| * (the edge most unlike the other two). | |||||
| * | |||||
| * \param r_tangent: Unit length tangent. | |||||
| */ | |||||
| void BM_vert_tri_calc_tangent_edge(BMVert *verts[3], float r_tangent[3]) | |||||
| { | { | ||||
| float lens[3]; | /* find the most 'unique' loop, (greatest difference to others) */ | ||||
| float difs[3]; | const float lens[3] = { | ||||
| len_v3v3(verts[0]->co, verts[1]->co), | |||||
| len_v3v3(verts[1]->co, verts[2]->co), | |||||
| len_v3v3(verts[2]->co, verts[0]->co), | |||||
| }; | |||||
| const float difs[3] = { | |||||
| fabsf(lens[1] - lens[2]), | |||||
| fabsf(lens[2] - lens[0]), | |||||
| fabsf(lens[0] - lens[1]), | |||||
| }; | |||||
| int order[3] = {0, 1, 2}; | int order[3] = {0, 1, 2}; | ||||
| axis_sort_v3(difs, order); | |||||
| lens[0] = len_v3v3(verts[0]->co, verts[1]->co); | sub_v3_v3v3(r_tangent, verts[order[0]]->co, verts[(order[0] + 1) % 3]->co); | ||||
| lens[1] = len_v3v3(verts[1]->co, verts[2]->co); | |||||
| lens[2] = len_v3v3(verts[2]->co, verts[0]->co); | normalize_v3(r_tangent); | ||||
| } | |||||
| /* find the shortest or the longest loop */ | |||||
| difs[0] = fabsf(lens[1] - lens[2]); | /** | ||||
| difs[1] = fabsf(lens[2] - lens[0]); | * Calculate a tangent from any 3 vertices, | ||||
| difs[2] = fabsf(lens[0] - lens[1]); | * | ||||
| * The tangent follows the center-line formed by the most unique edges center | |||||
| * and the opposite vertex. | |||||
| * | |||||
| * \param r_tangent: Unit length tangent. | |||||
| */ | |||||
| void BM_vert_tri_calc_tangent_edge_pair(BMVert *verts[3], float r_tangent[3]) | |||||
| { | |||||
| /* find the most 'unique' loop, (greatest difference to others) */ | |||||
| const float lens[3] = { | |||||
| len_v3v3(verts[0]->co, verts[1]->co), | |||||
| len_v3v3(verts[1]->co, verts[2]->co), | |||||
| len_v3v3(verts[2]->co, verts[0]->co), | |||||
| }; | |||||
| const float difs[3] = { | |||||
| fabsf(lens[1] - lens[2]), | |||||
| fabsf(lens[2] - lens[0]), | |||||
| fabsf(lens[0] - lens[1]), | |||||
| }; | |||||
| int order[3] = {0, 1, 2}; | |||||
| axis_sort_v3(difs, order); | axis_sort_v3(difs, order); | ||||
| sub_v3_v3v3(r_plane, verts[order[0]]->co, verts[(order[0] + 1) % 3]->co); | |||||
| const float *v_a = verts[order[0]]->co; | |||||
| const float *v_b = verts[(order[0] + 1) % 3]->co; | |||||
| const float *v_other = verts[(order[0] + 2) % 3]->co; | |||||
| float delta[2][3]; | |||||
| sub_v3_v3v3(delta[0], v_a, v_other); | |||||
| sub_v3_v3v3(delta[1], v_other, v_b); | |||||
| add_v3_v3v3(r_tangent, delta[0], delta[1]); | |||||
| normalize_v3(r_tangent); | |||||
| } | } | ||||
| /** | /** | ||||
| * Compute a meaningful direction along the face (use for manipulator axis). | * Compute the tanget of the face, using the longest edge. | ||||
| * \note result isnt normalized. | |||||
| */ | */ | ||||
| void BM_face_calc_plane(const BMFace *f, float r_plane[3]) | void BM_face_calc_tangent_edge(const BMFace *f, float r_tangent[3]) | ||||
| { | |||||
| const BMLoop *l_long = BM_face_find_longest_loop((BMFace *)f); | |||||
| sub_v3_v3v3(r_tangent, l_long->v->co, l_long->next->v->co); | |||||
| normalize_v3(r_tangent); | |||||
| } | |||||
| /** | |||||
| * Compute the tanget of the face, using the two longest disconected edges. | |||||
| * | |||||
| * \note r_tangent: Unit length tangent (or zero length in case of degenerate faces). | |||||
| */ | |||||
| void BM_face_calc_tangent_edge_pair(const BMFace *f, float r_tangent[3]) | |||||
| { | { | ||||
| if (f->len == 3) { | if (f->len == 3) { | ||||
| BMVert *verts[3]; | BMVert *verts[3]; | ||||
| BM_face_as_array_vert_tri((BMFace *)f, verts); | BM_face_as_array_vert_tri((BMFace *)f, verts); | ||||
campbellbarton: This can be done with less checking, looping.
Keep the loop from `BM_face_find_longest_loop`… | |||||
| BM_vert_tri_calc_plane(verts, r_plane); | BM_vert_tri_calc_tangent_edge_pair(verts, r_tangent); | ||||
| } | } | ||||
| else if (f->len == 4) { | else if (f->len == 4) { | ||||
| /* Use longest edge pair */ | |||||
| BMVert *verts[4]; | BMVert *verts[4]; | ||||
| float vec[3], vec_a[3], vec_b[3]; | float vec[3], vec_a[3], vec_b[3]; | ||||
| // BM_iter_as_array(NULL, BM_VERTS_OF_FACE, efa, (void **)verts, 4); | |||||
| BM_face_as_array_vert_quad((BMFace *)f, verts); | BM_face_as_array_vert_quad((BMFace *)f, verts); | ||||
| sub_v3_v3v3(vec_a, verts[3]->co, verts[2]->co); | sub_v3_v3v3(vec_a, verts[3]->co, verts[2]->co); | ||||
| sub_v3_v3v3(vec_b, verts[0]->co, verts[1]->co); | sub_v3_v3v3(vec_b, verts[0]->co, verts[1]->co); | ||||
| add_v3_v3v3(r_plane, vec_a, vec_b); | add_v3_v3v3(r_tangent, vec_a, vec_b); | ||||
| sub_v3_v3v3(vec_a, verts[0]->co, verts[3]->co); | sub_v3_v3v3(vec_a, verts[0]->co, verts[3]->co); | ||||
| sub_v3_v3v3(vec_b, verts[1]->co, verts[2]->co); | sub_v3_v3v3(vec_b, verts[1]->co, verts[2]->co); | ||||
| add_v3_v3v3(vec, vec_a, vec_b); | add_v3_v3v3(vec, vec_a, vec_b); | ||||
| /* use the biggest edge length */ | /* use the longest edge length */ | ||||
| if (len_squared_v3(r_plane) < len_squared_v3(vec)) { | if (len_squared_v3(r_tangent) < len_squared_v3(vec)) { | ||||
| copy_v3_v3(r_plane, vec); | copy_v3_v3(r_tangent, vec); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| const BMLoop *l_long = BM_face_find_longest_loop((BMFace *)f); | /* For ngons use two longest disconnected edges */ | ||||
| BMLoop *l_long = BM_face_find_longest_loop((BMFace *)f); | |||||
| BMLoop *l_long_other = NULL; | |||||
| float len_max_sq = 0.0f; | |||||
| float vec_a[3], vec_b[3]; | |||||
| sub_v3_v3v3(r_plane, l_long->v->co, l_long->next->v->co); | BMLoop *l_iter = l_long->prev->prev; | ||||
| BMLoop *l_last = l_long->next; | |||||
| do { | |||||
| const float len_sq = len_squared_v3v3(l_iter->v->co, l_iter->next->v->co); | |||||
| if (len_sq >= len_max_sq) { | |||||
| l_long_other = l_iter; | |||||
| len_max_sq = len_sq; | |||||
| } | } | ||||
| } while ((l_iter = l_iter->prev) != l_last); | |||||
| sub_v3_v3v3(vec_a, l_long->next->v->co, l_long->v->co); | |||||
| sub_v3_v3v3(vec_b, l_long_other->v->co, l_long_other->next->v->co); | |||||
| add_v3_v3v3(r_tangent, vec_a, vec_b); | |||||
| /* Edges may not be opposite side of the ngon, | |||||
| * this could cause problems for ngons with multiple-aligned edges of the same length. | |||||
| * Fallback to longest edge. */ | |||||
| if (UNLIKELY(normalize_v3(r_tangent) == 0.0f)) { | |||||
| normalize_v3_v3(r_tangent, vec_a); | |||||
| } | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Compute the tanget of the face, using the edge farthest away from any vertex in the face. | |||||
| */ | |||||
| void BM_face_calc_tangent_edge_diagonal(const BMFace *f, float r_tangent[3]) | |||||
| { | |||||
| float cent[3]; | |||||
Not Done Inline ActionsAgain, this could use the current loops next/prev to avoid checking against its self. Also think it might be better to split this into 2 functions (just keep them together and note its nearly the same logic). campbellbarton: Again, this could use the current loops next/prev to avoid checking against its self.
Also… | |||||
| float dist_max_sq = 0.0f; | |||||
| BMLoop *l_iter; | |||||
| BMLoop *l_first; | |||||
| normalize_v3(r_plane); | l_iter = l_first = BM_FACE_FIRST_LOOP(f); | ||||
| do { | |||||
| BMLoop *l_iter2 = l_iter->next; | |||||
| add_v3_v3v3(cent, l_iter->v->co, l_iter->next->v->co); | |||||
| mul_v3_fl(cent, 0.5f); | |||||
| do { | |||||
| float dist_sq; | |||||
| dist_sq = len_squared_v3v3(cent, l_iter2->v->co); | |||||
| if (dist_sq >= dist_max_sq) { | |||||
| dist_max_sq = dist_sq; | |||||
| sub_v3_v3v3(r_tangent, l_iter->v->co, l_iter->next->v->co); | |||||
| } | |||||
| } while ((l_iter2 = l_iter2->next) != l_iter); | |||||
| } while ((l_iter = l_iter->next) != l_first); | |||||
| normalize_v3(r_tangent); | |||||
| } | |||||
| /** | |||||
| * Compute the tanget of the face, using longest distance between vertices on the face. | |||||
| * \note The logic is almost identical to BM_face_calc_tangent_edge_diagonal | |||||
| */ | |||||
| void BM_face_calc_tangent_vert_diagonal(const BMFace *f, float r_tangent[3]) | |||||
| { | |||||
| float vec[3]; | |||||
| float dist_max_sq = 0.0f; | |||||
| BMLoop *l_iter; | |||||
| BMLoop *l_first; | |||||
| l_iter = l_first = BM_FACE_FIRST_LOOP(f); | |||||
| do { | |||||
| BMLoop *l_iter2 = l_iter->next; | |||||
| do { | |||||
| float dist_sq; | |||||
| sub_v3_v3v3(vec, l_iter->v->co, l_iter2->v->co); | |||||
| dist_sq = len_squared_v3(vec); | |||||
| if (dist_sq >= dist_max_sq) { | |||||
| dist_max_sq = dist_sq; | |||||
| copy_v3_v3(r_tangent, vec); | |||||
| } | |||||
| } while ((l_iter2 = l_iter2->next) != l_iter); | |||||
| } while ((l_iter = l_iter->next) != l_first); | |||||
| normalize_v3(r_tangent); | |||||
| } | |||||
| /** | |||||
| * Compute a meaningful direction along the face (use for manipulator axis). | |||||
| * | |||||
| * \note Callers shouldn't depend on the *exact* method used here. | |||||
| */ | |||||
| void BM_face_calc_tangent_auto(const BMFace *f, float r_tangent[3]) | |||||
| { | |||||
| if (f->len == 3) { | |||||
| /* most 'unique' edge of a triangle */ | |||||
| BMVert *verts[3]; | |||||
| BM_face_as_array_vert_tri((BMFace *)f, verts); | |||||
| BM_vert_tri_calc_tangent_edge(verts, r_tangent); | |||||
| } | |||||
| else if (f->len == 4) { | |||||
| /* longest edge pair of a quad */ | |||||
| BM_face_calc_tangent_edge_pair((BMFace *)f, r_tangent); | |||||
| } | |||||
| else { | |||||
| /* longest edge of an ngon */ | |||||
| BM_face_calc_tangent_edge((BMFace *)f, r_tangent); | |||||
| } | |||||
| } | } | ||||
| /** | /** | ||||
| * computes center of face in 3d. uses center of bounding box. | * computes center of face in 3d. uses center of bounding box. | ||||
| */ | */ | ||||
| void BM_face_calc_center_bounds(const BMFace *f, float r_cent[3]) | void BM_face_calc_center_bounds(const BMFace *f, float r_cent[3]) | ||||
| { | { | ||||
| const BMLoop *l_iter, *l_first; | const BMLoop *l_iter, *l_first; | ||||
| ▲ Show 20 Lines • Show All 1,062 Lines • Show Last 20 Lines | |||||
This can be done with less checking, looping.
Keep the loop from BM_face_find_longest_loop, then walk over the adjacent loops starting at longest_loop->prev->prev, finishing when you hit longest_loop->next.
This way theres no need to check if the edges are adjacent.