Fix T60015: snap to grid - snaps only to largest increment
[blender.git] / source / blender / editors / space_view3d / view3d_snap.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/space_view3d/view3d_snap.c
29  *  \ingroup spview3d
30  */
31
32
33 #include "MEM_guardedalloc.h"
34
35 #include "DNA_armature_types.h"
36 #include "DNA_object_types.h"
37
38 #include "BLI_blenlib.h"
39 #include "BLI_utildefines.h"
40 #include "BLI_math.h"
41
42 #include "BKE_action.h"
43 #include "BKE_armature.h"
44 #include "BKE_context.h"
45 #include "BKE_editmesh.h"
46 #include "BKE_layer.h"
47 #include "BKE_main.h"
48 #include "BKE_mball.h"
49 #include "BKE_object.h"
50 #include "BKE_report.h"
51 #include "BKE_tracking.h"
52
53 #include "DEG_depsgraph.h"
54 #include "DEG_depsgraph_query.h"
55
56 #include "WM_api.h"
57 #include "WM_types.h"
58
59 #include "RNA_access.h"
60 #include "RNA_define.h"
61
62 #include "ED_object.h"
63 #include "ED_transverts.h"
64 #include "ED_keyframing.h"
65 #include "ED_screen.h"
66
67 #include "view3d_intern.h"
68
69 static bool snap_curs_to_sel_ex(bContext *C, float cursor[3]);
70 static bool snap_calc_active_center(bContext *C, const bool select_only, float r_center[3]);
71
72
73 /* *********************** operators ******************** */
74
75 /** Snaps every individual object center to its nearest point on the grid. **/
76 static int snap_sel_to_grid_exec(bContext *C, wmOperator *UNUSED(op))
77 {
78         Depsgraph *depsgraph = CTX_data_depsgraph(C);
79         ViewLayer *view_layer_eval = DEG_get_evaluated_view_layer(depsgraph);
80         Object *obedit = CTX_data_edit_object(C);
81         Scene *scene = CTX_data_scene(C);
82         RegionView3D *rv3d = CTX_wm_region_data(C);
83         View3D *v3d = CTX_wm_view3d(C);
84         TransVertStore tvs = {NULL};
85         TransVert *tv;
86         float gridf, imat[3][3], bmat[3][3], vec[3];
87         int a;
88
89         gridf = ED_view3d_grid_view_scale(scene, v3d, rv3d, NULL);
90
91         if (obedit) {
92                 ViewLayer *view_layer = CTX_data_view_layer(C);
93                 uint objects_len = 0;
94                 Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
95                 for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
96                         obedit = objects[ob_index];
97
98                         if (obedit->type == OB_MESH) {
99                                 BMEditMesh *em = BKE_editmesh_from_object(obedit);
100
101                                 if (em->bm->totvertsel == 0) {
102                                         continue;
103                                 }
104                         }
105
106                         if (ED_transverts_check_obedit(obedit)) {
107                                 ED_transverts_create_from_obedit(&tvs, obedit, 0);
108                         }
109
110                         if (tvs.transverts_tot != 0) {
111                                 copy_m3_m4(bmat, obedit->obmat);
112                                 invert_m3_m3(imat, bmat);
113
114                                 tv = tvs.transverts;
115                                 for (a = 0; a < tvs.transverts_tot; a++, tv++) {
116                                         copy_v3_v3(vec, tv->loc);
117                                         mul_m3_v3(bmat, vec);
118                                         add_v3_v3(vec, obedit->obmat[3]);
119                                         vec[0] = gridf * floorf(0.5f + vec[0] / gridf);
120                                         vec[1] = gridf * floorf(0.5f + vec[1] / gridf);
121                                         vec[2] = gridf * floorf(0.5f + vec[2] / gridf);
122                                         sub_v3_v3(vec, obedit->obmat[3]);
123
124                                         mul_m3_v3(imat, vec);
125                                         copy_v3_v3(tv->loc, vec);
126                                 }
127                                 ED_transverts_update_obedit(&tvs, obedit);
128                         }
129                         ED_transverts_free(&tvs);
130                 }
131                 MEM_freeN(objects);
132         }
133         else {
134                 struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID);
135
136                 FOREACH_SELECTED_EDITABLE_OBJECT_BEGIN(view_layer_eval, v3d, ob_eval)
137                 {
138                         Object *ob = DEG_get_original_object(ob_eval);
139                         if (ob->mode & OB_MODE_POSE) {
140                                 bPoseChannel *pchan_eval;
141                                 bArmature *arm_eval = ob_eval->data;
142
143                                 invert_m4_m4(ob_eval->imat, ob_eval->obmat);
144
145                                 for (pchan_eval = ob_eval->pose->chanbase.first; pchan_eval; pchan_eval = pchan_eval->next) {
146                                         if (pchan_eval->bone->flag & BONE_SELECTED) {
147                                                 if (pchan_eval->bone->layer & arm_eval->layer) {
148                                                         if ((pchan_eval->bone->flag & BONE_CONNECTED) == 0) {
149                                                                 float nLoc[3];
150
151                                                                 /* get nearest grid point to snap to */
152                                                                 copy_v3_v3(nLoc, pchan_eval->pose_mat[3]);
153                                                                 /* We must operate in world space! */
154                                                                 mul_m4_v3(ob_eval->obmat, nLoc);
155                                                                 vec[0] = gridf * floorf(0.5f + nLoc[0] / gridf);
156                                                                 vec[1] = gridf * floorf(0.5f + nLoc[1] / gridf);
157                                                                 vec[2] = gridf * floorf(0.5f + nLoc[2] / gridf);
158                                                                 /* Back in object space... */
159                                                                 mul_m4_v3(ob_eval->imat, vec);
160
161                                                                 /* Get location of grid point in pose space. */
162                                                                 BKE_armature_loc_pose_to_bone(pchan_eval, vec, vec);
163
164                                                                 /* adjust location on the original pchan*/
165                                                                 bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, pchan_eval->name);
166                                                                 if ((pchan->protectflag & OB_LOCK_LOCX) == 0)
167                                                                         pchan->loc[0] = vec[0];
168                                                                 if ((pchan->protectflag & OB_LOCK_LOCY) == 0)
169                                                                         pchan->loc[1] = vec[1];
170                                                                 if ((pchan->protectflag & OB_LOCK_LOCZ) == 0)
171                                                                         pchan->loc[2] = vec[2];
172
173                                                                 /* auto-keyframing */
174                                                                 ED_autokeyframe_pchan(C, scene, ob, pchan, ks);
175                                                         }
176                                                         /* if the bone has a parent and is connected to the parent,
177                                                          * don't do anything - will break chain unless we do auto-ik.
178                                                          */
179                                                 }
180                                         }
181                                 }
182                                 ob->pose->flag |= (POSE_LOCKED | POSE_DO_UNLOCK);
183
184                                 DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
185                         }
186                         else {
187                                 vec[0] = -ob_eval->obmat[3][0] + gridf * floorf(0.5f + ob_eval->obmat[3][0] / gridf);
188                                 vec[1] = -ob_eval->obmat[3][1] + gridf * floorf(0.5f + ob_eval->obmat[3][1] / gridf);
189                                 vec[2] = -ob_eval->obmat[3][2] + gridf * floorf(0.5f + ob_eval->obmat[3][2] / gridf);
190
191                                 if (ob->parent) {
192                                         float originmat[3][3];
193                                         BKE_object_where_is_calc_ex(depsgraph, scene, NULL, ob, originmat);
194
195                                         invert_m3_m3(imat, originmat);
196                                         mul_m3_v3(imat, vec);
197                                 }
198                                 if ((ob->protectflag & OB_LOCK_LOCX) == 0)
199                                         ob->loc[0] = ob_eval->loc[0] + vec[0];
200                                 if ((ob->protectflag & OB_LOCK_LOCY) == 0)
201                                         ob->loc[1] = ob_eval->loc[1] + vec[1];
202                                 if ((ob->protectflag & OB_LOCK_LOCZ) == 0)
203                                         ob->loc[2] = ob_eval->loc[2] + vec[2];
204
205                                 /* auto-keyframing */
206                                 ED_autokeyframe_object(C, scene, ob, ks);
207
208                                 DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
209                         }
210                 }
211                 FOREACH_SELECTED_EDITABLE_OBJECT_END;
212         }
213
214         WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
215
216         return OPERATOR_FINISHED;
217 }
218
219 void VIEW3D_OT_snap_selected_to_grid(wmOperatorType *ot)
220 {
221         /* identifiers */
222         ot->name = "Snap Selection to Grid";
223         ot->description = "Snap selected item(s) to their nearest grid division";
224         ot->idname = "VIEW3D_OT_snap_selected_to_grid";
225
226         /* api callbacks */
227         ot->exec = snap_sel_to_grid_exec;
228         ot->poll = ED_operator_region_view3d_active;
229
230         /* flags */
231         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
232 }
233
234 /* *************************************************** */
235
236 /** Snaps the selection as a whole (use_offset=true) or each selected object to the given location.
237  *
238  * \param snap_target_global: a location in global space to snap to (eg. 3D cursor or active object).
239  * \param use_offset: if the selected objects should maintain their relative offsets and be snapped by the selection
240  *                    pivot point (median, active), or if every object origin should be snapped to the given location.
241 **/
242 static int snap_selected_to_location(bContext *C, const float snap_target_global[3], const bool use_offset)
243 {
244         Depsgraph *depsgraph = CTX_data_depsgraph(C);
245         Scene *scene = CTX_data_scene(C);
246         Object *obedit = CTX_data_edit_object(C);
247         Object *obact = CTX_data_active_object(C);
248         View3D *v3d = CTX_wm_view3d(C);
249         TransVertStore tvs = {NULL};
250         TransVert *tv;
251         float imat[3][3], bmat[3][3];
252         float center_global[3];
253         float offset_global[3];
254         int a;
255
256         if (use_offset) {
257                 if ((v3d && scene->toolsettings->transform_pivot_point == V3D_AROUND_ACTIVE) &&
258                     snap_calc_active_center(C, true, center_global))
259                 {
260                         /* pass */
261                 }
262                 else {
263                         snap_curs_to_sel_ex(C, center_global);
264                 }
265                 sub_v3_v3v3(offset_global, snap_target_global, center_global);
266         }
267
268         if (obedit) {
269                 float snap_target_local[3];
270                 ViewLayer *view_layer = CTX_data_view_layer(C);
271                 uint objects_len = 0;
272                 Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
273                 for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
274                         obedit = objects[ob_index];
275
276                         if (obedit->type == OB_MESH) {
277                                 BMEditMesh *em = BKE_editmesh_from_object(obedit);
278
279                                 if (em->bm->totvertsel == 0) {
280                                         continue;
281                                 }
282                         }
283
284                         if (ED_transverts_check_obedit(obedit)) {
285                                 ED_transverts_create_from_obedit(&tvs, obedit, 0);
286                         }
287
288                         if (tvs.transverts_tot != 0) {
289                                 copy_m3_m4(bmat, obedit->obmat);
290                                 invert_m3_m3(imat, bmat);
291
292                                 /* get the cursor in object space */
293                                 sub_v3_v3v3(snap_target_local, snap_target_global, obedit->obmat[3]);
294                                 mul_m3_v3(imat, snap_target_local);
295
296                                 if (use_offset) {
297                                         float offset_local[3];
298
299                                         mul_v3_m3v3(offset_local, imat, offset_global);
300
301                                         tv = tvs.transverts;
302                                         for (a = 0; a < tvs.transverts_tot; a++, tv++) {
303                                                 add_v3_v3(tv->loc, offset_local);
304                                         }
305                                 }
306                                 else {
307                                         tv = tvs.transverts;
308                                         for (a = 0; a < tvs.transverts_tot; a++, tv++) {
309                                                 copy_v3_v3(tv->loc, snap_target_local);
310                                         }
311                                 }
312                                 ED_transverts_update_obedit(&tvs, obedit);
313                         }
314                         ED_transverts_free(&tvs);
315                 }
316                 MEM_freeN(objects);
317         }
318         else if (obact && (obact->mode & OB_MODE_POSE)) {
319                 struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID);
320                 CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
321                 {
322                         bPoseChannel *pchan;
323                         bArmature *arm = ob->data;
324                         float snap_target_local[3];
325
326                         invert_m4_m4(ob->imat, ob->obmat);
327                         mul_v3_m4v3(snap_target_local, ob->imat, snap_target_global);
328
329                         for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
330                                 if ((pchan->bone->flag & BONE_SELECTED) &&
331                                     (PBONE_VISIBLE(arm, pchan->bone)) &&
332                                     /* if the bone has a parent and is connected to the parent,
333                                      * don't do anything - will break chain unless we do auto-ik.
334                                      */
335                                     (pchan->bone->flag & BONE_CONNECTED) == 0)
336                                 {
337                                         pchan->bone->flag |= BONE_TRANSFORM;
338                                 }
339                                 else {
340                                         pchan->bone->flag &= ~BONE_TRANSFORM;
341                                 }
342                         }
343
344                         for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
345                                 if ((pchan->bone->flag & BONE_TRANSFORM) &&
346                                     /* check that our parents not transformed (if we have one) */
347                                     ((pchan->bone->parent &&
348                                       BKE_armature_bone_flag_test_recursive(pchan->bone->parent, BONE_TRANSFORM)) == 0))
349                                 {
350                                         /* Get position in pchan (pose) space. */
351                                         float cursor_pose[3];
352
353                                         if (use_offset) {
354                                                 mul_v3_m4v3(cursor_pose, ob->obmat, pchan->pose_mat[3]);
355                                                 add_v3_v3(cursor_pose, offset_global);
356
357                                                 mul_m4_v3(ob->imat, cursor_pose);
358                                                 BKE_armature_loc_pose_to_bone(pchan, cursor_pose, cursor_pose);
359                                         }
360                                         else {
361                                                 BKE_armature_loc_pose_to_bone(pchan, snap_target_local, cursor_pose);
362                                         }
363
364                                         /* copy new position */
365                                         if ((pchan->protectflag & OB_LOCK_LOCX) == 0)
366                                                 pchan->loc[0] = cursor_pose[0];
367                                         if ((pchan->protectflag & OB_LOCK_LOCY) == 0)
368                                                 pchan->loc[1] = cursor_pose[1];
369                                         if ((pchan->protectflag & OB_LOCK_LOCZ) == 0)
370                                                 pchan->loc[2] = cursor_pose[2];
371
372                                         /* auto-keyframing */
373                                         ED_autokeyframe_pchan(C, scene, ob, pchan, ks);
374                                 }
375                         }
376
377                         for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
378                                 pchan->bone->flag &= ~BONE_TRANSFORM;
379                         }
380
381                         ob->pose->flag |= (POSE_LOCKED | POSE_DO_UNLOCK);
382
383                         DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
384                 }
385                 CTX_DATA_END;
386         }
387         else {
388                 struct KeyingSet *ks = ANIM_get_keyingset_for_autokeying(scene, ANIM_KS_LOCATION_ID);
389                 Main *bmain = CTX_data_main(C);
390
391                 ListBase ctx_data_list;
392                 CollectionPointerLink *ctx_ob;
393                 Object *ob;
394
395                 CTX_data_selected_editable_objects(C, &ctx_data_list);
396
397                 /* reset flags */
398                 for (ob = bmain->object.first; ob; ob = ob->id.next) {
399                         ob->flag &= ~OB_DONE;
400                 }
401
402                 /* tag objects we're transforming */
403                 for (ctx_ob = ctx_data_list.first; ctx_ob; ctx_ob = ctx_ob->next) {
404                         ob = ctx_ob->ptr.data;
405                         ob->flag |= OB_DONE;
406                 }
407
408                 for (ctx_ob = ctx_data_list.first; ctx_ob; ctx_ob = ctx_ob->next) {
409                         ob = ctx_ob->ptr.data;
410
411                         if ((ob->parent && BKE_object_flag_test_recursive(ob->parent, OB_DONE)) == 0) {
412
413                                 float cursor_parent[3];  /* parent-relative */
414
415                                 if (use_offset) {
416                                         add_v3_v3v3(cursor_parent, ob->obmat[3], offset_global);
417                                 }
418                                 else {
419                                         copy_v3_v3(cursor_parent, snap_target_global);
420                                 }
421
422                                 sub_v3_v3(cursor_parent, ob->obmat[3]);
423
424                                 if (ob->parent) {
425                                         float originmat[3][3];
426                                         BKE_object_where_is_calc_ex(depsgraph, scene, NULL, ob, originmat);
427
428                                         invert_m3_m3(imat, originmat);
429                                         mul_m3_v3(imat, cursor_parent);
430                                 }
431                                 if ((ob->protectflag & OB_LOCK_LOCX) == 0)
432                                         ob->loc[0] += cursor_parent[0];
433                                 if ((ob->protectflag & OB_LOCK_LOCY) == 0)
434                                         ob->loc[1] += cursor_parent[1];
435                                 if ((ob->protectflag & OB_LOCK_LOCZ) == 0)
436                                         ob->loc[2] += cursor_parent[2];
437
438                                 /* auto-keyframing */
439                                 ED_autokeyframe_object(C, scene, ob, ks);
440
441                                 DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
442                         }
443                 }
444
445                 BLI_freelistN(&ctx_data_list);
446         }
447
448         WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
449
450         return OPERATOR_FINISHED;
451 }
452
453 static int snap_selected_to_cursor_exec(bContext *C, wmOperator *op)
454 {
455         const bool use_offset = RNA_boolean_get(op->ptr, "use_offset");
456
457         Scene *scene = CTX_data_scene(C);
458
459         const float *snap_target_global = scene->cursor.location;
460
461         return snap_selected_to_location(C, snap_target_global, use_offset);
462 }
463
464 void VIEW3D_OT_snap_selected_to_cursor(wmOperatorType *ot)
465 {
466         /* identifiers */
467         ot->name = "Snap Selection to Cursor";
468         ot->description = "Snap selected item(s) to the 3D cursor";
469         ot->idname = "VIEW3D_OT_snap_selected_to_cursor";
470
471         /* api callbacks */
472         ot->exec = snap_selected_to_cursor_exec;
473         ot->poll = ED_operator_view3d_active;
474
475         /* flags */
476         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
477
478         /* rna */
479         RNA_def_boolean(ot->srna, "use_offset", 1, "Offset",
480                 "If the selection should be snapped as a whole or by each object center");
481 }
482
483 /* *************************************************** */
484
485 /** Snaps each selected object to the location of the active selected object. **/
486 static int snap_selected_to_active_exec(bContext *C, wmOperator *op)
487 {
488         float snap_target_global[3];
489
490         if (snap_calc_active_center(C, false, snap_target_global) == false) {
491                 BKE_report(op->reports, RPT_ERROR, "No active element found!");
492                 return OPERATOR_CANCELLED;
493         }
494
495         return snap_selected_to_location(C, snap_target_global, false);
496 }
497
498 void VIEW3D_OT_snap_selected_to_active(wmOperatorType *ot)
499 {
500         /* identifiers */
501         ot->name = "Snap Selection to Active";
502         ot->description = "Snap selected item(s) to the active item";
503         ot->idname = "VIEW3D_OT_snap_selected_to_active";
504
505         /* api callbacks */
506         ot->exec = snap_selected_to_active_exec;
507         ot->poll = ED_operator_view3d_active;
508
509         /* flags */
510         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
511 }
512
513
514 /* *************************************************** */
515
516 /** Snaps the 3D cursor location to its nearest point on the grid. **/
517 static int snap_curs_to_grid_exec(bContext *C, wmOperator *UNUSED(op))
518 {
519         Scene *scene = CTX_data_scene(C);
520         RegionView3D *rv3d = CTX_wm_region_data(C);
521         View3D *v3d = CTX_wm_view3d(C);
522         float gridf, *curs;
523
524         gridf = ED_view3d_grid_view_scale(scene, v3d, rv3d, NULL);
525         curs = scene->cursor.location;
526
527         curs[0] = gridf * floorf(0.5f + curs[0] / gridf);
528         curs[1] = gridf * floorf(0.5f + curs[1] / gridf);
529         curs[2] = gridf * floorf(0.5f + curs[2] / gridf);
530
531         WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);  /* hrm */
532         DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
533
534         return OPERATOR_FINISHED;
535 }
536
537 void VIEW3D_OT_snap_cursor_to_grid(wmOperatorType *ot)
538 {
539         /* identifiers */
540         ot->name = "Snap Cursor to Grid";
541         ot->description = "Snap 3D cursor to the nearest grid division";
542         ot->idname = "VIEW3D_OT_snap_cursor_to_grid";
543
544         /* api callbacks */
545         ot->exec = snap_curs_to_grid_exec;
546         ot->poll = ED_operator_region_view3d_active;
547
548         /* flags */
549         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
550 }
551
552 /* **************************************************** */
553
554 /** Returns the center position of a tracking marker visible on the viewport (useful to snap to). **/
555 static void bundle_midpoint(Scene *scene, Object *ob, float r_vec[3])
556 {
557         MovieClip *clip = BKE_object_movieclip_get(scene, ob, false);
558         MovieTracking *tracking;
559         MovieTrackingObject *object;
560         bool ok = false;
561         float min[3], max[3], mat[4][4], pos[3], cammat[4][4];
562
563         if (!clip)
564                 return;
565
566         tracking = &clip->tracking;
567
568         copy_m4_m4(cammat, ob->obmat);
569
570         BKE_tracking_get_camera_object_matrix(scene, ob, mat);
571
572         INIT_MINMAX(min, max);
573
574         for (object = tracking->objects.first; object; object = object->next) {
575                 ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
576                 MovieTrackingTrack *track = tracksbase->first;
577                 float obmat[4][4];
578
579                 if (object->flag & TRACKING_OBJECT_CAMERA) {
580                         copy_m4_m4(obmat, mat);
581                 }
582                 else {
583                         float imat[4][4];
584
585                         BKE_tracking_camera_get_reconstructed_interpolate(tracking, object, scene->r.cfra, imat);
586                         invert_m4(imat);
587
588                         mul_m4_m4m4(obmat, cammat, imat);
589                 }
590
591                 while (track) {
592                         if ((track->flag & TRACK_HAS_BUNDLE) && TRACK_SELECTED(track)) {
593                                 ok = 1;
594                                 mul_v3_m4v3(pos, obmat, track->bundle_pos);
595                                 minmax_v3v3_v3(min, max, pos);
596                         }
597
598                         track = track->next;
599                 }
600         }
601
602         if (ok) {
603                 mid_v3_v3v3(r_vec, min, max);
604         }
605 }
606
607 /** Snaps the 3D cursor location to the median point of the selection. **/
608 static bool snap_curs_to_sel_ex(bContext *C, float cursor[3])
609 {
610         Depsgraph *depsgraph = CTX_data_depsgraph(C);
611         ViewLayer *view_layer_eval = DEG_get_evaluated_view_layer(depsgraph);
612         Object *obedit = CTX_data_edit_object(C);
613         Scene *scene = CTX_data_scene(C);
614         View3D *v3d = CTX_wm_view3d(C);
615         TransVertStore tvs = {NULL};
616         TransVert *tv;
617         float bmat[3][3], vec[3], min[3], max[3], centroid[3];
618         int count, a;
619
620         count = 0;
621         INIT_MINMAX(min, max);
622         zero_v3(centroid);
623
624         if (obedit) {
625                 int global_transverts_tot = 0;
626                 ViewLayer *view_layer = CTX_data_view_layer(C);
627                 uint objects_len = 0;
628                 Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
629                 for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
630                         obedit = objects[ob_index];
631
632                         /* We can do that quick check for meshes only... */
633                         if (obedit->type == OB_MESH) {
634                                 BMEditMesh *em = BKE_editmesh_from_object(obedit);
635
636                                 if (em->bm->totvertsel == 0) {
637                                         continue;
638                                 }
639                         }
640
641                         if (ED_transverts_check_obedit(obedit)) {
642                                 ED_transverts_create_from_obedit(&tvs, obedit, TM_ALL_JOINTS | TM_SKIP_HANDLES);
643                         }
644
645                         global_transverts_tot += tvs.transverts_tot;
646                         if (tvs.transverts_tot != 0) {
647                                 Object *obedit_eval = DEG_get_evaluated_object(depsgraph, obedit);
648                                 copy_m3_m4(bmat, obedit_eval->obmat);
649
650                                 tv = tvs.transverts;
651                                 for (a = 0; a < tvs.transverts_tot; a++, tv++) {
652                                         copy_v3_v3(vec, tv->loc);
653                                         mul_m3_v3(bmat, vec);
654                                         add_v3_v3(vec, obedit_eval->obmat[3]);
655                                         add_v3_v3(centroid, vec);
656                                         minmax_v3v3_v3(min, max, vec);
657                                 }
658                         }
659                         ED_transverts_free(&tvs);
660                 }
661                 MEM_freeN(objects);
662
663                 if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CENTER_MEDIAN) {
664                         mul_v3_fl(centroid, 1.0f / (float)global_transverts_tot);
665                         copy_v3_v3(cursor, centroid);
666                 }
667                 else {
668                         mid_v3_v3v3(cursor, min, max);
669                 }
670         }
671         else {
672                 Object *obact = CTX_data_active_object(C);
673
674                 if (obact && (obact->mode & OB_MODE_POSE)) {
675                         Object *obact_eval = DEG_get_evaluated_object(depsgraph, obact);
676                         bArmature *arm = obact_eval->data;
677                         bPoseChannel *pchan;
678                         for (pchan = obact_eval->pose->chanbase.first; pchan; pchan = pchan->next) {
679                                 if (arm->layer & pchan->bone->layer) {
680                                         if (pchan->bone->flag & BONE_SELECTED) {
681                                                 copy_v3_v3(vec, pchan->pose_head);
682                                                 mul_m4_v3(obact_eval->obmat, vec);
683                                                 add_v3_v3(centroid, vec);
684                                                 minmax_v3v3_v3(min, max, vec);
685                                                 count++;
686                                         }
687                                 }
688                         }
689                 }
690                 else {
691                         FOREACH_SELECTED_OBJECT_BEGIN(view_layer_eval, v3d, ob_eval)
692                         {
693                                 copy_v3_v3(vec, ob_eval->obmat[3]);
694
695                                 /* special case for camera -- snap to bundles */
696                                 if (ob_eval->type == OB_CAMERA) {
697                                         /* snap to bundles should happen only when bundles are visible */
698                                         if (v3d->flag2 & V3D_SHOW_RECONSTRUCTION) {
699                                                 bundle_midpoint(scene, DEG_get_original_object(ob_eval), vec);
700                                         }
701                                 }
702
703                                 add_v3_v3(centroid, vec);
704                                 minmax_v3v3_v3(min, max, vec);
705                                 count++;
706                         }
707                         FOREACH_SELECTED_OBJECT_END;
708                 }
709
710                 if (count == 0) {
711                         return false;
712                 }
713
714                 if (scene->toolsettings->transform_pivot_point == V3D_AROUND_CENTER_MEDIAN) {
715                         mul_v3_fl(centroid, 1.0f / (float)count);
716                         copy_v3_v3(cursor, centroid);
717                 }
718                 else {
719                         mid_v3_v3v3(cursor, min, max);
720                 }
721         }
722         return true;
723 }
724
725 static int snap_curs_to_sel_exec(bContext *C, wmOperator *UNUSED(op))
726 {
727         Scene *scene = CTX_data_scene(C);
728         if (snap_curs_to_sel_ex(C, scene->cursor.location)) {
729                 WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
730                 DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
731
732                 return OPERATOR_FINISHED;
733         }
734         else {
735                 return OPERATOR_CANCELLED;
736         }
737 }
738
739 void VIEW3D_OT_snap_cursor_to_selected(wmOperatorType *ot)
740 {
741         /* identifiers */
742         ot->name = "Snap Cursor to Selected";
743         ot->description = "Snap 3D cursor to the middle of the selected item(s)";
744         ot->idname = "VIEW3D_OT_snap_cursor_to_selected";
745
746         /* api callbacks */
747         ot->exec = snap_curs_to_sel_exec;
748         ot->poll = ED_operator_view3d_active;
749
750         /* flags */
751         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
752 }
753
754 /* ********************************************** */
755
756 /** Calculates the center position of the active object in global space.
757  *
758  * Note: this could be exported to be a generic function.
759  * see: calculateCenterActive
760  */
761 static bool snap_calc_active_center(bContext *C, const bool select_only, float r_center[3])
762 {
763         Object *ob = CTX_data_active_object(C);
764         if (ob == NULL) {
765                 return false;
766         }
767         return ED_object_calc_active_center(ob, select_only, r_center);
768 }
769
770 static int snap_curs_to_active_exec(bContext *C, wmOperator *UNUSED(op))
771 {
772         Scene *scene = CTX_data_scene(C);
773         View3D *v3d = CTX_wm_view3d(C);
774
775         if (snap_calc_active_center(C, false, scene->cursor.location)) {
776                 WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
777                 DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
778
779                 return OPERATOR_FINISHED;
780         }
781         else {
782                 return OPERATOR_CANCELLED;
783         }
784 }
785
786 void VIEW3D_OT_snap_cursor_to_active(wmOperatorType *ot)
787 {
788         /* identifiers */
789         ot->name = "Snap Cursor to Active";
790         ot->description = "Snap 3D cursor to the active item";
791         ot->idname = "VIEW3D_OT_snap_cursor_to_active";
792
793         /* api callbacks */
794         ot->exec = snap_curs_to_active_exec;
795         ot->poll = ED_operator_view3d_active;
796
797         /* flags */
798         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_USE_EVAL_DATA;
799 }
800
801 /* **************************************************** */
802
803 /** Snaps the 3D cursor location to the origin. **/
804 static int snap_curs_to_center_exec(bContext *C, wmOperator *UNUSED(op))
805 {
806         Scene *scene = CTX_data_scene(C);
807
808         zero_v3(scene->cursor.location);
809
810         DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE);
811
812         WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
813         return OPERATOR_FINISHED;
814 }
815
816 void VIEW3D_OT_snap_cursor_to_center(wmOperatorType *ot)
817 {
818         /* identifiers */
819         ot->name = "Snap Cursor to World Origin";
820         ot->description = "Snap 3D cursor to the world origin";
821         ot->idname = "VIEW3D_OT_snap_cursor_to_center";
822
823         /* api callbacks */
824         ot->exec = snap_curs_to_center_exec;
825         ot->poll = ED_operator_view3d_active;
826
827         /* flags */
828         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
829 }
830
831 /* **************************************************** */
832
833 /** Calculates the bounding box corners (min and max) for \a obedit. The returned values are in global space. **/
834 bool ED_view3d_minmax_verts(Object *obedit, float r_min[3], float r_max[3])
835 {
836         TransVertStore tvs = {NULL};
837         TransVert *tv;
838         float centroid[3], vec[3], bmat[3][3];
839
840         /* Metaballs are an exception. */
841         if (obedit->type == OB_MBALL) {
842                 float ob_min[3], ob_max[3];
843                 bool changed;
844
845                 changed = BKE_mball_minmax_ex(obedit->data, ob_min, ob_max, obedit->obmat, SELECT);
846                 if (changed) {
847                         minmax_v3v3_v3(r_min, r_max, ob_min);
848                         minmax_v3v3_v3(r_min, r_max, ob_max);
849                 }
850                 return changed;
851         }
852
853         if (ED_transverts_check_obedit(obedit))
854                 ED_transverts_create_from_obedit(&tvs, obedit, TM_ALL_JOINTS);
855
856         if (tvs.transverts_tot == 0)
857                 return false;
858
859         copy_m3_m4(bmat, obedit->obmat);
860
861         tv = tvs.transverts;
862         for (int a = 0; a < tvs.transverts_tot; a++, tv++) {
863                 copy_v3_v3(vec, (tv->flag & TX_VERT_USE_MAPLOC) ? tv->maploc : tv->loc);
864                 mul_m3_v3(bmat, vec);
865                 add_v3_v3(vec, obedit->obmat[3]);
866                 add_v3_v3(centroid, vec);
867                 minmax_v3v3_v3(r_min, r_max, vec);
868         }
869
870         ED_transverts_free(&tvs);
871
872         return true;
873 }