diff options
author | Campbell Barton <ideasman42@gmail.com> | 2015-03-02 05:04:46 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2015-03-02 05:04:46 +0300 |
commit | 9d85e32ee3201654ec15e994b023650fd1834d29 (patch) | |
tree | 36c8e375bf6d64e87e6ce15ccef49950d51a9400 /source/blender/bmesh/operators | |
parent | 56935e23c491db3d1a0b0d1053f82e30af65bd6b (diff) |
BMesh: calc normals, use area weighted center
Prevents many small faces skewing center calculation.
Diffstat (limited to 'source/blender/bmesh/operators')
-rw-r--r-- | source/blender/bmesh/operators/bmo_normals.c | 25 |
1 files changed, 19 insertions, 6 deletions
diff --git a/source/blender/bmesh/operators/bmo_normals.c b/source/blender/bmesh/operators/bmo_normals.c index d0f08871400..ed49d0751ce 100644 --- a/source/blender/bmesh/operators/bmo_normals.c +++ b/source/blender/bmesh/operators/bmo_normals.c @@ -59,10 +59,12 @@ static void bmo_recalc_face_normals_array(BMesh *bm, BMFace **faces, const int f { float cent[3], tvec[3]; float (*faces_center)[3] = MEM_mallocN(sizeof(*faces_center) * faces_len, __func__); + float *faces_area = MEM_mallocN(sizeof(*faces_area) * faces_len, __func__); const float cent_fac = 1.0f / (float)faces_len; int i, f_start_index; const short oflag_flip = oflag | FACE_FLIP; + float cent_area_accum = 0.0f; float f_len_best_sq; BMFace *f; @@ -73,13 +75,20 @@ static void bmo_recalc_face_normals_array(BMesh *bm, BMFace **faces, const int f /* first calculate the center */ for (i = 0; i < faces_len; i++) { float *f_cent = faces_center[i]; + const float f_area = BM_face_calc_area(faces[i]); BM_face_calc_center_mean_weighted(faces[i], f_cent); - madd_v3_v3fl(cent, f_cent, cent_fac); + madd_v3_v3fl(cent, f_cent, cent_fac * f_area); + cent_area_accum += f_area; + faces_area[i] = f_area; BLI_assert(BMO_elem_flag_test(bm, faces[i], FACE_TEMP) == 0); BLI_assert(BM_face_is_normal_valid(faces[i])); } + if (cent_area_accum != 0.0f) { + mul_v3_fl(cent, 1.0f / cent_area_accum); + } + f_len_best_sq = -FLT_MAX; /* used in degenerate cases only */ f_start_index = 0; @@ -87,20 +96,24 @@ static void bmo_recalc_face_normals_array(BMesh *bm, BMFace **faces, const int f for (i = 0; i < faces_len; i++) { float f_len_test_sq; - if ((f_len_test_sq = len_squared_v3v3(faces_center[i], cent)) > f_len_best_sq) { - f_len_best_sq = f_len_test_sq; - f_start_index = i; + if (faces_area[i] > FLT_EPSILON) { + if ((f_len_test_sq = len_squared_v3v3(faces_center[i], cent)) > f_len_best_sq) { + f_len_best_sq = f_len_test_sq; + f_start_index = i; + } } } + /* make sure the starting face has the correct winding */ sub_v3_v3v3(tvec, faces_center[f_start_index], cent); + MEM_freeN(faces_center); + MEM_freeN(faces_area); + if (dot_v3v3(tvec, faces[f_start_index]->no) < 0.0f) { BMO_elem_flag_enable(bm, faces[f_start_index], FACE_FLIP); } - MEM_freeN(faces_center); - /* now that we've found our starting face, make all connected faces * have the same winding. this is done recursively, using a manual * stack (if we use simple function recursion, we'd end up overloading |