diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c index 8c96c938cef..8374fd8f51f 100644 --- a/source/blender/bmesh/intern/bmesh_polygon.c +++ b/source/blender/bmesh/intern/bmesh_polygon.c @@ -30,6 +30,7 @@ #include "DNA_listBase.h" #include "DNA_modifier_types.h" +#include "DNA_object_types.h" #include "MEM_guardedalloc.h" @@ -239,6 +240,30 @@ float BM_face_calc_area(const BMFace *f) return len_v3(n) * 0.5f; } +/** + * Get the area of the face in world space. + */ +float BM_face_calc_area_worldspace(Object *ob, const BMFace *f) +{ + /* inline 'area_poly_v3' logic, avoid creating a temp array */ + const BMLoop *l_iter, *l_first; + float n[3]; + + zero_v3(n); + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + float rsmat[3][3]; + copy_m3_m4(rsmat, ob->obmat); + do { + float co[3], co_next[3]; + copy_v3_v3(co, l_iter->v->co); + copy_v3_v3(co_next, l_iter->next->v->co); + mul_m3_v3(rsmat, co); + mul_m3_v3(rsmat, co_next); + add_newell_cross_v3_v3v3(n, co, co_next); + } while ((l_iter = l_iter->next) != l_first); + return len_v3(n) * 0.5f; +} + /** * compute the perimeter of an ngon */ @@ -255,6 +280,29 @@ float BM_face_calc_perimeter(const BMFace *f) return perimeter; } +/** + * Calculate the perimeter of a ngon in world space. + */ +float BM_face_calc_perimeter_worldspace(Object *ob, const BMFace *f) +{ + const BMLoop *l_iter, *l_first; + float perimeter = 0.0f; + + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + float rsmat[3][3]; + copy_m3_m4(rsmat, ob->obmat); + do { + float co[3], co_next[3]; + copy_v3_v3(co, l_iter->v->co); + copy_v3_v3(co_next, l_iter->next->v->co); + mul_m3_v3(rsmat, co); + mul_m3_v3(rsmat, co_next); + perimeter += len_v3v3(co, co_next); + } while ((l_iter = l_iter->next) != l_first); + + return perimeter; +} + /** * Utility function to calculate the edge which is most different from the other two. * diff --git a/source/blender/bmesh/intern/bmesh_polygon.h b/source/blender/bmesh/intern/bmesh_polygon.h index a40da2bfbfa..29bb49a8e40 100644 --- a/source/blender/bmesh/intern/bmesh_polygon.h +++ b/source/blender/bmesh/intern/bmesh_polygon.h @@ -28,6 +28,7 @@ */ struct Heap; +struct Object; #include "BLI_compiler_attrs.h" @@ -44,7 +45,9 @@ float BM_face_calc_normal_vcos( float const (*vertexCos)[3]) ATTR_NONNULL(); float BM_face_calc_normal_subset(const BMLoop *l_first, const BMLoop *l_last, float r_no[3]) ATTR_NONNULL(); float BM_face_calc_area(const BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +float BM_face_calc_area_worldspace(struct Object *ob, const BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); float BM_face_calc_perimeter(const BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +float BM_face_calc_perimeter_worldspace(struct Object *ob, const BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); void BM_face_calc_tangent_edge(const BMFace *f, float r_plane[3]) ATTR_NONNULL(); void BM_face_calc_tangent_edge_pair(const BMFace *f, float r_plane[3]) ATTR_NONNULL(); void BM_face_calc_tangent_edge_diagonal(const BMFace *f, float r_plane[3]) ATTR_NONNULL(); diff --git a/source/blender/bmesh/intern/bmesh_query.c b/source/blender/bmesh/intern/bmesh_query.c index 540888ac0b9..c51c6322136 100644 --- a/source/blender/bmesh/intern/bmesh_query.c +++ b/source/blender/bmesh/intern/bmesh_query.c @@ -31,6 +31,8 @@ * of inspecting the mesh structure directly. */ +#include "DNA_object_types.h" + #include "MEM_guardedalloc.h" #include "BLI_math.h" @@ -39,6 +41,7 @@ #include "BLI_utildefines_stack.h" #include "BKE_customdata.h" +#include "BKE_object.h" #include "bmesh.h" #include "intern/bmesh_private.h" @@ -1677,6 +1680,43 @@ float BM_edge_calc_face_angle(const BMEdge *e) return BM_edge_calc_face_angle_ex(e, DEG2RADF(90.0f)); } +/** +* \brief BMESH EDGE/FACE ANGLE +* +* Calculates the angle between two faces in world space. +* Assumes the face normals are correct. +* +* \return angle in radians +*/ +float BM_edge_calc_face_angle_worldspace_ex(Object *ob, const BMEdge *e, const float fallback) +{ + if (BM_edge_is_manifold(e)) { + const BMLoop *l1 = e->l; + const BMLoop *l2 = e->l->radial_next; + float no1[3], no2[3]; + copy_v3_v3(no1, l1->f->no); + copy_v3_v3(no2, l2->f->no); + + float smat[3][3]; + BKE_object_scale_to_mat3(ob, smat); + invert_m3(smat); + + mul_m3_v3(smat, no1); + mul_m3_v3(smat, no2); + normalize_v3(no1); + normalize_v3(no2); + + return angle_normalized_v3v3(no1, no2); + } + else { + return fallback; + } +} +float BM_edge_calc_face_angle_worldspace(Object *ob, const BMEdge *e) +{ + return BM_edge_calc_face_angle_worldspace_ex(ob, e, DEG2RADF(90.0f)); +} + /** * \brief BMESH EDGE/FACE ANGLE * diff --git a/source/blender/bmesh/intern/bmesh_query.h b/source/blender/bmesh/intern/bmesh_query.h index 51956761d8f..1cfd6cc07a3 100644 --- a/source/blender/bmesh/intern/bmesh_query.h +++ b/source/blender/bmesh/intern/bmesh_query.h @@ -27,6 +27,8 @@ * \ingroup bmesh */ +struct Object; + bool BM_vert_in_face(BMVert *v, BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); int BM_verts_in_face_count(BMVert **varr, int len, BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); bool BM_verts_in_face(BMVert **varr, int len, BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); @@ -123,6 +125,8 @@ void BM_loop_calc_face_tangent(const BMLoop *l, float r_tangent[3]); float BM_edge_calc_face_angle_ex(const BMEdge *e, const float fallback) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); float BM_edge_calc_face_angle(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); float BM_edge_calc_face_angle_signed_ex(const BMEdge *e, const float fallback) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +float BM_edge_calc_face_angle_worldspace_ex(struct Object *ob, const BMEdge *e, const float fallback) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +float BM_edge_calc_face_angle_worldspace(struct Object *ob, const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); float BM_edge_calc_face_angle_signed(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); void BM_edge_calc_face_tangent(const BMEdge *e, const BMLoop *e_loop, float r_tangent[3]) ATTR_NONNULL(); diff --git a/source/blender/editors/mesh/editmesh_select_similar.c b/source/blender/editors/mesh/editmesh_select_similar.c index d33802dca05..85b59cb78c3 100644 --- a/source/blender/editors/mesh/editmesh_select_similar.c +++ b/source/blender/editors/mesh/editmesh_select_similar.c @@ -293,14 +293,14 @@ static int similar_face_select_exec(bContext *C, wmOperator *op) } case SIMFACE_AREA: { - float area = BM_face_calc_area(face); + float area = BM_face_calc_area_worldspace(ob, face); float dummy[3] = {area, 0.0f, 0.0f}; BLI_kdtree_insert(tree, tree_index++, dummy); break; } case SIMFACE_PERIMETER: { - float perimeter = BM_face_calc_perimeter(face); + float perimeter = BM_face_calc_perimeter_worldspace(ob, face); float dummy[3] = {perimeter, 0.0f, 0.0f}; BLI_kdtree_insert(tree, tree_index++, dummy); break; @@ -440,7 +440,7 @@ static int similar_face_select_exec(bContext *C, wmOperator *op) } case SIMFACE_AREA: { - float area = BM_face_calc_area(face); + float area = BM_face_calc_area_worldspace(ob, face); if (ED_select_similar_compare_float_tree(tree, area, thresh, compare)) { select = true; } @@ -448,7 +448,7 @@ static int similar_face_select_exec(bContext *C, wmOperator *op) } case SIMFACE_PERIMETER: { - float perimeter = BM_face_calc_perimeter(face); + float perimeter = BM_face_calc_perimeter_worldspace(ob, face); if (ED_select_similar_compare_float_tree(tree, perimeter, thresh, compare)) { select = true; } @@ -774,7 +774,7 @@ static int similar_edge_select_exec(bContext *C, wmOperator *op) case SIMEDGE_FACE_ANGLE: { if (BM_edge_face_count_at_most(edge, 2) == 2) { - float angle = BM_edge_calc_face_angle(edge); + float angle = BM_edge_calc_face_angle_worldspace(ob, edge); float dummy[3] = {angle, 0.0f, 0.0f}; BLI_kdtree_insert(tree, tree_index++, dummy); } @@ -904,7 +904,7 @@ static int similar_edge_select_exec(bContext *C, wmOperator *op) case SIMEDGE_FACE_ANGLE: { if (BM_edge_face_count_at_most(edge, 2) == 2) { - float angle = BM_edge_calc_face_angle(edge); + float angle = BM_edge_calc_face_angle_worldspace(ob, edge); if (ED_select_similar_compare_float_tree(tree, angle, thresh, SIM_CMP_EQ)) { select = true; }