Commit: 149ca1320b183632921c5c06110ee910a768eb93
Author: Campbell Barton
Date:   Thu Sep 11 17:53:03 2014 +1000
Branches: master
https://developer.blender.org/rB149ca1320b183632921c5c06110ee910a768eb93

Fix non-deterministic editmesh normal orientations

- selecting a boundary edge would randomly point in/outside the face (now point 
away).
- selecting 3 verts would use the first selected edge as the tangent (now use 
longest).
- selecting 1 vert betweem edges, uses the edges to define the tangent.

===================================================================

M       source/blender/bmesh/intern/bmesh_polygon.c
M       source/blender/bmesh/intern/bmesh_polygon.h
M       source/blender/editors/transform/transform_orientations.c

===================================================================

diff --git a/source/blender/bmesh/intern/bmesh_polygon.c 
b/source/blender/bmesh/intern/bmesh_polygon.c
index 9a0fce9..9a1914b 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.c
+++ b/source/blender/bmesh/intern/bmesh_polygon.c
@@ -239,6 +239,25 @@ float BM_face_calc_perimeter(BMFace *f)
        return perimeter;
 }
 
+void BM_vert_tri_calc_plane(BMVert *verts[3], float r_plane[3])
+{
+       float lens[3];
+       float difs[3];
+       int  order[3] = {0, 1, 2};
+
+       lens[0] = len_v3v3(verts[0]->co, verts[1]->co);
+       lens[1] = len_v3v3(verts[1]->co, verts[2]->co);
+       lens[2] = len_v3v3(verts[2]->co, verts[0]->co);
+
+       /* find the shortest or the longest loop */
+       difs[0] = fabsf(lens[1] - lens[2]);
+       difs[1] = fabsf(lens[2] - lens[0]);
+       difs[2] = fabsf(lens[0] - lens[1]);
+
+       axis_sort_v3(difs, order);
+       sub_v3_v3v3(r_plane, verts[order[0]]->co, verts[(order[0] + 1) % 
3]->co);
+}
+
 /**
  * Compute a meaningful direction along the face (use for manipulator axis).
  * \note result isnt normalized.
@@ -247,23 +266,10 @@ void BM_face_calc_plane(BMFace *f, float r_plane[3])
 {
        if (f->len == 3) {
                BMVert *verts[3];
-               float lens[3];
-               float difs[3];
-               int  order[3] = {0, 1, 2};
 
                BM_face_as_array_vert_tri(f, verts);
 
-               lens[0] = len_v3v3(verts[0]->co, verts[1]->co);
-               lens[1] = len_v3v3(verts[1]->co, verts[2]->co);
-               lens[2] = len_v3v3(verts[2]->co, verts[0]->co);
-
-               /* find the shortest or the longest loop */
-               difs[0] = fabsf(lens[1] - lens[2]);
-               difs[1] = fabsf(lens[2] - lens[0]);
-               difs[2] = fabsf(lens[0] - lens[1]);
-
-               axis_sort_v3(difs, order);
-               sub_v3_v3v3(r_plane, verts[order[0]]->co, verts[(order[0] + 1) 
% 3]->co);
+               BM_vert_tri_calc_plane(verts, r_plane);
        }
        else if (f->len == 4) {
                BMVert *verts[4];
diff --git a/source/blender/bmesh/intern/bmesh_polygon.h 
b/source/blender/bmesh/intern/bmesh_polygon.h
index bc0e7e8..91e649e 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.h
+++ b/source/blender/bmesh/intern/bmesh_polygon.h
@@ -71,4 +71,6 @@ void BM_face_as_array_vert_quad(BMFace *f, BMVert 
*r_verts[4]) ATTR_NONNULL();
 void BM_face_as_array_loop_tri(BMFace *f, BMLoop *r_loops[3]) ATTR_NONNULL();
 void BM_face_as_array_loop_quad(BMFace *f, BMLoop *r_loops[4]) ATTR_NONNULL();
 
+void BM_vert_tri_calc_plane(BMVert *verts[3], float r_plane[3]);
+
 #endif /* __BMESH_POLYGON_H__ */
diff --git a/source/blender/editors/transform/transform_orientations.c 
b/source/blender/editors/transform/transform_orientations.c
index 69d135b..29a1ec3 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -509,6 +509,100 @@ void initTransformOrientation(bContext *C, TransInfo *t)
        }
 }
 
