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