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