+/**
+ * utility function - get first n, selected vert/edge/faces
+ */
+static unsigned int bm_mesh_elems_select_get_n__internal(
+        BMesh *bm, BMElem **elems, const unsigned int n,
+        const BMIterType itype, const char htype)
+{
+       BMIter iter;
+       BMElem *ele;
+       unsigned int i;
+
+       BLI_assert(ELEM(htype, BM_VERT, BM_EDGE, BM_FACE));
+       BLI_assert(ELEM(itype, BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, 
BM_FACES_OF_MESH));
+
+       if (!BLI_listbase_is_empty(&bm->selected)) {
+               /* quick check */
+               BMEditSelection *ese;
+               i = 0;
+               for (ese = bm->selected.last; ese; ese = ese->prev) {
+                       /* shouldn't need this check */
+                       if (BM_elem_flag_test(ese->ele, BM_ELEM_SELECT)) {
+
+                               /* only use contiguous selection */
+                               if (ese->htype != htype) {
+                                       i = 0;
+                                       break;
+                               }
+
+                               elems[i++] = ese->ele;
+                               if (n == i) {
+                                       break;
+                               }
+                       }
+                       else {
+                               BLI_assert(0);
+                       }
+               }
+
+               if (i == 0) {
+                       /* pass */
+               }
+               else if (n == i) {
+                       return i;
+               }
+               else {
+                       /* check if the elems we found are all that's selected 
*/
+                       unsigned int n_sel;
+                       switch (itype) {
+                               case BM_VERTS_OF_MESH: n_sel = bm->totvertsel; 
break;
+                               case BM_EDGES_OF_MESH: n_sel = bm->totedgesel; 
break;
+                               default:               n_sel = bm->totfacesel; 
break;
+                       }
+                       if (n_sel == i) {
+                               return i;
+                       }
+                       /* start over reading the selection */
+               }
+       }
+
+       i = 0;
+       BM_ITER_MESH (ele, &iter, bm, itype) {
+               BLI_assert(ele->head.htype == htype);
+               if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
+                       elems[i++] = ele;
+                       if (n == i) {
+                               break;
+                       }
+               }
+       }
+
+       return i;
+}
+
+static unsigned int bm_mesh_verts_select_get_n(BMesh *bm, BMVert **elems, 
const unsigned int n)
+{
+       return bm_mesh_elems_select_get_n__internal(
+               bm, (BMElem **)elems, min_ii(n, bm->totvertsel),
+               BM_VERTS_OF_MESH, BM_VERT);
+}
+static unsigned int bm_mesh_edges_select_get_n(BMesh *bm, BMEdge **elems, 
const unsigned int n)
+{
+       return bm_mesh_elems_select_get_n__internal(
+               bm, (BMElem **)elems, min_ii(n, bm->totedgesel),
+               BM_EDGES_OF_MESH, BM_EDGE);
+}
+#if 0
+static unsigned int bm_mesh_faces_select_get_n(BMesh *bm, BMVert **elems, 
const unsigned int n)
+{
+       return bm_mesh_elems_select_get_n__internal(
+               bm, (BMElem **)elems, min_ii(n, bm->totfacesel),
+               BM_FACES_OF_MESH, BM_FACE);
+}
+#endif
+
 int getTransformOrientation(const bContext *C, float normal[3], float 
plane[3], const bool activeOnly)
 {
        Scene *scene = CTX_data_scene(C);
@@ -534,7 +628,6 @@ int getTransformOrientation(const bContext *C, float 
normal[3], float plane[3],
 
                if (ob->type == OB_MESH) {
                        BMEditMesh *em = BKE_editmesh_from_object(ob);
-                       BMVert *eve;
                        BMEditSelection ese;
                        float vec[3] = {0, 0, 0};
                        
@@ -571,97 +664,78 @@ int getTransformOrientation(const bContext *C, float 
normal[3], float plane[3],
                                        result = ORIENTATION_FACE;
                                }
                                else if (em->bm->totvertsel == 3) {
-                                       BMVert *v1 = NULL, *v2 = NULL, *v3 = 
NULL;
-                                       BMIter iter;
-                                       
-                                       BM_ITER_MESH (eve, &iter, em->bm, 
BM_VERTS_OF_MESH) {
-                                               if (BM_elem_flag_test(eve, 
BM_ELEM_SELECT)) {
-                                                       if (v1 == NULL) {
-                                                               v1 = eve; 
-                                                       }
-                                                       else if (v2 == NULL) {
-                                                               v2 = eve;
-                                                       }
-                                                       else {
-                                                               float 
no_test[3];
+                                       BMVert *v_tri[3];
 
-                                                               float tan_a[3], 
tan_b[3], tan_c[3];
-                                                               float len_a, 
len_b, len_c;
-                                                               const float 
*tan_best;
+                                       if (bm_mesh_verts_select_get_n(em->bm, 
v_tri, 3) == 3) {
+                                               BMEdge *e = NULL;
+                                               float no_test[3];
 
+                                               normal_tri_v3(normal, 
v_tri[0]->co, v_tri[1]->co, v_tri[2]->co);
 
-                                                               v3 = eve;
-                                                               
sub_v3_v3v3(tan_a, v2->co, v1->co);
-                                                               
sub_v3_v3v3(tan_b, v3->co, v2->co);
-                                                               
sub_v3_v3v3(tan_c, v1->co, v3->co);
-                                                               
cross_v3_v3v3(normal, tan_b, tan_a);
+                                               /* check if the normal is 
pointing opposite to vert normals */
+                                               no_test[0] = v_tri[0]->no[0] + 
v_tri[1]->no[0] + v_tri[2]->no[0];
+                                               no_test[1] = v_tri[0]->no[1] + 
v_tri[1]->no[1] + v_tri[2]->no[1];
+                                               no_test[2] = v_tri[0]->no[2] + 
v_tri[1]->no[2] + v_tri[2]->no[2];
+                                               if (dot_v3v3(no_test, normal) < 
0.0f) {
+                                                       negate_v3(normal);
+                                               }
 
-                                                               /* check if the 
normal is pointing opposite to vert normals */
-                                                               no_test[0] = 
v1->no[0] + v2->no[0] + v3->no[0];
-                                                               no_test[1] = 
v1->no[1] + v2->no[1] + v3->no[1];
-                                                               no_test[2] = 
v1->no[2] + v2->no[2] + v3->no[2];
-                                                               if 
(dot_v3v3(no_test, normal) < 0.0f) {
-                                                                       
negate_v3(normal);
+                                               if (em->bm->totedgesel >= 1) {
+                                                       /* find an edge thats 
apart of v_tri (no need to search all edges) */
+                                                       float e_length;
+                                                       int j;
+
+                                                       for (j = 0; j < 3; j++) 
{
+                                                               BMEdge *e_test 
= BM_edge_exists(v_tri[j], v_tri[(j + 1) % 3]);
+                                                               if (e_test && 
BM_elem_flag_test(e_test, BM_ELEM_SELECT)) {
+                                                                       const 
float e_test_length = BM_edge_calc_length_squared(e_test);
+                                                                       if ((e 
== NULL) || (e_length < e_test_length)) {
+                                                                               
e = e_test;
+                                                                               
e_length = e_test_length;
+                                                                       }
                                                                }
-
-                                                               /* always give 
the plane to the 2 most distant verts */
-                                                               len_a = 
len_squared_v3(tan_a);
-                                                               len_b = 
len_squared_v3(tan_b);
-                                                               len_c = 
len_squared_v3(tan_c);
-
-                                                               tan_best = 
MAX3_PAIR(len_a, len_b, len_c,
-                                                                               
     tan_a, tan_b, tan_c);
-
-                                                               
copy_v3_v3(plane, tan_best);
-
-                                                               break;
                                                        }
                                                }
-                                       }
 
-                                       /* if there's an edge available, use 
that for the tangent */
-                                       if (em->bm->totedgesel >= 1) {
-                                               BMEdge *eed = NULL;
-                                               
-                                               BM_ITER_MESH (eed, &iter, 
em->bm, BM_EDGES_OF_MESH) {
-                                                       if 
(BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
-                                                               
sub_v3_v3v3(plane, eed->v2->co, eed->v1->co);
-                                                               break;
+                                               if (e) {
+                                                       BMVert *v_pair[2];
+                                                       if 
(BM_edge_is_boundary(e)) {
+                                                               
BM_edge_ordered_verts(e, &v_pair[0], &v_pair[1]);
                                                        }
+                                                       else {
+                                                               v_pair[0] = 
e->v1;
+                                                               v_pair[1] = 
e->v2;
+                                                       }
+                                                       sub_v3_v3v3(plane, 
v_pair[0]->co, v_pair[1]->co);
+                                               }
+                                               else {
+                                                       
BM_vert_tri_calc_plane(v_tri, plane);
                                                }
                                        }
+                                       else {
+                                               BLI_assert(0);
+                                       }
 
                                        result = ORIENTATION_FACE;
                                }
                                else if (em->bm->totedgesel == 1 || 
em->bm->totvertsel == 2) {
-                                       BMVert *v1 = NULL, *v2 = NULL;
-                                       BMIter iter;
+                                       BMVert *v_pair[2] = {NULL, NULL};
+                                       BMEdge *eed = NULL;
                                        
                                        if (em->bm->totedgesel == 1) {
-                                               BMEdge *eed = NULL;
-                                               BM_ITER_MESH (eed, &iter, 
em->bm, BM_EDGES_OF_MESH) {
-                                                       if 
(BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
-                                                               v1 = eed->v1;
-                                                               v2 = eed->v2;
-                                                       }
+                                               if 
(bm_mesh_edges_select_get_n(em->bm, &eed, 1) == 1) {
+                                                       v_pair[0] = eed->v1;
+                                                       v_pair[1] = eed->v2;
                                                }
                                        }
                                        else {
-                                               BM_ITER_MESH (eve, &iter, 
em->bm, BM_VERTS_OF_MESH) {
-                                                       if 
(BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
-                                                               if (v1 == NULL) 
{
-                                                                       v1 = 
eve;
-                                                               }
-                                                               else {
-                                                                       v2 = 
eve;
-                                                                       break;
-                                                               }
-                                                       }
-                                               }
+                                               BLI_assert(em->bm->totvertsel 
== 2);
+                                               
bm_mesh_verts_select_get_n(em->bm, v_pair, 2);
                                        }
 
                                        /* should never fail */
-                                       if (LIKELY(v1 && v2)) {
+                                       if (LIKELY(v_pair[0] && v_pair[1])) {
+                                               bool v_pair_swap = false;
                                                /* Logic explained:
                                                 *
                                                 * - Edges and vert-pairs 
treated the same way.
@@ -672,13 +746,23 @@ int getTransformOrientation(const bContext *C, float 
normal[3], float plane[3],
                                                 * whic

@@ Diff output truncated at 10240 characters. @@

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
http://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to