Base refactor 3/4
[blender.git] / source / blender / editors / transform / transform_orientations.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor(s): Martin Poirier
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/editors/transform/transform_orientations.c
24  *  \ingroup edtransform
25  */
26
27 #include <string.h>
28 #include <stddef.h>
29 #include <ctype.h>
30
31 #include "MEM_guardedalloc.h"
32
33 #include "DNA_armature_types.h"
34 #include "DNA_curve_types.h"
35 #include "DNA_meta_types.h"
36 #include "DNA_object_types.h"
37 #include "DNA_scene_types.h"
38 #include "DNA_screen_types.h"
39 #include "DNA_space_types.h"
40 #include "DNA_view3d_types.h"
41
42 #include "BLI_math.h"
43 #include "BLI_listbase.h"
44 #include "BLI_string.h"
45 #include "BLI_string_utils.h"
46 #include "BLI_utildefines.h"
47
48 #include "BKE_action.h"
49 #include "BKE_curve.h"
50 #include "BKE_context.h"
51 #include "BKE_editmesh.h"
52 #include "BKE_report.h"
53 #include "BKE_main.h"
54 #include "BKE_screen.h"
55
56 #include "BLT_translation.h"
57
58 #include "ED_armature.h"
59
60 #include "transform.h"
61
62 /* *********************** TransSpace ************************** */
63
64 void BIF_clearTransformOrientation(bContext *C)
65 {
66         View3D *v3d = CTX_wm_view3d(C);
67
68         ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
69         BLI_freelistN(transform_spaces);
70         
71         // Need to loop over all view3d
72         if (v3d && v3d->twmode >= V3D_MANIP_CUSTOM) {
73                 v3d->twmode = V3D_MANIP_GLOBAL; /* fallback to global   */
74         }
75 }
76
77 static TransformOrientation *findOrientationName(ListBase *lb, const char *name)
78 {
79         return BLI_findstring(lb, name, offsetof(TransformOrientation, name));
80 }
81
82 static bool uniqueOrientationNameCheck(void *arg, const char *name)
83 {
84         return findOrientationName((ListBase *)arg, name) != NULL;
85 }
86
87 static void uniqueOrientationName(ListBase *lb, char *name)
88 {
89         BLI_uniquename_cb(uniqueOrientationNameCheck, lb, CTX_DATA_(BLT_I18NCONTEXT_ID_SCENE, "Space"), '.', name,
90                           sizeof(((TransformOrientation *)NULL)->name));
91 }
92
93 static TransformOrientation *createViewSpace(bContext *C, ReportList *UNUSED(reports),
94                                              const char *name, const bool overwrite)
95 {
96         RegionView3D *rv3d = CTX_wm_region_view3d(C);
97         float mat[3][3];
98
99         if (!rv3d)
100                 return NULL;
101
102         copy_m3_m4(mat, rv3d->viewinv);
103         normalize_m3(mat);
104
105         if (name[0] == 0) {
106                 View3D *v3d = CTX_wm_view3d(C);
107                 if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
108                         /* If an object is used as camera, then this space is the same as object space! */
109                         name = v3d->camera->id.name + 2;
110                 }
111                 else {
112                         name = "Custom View";
113                 }
114         }
115
116         return addMatrixSpace(C, mat, name, overwrite);
117 }
118
119 static TransformOrientation *createObjectSpace(bContext *C, ReportList *UNUSED(reports),
120                                                const char *name, const bool overwrite)
121 {
122         ObjectBase *base = CTX_data_active_base(C);
123         Object *ob;
124         float mat[3][3];
125
126         if (base == NULL)
127                 return NULL;
128
129         ob = base->object;
130
131         copy_m3_m4(mat, ob->obmat);
132         normalize_m3(mat);
133
134         /* use object name if no name is given */
135         if (name[0] == 0) {
136                 name = ob->id.name + 2;
137         }
138
139         return addMatrixSpace(C, mat, name, overwrite);
140 }
141
142 static TransformOrientation *createBoneSpace(bContext *C, ReportList *reports,
143                                              const char *name, const bool overwrite)
144 {
145         float mat[3][3];
146         float normal[3], plane[3];
147
148         getTransformOrientation(C, normal, plane);
149
150         if (createSpaceNormalTangent(mat, normal, plane) == 0) {
151                 BKE_reports_prepend(reports, "Cannot use zero-length bone");
152                 return NULL;
153         }
154
155         if (name[0] == 0) {
156                 name = "Bone";
157         }
158
159         return addMatrixSpace(C, mat, name, overwrite);
160 }
161
162 static TransformOrientation *createCurveSpace(bContext *C, ReportList *reports,
163                                               const char *name, const bool overwrite)
164 {
165         float mat[3][3];
166         float normal[3], plane[3];
167
168         getTransformOrientation(C, normal, plane);
169
170         if (createSpaceNormalTangent(mat, normal, plane) == 0) {
171                 BKE_reports_prepend(reports, "Cannot use zero-length curve");
172                 return NULL;
173         }
174
175         if (name[0] == 0) {
176                 name = "Curve";
177         }
178
179         return addMatrixSpace(C, mat, name, overwrite);
180 }
181
182
183 static TransformOrientation *createMeshSpace(bContext *C, ReportList *reports,
184                                              const char *name, const bool overwrite)
185 {
186         float mat[3][3];
187         float normal[3], plane[3];
188         int type;
189
190         type = getTransformOrientation(C, normal, plane);
191         
192         switch (type) {
193                 case ORIENTATION_VERT:
194                         if (createSpaceNormal(mat, normal) == 0) {
195                                 BKE_reports_prepend(reports, "Cannot use vertex with zero-length normal");
196                                 return NULL;
197                         }
198         
199                         if (name[0] == 0) {
200                                 name = "Vertex";
201                         }
202                         break;
203                 case ORIENTATION_EDGE:
204                         if (createSpaceNormalTangent(mat, normal, plane) == 0) {
205                                 BKE_reports_prepend(reports, "Cannot use zero-length edge");
206                                 return NULL;
207                         }
208         
209                         if (name[0] == 0) {
210                                 name = "Edge";
211                         }
212                         break;
213                 case ORIENTATION_FACE:
214                         if (createSpaceNormalTangent(mat, normal, plane) == 0) {
215                                 BKE_reports_prepend(reports, "Cannot use zero-area face");
216                                 return NULL;
217                         }
218         
219                         if (name[0] == 0) {
220                                 name = "Face";
221                         }
222                         break;
223                 default:
224                         return NULL;
225         }
226
227         return addMatrixSpace(C, mat, name, overwrite);
228 }
229
230 bool createSpaceNormal(float mat[3][3], const float normal[3])
231 {
232         float tangent[3] = {0.0f, 0.0f, 1.0f};
233         
234         copy_v3_v3(mat[2], normal);
235         if (normalize_v3(mat[2]) == 0.0f) {
236                 return false;  /* error return */
237         }
238
239         cross_v3_v3v3(mat[0], mat[2], tangent);
240         if (is_zero_v3(mat[0])) {
241                 tangent[0] = 1.0f;
242                 tangent[1] = tangent[2] = 0.0f;
243                 cross_v3_v3v3(mat[0], tangent, mat[2]);
244         }
245
246         cross_v3_v3v3(mat[1], mat[2], mat[0]);
247
248         normalize_m3(mat);
249         
250         return true;
251 }
252
253 /**
254  * \note To recreate an orientation from the matrix:
255  * - (plane  == mat[1])
256  * - (normal == mat[2])
257  */
258 bool createSpaceNormalTangent(float mat[3][3], const float normal[3], const float tangent[3])
259 {
260         if (normalize_v3_v3(mat[2], normal) == 0.0f) {
261                 return false;  /* error return */
262         }
263
264         /* negate so we can use values from the matrix as input */
265         negate_v3_v3(mat[1], tangent);
266         /* preempt zero length tangent from causing trouble */
267         if (is_zero_v3(mat[1])) {
268                 mat[1][2] = 1.0f;
269         }
270
271         cross_v3_v3v3(mat[0], mat[2], mat[1]);
272         if (normalize_v3(mat[0]) == 0.0f) {
273                 return false;  /* error return */
274         }
275         
276         cross_v3_v3v3(mat[1], mat[2], mat[0]);
277         normalize_v3(mat[1]);
278
279         /* final matrix must be normalized, do inline */
280         // normalize_m3(mat);
281         
282         return true;
283 }
284
285 void BIF_createTransformOrientation(bContext *C, ReportList *reports,
286                                     const char *name, const bool use_view,
287                                     const bool activate, const bool overwrite)
288 {
289         TransformOrientation *ts = NULL;
290
291         if (use_view) {
292                 ts = createViewSpace(C, reports, name, overwrite);
293         }
294         else {
295                 Object *obedit = CTX_data_edit_object(C);
296                 Object *ob = CTX_data_active_object(C);
297                 if (obedit) {
298                         if (obedit->type == OB_MESH)
299                                 ts = createMeshSpace(C, reports, name, overwrite);
300                         else if (obedit->type == OB_ARMATURE)
301                                 ts = createBoneSpace(C, reports, name, overwrite);
302                         else if (obedit->type == OB_CURVE)
303                                 ts = createCurveSpace(C, reports, name, overwrite);
304                 }
305                 else if (ob && (ob->mode & OB_MODE_POSE)) {
306                         ts = createBoneSpace(C, reports, name, overwrite);
307                 }
308                 else {
309                         ts = createObjectSpace(C, reports, name, overwrite);
310                 }
311         }
312
313         if (activate && ts != NULL) {
314                 BIF_selectTransformOrientation(C, ts);
315         }
316 }
317
318 TransformOrientation *addMatrixSpace(bContext *C, float mat[3][3],
319                                      const char *name, const bool overwrite)
320 {
321         ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
322         TransformOrientation *ts = NULL;
323         char name_unique[sizeof(ts->name)];
324
325         if (overwrite) {
326                 ts = findOrientationName(transform_spaces, name);
327         }
328         else {
329                 BLI_strncpy(name_unique, name, sizeof(name_unique));
330                 uniqueOrientationName(transform_spaces, name_unique);
331                 name = name_unique;
332         }
333
334         /* if not, create a new one */
335         if (ts == NULL) {
336                 ts = MEM_callocN(sizeof(TransformOrientation), "UserTransSpace from matrix");
337                 BLI_addtail(transform_spaces, ts);
338                 BLI_strncpy(ts->name, name, sizeof(ts->name));
339         }
340
341         /* copy matrix into transform space */
342         copy_m3_m3(ts->mat, mat);
343
344         return ts;
345 }
346
347 void BIF_removeTransformOrientation(bContext *C, TransformOrientation *target)
348 {
349         Scene *scene = CTX_data_scene(C);
350         ListBase *transform_spaces = &scene->transform_spaces;
351         const int i = BLI_findindex(transform_spaces, target);
352
353         if (i != -1) {
354                 Main *bmain = CTX_data_main(C);
355                 BKE_screen_view3d_main_twmode_remove(&bmain->screen, scene, i);
356                 BLI_freelinkN(transform_spaces, target);
357         }
358 }
359
360 void BIF_removeTransformOrientationIndex(bContext *C, int index)
361 {
362         ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
363         TransformOrientation *ts = BLI_findlink(transform_spaces, index);
364
365         if (ts) {
366                 BIF_removeTransformOrientation(C, ts);
367         }
368 }
369
370 void BIF_selectTransformOrientation(bContext *C, TransformOrientation *target)
371 {
372         ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
373         const int i = BLI_findindex(transform_spaces, target);
374
375         if (i != -1) {
376                 View3D *v3d = CTX_wm_view3d(C);
377                 v3d->twmode = V3D_MANIP_CUSTOM + i;
378         }
379 }
380
381 void BIF_selectTransformOrientationValue(bContext *C, int orientation)
382 {
383         View3D *v3d = CTX_wm_view3d(C);
384         if (v3d) /* currently using generic poll */
385                 v3d->twmode = orientation;
386 }
387
388 int BIF_countTransformOrientation(const bContext *C)
389 {
390         ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
391         return BLI_listbase_count(transform_spaces);
392 }
393
394 bool applyTransformOrientation(const bContext *C, float mat[3][3], char *r_name, int index)
395 {
396         ListBase *transform_spaces = &CTX_data_scene(C)->transform_spaces;
397         TransformOrientation *ts = BLI_findlink(transform_spaces, index);
398
399         BLI_assert(index >= 0);
400
401         if (ts) {
402                 if (r_name) {
403                         BLI_strncpy(r_name, ts->name, MAX_NAME);
404                 }
405
406                 copy_m3_m3(mat, ts->mat);
407                 return true;
408         }
409         else {
410                 /* invalid index, can happen sometimes */
411                 return false;
412         }
413 }
414
415 static int count_bone_select(bArmature *arm, ListBase *lb, const bool do_it)
416 {
417         Bone *bone;
418         bool do_next;
419         int total = 0;
420         
421         for (bone = lb->first; bone; bone = bone->next) {
422                 bone->flag &= ~BONE_TRANSFORM;
423                 do_next = do_it;
424                 if (do_it) {
425                         if (bone->layer & arm->layer) {
426                                 if (bone->flag & BONE_SELECTED) {
427                                         bone->flag |= BONE_TRANSFORM;
428                                         total++;
429
430                                         /* no transform on children if one parent bone is selected */
431                                         do_next = false;
432                                 }
433                         }
434                 }
435                 total += count_bone_select(arm, &bone->childbase, do_next);
436         }
437         
438         return total;
439 }
440
441 void initTransformOrientation(bContext *C, TransInfo *t)
442 {
443         Object *ob = CTX_data_active_object(C);
444         Object *obedit = CTX_data_active_object(C);
445
446         switch (t->current_orientation) {
447                 case V3D_MANIP_GLOBAL:
448                         unit_m3(t->spacemtx);
449                         BLI_strncpy(t->spacename, IFACE_("global"), sizeof(t->spacename));
450                         break;
451
452                 case V3D_MANIP_GIMBAL:
453                         unit_m3(t->spacemtx);
454                         if (gimbal_axis(ob, t->spacemtx)) {
455                                 BLI_strncpy(t->spacename, IFACE_("gimbal"), sizeof(t->spacename));
456                                 break;
457                         }
458                         /* fall-through */  /* no gimbal fallthrough to normal */
459                 case V3D_MANIP_NORMAL:
460                         if (obedit || (ob && ob->mode & OB_MODE_POSE)) {
461                                 BLI_strncpy(t->spacename, IFACE_("normal"), sizeof(t->spacename));
462                                 ED_getTransformOrientationMatrix(C, t->spacemtx, t->around);
463                                 break;
464                         }
465                         /* fall-through */  /* we define 'normal' as 'local' in Object mode */
466                 case V3D_MANIP_LOCAL:
467                         BLI_strncpy(t->spacename, IFACE_("local"), sizeof(t->spacename));
468                 
469                         if (ob) {
470                                 copy_m3_m4(t->spacemtx, ob->obmat);
471                                 normalize_m3(t->spacemtx);
472                         }
473                         else {
474                                 unit_m3(t->spacemtx);
475                         }
476                 
477                         break;
478                 
479                 case V3D_MANIP_VIEW:
480                         if ((t->spacetype == SPACE_VIEW3D) &&
481                             (t->ar->regiontype == RGN_TYPE_WINDOW))
482                         {
483                                 RegionView3D *rv3d = t->ar->regiondata;
484                                 float mat[3][3];
485
486                                 BLI_strncpy(t->spacename, IFACE_("view"), sizeof(t->spacename));
487                                 copy_m3_m4(mat, rv3d->viewinv);
488                                 normalize_m3(mat);
489                                 copy_m3_m3(t->spacemtx, mat);
490                         }
491                         else {
492                                 unit_m3(t->spacemtx);
493                         }
494                         break;
495                 default: /* V3D_MANIP_CUSTOM */
496                         if (applyTransformOrientation(C, t->spacemtx, t->spacename, t->current_orientation - V3D_MANIP_CUSTOM)) {
497                                 /* pass */
498                         }
499                         else {
500                                 unit_m3(t->spacemtx);
501                         }
502                         break;
503         }
504 }
505
506 /**
507  * utility function - get first n, selected vert/edge/faces
508  */
509 static unsigned int bm_mesh_elems_select_get_n__internal(
510         BMesh *bm, BMElem **elems, const unsigned int n,
511         const BMIterType itype, const char htype)
512 {
513         BMIter iter;
514         BMElem *ele;
515         unsigned int i;
516
517         BLI_assert(ELEM(htype, BM_VERT, BM_EDGE, BM_FACE));
518         BLI_assert(ELEM(itype, BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH));
519
520         if (!BLI_listbase_is_empty(&bm->selected)) {
521                 /* quick check */
522                 BMEditSelection *ese;
523                 i = 0;
524                 for (ese = bm->selected.last; ese; ese = ese->prev) {
525                         /* shouldn't need this check */
526                         if (BM_elem_flag_test(ese->ele, BM_ELEM_SELECT)) {
527
528                                 /* only use contiguous selection */
529                                 if (ese->htype != htype) {
530                                         i = 0;
531                                         break;
532                                 }
533
534                                 elems[i++] = ese->ele;
535                                 if (n == i) {
536                                         break;
537                                 }
538                         }
539                         else {
540                                 BLI_assert(0);
541                         }
542                 }
543
544                 if (i == 0) {
545                         /* pass */
546                 }
547                 else if (i == n) {
548                         return i;
549                 }
550         }
551
552         i = 0;
553         BM_ITER_MESH (ele, &iter, bm, itype) {
554                 BLI_assert(ele->head.htype == htype);
555                 if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
556                         elems[i++] = ele;
557                         if (n == i) {
558                                 break;
559                         }
560                 }
561         }
562
563         return i;
564 }
565
566 static unsigned int bm_mesh_verts_select_get_n(BMesh *bm, BMVert **elems, const unsigned int n)
567 {
568         return bm_mesh_elems_select_get_n__internal(
569                 bm, (BMElem **)elems, min_ii(n, bm->totvertsel),
570                 BM_VERTS_OF_MESH, BM_VERT);
571 }
572 static unsigned int bm_mesh_edges_select_get_n(BMesh *bm, BMEdge **elems, const unsigned int n)
573 {
574         return bm_mesh_elems_select_get_n__internal(
575                 bm, (BMElem **)elems, min_ii(n, bm->totedgesel),
576                 BM_EDGES_OF_MESH, BM_EDGE);
577 }
578 #if 0
579 static unsigned int bm_mesh_faces_select_get_n(BMesh *bm, BMVert **elems, const unsigned int n)
580 {
581         return bm_mesh_elems_select_get_n__internal(
582                 bm, (BMElem **)elems, min_ii(n, bm->totfacesel),
583                 BM_FACES_OF_MESH, BM_FACE);
584 }
585 #endif
586
587 int getTransformOrientation_ex(const bContext *C, float normal[3], float plane[3], const short around)
588 {
589         Scene *scene = CTX_data_scene(C);
590         Object *obedit = CTX_data_edit_object(C);
591         BaseLegacy *base;
592         Object *ob = OBACT;
593         int result = ORIENTATION_NONE;
594         const bool activeOnly = (around == V3D_AROUND_ACTIVE);
595
596         zero_v3(normal);
597         zero_v3(plane);
598
599         if (obedit) {
600                 float imat[3][3], mat[3][3];
601                 
602                 /* we need the transpose of the inverse for a normal... */
603                 copy_m3_m4(imat, ob->obmat);
604                 
605                 invert_m3_m3(mat, imat);
606                 transpose_m3(mat);
607
608                 ob = obedit;
609
610                 if (ob->type == OB_MESH) {
611                         BMEditMesh *em = BKE_editmesh_from_object(ob);
612                         BMEditSelection ese;
613                         float vec[3] = {0, 0, 0};
614                         
615                         /* USE LAST SELECTED WITH ACTIVE */
616                         if (activeOnly && BM_select_history_active_get(em->bm, &ese)) {
617                                 BM_editselection_normal(&ese, normal);
618                                 BM_editselection_plane(&ese, plane);
619                                 
620                                 switch (ese.htype) {
621                                         case BM_VERT:
622                                                 result = ORIENTATION_VERT;
623                                                 break;
624                                         case BM_EDGE:
625                                                 result = ORIENTATION_EDGE;
626                                                 break;
627                                         case BM_FACE:
628                                                 result = ORIENTATION_FACE;
629                                                 break;
630                                 }
631                         }
632                         else {
633                                 if (em->bm->totfacesel >= 1) {
634                                         BMFace *efa;
635                                         BMIter iter;
636
637                                         BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
638                                                 if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
639                                                         BM_face_calc_tangent_auto(efa, vec);
640                                                         add_v3_v3(normal, efa->no);
641                                                         add_v3_v3(plane, vec);
642                                                 }
643                                         }
644                                         
645                                         result = ORIENTATION_FACE;
646                                 }
647                                 else if (em->bm->totvertsel == 3) {
648                                         BMVert *v_tri[3];
649
650                                         if (bm_mesh_verts_select_get_n(em->bm, v_tri, 3) == 3) {
651                                                 BMEdge *e = NULL;
652                                                 float no_test[3];
653
654                                                 normal_tri_v3(normal, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co);
655
656                                                 /* check if the normal is pointing opposite to vert normals */
657                                                 no_test[0] = v_tri[0]->no[0] + v_tri[1]->no[0] + v_tri[2]->no[0];
658                                                 no_test[1] = v_tri[0]->no[1] + v_tri[1]->no[1] + v_tri[2]->no[1];
659                                                 no_test[2] = v_tri[0]->no[2] + v_tri[1]->no[2] + v_tri[2]->no[2];
660                                                 if (dot_v3v3(no_test, normal) < 0.0f) {
661                                                         negate_v3(normal);
662                                                 }
663
664                                                 if (em->bm->totedgesel >= 1) {
665                                                         /* find an edge thats apart of v_tri (no need to search all edges) */
666                                                         float e_length;
667                                                         int j;
668
669                                                         for (j = 0; j < 3; j++) {
670                                                                 BMEdge *e_test = BM_edge_exists(v_tri[j], v_tri[(j + 1) % 3]);
671                                                                 if (e_test && BM_elem_flag_test(e_test, BM_ELEM_SELECT)) {
672                                                                         const float e_test_length = BM_edge_calc_length_squared(e_test);
673                                                                         if ((e == NULL) || (e_length < e_test_length)) {
674                                                                                 e = e_test;
675                                                                                 e_length = e_test_length;
676                                                                         }
677                                                                 }
678                                                         }
679                                                 }
680
681                                                 if (e) {
682                                                         BMVert *v_pair[2];
683                                                         if (BM_edge_is_boundary(e)) {
684                                                                 BM_edge_ordered_verts(e, &v_pair[0], &v_pair[1]);
685                                                         }
686                                                         else {
687                                                                 v_pair[0] = e->v1;
688                                                                 v_pair[1] = e->v2;
689                                                         }
690                                                         sub_v3_v3v3(plane, v_pair[0]->co, v_pair[1]->co);
691                                                 }
692                                                 else {
693                                                         BM_vert_tri_calc_tangent_edge(v_tri, plane);
694                                                 }
695                                         }
696                                         else {
697                                                 BLI_assert(0);
698                                         }
699
700                                         result = ORIENTATION_FACE;
701                                 }
702                                 else if (em->bm->totedgesel == 1 || em->bm->totvertsel == 2) {
703                                         BMVert *v_pair[2] = {NULL, NULL};
704                                         BMEdge *eed = NULL;
705                                         
706                                         if (em->bm->totedgesel == 1) {
707                                                 if (bm_mesh_edges_select_get_n(em->bm, &eed, 1) == 1) {
708                                                         v_pair[0] = eed->v1;
709                                                         v_pair[1] = eed->v2;
710                                                 }
711                                         }
712                                         else {
713                                                 BLI_assert(em->bm->totvertsel == 2);
714                                                 bm_mesh_verts_select_get_n(em->bm, v_pair, 2);
715                                         }
716
717                                         /* should never fail */
718                                         if (LIKELY(v_pair[0] && v_pair[1])) {
719                                                 bool v_pair_swap = false;
720                                                 /**
721                                                  * Logic explained:
722                                                  *
723                                                  * - Edges and vert-pairs treated the same way.
724                                                  * - Point the Y axis along the edge vector (towards the active vertex).
725                                                  * - Point the Z axis outwards (the same direction as the normals).
726                                                  *
727                                                  * \note Z points outwards - along the normal.
728                                                  * take care making changes here, see: T38592, T43708
729                                                  */
730
731                                                 /* be deterministic where possible and ensure v_pair[0] is active */
732                                                 if (BM_mesh_active_vert_get(em->bm) == v_pair[1]) {
733                                                         v_pair_swap = true;
734                                                 }
735                                                 else if (eed && BM_edge_is_boundary(eed)) {
736                                                         /* predictable direction for boundary edges */
737                                                         if (eed->l->v != v_pair[0]) {
738                                                                 v_pair_swap = true;
739                                                         }
740                                                 }
741
742                                                 if (v_pair_swap) {
743                                                         SWAP(BMVert *, v_pair[0], v_pair[1]);
744                                                 }
745
746                                                 add_v3_v3v3(normal, v_pair[0]->no, v_pair[1]->no);
747                                                 sub_v3_v3v3(plane, v_pair[0]->co, v_pair[1]->co);
748                                                 /* flip the plane normal so we point outwards */
749                                                 negate_v3(plane);
750                                         }
751
752                                         result = ORIENTATION_EDGE;
753                                 }
754                                 else if (em->bm->totvertsel == 1) {
755                                         BMVert *v = NULL;
756
757                                         if (bm_mesh_verts_select_get_n(em->bm, &v, 1) == 1) {
758                                                 copy_v3_v3(normal, v->no);
759                                                 BMEdge *e_pair[2];
760
761                                                 if (BM_vert_edge_pair(v, &e_pair[0], &e_pair[1])) {
762                                                         bool v_pair_swap = false;
763                                                         BMVert *v_pair[2] = {BM_edge_other_vert(e_pair[0], v), BM_edge_other_vert(e_pair[1], v)};
764                                                         float dir_pair[2][3];
765
766                                                         if (BM_edge_is_boundary(e_pair[0])) {
767                                                                 if (e_pair[0]->l->v != v) {
768                                                                         v_pair_swap = true;
769                                                                 }
770                                                         }
771                                                         else {
772                                                                 if (BM_edge_calc_length_squared(e_pair[0]) < BM_edge_calc_length_squared(e_pair[1])) {
773                                                                         v_pair_swap = true;
774                                                                 }
775                                                         }
776
777                                                         if (v_pair_swap) {
778                                                                 SWAP(BMVert *, v_pair[0], v_pair[1]);
779                                                         }
780
781                                                         sub_v3_v3v3(dir_pair[0], v->co, v_pair[0]->co);
782                                                         sub_v3_v3v3(dir_pair[1], v_pair[1]->co, v->co);
783                                                         normalize_v3(dir_pair[0]);
784                                                         normalize_v3(dir_pair[1]);
785
786                                                         add_v3_v3v3(plane, dir_pair[0], dir_pair[1]);
787                                                 }
788                                         }
789
790                                         if (is_zero_v3(plane)) {
791                                                 result = ORIENTATION_VERT;
792                                         }
793                                         else {
794                                                 result = ORIENTATION_EDGE;
795                                         }
796                                 }
797                                 else if (em->bm->totvertsel > 3) {
798                                         BMIter iter;
799                                         BMVert *v;
800
801                                         zero_v3(normal);
802
803                                         BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
804                                                 if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
805                                                         add_v3_v3(normal, v->no);
806                                                 }
807                                         }
808                                         normalize_v3(normal);
809                                         result = ORIENTATION_VERT;
810                                 }
811                         }
812
813                         /* not needed but this matches 2.68 and older behavior */
814                         negate_v3(plane);
815
816                 } /* end editmesh */
817                 else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
818                         Curve *cu = obedit->data;
819                         Nurb *nu = NULL;
820                         BezTriple *bezt = NULL;
821                         int a;
822                         ListBase *nurbs = BKE_curve_editNurbs_get(cu);
823
824                         if (activeOnly && BKE_curve_nurb_vert_active_get(cu, &nu, (void *)&bezt)) {
825                                 if (nu->type == CU_BEZIER) {
826                                         BKE_nurb_bezt_calc_normal(nu, bezt, normal);
827                                         BKE_nurb_bezt_calc_plane(nu, bezt, plane);
828                                 }
829                         }
830                         else {
831                                 const bool use_handle = (cu->drawflag & CU_HIDE_HANDLES) == 0;
832
833                                 for (nu = nurbs->first; nu; nu = nu->next) {
834                                         /* only bezier has a normal */
835                                         if (nu->type == CU_BEZIER) {
836                                                 bezt = nu->bezt;
837                                                 a = nu->pntsu;
838                                                 while (a--) {
839                                                         short flag = 0;
840
841 #define SEL_F1 (1 << 0)
842 #define SEL_F2 (1 << 1)
843 #define SEL_F3 (1 << 2)
844
845                                                         if (use_handle) {
846                                                                 if (bezt->f1 & SELECT) flag |= SEL_F1;
847                                                                 if (bezt->f2 & SELECT) flag |= SEL_F2;
848                                                                 if (bezt->f3 & SELECT) flag |= SEL_F3;
849                                                         }
850                                                         else {
851                                                                 flag = (bezt->f2 & SELECT) ? (SEL_F1 | SEL_F2 | SEL_F3) : 0;
852                                                         }
853
854                                                         /* exception */
855                                                         if (flag) {
856                                                                 float tvec[3];
857                                                                 if ((around == V3D_AROUND_LOCAL_ORIGINS) ||
858                                                                     ELEM(flag, SEL_F2, SEL_F1 | SEL_F3, SEL_F1 | SEL_F2 | SEL_F3))
859                                                                 {
860                                                                         BKE_nurb_bezt_calc_normal(nu, bezt, tvec);
861                                                                         add_v3_v3(normal, tvec);
862                                                                 }
863                                                                 else {
864                                                                         /* ignore bezt->f2 in this case */
865                                                                         if (flag & SEL_F1) {
866                                                                                 sub_v3_v3v3(tvec, bezt->vec[0], bezt->vec[1]);
867                                                                                 normalize_v3(tvec);
868                                                                                 add_v3_v3(normal, tvec);
869                                                                         }
870                                                                         if (flag & SEL_F3) {
871                                                                                 sub_v3_v3v3(tvec, bezt->vec[1], bezt->vec[2]);
872                                                                                 normalize_v3(tvec);
873                                                                                 add_v3_v3(normal, tvec);
874                                                                         }
875                                                                 }
876
877                                                                 BKE_nurb_bezt_calc_plane(nu, bezt, tvec);
878                                                                 add_v3_v3(plane, tvec);
879                                                         }
880
881 #undef SEL_F1
882 #undef SEL_F2
883 #undef SEL_F3
884
885                                                         bezt++;
886                                                 }
887                                         }
888                                 }
889                         }
890                         
891                         if (!is_zero_v3(normal)) {
892                                 result = ORIENTATION_FACE;
893                         }
894                 }
895                 else if (obedit->type == OB_MBALL) {
896                         MetaBall *mb = obedit->data;
897                         MetaElem *ml;
898                         bool ok = false;
899                         float tmat[3][3];
900                         
901                         if (activeOnly && (ml = mb->lastelem)) {
902                                 quat_to_mat3(tmat, ml->quat);
903                                 add_v3_v3(normal, tmat[2]);
904                                 add_v3_v3(plane, tmat[1]);
905                                 ok = true;
906                         }
907                         else {
908                                 for (ml = mb->editelems->first; ml; ml = ml->next) {
909                                         if (ml->flag & SELECT) {
910                                                 quat_to_mat3(tmat, ml->quat);
911                                                 add_v3_v3(normal, tmat[2]);
912                                                 add_v3_v3(plane, tmat[1]);
913                                                 ok = true;
914                                         }
915                                 }
916                         }
917
918                         if (ok) {
919                                 if (!is_zero_v3(plane)) {
920                                         result = ORIENTATION_FACE;
921                                 }
922                         }
923                 }
924                 else if (obedit->type == OB_ARMATURE) {
925                         bArmature *arm = obedit->data;
926                         EditBone *ebone;
927                         bool ok = false;
928                         float tmat[3][3];
929
930                         if (activeOnly && (ebone = arm->act_edbone)) {
931                                 ED_armature_ebone_to_mat3(ebone, tmat);
932                                 add_v3_v3(normal, tmat[2]);
933                                 add_v3_v3(plane, tmat[1]);
934                                 ok = true;
935                         }
936                         else {
937                                 for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
938                                         if (arm->layer & ebone->layer) {
939                                                 if (ebone->flag & BONE_SELECTED) {
940                                                         ED_armature_ebone_to_mat3(ebone, tmat);
941                                                         add_v3_v3(normal, tmat[2]);
942                                                         add_v3_v3(plane, tmat[1]);
943                                                         ok = true;
944                                                 }
945                                         }
946                                 }
947                         }
948                         
949                         if (ok) {
950                                 if (!is_zero_v3(plane)) {
951                                         result = ORIENTATION_EDGE;
952                                 }
953                         }
954                 }
955
956                 /* Vectors from edges don't need the special transpose inverse multiplication */
957                 if (result == ORIENTATION_EDGE) {
958                         float tvec[3];
959
960                         mul_mat3_m4_v3(ob->obmat, normal);
961                         mul_mat3_m4_v3(ob->obmat, plane);
962
963                         /* align normal to edge direction (so normal is perpendicular to the plane).
964                          * 'ORIENTATION_EDGE' will do the other way around.
965                          * This has to be done **after** applying obmat, see T45775! */
966                         project_v3_v3v3(tvec, normal, plane);
967                         sub_v3_v3(normal, tvec);
968                 }
969                 else {
970                         mul_m3_v3(mat, normal);
971                         mul_m3_v3(mat, plane);
972                 }
973         }
974         else if (ob && (ob->mode & OB_MODE_POSE)) {
975                 bArmature *arm = ob->data;
976                 bPoseChannel *pchan;
977                 float imat[3][3], mat[3][3];
978                 bool ok = false;
979
980                 if (activeOnly && (pchan = BKE_pose_channel_active(ob))) {
981                         add_v3_v3(normal, pchan->pose_mat[2]);
982                         add_v3_v3(plane, pchan->pose_mat[1]);
983                         ok = true;
984                 }
985                 else {
986                         int totsel;
987
988                         totsel = count_bone_select(arm, &arm->bonebase, true);
989                         if (totsel) {
990                                 /* use channels to get stats */
991                                 for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
992                                         if (pchan->bone && pchan->bone->flag & BONE_TRANSFORM) {
993                                                 add_v3_v3(normal, pchan->pose_mat[2]);
994                                                 add_v3_v3(plane, pchan->pose_mat[1]);
995                                         }
996                                 }
997                                 ok = true;
998                         }
999                 }
1000
1001                 /* use for both active & all */
1002                 if (ok) {
1003                         /* we need the transpose of the inverse for a normal... */
1004                         copy_m3_m4(imat, ob->obmat);
1005                         
1006                         invert_m3_m3(mat, imat);
1007                         transpose_m3(mat);
1008                         mul_m3_v3(mat, normal);
1009                         mul_m3_v3(mat, plane);
1010                         
1011                         result = ORIENTATION_EDGE;
1012                 }
1013         }
1014         else if (ob && (ob->mode & (OB_MODE_ALL_PAINT | OB_MODE_PARTICLE_EDIT))) {
1015                 /* pass */
1016         }
1017         else {
1018                 /* we need the one selected object, if its not active */
1019                 View3D *v3d = CTX_wm_view3d(C);
1020                 ob = OBACT;
1021                 if (ob && (ob->flag & SELECT)) {
1022                         /* pass */
1023                 }
1024                 else {
1025                         /* first selected */
1026                         ob = NULL;
1027                         for (base = scene->base.first; base; base = base->next) {
1028                                 if (TESTBASELIB(v3d, base)) {
1029                                         ob = base->object;
1030                                         break;
1031                                 }
1032                         }
1033                 }
1034                 
1035                 if (ob) {
1036                         copy_v3_v3(normal, ob->obmat[2]);
1037                         copy_v3_v3(plane, ob->obmat[1]);
1038                 }
1039                 result = ORIENTATION_NORMAL;
1040         }
1041         
1042         return result;
1043 }
1044
1045 int getTransformOrientation(const bContext *C, float normal[3], float plane[3])
1046 {
1047         /* dummy value, not V3D_AROUND_ACTIVE and not V3D_AROUND_LOCAL_ORIGINS */
1048         short around = V3D_AROUND_CENTER_BOUNDS;
1049
1050         return getTransformOrientation_ex(C, normal, plane, around);
1051 }
1052
1053 void ED_getTransformOrientationMatrix(const bContext *C, float orientation_mat[3][3], const short around)
1054 {
1055         float normal[3] = {0.0, 0.0, 0.0};
1056         float plane[3] = {0.0, 0.0, 0.0};
1057
1058         int type;
1059
1060         type = getTransformOrientation_ex(C, normal, plane, around);
1061
1062         switch (type) {
1063                 case ORIENTATION_NORMAL:
1064                         if (createSpaceNormalTangent(orientation_mat, normal, plane) == 0) {
1065                                 type = ORIENTATION_NONE;
1066                         }
1067                         break;
1068                 case ORIENTATION_VERT:
1069                         if (createSpaceNormal(orientation_mat, normal) == 0) {
1070                                 type = ORIENTATION_NONE;
1071                         }
1072                         break;
1073                 case ORIENTATION_EDGE:
1074                         if (createSpaceNormalTangent(orientation_mat, normal, plane) == 0) {
1075                                 type = ORIENTATION_NONE;
1076                         }
1077                         break;
1078                 case ORIENTATION_FACE:
1079                         if (createSpaceNormalTangent(orientation_mat, normal, plane) == 0) {
1080                                 type = ORIENTATION_NONE;
1081                         }
1082                         break;
1083         }
1084
1085         if (type == ORIENTATION_NONE) {
1086                 unit_m3(orientation_mat);
1087         }
1088 }