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