Blender  V3.3
view3d_snap.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2001-2002 NaN Holding BV. All rights reserved. */
3 
8 #include "MEM_guardedalloc.h"
9 
10 #include "DNA_armature_types.h"
11 #include "DNA_object_types.h"
12 
13 #include "BLI_array.h"
14 #include "BLI_math.h"
15 #include "BLI_utildefines.h"
16 
17 #include "BKE_action.h"
18 #include "BKE_armature.h"
19 #include "BKE_context.h"
20 #include "BKE_editmesh.h"
21 #include "BKE_layer.h"
22 #include "BKE_main.h"
23 #include "BKE_mball.h"
24 #include "BKE_object.h"
25 #include "BKE_report.h"
26 #include "BKE_scene.h"
27 #include "BKE_tracking.h"
28 
29 #include "DEG_depsgraph.h"
30 #include "DEG_depsgraph_query.h"
31 
32 #include "WM_api.h"
33 #include "WM_types.h"
34 
35 #include "RNA_access.h"
36 #include "RNA_define.h"
37 
38 #include "ED_keyframing.h"
39 #include "ED_object.h"
40 #include "ED_screen.h"
41 #include "ED_transverts.h"
42 
43 #include "view3d_intern.h"
44 
45 static bool snap_curs_to_sel_ex(bContext *C, const int pivot_point, float r_cursor[3]);
46 static bool snap_calc_active_center(bContext *C, const bool select_only, float r_center[3]);
47 
48 /* -------------------------------------------------------------------- */
54 {
59  ARegion *region = CTX_wm_region(C);
60  View3D *v3d = CTX_wm_view3d(C);
61  TransVertStore tvs = {NULL};
62  TransVert *tv;
63  float gridf, imat[3][3], bmat[3][3], vec[3];
64  int a;
65 
66  gridf = ED_view3d_grid_view_scale(scene, v3d, region, NULL);
67 
68  if (OBEDIT_FROM_OBACT(obact)) {
69  ViewLayer *view_layer = CTX_data_view_layer(C);
70  uint objects_len = 0;
72  view_layer, CTX_wm_view3d(C), &objects_len);
73  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
74  Object *obedit = objects[ob_index];
75 
76  if (obedit->type == OB_MESH) {
78 
79  if (em->bm->totvertsel == 0) {
80  continue;
81  }
82  }
83 
84  if (ED_transverts_check_obedit(obedit)) {
85  ED_transverts_create_from_obedit(&tvs, obedit, 0);
86  }
87 
88  if (tvs.transverts_tot != 0) {
89  copy_m3_m4(bmat, obedit->obmat);
90  invert_m3_m3(imat, bmat);
91 
92  tv = tvs.transverts;
93  for (a = 0; a < tvs.transverts_tot; a++, tv++) {
94  copy_v3_v3(vec, tv->loc);
95  mul_m3_v3(bmat, vec);
96  add_v3_v3(vec, obedit->obmat[3]);
97  vec[0] = gridf * floorf(0.5f + vec[0] / gridf);
98  vec[1] = gridf * floorf(0.5f + vec[1] / gridf);
99  vec[2] = gridf * floorf(0.5f + vec[2] / gridf);
100  sub_v3_v3(vec, obedit->obmat[3]);
101 
102  mul_m3_v3(imat, vec);
103  copy_v3_v3(tv->loc, vec);
104  }
105  ED_transverts_update_obedit(&tvs, obedit);
106  }
107  ED_transverts_free(&tvs);
108  }
109  MEM_freeN(objects);
110  }
111  else if (OBPOSE_FROM_OBACT(obact)) {
113  uint objects_len = 0;
114  Object **objects_eval = BKE_object_pose_array_get(view_layer_eval, v3d, &objects_len);
115  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
116  Object *ob_eval = objects_eval[ob_index];
117  Object *ob = DEG_get_original_object(ob_eval);
118  bPoseChannel *pchan_eval;
119  bArmature *arm_eval = ob_eval->data;
120 
121  invert_m4_m4(ob_eval->imat, ob_eval->obmat);
122 
123  for (pchan_eval = ob_eval->pose->chanbase.first; pchan_eval; pchan_eval = pchan_eval->next) {
124  if (pchan_eval->bone->flag & BONE_SELECTED) {
125  if (pchan_eval->bone->layer & arm_eval->layer) {
126  if ((pchan_eval->bone->flag & BONE_CONNECTED) == 0) {
127  float nLoc[3];
128 
129  /* get nearest grid point to snap to */
130  copy_v3_v3(nLoc, pchan_eval->pose_mat[3]);
131  /* We must operate in world space! */
132  mul_m4_v3(ob_eval->obmat, nLoc);
133  vec[0] = gridf * floorf(0.5f + nLoc[0] / gridf);
134  vec[1] = gridf * floorf(0.5f + nLoc[1] / gridf);
135  vec[2] = gridf * floorf(0.5f + nLoc[2] / gridf);
136  /* Back in object space... */
137  mul_m4_v3(ob_eval->imat, vec);
138 
139  /* Get location of grid point in pose space. */
140  BKE_armature_loc_pose_to_bone(pchan_eval, vec, vec);
141 
142  /* Adjust location on the original pchan. */
143  bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, pchan_eval->name);
144  if ((pchan->protectflag & OB_LOCK_LOCX) == 0) {
145  pchan->loc[0] = vec[0];
146  }
147  if ((pchan->protectflag & OB_LOCK_LOCY) == 0) {
148  pchan->loc[1] = vec[1];
149  }
150  if ((pchan->protectflag & OB_LOCK_LOCZ) == 0) {
151  pchan->loc[2] = vec[2];
152  }
153 
154  /* auto-keyframing */
155  ED_autokeyframe_pchan(C, scene, ob, pchan, ks);
156  }
157  /* if the bone has a parent and is connected to the parent,
158  * don't do anything - will break chain unless we do auto-ik.
159  */
160  }
161  }
162  }
163  ob->pose->flag |= (POSE_LOCKED | POSE_DO_UNLOCK);
164 
166  }
167  MEM_freeN(objects_eval);
168  }
169  else {
170  /* Object mode. */
171  Main *bmain = CTX_data_main(C);
172 
174 
175  const bool use_transform_skip_children = (scene->toolsettings->transform_flag &
177  const bool use_transform_data_origin = (scene->toolsettings->transform_flag &
179  struct XFormObjectSkipChild_Container *xcs = NULL;
180  struct XFormObjectData_Container *xds = NULL;
181 
182  /* Build object array. */
183  Object **objects_eval = NULL;
184  uint objects_eval_len;
185  {
186  BLI_array_declare(objects_eval);
187  FOREACH_SELECTED_EDITABLE_OBJECT_BEGIN (view_layer_eval, v3d, ob_eval) {
188  BLI_array_append(objects_eval, ob_eval);
189  }
191  objects_eval_len = BLI_array_len(objects_eval);
192  }
193 
194  if (use_transform_skip_children) {
195  ViewLayer *view_layer = CTX_data_view_layer(C);
196 
197  Object **objects = MEM_malloc_arrayN(objects_eval_len, sizeof(*objects), __func__);
198 
199  for (int ob_index = 0; ob_index < objects_eval_len; ob_index++) {
200  Object *ob_eval = objects_eval[ob_index];
201  objects[ob_index] = DEG_get_original_object(ob_eval);
202  }
206  xcs, view_layer, objects, objects_eval_len);
207  MEM_freeN(objects);
208  }
209  if (use_transform_data_origin) {
212  }
213 
214  for (int ob_index = 0; ob_index < objects_eval_len; ob_index++) {
215  Object *ob_eval = objects_eval[ob_index];
216  Object *ob = DEG_get_original_object(ob_eval);
217  vec[0] = -ob_eval->obmat[3][0] + gridf * floorf(0.5f + ob_eval->obmat[3][0] / gridf);
218  vec[1] = -ob_eval->obmat[3][1] + gridf * floorf(0.5f + ob_eval->obmat[3][1] / gridf);
219  vec[2] = -ob_eval->obmat[3][2] + gridf * floorf(0.5f + ob_eval->obmat[3][2] / gridf);
220 
221  if (ob->parent) {
222  float originmat[3][3];
224 
225  invert_m3_m3(imat, originmat);
226  mul_m3_v3(imat, vec);
227  }
228  if ((ob->protectflag & OB_LOCK_LOCX) == 0) {
229  ob->loc[0] = ob_eval->loc[0] + vec[0];
230  }
231  if ((ob->protectflag & OB_LOCK_LOCY) == 0) {
232  ob->loc[1] = ob_eval->loc[1] + vec[1];
233  }
234  if ((ob->protectflag & OB_LOCK_LOCZ) == 0) {
235  ob->loc[2] = ob_eval->loc[2] + vec[2];
236  }
237 
238  /* auto-keyframing */
239  ED_autokeyframe_object(C, scene, ob, ks);
240 
241  if (use_transform_data_origin) {
243  }
244 
246  }
247 
248  if (objects_eval) {
249  MEM_freeN(objects_eval);
250  }
251 
252  if (use_transform_skip_children) {
255  }
256  if (use_transform_data_origin) {
259  }
260  }
261 
263 
264  return OPERATOR_FINISHED;
265 }
266 
268 {
269  /* identifiers */
270  ot->name = "Snap Selection to Grid";
271  ot->description = "Snap selected item(s) to their nearest grid division";
272  ot->idname = "VIEW3D_OT_snap_selected_to_grid";
273 
274  /* api callbacks */
277 
278  /* flags */
280 }
281 
284 /* -------------------------------------------------------------------- */
298  const float snap_target_global[3],
299  const bool use_offset,
300  const int pivot_point,
301  const bool use_toolsettings)
302 {
304  Object *obedit = CTX_data_edit_object(C);
305  Object *obact = CTX_data_active_object(C);
306  View3D *v3d = CTX_wm_view3d(C);
307  TransVertStore tvs = {NULL};
308  TransVert *tv;
309  float imat[3][3], bmat[3][3];
310  float center_global[3];
311  float offset_global[3];
312  int a;
313 
314  if (use_offset) {
315  if ((pivot_point == V3D_AROUND_ACTIVE) && snap_calc_active_center(C, true, center_global)) {
316  /* pass */
317  }
318  else {
319  snap_curs_to_sel_ex(C, pivot_point, center_global);
320  }
321  sub_v3_v3v3(offset_global, snap_target_global, center_global);
322  }
323 
324  if (obedit) {
325  float snap_target_local[3];
326  ViewLayer *view_layer = CTX_data_view_layer(C);
327  uint objects_len = 0;
329  view_layer, v3d, &objects_len);
330  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
331  obedit = objects[ob_index];
332 
333  if (obedit->type == OB_MESH) {
334  BMEditMesh *em = BKE_editmesh_from_object(obedit);
335 
336  if (em->bm->totvertsel == 0) {
337  continue;
338  }
339  }
340 
341  if (ED_transverts_check_obedit(obedit)) {
342  ED_transverts_create_from_obedit(&tvs, obedit, 0);
343  }
344 
345  if (tvs.transverts_tot != 0) {
346  copy_m3_m4(bmat, obedit->obmat);
347  invert_m3_m3(imat, bmat);
348 
349  /* get the cursor in object space */
350  sub_v3_v3v3(snap_target_local, snap_target_global, obedit->obmat[3]);
351  mul_m3_v3(imat, snap_target_local);
352 
353  if (use_offset) {
354  float offset_local[3];
355 
356  mul_v3_m3v3(offset_local, imat, offset_global);
357 
358  tv = tvs.transverts;
359  for (a = 0; a < tvs.transverts_tot; a++, tv++) {
360  add_v3_v3(tv->loc, offset_local);
361  }
362  }
363  else {
364  tv = tvs.transverts;
365  for (a = 0; a < tvs.transverts_tot; a++, tv++) {
366  copy_v3_v3(tv->loc, snap_target_local);
367  }
368  }
369  ED_transverts_update_obedit(&tvs, obedit);
370  }
371  ED_transverts_free(&tvs);
372  }
373  MEM_freeN(objects);
374  }
375  else if (OBPOSE_FROM_OBACT(obact)) {
377  ViewLayer *view_layer = CTX_data_view_layer(C);
378  uint objects_len = 0;
379  Object **objects = BKE_object_pose_array_get(view_layer, v3d, &objects_len);
380 
381  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
382  Object *ob = objects[ob_index];
383  bPoseChannel *pchan;
384  bArmature *arm = ob->data;
385  float snap_target_local[3];
386 
387  invert_m4_m4(ob->imat, ob->obmat);
388  mul_v3_m4v3(snap_target_local, ob->imat, snap_target_global);
389 
390  for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
391  if ((pchan->bone->flag & BONE_SELECTED) && (PBONE_VISIBLE(arm, pchan->bone)) &&
392  /* if the bone has a parent and is connected to the parent,
393  * don't do anything - will break chain unless we do auto-ik.
394  */
395  (pchan->bone->flag & BONE_CONNECTED) == 0) {
396  pchan->bone->flag |= BONE_TRANSFORM;
397  }
398  else {
399  pchan->bone->flag &= ~BONE_TRANSFORM;
400  }
401  }
402 
403  for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
404  if ((pchan->bone->flag & BONE_TRANSFORM) &&
405  /* check that our parents not transformed (if we have one) */
406  ((pchan->bone->parent &&
408  /* Get position in pchan (pose) space. */
409  float cursor_pose[3];
410 
411  if (use_offset) {
412  mul_v3_m4v3(cursor_pose, ob->obmat, pchan->pose_mat[3]);
413  add_v3_v3(cursor_pose, offset_global);
414 
415  mul_m4_v3(ob->imat, cursor_pose);
416  BKE_armature_loc_pose_to_bone(pchan, cursor_pose, cursor_pose);
417  }
418  else {
419  BKE_armature_loc_pose_to_bone(pchan, snap_target_local, cursor_pose);
420  }
421 
422  /* copy new position */
423  if (use_toolsettings) {
424  if ((pchan->protectflag & OB_LOCK_LOCX) == 0) {
425  pchan->loc[0] = cursor_pose[0];
426  }
427  if ((pchan->protectflag & OB_LOCK_LOCY) == 0) {
428  pchan->loc[1] = cursor_pose[1];
429  }
430  if ((pchan->protectflag & OB_LOCK_LOCZ) == 0) {
431  pchan->loc[2] = cursor_pose[2];
432  }
433 
434  /* auto-keyframing */
435  ED_autokeyframe_pchan(C, scene, ob, pchan, ks);
436  }
437  else {
438  copy_v3_v3(pchan->loc, cursor_pose);
439  }
440  }
441  }
442 
443  for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
444  pchan->bone->flag &= ~BONE_TRANSFORM;
445  }
446 
447  ob->pose->flag |= (POSE_LOCKED | POSE_DO_UNLOCK);
448 
450  }
451  MEM_freeN(objects);
452  }
453  else {
455  Main *bmain = CTX_data_main(C);
457 
458  /* Reset flags. */
459  for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) {
460  ob->flag &= ~OB_DONE;
461  }
462 
463  /* Build object array, tag objects we're transforming. */
464  ViewLayer *view_layer = CTX_data_view_layer(C);
465  Object **objects = NULL;
466  uint objects_len;
467  {
468  BLI_array_declare(objects);
469  FOREACH_SELECTED_EDITABLE_OBJECT_BEGIN (view_layer, v3d, ob) {
470  BLI_array_append(objects, ob);
471  ob->flag |= OB_DONE;
472  }
474  objects_len = BLI_array_len(objects);
475  }
476 
477  const bool use_transform_skip_children = use_toolsettings &&
480  const bool use_transform_data_origin = use_toolsettings &&
483  struct XFormObjectSkipChild_Container *xcs = NULL;
484  struct XFormObjectData_Container *xds = NULL;
485 
486  if (use_transform_skip_children) {
490  xcs, view_layer, objects, objects_len);
491  }
492  if (use_transform_data_origin) {
495 
496  /* Initialize the transform data in a separate loop because the depsgraph
497  * may be evaluated while setting the locations. */
498  for (int ob_index = 0; ob_index < objects_len; ob_index++) {
499  Object *ob = objects[ob_index];
501  }
502  }
503 
504  for (int ob_index = 0; ob_index < objects_len; ob_index++) {
505  Object *ob = objects[ob_index];
507  continue;
508  }
509 
510  float cursor_parent[3]; /* parent-relative */
511 
512  if (use_offset) {
513  add_v3_v3v3(cursor_parent, ob->obmat[3], offset_global);
514  }
515  else {
516  copy_v3_v3(cursor_parent, snap_target_global);
517  }
518 
519  sub_v3_v3(cursor_parent, ob->obmat[3]);
520 
521  if (ob->parent) {
522  float originmat[3][3], parentmat[4][4];
523  /* Use the evaluated object here because sometimes
524  * `ob->parent->runtime.curve_cache` is required. */
526  Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
527 
528  BKE_object_get_parent_matrix(ob_eval, ob_eval->parent, parentmat);
529  mul_m3_m4m4(originmat, parentmat, ob->parentinv);
530  invert_m3_m3(imat, originmat);
531  mul_m3_v3(imat, cursor_parent);
532  }
533  if (use_toolsettings) {
534  if ((ob->protectflag & OB_LOCK_LOCX) == 0) {
535  ob->loc[0] += cursor_parent[0];
536  }
537  if ((ob->protectflag & OB_LOCK_LOCY) == 0) {
538  ob->loc[1] += cursor_parent[1];
539  }
540  if ((ob->protectflag & OB_LOCK_LOCZ) == 0) {
541  ob->loc[2] += cursor_parent[2];
542  }
543 
544  /* auto-keyframing */
545  ED_autokeyframe_object(C, scene, ob, ks);
546  }
547  else {
548  add_v3_v3(ob->loc, cursor_parent);
549  }
550 
552  }
553 
554  if (objects) {
555  MEM_freeN(objects);
556  }
557 
558  if (use_transform_skip_children) {
561  }
562  if (use_transform_data_origin) {
565  }
566  }
567 
569 
570  return true;
571 }
572 
574  const float snap_target_global[3],
575  const int pivot_point)
576 {
577  /* These could be passed as arguments if needed. */
578  /* Always use pivot point. */
579  const bool use_offset = true;
580  /* Disable object protected flags & auto-keyframing,
581  * so this can be used as a low level function. */
582  const bool use_toolsettings = false;
584  C, snap_target_global, use_offset, pivot_point, use_toolsettings);
585 }
586 
589 /* -------------------------------------------------------------------- */
594 {
595  const bool use_offset = RNA_boolean_get(op->ptr, "use_offset");
596 
598 
599  const float *snap_target_global = scene->cursor.location;
600  const int pivot_point = scene->toolsettings->transform_pivot_point;
601 
602  if (snap_selected_to_location(C, snap_target_global, use_offset, pivot_point, true)) {
603  return OPERATOR_FINISHED;
604  }
605  return OPERATOR_CANCELLED;
606 }
607 
609 {
610  /* identifiers */
611  ot->name = "Snap Selection to Cursor";
612  ot->description = "Snap selected item(s) to the 3D cursor";
613  ot->idname = "VIEW3D_OT_snap_selected_to_cursor";
614 
615  /* api callbacks */
618 
619  /* flags */
621 
622  /* rna */
624  "use_offset",
625  1,
626  "Offset",
627  "If the selection should be snapped as a whole or by each object center");
628 }
629 
632 /* -------------------------------------------------------------------- */
638 {
639  float snap_target_global[3];
640 
641  if (snap_calc_active_center(C, false, snap_target_global) == false) {
642  BKE_report(op->reports, RPT_ERROR, "No active element found!");
643  return OPERATOR_CANCELLED;
644  }
645 
646  if (!snap_selected_to_location(C, snap_target_global, false, -1, true)) {
647  return OPERATOR_CANCELLED;
648  }
649  return OPERATOR_FINISHED;
650 }
651 
653 {
654  /* identifiers */
655  ot->name = "Snap Selection to Active";
656  ot->description = "Snap selected item(s) to the active item";
657  ot->idname = "VIEW3D_OT_snap_selected_to_active";
658 
659  /* api callbacks */
662 
663  /* flags */
665 }
666 
669 /* -------------------------------------------------------------------- */
675 {
677  ARegion *region = CTX_wm_region(C);
678  View3D *v3d = CTX_wm_view3d(C);
679  float gridf, *curs;
680 
681  gridf = ED_view3d_grid_view_scale(scene, v3d, region, NULL);
682  curs = scene->cursor.location;
683 
684  curs[0] = gridf * floorf(0.5f + curs[0] / gridf);
685  curs[1] = gridf * floorf(0.5f + curs[1] / gridf);
686  curs[2] = gridf * floorf(0.5f + curs[2] / gridf);
687 
690 
691  return OPERATOR_FINISHED;
692 }
693 
695 {
696  /* identifiers */
697  ot->name = "Snap Cursor to Grid";
698  ot->description = "Snap 3D cursor to the nearest grid division";
699  ot->idname = "VIEW3D_OT_snap_cursor_to_grid";
700 
701  /* api callbacks */
704 
705  /* flags */
707 }
708 
711 /* -------------------------------------------------------------------- */
719 static void bundle_midpoint(Scene *scene, Object *ob, float r_vec[3])
720 {
721  MovieClip *clip = BKE_object_movieclip_get(scene, ob, false);
722  MovieTracking *tracking;
723  MovieTrackingObject *object;
724  bool ok = false;
725  float min[3], max[3], mat[4][4], pos[3], cammat[4][4];
726 
727  if (!clip) {
728  return;
729  }
730 
731  tracking = &clip->tracking;
732 
733  copy_m4_m4(cammat, ob->obmat);
734 
736 
737  INIT_MINMAX(min, max);
738 
739  for (object = tracking->objects.first; object; object = object->next) {
740  ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
741  MovieTrackingTrack *track = tracksbase->first;
742  float obmat[4][4];
743 
744  if (object->flag & TRACKING_OBJECT_CAMERA) {
745  copy_m4_m4(obmat, mat);
746  }
747  else {
748  float imat[4][4];
749 
751  invert_m4(imat);
752 
753  mul_m4_m4m4(obmat, cammat, imat);
754  }
755 
756  while (track) {
757  if ((track->flag & TRACK_HAS_BUNDLE) && TRACK_SELECTED(track)) {
758  ok = 1;
759  mul_v3_m4v3(pos, obmat, track->bundle_pos);
761  }
762 
763  track = track->next;
764  }
765  }
766 
767  if (ok) {
768  mid_v3_v3v3(r_vec, min, max);
769  }
770 }
771 
773 static bool snap_curs_to_sel_ex(bContext *C, const int pivot_point, float r_cursor[3])
774 {
777  Object *obedit = CTX_data_edit_object(C);
779  View3D *v3d = CTX_wm_view3d(C);
780  TransVertStore tvs = {NULL};
781  TransVert *tv;
782  float bmat[3][3], vec[3], min[3], max[3], centroid[3];
783  int count = 0;
784 
785  INIT_MINMAX(min, max);
786  zero_v3(centroid);
787 
788  if (obedit) {
789  ViewLayer *view_layer = CTX_data_view_layer(C);
790  uint objects_len = 0;
792  view_layer, CTX_wm_view3d(C), &objects_len);
793  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
794  obedit = objects[ob_index];
795 
796  /* We can do that quick check for meshes only... */
797  if (obedit->type == OB_MESH) {
798  BMEditMesh *em = BKE_editmesh_from_object(obedit);
799 
800  if (em->bm->totvertsel == 0) {
801  continue;
802  }
803  }
804 
805  if (ED_transverts_check_obedit(obedit)) {
807  }
808 
809  count += tvs.transverts_tot;
810  if (tvs.transverts_tot != 0) {
811  Object *obedit_eval = DEG_get_evaluated_object(depsgraph, obedit);
812  copy_m3_m4(bmat, obedit_eval->obmat);
813 
814  tv = tvs.transverts;
815  for (int i = 0; i < tvs.transverts_tot; i++, tv++) {
816  copy_v3_v3(vec, tv->loc);
817  mul_m3_v3(bmat, vec);
818  add_v3_v3(vec, obedit_eval->obmat[3]);
819  add_v3_v3(centroid, vec);
820  minmax_v3v3_v3(min, max, vec);
821  }
822  }
823  ED_transverts_free(&tvs);
824  }
825  MEM_freeN(objects);
826  }
827  else {
828  Object *obact = CTX_data_active_object(C);
829 
830  if (obact && (obact->mode & OB_MODE_POSE)) {
831  Object *obact_eval = DEG_get_evaluated_object(depsgraph, obact);
832  bArmature *arm = obact_eval->data;
833  bPoseChannel *pchan;
834  for (pchan = obact_eval->pose->chanbase.first; pchan; pchan = pchan->next) {
835  if (arm->layer & pchan->bone->layer) {
836  if (pchan->bone->flag & BONE_SELECTED) {
837  copy_v3_v3(vec, pchan->pose_head);
838  mul_m4_v3(obact_eval->obmat, vec);
839  add_v3_v3(centroid, vec);
840  minmax_v3v3_v3(min, max, vec);
841  count++;
842  }
843  }
844  }
845  }
846  else {
847  FOREACH_SELECTED_OBJECT_BEGIN (view_layer_eval, v3d, ob_eval) {
848  copy_v3_v3(vec, ob_eval->obmat[3]);
849 
850  /* special case for camera -- snap to bundles */
851  if (ob_eval->type == OB_CAMERA) {
852  /* snap to bundles should happen only when bundles are visible */
853  if (v3d->flag2 & V3D_SHOW_RECONSTRUCTION) {
855  }
856  }
857 
858  add_v3_v3(centroid, vec);
859  minmax_v3v3_v3(min, max, vec);
860  count++;
861  }
863  }
864  }
865 
866  if (count == 0) {
867  return false;
868  }
869 
870  if (pivot_point == V3D_AROUND_CENTER_BOUNDS) {
871  mid_v3_v3v3(r_cursor, min, max);
872  }
873  else {
874  mul_v3_fl(centroid, 1.0f / (float)count);
875  copy_v3_v3(r_cursor, centroid);
876  }
877  return true;
878 }
879 
881 {
883  const int pivot_point = scene->toolsettings->transform_pivot_point;
884  if (snap_curs_to_sel_ex(C, pivot_point, scene->cursor.location)) {
887 
888  return OPERATOR_FINISHED;
889  }
890  return OPERATOR_CANCELLED;
891 }
892 
894 {
895  /* identifiers */
896  ot->name = "Snap Cursor to Selected";
897  ot->description = "Snap 3D cursor to the middle of the selected item(s)";
898  ot->idname = "VIEW3D_OT_snap_cursor_to_selected";
899 
900  /* api callbacks */
903 
904  /* flags */
906 }
907 
910 /* -------------------------------------------------------------------- */
920 static bool snap_calc_active_center(bContext *C, const bool select_only, float r_center[3])
921 {
923  if (ob == NULL) {
924  return false;
925  }
926  return ED_object_calc_active_center(ob, select_only, r_center);
927 }
928 
930 {
932 
936 
937  return OPERATOR_FINISHED;
938  }
939  return OPERATOR_CANCELLED;
940 }
941 
943 {
944  /* identifiers */
945  ot->name = "Snap Cursor to Active";
946  ot->description = "Snap 3D cursor to the active item";
947  ot->idname = "VIEW3D_OT_snap_cursor_to_active";
948 
949  /* api callbacks */
952 
953  /* flags */
955 }
956 
959 /* -------------------------------------------------------------------- */
965 {
967  float mat3[3][3];
968  unit_m3(mat3);
969 
971  BKE_scene_cursor_mat3_to_rot(&scene->cursor, mat3, false);
972 
974 
976  return OPERATOR_FINISHED;
977 }
978 
980 {
981  /* identifiers */
982  ot->name = "Snap Cursor to World Origin";
983  ot->description = "Snap 3D cursor to the world origin";
984  ot->idname = "VIEW3D_OT_snap_cursor_to_center";
985 
986  /* api callbacks */
989 
990  /* flags */
992 }
993 
996 /* -------------------------------------------------------------------- */
1000 bool ED_view3d_minmax_verts(Object *obedit, float r_min[3], float r_max[3])
1001 {
1002  TransVertStore tvs = {NULL};
1003  TransVert *tv;
1004  float centroid[3], vec[3], bmat[3][3];
1005 
1006  /* Metaballs are an exception. */
1007  if (obedit->type == OB_MBALL) {
1008  float ob_min[3], ob_max[3];
1009  bool changed;
1010 
1011  changed = BKE_mball_minmax_ex(obedit->data, ob_min, ob_max, obedit->obmat, SELECT);
1012  if (changed) {
1013  minmax_v3v3_v3(r_min, r_max, ob_min);
1014  minmax_v3v3_v3(r_min, r_max, ob_max);
1015  }
1016  return changed;
1017  }
1018 
1019  if (ED_transverts_check_obedit(obedit)) {
1021  }
1022 
1023  if (tvs.transverts_tot == 0) {
1024  return false;
1025  }
1026 
1027  copy_m3_m4(bmat, obedit->obmat);
1028 
1029  tv = tvs.transverts;
1030  for (int a = 0; a < tvs.transverts_tot; a++, tv++) {
1031  copy_v3_v3(vec, (tv->flag & TX_VERT_USE_MAPLOC) ? tv->maploc : tv->loc);
1032  mul_m3_v3(bmat, vec);
1033  add_v3_v3(vec, obedit->obmat[3]);
1034  add_v3_v3(centroid, vec);
1035  minmax_v3v3_v3(r_min, r_max, vec);
1036  }
1037 
1038  ED_transverts_free(&tvs);
1039 
1040  return true;
1041 }
1042 
Blender kernel action and pose functionality.
struct bPoseChannel * BKE_pose_channel_find_name(const struct bPose *pose, const char *name)
void BKE_armature_loc_pose_to_bone(struct bPoseChannel *pchan, const float inloc[3], float outloc[3])
Definition: armature.c:1870
bool BKE_armature_bone_flag_test_recursive(const struct Bone *bone, int flag)
#define PBONE_VISIBLE(arm, bone)
Definition: BKE_armature.h:549
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1090
struct Object * CTX_data_edit_object(const bContext *C)
Definition: context.c:1370
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1100
struct Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Definition: context.c:1528
struct Object * CTX_data_active_object(const bContext *C)
Definition: context.c:1353
struct View3D * CTX_wm_view3d(const bContext *C)
Definition: context.c:784
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:749
struct Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Definition: context.c:1505
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1074
BMEditMesh * BKE_editmesh_from_object(struct Object *ob)
Return the BMEditMesh for a given object.
Definition: editmesh.c:58
#define FOREACH_SELECTED_EDITABLE_OBJECT_END
Definition: BKE_layer.h:332
#define FOREACH_SELECTED_OBJECT_BEGIN(_view_layer, _v3d, _instance)
Definition: BKE_layer.h:303
#define BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, v3d, r_len)
Definition: BKE_layer.h:542
#define FOREACH_SELECTED_EDITABLE_OBJECT_BEGIN(_view_layer, _v3d, _instance)
Definition: BKE_layer.h:320
#define FOREACH_SELECTED_OBJECT_END
Definition: BKE_layer.h:315
bool BKE_mball_minmax_ex(const struct MetaBall *mb, float min[3], float max[3], const float obmat[4][4], short flag)
General operations, lookup, etc. for blender objects.
struct MovieClip * BKE_object_movieclip_get(struct Scene *scene, struct Object *ob, bool use_default)
Definition: object.cc:5042
void BKE_object_get_parent_matrix(struct Object *ob, struct Object *par, float r_parentmat[4][4])
Definition: object.cc:3342
struct Object ** BKE_object_pose_array_get(struct ViewLayer *view_layer, struct View3D *v3d, unsigned int *r_objects_len)
Definition: object.cc:2598
void BKE_object_where_is_calc_ex(struct Depsgraph *depsgraph, struct Scene *scene, struct RigidBodyWorld *rbw, struct Object *ob, float r_originmat[3][3])
Definition: object.cc:3489
bool BKE_object_flag_test_recursive(const struct Object *ob, short flag)
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition: report.c:83
void BKE_scene_cursor_mat3_to_rot(struct View3DCursor *cursor, const float mat[3][3], bool use_compat)
Definition: scene.cc:3612
void BKE_scene_graph_evaluated_ensure(struct Depsgraph *depsgraph, struct Main *bmain)
Definition: scene.cc:2653
void BKE_tracking_get_camera_object_matrix(struct Object *camera_object, float mat[4][4])
Definition: tracking.c:375
void BKE_tracking_camera_get_reconstructed_interpolate(struct MovieTracking *tracking, struct MovieTrackingObject *object, float framenr, float mat[4][4])
Definition: tracking.c:2269
#define TRACK_SELECTED(track)
Definition: BKE_tracking.h:823
struct ListBase * BKE_tracking_object_get_tracks(struct MovieTracking *tracking, struct MovieTrackingObject *object)
Definition: tracking.c:2112
A (mainly) macro array library.
#define BLI_array_append(arr, item)
Definition: BLI_array.h:98
#define BLI_array_declare(arr)
Definition: BLI_array.h:50
#define BLI_array_len(arr)
Definition: BLI_array.h:63
void mul_m3_v3(const float M[3][3], float r[3])
Definition: math_matrix.c:926
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
Definition: math_matrix.c:259
bool invert_m4(float R[4][4])
Definition: math_matrix.c:1206
void unit_m3(float m[3][3])
Definition: math_matrix.c:40
void copy_m3_m4(float m1[3][3], const float m2[4][4])
Definition: math_matrix.c:87
bool invert_m4_m4(float R[4][4], const float A[4][4])
Definition: math_matrix.c:1287
void mul_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:729
bool invert_m3_m3(float R[3][3], const float A[3][3])
Definition: math_matrix.c:1180
void copy_m4_m4(float m1[4][4], const float m2[4][4])
Definition: math_matrix.c:77
void mul_v3_m4v3(float r[3], const float M[4][4], const float v[3])
Definition: math_matrix.c:739
void mul_v3_m3v3(float r[3], const float M[3][3], const float a[3])
Definition: math_matrix.c:897
void mul_m3_m4m4(float R[3][3], const float A[4][4], const float B[4][4])
Definition: math_matrix.c:520
void minmax_v3v3_v3(float min[3], float max[3], const float vec[3])
Definition: math_vector.c:867
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
void mid_v3_v3v3(float r[3], const float a[3], const float b[3])
Definition: math_vector.c:237
MINLINE void zero_v3(float r[3])
MINLINE void add_v3_v3(float r[3], const float a[3])
unsigned int uint
Definition: BLI_sys_types.h:67
#define INIT_MINMAX(min, max)
#define UNUSED(x)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
void DEG_id_tag_update(struct ID *id, int flag)
struct Object * DEG_get_original_object(struct Object *object)
struct ViewLayer * DEG_get_evaluated_view_layer(const struct Depsgraph *graph)
struct Object * DEG_get_evaluated_object(const struct Depsgraph *depsgraph, struct Object *object)
@ ID_RECALC_TRANSFORM
Definition: DNA_ID.h:771
@ ID_RECALC_COPY_ON_WRITE
Definition: DNA_ID.h:834
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:791
@ POSE_LOCKED
@ POSE_DO_UNLOCK
@ BONE_SELECTED
@ BONE_TRANSFORM
@ BONE_CONNECTED
@ OB_MODE_POSE
Object is a sort of wrapper for general info.
#define OB_DONE
@ OB_MBALL
@ OB_CAMERA
@ OB_MESH
@ OB_LOCK_LOCY
@ OB_LOCK_LOCZ
@ OB_LOCK_LOCX
#define OBPOSE_FROM_OBACT(ob)
@ SCE_XFORM_SKIP_CHILDREN
@ SCE_XFORM_DATA_ORIGIN
#define OBEDIT_FROM_OBACT(ob)
@ TRACKING_OBJECT_CAMERA
@ TRACK_HAS_BUNDLE
@ V3D_AROUND_ACTIVE
@ V3D_AROUND_CENTER_BOUNDS
#define V3D_SHOW_RECONSTRUCTION
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
#define ANIM_KS_LOCATION_ID
void ED_object_xform_skip_child_container_item_ensure_from_array(struct XFormObjectSkipChild_Container *xcs, struct ViewLayer *view_layer, struct Object **objects, uint objects_len)
Definition: object_utils.c:170
bool ED_object_calc_active_center(struct Object *ob, bool select_only, float r_center[3])
Definition: object_utils.c:112
void ED_object_xform_skip_child_container_update_all(struct XFormObjectSkipChild_Container *xcs, struct Main *bmain, struct Depsgraph *depsgraph)
Definition: object_utils.c:257
void ED_object_xform_skip_child_container_destroy(struct XFormObjectSkipChild_Container *xcs)
Definition: object_utils.c:230
struct XFormObjectSkipChild_Container * ED_object_xform_skip_child_container_create(void)
Definition: object_utils.c:161
void ED_object_data_xform_container_destroy(struct XFormObjectData_Container *xds)
Definition: object_utils.c:409
void ED_object_data_xform_container_item_ensure(struct XFormObjectData_Container *xds, struct Object *ob)
Definition: object_utils.c:341
void ED_object_data_xform_container_update_all(struct XFormObjectData_Container *xds, struct Main *bmain, struct Depsgraph *depsgraph)
Definition: object_utils.c:358
struct XFormObjectData_Container * ED_object_data_xform_container_create(void)
Definition: object_utils.c:402
bool ED_operator_view3d_active(struct bContext *C)
Definition: screen_ops.c:225
bool ED_operator_region_view3d_active(struct bContext *C)
Definition: screen_ops.c:230
void ED_transverts_update_obedit(TransVertStore *tvs, struct Object *obedit)
Definition: ed_transverts.c:37
void ED_transverts_create_from_obedit(TransVertStore *tvs, const struct Object *obedit, int mode)
void ED_transverts_free(TransVertStore *tvs)
@ TM_SKIP_HANDLES
Definition: ED_transverts.h:55
@ TM_CALC_MAPLOC
Definition: ED_transverts.h:59
@ TM_ALL_JOINTS
Definition: ED_transverts.h:53
@ TX_VERT_USE_MAPLOC
Definition: ED_transverts.h:65
bool ED_transverts_check_obedit(const struct Object *obedit)
float ED_view3d_grid_view_scale(struct Scene *scene, struct View3D *v3d, struct ARegion *region, const char **r_grid_unit)
Definition: view3d_draw.c:901
Read Guarded memory(de)allocation.
#define C
Definition: RandGen.cpp:25
@ OPTYPE_UNDO
Definition: WM_types.h:148
@ OPTYPE_REGISTER
Definition: WM_types.h:146
#define ND_TRANSFORM
Definition: WM_types.h:405
#define ND_SPACE_VIEW3D
Definition: WM_types.h:471
#define NC_OBJECT
Definition: WM_types.h:329
#define NC_SPACE
Definition: WM_types.h:342
#define SELECT
Scene scene
const Depsgraph * depsgraph
uint pos
int count
bool ED_autokeyframe_object(bContext *C, Scene *scene, Object *ob, KeyingSet *ks)
Definition: keyframing.c:3070
bool ED_autokeyframe_pchan(bContext *C, Scene *scene, Object *ob, bPoseChannel *pchan, KeyingSet *ks)
Definition: keyframing.c:3090
KeyingSet * ANIM_get_keyingset_for_autokeying(const Scene *scene, const char *transformKSName)
Definition: keyingsets.c:696
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:34
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
#define floorf(x)
Definition: metal/compat.h:224
static unsigned a[3]
Definition: RandGen.cpp:78
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:4863
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3493
#define min(a, b)
Definition: sort.c:35
struct BMesh * bm
Definition: BKE_editmesh.h:40
int totvertsel
Definition: bmesh_class.h:298
struct Bone * parent
void * first
Definition: DNA_listBase.h:31
Definition: BKE_main.h:121
ListBase objects
Definition: BKE_main.h:170
struct MovieTracking tracking
struct MovieTrackingObject * next
struct MovieTrackingTrack * next
struct bPose * pose
float loc[3]
float imat[4][4]
float parentinv[4][4]
float obmat[4][4]
short protectflag
struct Object * parent
void * data
struct ToolSettings * toolsettings
struct RenderData r
View3DCursor cursor
char transform_pivot_point
struct TransVert * transverts
Definition: ED_transverts.h:25
float * loc
Definition: ED_transverts.h:18
float maploc[3]
Definition: ED_transverts.h:19
unsigned int layer
struct Bone * bone
float pose_head[3]
struct bPoseChannel * next
float pose_mat[4][4]
ListBase chanbase
short flag
const char * name
Definition: WM_types.h:888
const char * idname
Definition: WM_types.h:890
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:943
struct StructRNA * srna
Definition: WM_types.h:969
const char * description
Definition: WM_types.h:893
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:903
struct ReportList * reports
struct PointerRNA * ptr
float max
bool ED_view3d_minmax_verts(Object *obedit, float r_min[3], float r_max[3])
Definition: view3d_snap.c:1000
static int snap_sel_to_grid_exec(bContext *C, wmOperator *UNUSED(op))
Definition: view3d_snap.c:53
void VIEW3D_OT_snap_cursor_to_grid(wmOperatorType *ot)
Definition: view3d_snap.c:694
static void bundle_midpoint(Scene *scene, Object *ob, float r_vec[3])
Definition: view3d_snap.c:719
bool ED_view3d_snap_selected_to_location(bContext *C, const float snap_target_global[3], const int pivot_point)
Definition: view3d_snap.c:573
static bool snap_curs_to_sel_ex(bContext *C, const int pivot_point, float r_cursor[3])
Definition: view3d_snap.c:773
static int snap_curs_to_active_exec(bContext *C, wmOperator *UNUSED(op))
Definition: view3d_snap.c:929
static int snap_curs_to_grid_exec(bContext *C, wmOperator *UNUSED(op))
Definition: view3d_snap.c:674
void VIEW3D_OT_snap_selected_to_grid(wmOperatorType *ot)
Definition: view3d_snap.c:267
void VIEW3D_OT_snap_cursor_to_selected(wmOperatorType *ot)
Definition: view3d_snap.c:893
static bool snap_selected_to_location(bContext *C, const float snap_target_global[3], const bool use_offset, const int pivot_point, const bool use_toolsettings)
Definition: view3d_snap.c:297
static int snap_selected_to_active_exec(bContext *C, wmOperator *op)
Definition: view3d_snap.c:637
void VIEW3D_OT_snap_cursor_to_center(wmOperatorType *ot)
Definition: view3d_snap.c:979
static int snap_curs_to_sel_exec(bContext *C, wmOperator *UNUSED(op))
Definition: view3d_snap.c:880
static bool snap_calc_active_center(bContext *C, const bool select_only, float r_center[3])
Definition: view3d_snap.c:920
static int snap_selected_to_cursor_exec(bContext *C, wmOperator *op)
Definition: view3d_snap.c:593
void VIEW3D_OT_snap_selected_to_active(wmOperatorType *ot)
Definition: view3d_snap.c:652
static int snap_curs_to_center_exec(bContext *C, wmOperator *UNUSED(op))
Definition: view3d_snap.c:964
void VIEW3D_OT_snap_cursor_to_active(wmOperatorType *ot)
Definition: view3d_snap.c:942
void VIEW3D_OT_snap_selected_to_cursor(wmOperatorType *ot)
Definition: view3d_snap.c:608
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition: wm_files.c:3479