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