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