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