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