Cleanup: trailing space
[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         Base *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 (ob && gimbal_axis(ob, t->spacemtx)) {
455                                 BLI_strncpy(t->spacename, IFACE_("gimbal"), sizeof(t->spacename));
456                                 break;
457                         }
458                         ATTR_FALLTHROUGH;  /* 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                         ATTR_FALLTHROUGH;  /* 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         Base *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[1]->no, v_pair[0]->no);
747                                                 sub_v3_v3v3(plane, v_pair[1]->co, v_pair[0]->co);
748
749                                                 if (normalize_v3(plane) != 0.0f) {
750                                                         /* For edges it'd important the resulting matrix can rotate around the edge,
751                                                          * project onto the plane so we can use a fallback value. */
752                                                         project_plane_normalized_v3_v3v3(normal, normal, plane);
753                                                         if (UNLIKELY(normalize_v3(normal) == 0.0f)) {
754                                                                 /* in the case the normal and plane are aligned,
755                                                                  * use a fallback normal which is orthogonal to the plane. */
756                                                                 ortho_v3_v3(normal, plane);
757                                                         }
758                                                 }
759                                         }
760
761                                         result = ORIENTATION_EDGE;
762                                 }
763                                 else if (em->bm->totvertsel == 1) {
764                                         BMVert *v = NULL;
765
766                                         if (bm_mesh_verts_select_get_n(em->bm, &v, 1) == 1) {
767                                                 copy_v3_v3(normal, v->no);
768                                                 BMEdge *e_pair[2];
769
770                                                 if (BM_vert_edge_pair(v, &e_pair[0], &e_pair[1])) {
771                                                         bool v_pair_swap = false;
772                                                         BMVert *v_pair[2] = {BM_edge_other_vert(e_pair[0], v), BM_edge_other_vert(e_pair[1], v)};
773                                                         float dir_pair[2][3];
774
775                                                         if (BM_edge_is_boundary(e_pair[0])) {
776                                                                 if (e_pair[0]->l->v != v) {
777                                                                         v_pair_swap = true;
778                                                                 }
779                                                         }
780                                                         else {
781                                                                 if (BM_edge_calc_length_squared(e_pair[0]) < BM_edge_calc_length_squared(e_pair[1])) {
782                                                                         v_pair_swap = true;
783                                                                 }
784                                                         }
785
786                                                         if (v_pair_swap) {
787                                                                 SWAP(BMVert *, v_pair[0], v_pair[1]);
788                                                         }
789
790                                                         sub_v3_v3v3(dir_pair[0], v->co, v_pair[0]->co);
791                                                         sub_v3_v3v3(dir_pair[1], v_pair[1]->co, v->co);
792                                                         normalize_v3(dir_pair[0]);
793                                                         normalize_v3(dir_pair[1]);
794
795                                                         add_v3_v3v3(plane, dir_pair[0], dir_pair[1]);
796                                                 }
797                                         }
798
799                                         if (is_zero_v3(plane)) {
800                                                 result = ORIENTATION_VERT;
801                                         }
802                                         else {
803                                                 result = ORIENTATION_EDGE;
804                                         }
805                                 }
806                                 else if (em->bm->totvertsel > 3) {
807                                         BMIter iter;
808                                         BMVert *v;
809
810                                         zero_v3(normal);
811
812                                         BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
813                                                 if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
814                                                         add_v3_v3(normal, v->no);
815                                                 }
816                                         }
817                                         normalize_v3(normal);
818                                         result = ORIENTATION_VERT;
819                                 }
820                         }
821
822                         /* not needed but this matches 2.68 and older behavior */
823                         negate_v3(plane);
824
825                 } /* end editmesh */
826                 else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
827                         Curve *cu = obedit->data;
828                         Nurb *nu = NULL;
829                         int a;
830                         ListBase *nurbs = BKE_curve_editNurbs_get(cu);
831
832                         void *vert_act = NULL;
833                         if (activeOnly && BKE_curve_nurb_vert_active_get(cu, &nu, &vert_act)) {
834                                 if (nu->type == CU_BEZIER) {
835                                         BezTriple *bezt = vert_act;
836                                         BKE_nurb_bezt_calc_normal(nu, bezt, normal);
837                                         BKE_nurb_bezt_calc_plane(nu, bezt, plane);
838                                 }
839                                 else {
840                                         BPoint *bp = vert_act;
841                                         BKE_nurb_bpoint_calc_normal(nu, bp, normal);
842                                         BKE_nurb_bpoint_calc_plane(nu, bp, plane);
843                                 }
844                         }
845                         else {
846                                 const bool use_handle = (cu->drawflag & CU_HIDE_HANDLES) == 0;
847
848                                 for (nu = nurbs->first; nu; nu = nu->next) {
849                                         /* only bezier has a normal */
850                                         if (nu->type == CU_BEZIER) {
851                                                 BezTriple *bezt = nu->bezt;
852                                                 a = nu->pntsu;
853                                                 while (a--) {
854                                                         short flag = 0;
855
856 #define SEL_F1 (1 << 0)
857 #define SEL_F2 (1 << 1)
858 #define SEL_F3 (1 << 2)
859
860                                                         if (use_handle) {
861                                                                 if (bezt->f1 & SELECT) flag |= SEL_F1;
862                                                                 if (bezt->f2 & SELECT) flag |= SEL_F2;
863                                                                 if (bezt->f3 & SELECT) flag |= SEL_F3;
864                                                         }
865                                                         else {
866                                                                 flag = (bezt->f2 & SELECT) ? (SEL_F1 | SEL_F2 | SEL_F3) : 0;
867                                                         }
868
869                                                         /* exception */
870                                                         if (flag) {
871                                                                 float tvec[3];
872                                                                 if ((around == V3D_AROUND_LOCAL_ORIGINS) ||
873                                                                     ELEM(flag, SEL_F2, SEL_F1 | SEL_F3, SEL_F1 | SEL_F2 | SEL_F3))
874                                                                 {
875                                                                         BKE_nurb_bezt_calc_normal(nu, bezt, tvec);
876                                                                         add_v3_v3(normal, tvec);
877                                                                 }
878                                                                 else {
879                                                                         /* ignore bezt->f2 in this case */
880                                                                         if (flag & SEL_F1) {
881                                                                                 sub_v3_v3v3(tvec, bezt->vec[0], bezt->vec[1]);
882                                                                                 normalize_v3(tvec);
883                                                                                 add_v3_v3(normal, tvec);
884                                                                         }
885                                                                         if (flag & SEL_F3) {
886                                                                                 sub_v3_v3v3(tvec, bezt->vec[1], bezt->vec[2]);
887                                                                                 normalize_v3(tvec);
888                                                                                 add_v3_v3(normal, tvec);
889                                                                         }
890                                                                 }
891
892                                                                 BKE_nurb_bezt_calc_plane(nu, bezt, tvec);
893                                                                 add_v3_v3(plane, tvec);
894                                                         }
895
896 #undef SEL_F1
897 #undef SEL_F2
898 #undef SEL_F3
899
900                                                         bezt++;
901                                                 }
902                                         }
903                                         else if (nu->bp && (nu->pntsv == 1)) {
904                                                 BPoint *bp = nu->bp;
905                                                 a = nu->pntsu;
906                                                 while (a--) {
907                                                         if (bp->f1 & SELECT) {
908                                                                 float tvec[3];
909
910                                                                 BPoint *bp_prev = BKE_nurb_bpoint_get_prev(nu, bp);
911                                                                 BPoint *bp_next = BKE_nurb_bpoint_get_next(nu, bp);
912
913                                                                 const bool is_prev_sel = bp_prev && (bp_prev->f1 & SELECT);
914                                                                 const bool is_next_sel = bp_next && (bp_next->f1 & SELECT);
915                                                                 if (is_prev_sel == false && is_next_sel == false) {
916                                                                         /* Isolated, add based on surrounding */
917                                                                         BKE_nurb_bpoint_calc_normal(nu, bp, tvec);
918                                                                         add_v3_v3(normal, tvec);
919                                                                 }
920                                                                 else if (is_next_sel) {
921                                                                         /* A segment, add the edge normal */
922                                                                         sub_v3_v3v3(tvec, bp->vec, bp_next->vec);
923                                                                         normalize_v3(tvec);
924                                                                         add_v3_v3(normal, tvec);
925                                                                 }
926
927                                                                 BKE_nurb_bpoint_calc_plane(nu, bp, tvec);
928                                                                 add_v3_v3(plane, tvec);
929                                                         }
930                                                         bp++;
931                                                 }
932                                         }
933                                 }
934                         }
935
936                         if (!is_zero_v3(normal)) {
937                                 result = ORIENTATION_FACE;
938                         }
939                 }
940                 else if (obedit->type == OB_MBALL) {
941                         MetaBall *mb = obedit->data;
942                         MetaElem *ml;
943                         bool ok = false;
944                         float tmat[3][3];
945
946                         if (activeOnly && (ml = mb->lastelem)) {
947                                 quat_to_mat3(tmat, ml->quat);
948                                 add_v3_v3(normal, tmat[2]);
949                                 add_v3_v3(plane, tmat[1]);
950                                 ok = true;
951                         }
952                         else {
953                                 for (ml = mb->editelems->first; ml; ml = ml->next) {
954                                         if (ml->flag & SELECT) {
955                                                 quat_to_mat3(tmat, ml->quat);
956                                                 add_v3_v3(normal, tmat[2]);
957                                                 add_v3_v3(plane, tmat[1]);
958                                                 ok = true;
959                                         }
960                                 }
961                         }
962
963                         if (ok) {
964                                 if (!is_zero_v3(plane)) {
965                                         result = ORIENTATION_FACE;
966                                 }
967                         }
968                 }
969                 else if (obedit->type == OB_ARMATURE) {
970                         bArmature *arm = obedit->data;
971                         EditBone *ebone;
972                         bool ok = false;
973                         float tmat[3][3];
974
975                         if (activeOnly && (ebone = arm->act_edbone)) {
976                                 ED_armature_ebone_to_mat3(ebone, tmat);
977                                 add_v3_v3(normal, tmat[2]);
978                                 add_v3_v3(plane, tmat[1]);
979                                 ok = true;
980                         }
981                         else {
982                                 for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
983                                         if (arm->layer & ebone->layer) {
984                                                 if (ebone->flag & BONE_SELECTED) {
985                                                         ED_armature_ebone_to_mat3(ebone, tmat);
986                                                         add_v3_v3(normal, tmat[2]);
987                                                         add_v3_v3(plane, tmat[1]);
988                                                         ok = true;
989                                                 }
990                                         }
991                                 }
992                         }
993
994                         if (ok) {
995                                 if (!is_zero_v3(plane)) {
996                                         result = ORIENTATION_EDGE;
997                                 }
998                         }
999                 }
1000
1001                 /* Vectors from edges don't need the special transpose inverse multiplication */
1002                 if (result == ORIENTATION_EDGE) {
1003                         float tvec[3];
1004
1005                         mul_mat3_m4_v3(ob->obmat, normal);
1006                         mul_mat3_m4_v3(ob->obmat, plane);
1007
1008                         /* align normal to edge direction (so normal is perpendicular to the plane).
1009                          * 'ORIENTATION_EDGE' will do the other way around.
1010                          * This has to be done **after** applying obmat, see T45775! */
1011                         project_v3_v3v3(tvec, normal, plane);
1012                         sub_v3_v3(normal, tvec);
1013                 }
1014                 else {
1015                         mul_m3_v3(mat, normal);
1016                         mul_m3_v3(mat, plane);
1017                 }
1018         }
1019         else if (ob && (ob->mode & OB_MODE_POSE)) {
1020                 bArmature *arm = ob->data;
1021                 bPoseChannel *pchan;
1022                 float imat[3][3], mat[3][3];
1023                 bool ok = false;
1024
1025                 if (activeOnly && (pchan = BKE_pose_channel_active(ob))) {
1026                         add_v3_v3(normal, pchan->pose_mat[2]);
1027                         add_v3_v3(plane, pchan->pose_mat[1]);
1028                         ok = true;
1029                 }
1030                 else {
1031                         int totsel;
1032
1033                         totsel = count_bone_select(arm, &arm->bonebase, true);
1034                         if (totsel) {
1035                                 /* use channels to get stats */
1036                                 for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
1037                                         if (pchan->bone && pchan->bone->flag & BONE_TRANSFORM) {
1038                                                 add_v3_v3(normal, pchan->pose_mat[2]);
1039                                                 add_v3_v3(plane, pchan->pose_mat[1]);
1040                                         }
1041                                 }
1042                                 ok = true;
1043                         }
1044                 }
1045
1046                 /* use for both active & all */
1047                 if (ok) {
1048                         /* we need the transpose of the inverse for a normal... */
1049                         copy_m3_m4(imat, ob->obmat);
1050
1051                         invert_m3_m3(mat, imat);
1052                         transpose_m3(mat);
1053                         mul_m3_v3(mat, normal);
1054                         mul_m3_v3(mat, plane);
1055
1056                         result = ORIENTATION_EDGE;
1057                 }
1058         }
1059         else if (ob && (ob->mode & (OB_MODE_ALL_PAINT | OB_MODE_PARTICLE_EDIT))) {
1060                 /* pass */
1061         }
1062         else {
1063                 /* we need the one selected object, if its not active */
1064                 View3D *v3d = CTX_wm_view3d(C);
1065                 ob = OBACT;
1066                 if (ob && (ob->flag & SELECT)) {
1067                         /* pass */
1068                 }
1069                 else {
1070                         /* first selected */
1071                         ob = NULL;
1072                         for (base = scene->base.first; base; base = base->next) {
1073                                 if (TESTBASELIB(v3d, base)) {
1074                                         ob = base->object;
1075                                         break;
1076                                 }
1077                         }
1078                 }
1079
1080                 if (ob) {
1081                         copy_v3_v3(normal, ob->obmat[2]);
1082                         copy_v3_v3(plane, ob->obmat[1]);
1083                 }
1084                 result = ORIENTATION_NORMAL;
1085         }
1086
1087         return result;
1088 }
1089
1090 int getTransformOrientation(const bContext *C, float normal[3], float plane[3])
1091 {
1092         /* dummy value, not V3D_AROUND_ACTIVE and not V3D_AROUND_LOCAL_ORIGINS */
1093         short around = V3D_AROUND_CENTER_BOUNDS;
1094
1095         return getTransformOrientation_ex(C, normal, plane, around);
1096 }
1097
1098 void ED_getTransformOrientationMatrix(const bContext *C, float orientation_mat[3][3], const short around)
1099 {
1100         float normal[3] = {0.0, 0.0, 0.0};
1101         float plane[3] = {0.0, 0.0, 0.0};
1102
1103         int type;
1104
1105         type = getTransformOrientation_ex(C, normal, plane, around);
1106
1107         switch (type) {
1108                 case ORIENTATION_NORMAL:
1109                         if (createSpaceNormalTangent(orientation_mat, normal, plane) == 0) {
1110                                 type = ORIENTATION_NONE;
1111                         }
1112                         break;
1113                 case ORIENTATION_VERT:
1114                         if (createSpaceNormal(orientation_mat, normal) == 0) {
1115                                 type = ORIENTATION_NONE;
1116                         }
1117                         break;
1118                 case ORIENTATION_EDGE:
1119                         if (createSpaceNormalTangent(orientation_mat, normal, plane) == 0) {
1120                                 type = ORIENTATION_NONE;
1121                         }
1122                         break;
1123                 case ORIENTATION_FACE:
1124                         if (createSpaceNormalTangent(orientation_mat, normal, plane) == 0) {
1125                                 type = ORIENTATION_NONE;
1126                         }
1127                         break;
1128         }
1129
1130         if (type == ORIENTATION_NONE) {
1131                 unit_m3(orientation_mat);
1132         }
1133 }