2 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
18 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19 * All rights reserved.
21 * Contributor(s): Blender Foundation, 2002-2008 full recode
23 * ***** END GPL LICENSE BLOCK *****
26 /** \file blender/editors/object/object_transform.c
34 #include "DNA_anim_types.h"
35 #include "DNA_armature_types.h"
36 #include "DNA_key_types.h"
37 #include "DNA_meshdata_types.h"
38 #include "DNA_object_types.h"
39 #include "DNA_scene_types.h"
40 #include "DNA_group_types.h"
43 #include "BLI_editVert.h"
44 #include "BLI_listbase.h"
45 #include "BLI_utildefines.h"
47 #include "BKE_context.h"
48 #include "BKE_curve.h"
49 #include "BKE_depsgraph.h"
52 #include "BKE_object.h"
53 #include "BKE_report.h"
54 #include "BKE_tessmesh.h"
55 #include "BKE_multires.h"
56 #include "BKE_armature.h"
58 #include "RNA_define.h"
59 #include "RNA_access.h"
64 #include "ED_armature.h"
65 #include "ED_keyframing.h"
67 #include "ED_screen.h"
68 #include "ED_view3d.h"
70 #include "object_intern.h"
72 /*************************** Clear Transformation ****************************/
74 /* clear location of object */
75 static void object_clear_loc(Object *ob)
77 /* clear location if not locked */
78 if ((ob->protectflag & OB_LOCK_LOCX)==0)
79 ob->loc[0]= ob->dloc[0]= 0.0f;
80 if ((ob->protectflag & OB_LOCK_LOCY)==0)
81 ob->loc[1]= ob->dloc[1]= 0.0f;
82 if ((ob->protectflag & OB_LOCK_LOCZ)==0)
83 ob->loc[2]= ob->dloc[2]= 0.0f;
86 /* clear rotation of object */
87 static void object_clear_rot(Object *ob)
89 /* clear rotations that aren't locked */
90 if (ob->protectflag & (OB_LOCK_ROTX|OB_LOCK_ROTY|OB_LOCK_ROTZ|OB_LOCK_ROTW)) {
91 if (ob->protectflag & OB_LOCK_ROT4D) {
92 /* perform clamping on a component by component basis */
93 if (ob->rotmode == ROT_MODE_AXISANGLE) {
94 if ((ob->protectflag & OB_LOCK_ROTW) == 0)
95 ob->rotAngle= ob->drotAngle= 0.0f;
96 if ((ob->protectflag & OB_LOCK_ROTX) == 0)
97 ob->rotAxis[0]= ob->drotAxis[0]= 0.0f;
98 if ((ob->protectflag & OB_LOCK_ROTY) == 0)
99 ob->rotAxis[1]= ob->drotAxis[1]= 0.0f;
100 if ((ob->protectflag & OB_LOCK_ROTZ) == 0)
101 ob->rotAxis[2]= ob->drotAxis[2]= 0.0f;
103 /* check validity of axis - axis should never be 0,0,0 (if so, then we make it rotate about y) */
104 if (IS_EQF(ob->rotAxis[0], ob->rotAxis[1]) && IS_EQF(ob->rotAxis[1], ob->rotAxis[2]))
105 ob->rotAxis[1] = 1.0f;
106 if (IS_EQF(ob->drotAxis[0], ob->drotAxis[1]) && IS_EQF(ob->drotAxis[1], ob->drotAxis[2]))
107 ob->drotAxis[1]= 1.0f;
109 else if (ob->rotmode == ROT_MODE_QUAT) {
110 if ((ob->protectflag & OB_LOCK_ROTW) == 0)
111 ob->quat[0]= ob->dquat[0]= 1.0f;
112 if ((ob->protectflag & OB_LOCK_ROTX) == 0)
113 ob->quat[1]= ob->dquat[1]= 0.0f;
114 if ((ob->protectflag & OB_LOCK_ROTY) == 0)
115 ob->quat[2]= ob->dquat[2]= 0.0f;
116 if ((ob->protectflag & OB_LOCK_ROTZ) == 0)
117 ob->quat[3]= ob->dquat[3]= 0.0f;
119 // TODO: does this quat need normalising now?
122 /* the flag may have been set for the other modes, so just ignore the extra flag... */
123 if ((ob->protectflag & OB_LOCK_ROTX) == 0)
124 ob->rot[0]= ob->drot[0]= 0.0f;
125 if ((ob->protectflag & OB_LOCK_ROTY) == 0)
126 ob->rot[1]= ob->drot[1]= 0.0f;
127 if ((ob->protectflag & OB_LOCK_ROTZ) == 0)
128 ob->rot[2]= ob->drot[2]= 0.0f;
132 /* perform clamping using euler form (3-components) */
133 // FIXME: deltas are not handled for these cases yet...
134 float eul[3], oldeul[3], quat1[4] = {0};
136 if (ob->rotmode == ROT_MODE_QUAT) {
137 copy_qt_qt(quat1, ob->quat);
138 quat_to_eul(oldeul, ob->quat);
140 else if (ob->rotmode == ROT_MODE_AXISANGLE) {
141 axis_angle_to_eulO(oldeul, EULER_ORDER_DEFAULT, ob->rotAxis, ob->rotAngle);
144 copy_v3_v3(oldeul, ob->rot);
147 eul[0]= eul[1]= eul[2]= 0.0f;
149 if (ob->protectflag & OB_LOCK_ROTX)
151 if (ob->protectflag & OB_LOCK_ROTY)
153 if (ob->protectflag & OB_LOCK_ROTZ)
156 if (ob->rotmode == ROT_MODE_QUAT) {
157 eul_to_quat(ob->quat, eul);
158 /* quaternions flip w sign to accumulate rotations correctly */
159 if ((quat1[0]<0.0f && ob->quat[0]>0.0f) || (quat1[0]>0.0f && ob->quat[0]<0.0f)) {
160 mul_qt_fl(ob->quat, -1.0f);
163 else if (ob->rotmode == ROT_MODE_AXISANGLE) {
164 eulO_to_axis_angle(ob->rotAxis, &ob->rotAngle,eul, EULER_ORDER_DEFAULT);
167 copy_v3_v3(ob->rot, eul);
170 } // Duplicated in source/blender/editors/armature/editarmature.c
172 if (ob->rotmode == ROT_MODE_QUAT) {
176 else if (ob->rotmode == ROT_MODE_AXISANGLE) {
177 unit_axis_angle(ob->rotAxis, &ob->rotAngle);
178 unit_axis_angle(ob->drotAxis, &ob->drotAngle);
187 /* clear scale of object */
188 static void object_clear_scale(Object *ob)
190 /* clear scale factors which are not locked */
191 if ((ob->protectflag & OB_LOCK_SCALEX)==0) {
195 if ((ob->protectflag & OB_LOCK_SCALEY)==0) {
199 if ((ob->protectflag & OB_LOCK_SCALEZ)==0) {
205 /* --------------- */
207 /* generic exec for clear-transform operators */
208 static int object_clear_transform_generic_exec(bContext *C, wmOperator *op,
209 void (*clear_func)(Object*), const char default_ksName[])
211 Main *bmain = CTX_data_main(C);
212 Scene *scene= CTX_data_scene(C);
216 if ELEM(NULL, clear_func, default_ksName) {
217 BKE_report(op->reports, RPT_ERROR, "Programming error: missing clear transform func or Keying Set Name");
218 return OPERATOR_CANCELLED;
221 /* get KeyingSet to use */
222 ks = ANIM_get_keyingset_for_autokeying(scene, default_ksName);
224 /* operate on selected objects only if they aren't in weight-paint mode
225 * (so that object-transform clearing won't be applied at same time as bone-clearing)
227 CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects)
229 if (!(ob->mode & OB_MODE_WEIGHT_PAINT)) {
230 /* run provided clearing function */
233 ED_autokeyframe_object(C, scene, ob, ks);
235 /* tag for updates */
236 DAG_id_tag_update(&ob->id, OB_RECALC_OB);
241 /* this is needed so children are also updated */
242 DAG_ids_flush_update(bmain, 0);
244 WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
246 return OPERATOR_FINISHED;
249 /* --------------- */
252 static int object_location_clear_exec(bContext *C, wmOperator *op)
254 return object_clear_transform_generic_exec(C, op, object_clear_loc, ANIM_KS_LOCATION_ID);
257 void OBJECT_OT_location_clear(wmOperatorType *ot)
260 ot->name= "Clear Location";
261 ot->description = "Clear the object's location";
262 ot->idname= "OBJECT_OT_location_clear";
265 ot->exec= object_location_clear_exec;
266 ot->poll= ED_operator_scene_editable;
269 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
272 static int object_rotation_clear_exec(bContext *C, wmOperator *op)
274 return object_clear_transform_generic_exec(C, op, object_clear_rot, ANIM_KS_ROTATION_ID);
277 void OBJECT_OT_rotation_clear(wmOperatorType *ot)
280 ot->name= "Clear Rotation";
281 ot->description = "Clear the object's rotation";
282 ot->idname= "OBJECT_OT_rotation_clear";
285 ot->exec= object_rotation_clear_exec;
286 ot->poll= ED_operator_scene_editable;
289 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
292 static int object_scale_clear_exec(bContext *C, wmOperator *op)
294 return object_clear_transform_generic_exec(C, op, object_clear_scale, ANIM_KS_SCALING_ID);
297 void OBJECT_OT_scale_clear(wmOperatorType *ot)
300 ot->name= "Clear Scale";
301 ot->description = "Clear the object's scale";
302 ot->idname= "OBJECT_OT_scale_clear";
305 ot->exec= object_scale_clear_exec;
306 ot->poll= ED_operator_scene_editable;
309 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
312 /* --------------- */
314 static int object_origin_clear_exec(bContext *C, wmOperator *UNUSED(op))
316 Main *bmain= CTX_data_main(C);
320 CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects)
323 /* vectors pointed to by v1 and v3 will get modified */
325 v3= ob->parentinv[3];
327 copy_m3_m4(mat, ob->parentinv);
328 negate_v3_v3(v3, v1);
332 DAG_id_tag_update(&ob->id, OB_RECALC_OB);
336 DAG_ids_flush_update(bmain, 0);
338 WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
340 return OPERATOR_FINISHED;
343 void OBJECT_OT_origin_clear(wmOperatorType *ot)
346 ot->name= "Clear Origin";
347 ot->description = "Clear the object's origin";
348 ot->idname= "OBJECT_OT_origin_clear";
351 ot->exec= object_origin_clear_exec;
352 ot->poll= ED_operator_scene_editable;
355 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
358 /*************************** Apply Transformation ****************************/
360 /* use this when the loc/size/rot of the parent has changed but the children
361 * should stay in the same place, e.g. for apply-size-rot or object center */
362 static void ignore_parent_tx(Main *bmain, Scene *scene, Object *ob )
367 /* a change was made, adjust the children to compensate */
368 for(ob_child=bmain->object.first; ob_child; ob_child=ob_child->id.next) {
369 if(ob_child->parent == ob) {
370 object_apply_mat4(ob_child, ob_child->obmat, TRUE, FALSE);
371 what_does_parent(scene, ob_child, &workob);
372 invert_m4_m4(ob_child->parentinv, workob.obmat);
377 static int apply_objects_internal(bContext *C, ReportList *reports, int apply_loc, int apply_rot, int apply_scale)
379 Main *bmain= CTX_data_main(C);
380 Scene *scene= CTX_data_scene(C);
381 float rsmat[3][3], tmat[3][3], obmat[3][3], iobmat[3][3], mat[4][4], scale;
384 /* first check if we can execute */
385 CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
387 if(ob->type==OB_MESH) {
388 if(ID_REAL_USERS(ob->data) > 1) {
389 BKE_report(reports, RPT_ERROR, "Can't apply to a multi user mesh, doing nothing");
390 return OPERATOR_CANCELLED;
393 else if(ob->type==OB_ARMATURE) {
394 if(ID_REAL_USERS(ob->data) > 1) {
395 BKE_report(reports, RPT_ERROR, "Can't apply to a multi user armature, doing nothing");
396 return OPERATOR_CANCELLED;
399 else if(ELEM(ob->type, OB_CURVE, OB_SURF)) {
402 if(ID_REAL_USERS(ob->data) > 1) {
403 BKE_report(reports, RPT_ERROR, "Can't apply to a multi user curve, doing nothing");
404 return OPERATOR_CANCELLED;
409 if(!(cu->flag & CU_3D) && (apply_rot || apply_loc)) {
410 BKE_report(reports, RPT_ERROR, "Neither rotation nor location could be applied to a 2d curve, doing nothing");
411 return OPERATOR_CANCELLED;
414 BKE_report(reports, RPT_ERROR, "Can't apply to a curve with vertex keys, doing nothing");
415 return OPERATOR_CANCELLED;
422 CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
424 /* calculate rotation/scale matrix */
425 if(apply_scale && apply_rot)
426 object_to_mat3(ob, rsmat);
428 object_scale_to_mat3(ob, rsmat);
430 float tmat[3][3], timat[3][3];
432 /* simple rotation matrix */
433 object_rot_to_mat3(ob, rsmat);
435 /* correct for scale, note mul_m3_m3m3 has swapped args! */
436 object_scale_to_mat3(ob, tmat);
437 invert_m3_m3(timat, tmat);
438 mul_m3_m3m3(rsmat, timat, rsmat);
439 mul_m3_m3m3(rsmat, rsmat, tmat);
444 copy_m4_m3(mat, rsmat);
446 /* calculate translation */
448 copy_v3_v3(mat[3], ob->loc);
450 if(!(apply_scale && apply_rot)) {
451 /* correct for scale and rotation that is still applied */
452 object_to_mat3(ob, obmat);
453 invert_m3_m3(iobmat, obmat);
454 mul_m3_m3m3(tmat, rsmat, iobmat);
455 mul_m3_v3(tmat, mat[3]);
459 /* apply to object data */
460 if(ob->type==OB_MESH) {
464 multiresModifier_scale_disp(scene, ob);
468 for(a=0; a<me->totvert; a++, mvert++)
469 mul_m4_v3(mat, mvert->co);
474 for(kb=me->key->block.first; kb; kb=kb->next) {
477 for(a=0; a<kb->totelem; a++, fp+=3)
483 mesh_calc_normals_mapping(me->mvert, me->totvert, me->mloop, me->mpoly, me->totloop, me->totpoly, NULL, NULL, 0, NULL, NULL);
485 else if (ob->type==OB_ARMATURE) {
486 ED_armature_apply_transform(ob, mat);
488 else if(ELEM(ob->type, OB_CURVE, OB_SURF)) {
495 scale = mat3_to_scale(rsmat);
497 for(nu=cu->nurb.first; nu; nu=nu->next) {
498 if(nu->type == CU_BEZIER) {
500 for(bezt= nu->bezt; a--; bezt++) {
501 mul_m4_v3(mat, bezt->vec[0]);
502 mul_m4_v3(mat, bezt->vec[1]);
503 mul_m4_v3(mat, bezt->vec[2]);
504 bezt->radius *= scale;
509 a= nu->pntsu*nu->pntsv;
510 for(bp= nu->bp; a--; bp++)
511 mul_m4_v3(mat, bp->vec);
521 ob->size[0]= ob->size[1]= ob->size[2]= 1.0f;
525 unit_axis_angle(ob->rotAxis, &ob->rotAngle);
528 where_is_object(scene, ob);
529 if(ob->type==OB_ARMATURE) {
530 where_is_pose(scene, ob); /* needed for bone parents */
533 ignore_parent_tx(bmain, scene, ob);
535 DAG_id_tag_update(&ob->id, OB_RECALC_OB|OB_RECALC_DATA);
542 return OPERATOR_CANCELLED;
544 WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
545 return OPERATOR_FINISHED;
548 static int visual_transform_apply_exec(bContext *C, wmOperator *UNUSED(op))
550 Scene *scene= CTX_data_scene(C);
553 CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
554 where_is_object(scene, ob);
555 object_apply_mat4(ob, ob->obmat, TRUE, TRUE);
556 where_is_object(scene, ob);
558 /* update for any children that may get moved */
559 DAG_id_tag_update(&ob->id, OB_RECALC_OB);
566 return OPERATOR_CANCELLED;
568 WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
569 return OPERATOR_FINISHED;
572 void OBJECT_OT_visual_transform_apply(wmOperatorType *ot)
575 ot->name= "Apply Visual Transform";
576 ot->description = "Apply the object's visual transformation to its data";
577 ot->idname= "OBJECT_OT_visual_transform_apply";
580 ot->exec= visual_transform_apply_exec;
581 ot->poll= ED_operator_scene_editable;
584 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
587 static int object_transform_apply_exec(bContext *C, wmOperator *op)
589 const int loc= RNA_boolean_get(op->ptr, "location");
590 const int rot= RNA_boolean_get(op->ptr, "rotation");
591 const int sca= RNA_boolean_get(op->ptr, "scale");
593 if(loc || rot || sca) {
594 return apply_objects_internal(C, op->reports, loc, rot, sca);
597 return OPERATOR_CANCELLED;
601 void OBJECT_OT_transform_apply(wmOperatorType *ot)
604 ot->name= "Apply Object Transform";
605 ot->description = "Apply the object's transformation to its data";
606 ot->idname= "OBJECT_OT_transform_apply";
609 ot->exec= object_transform_apply_exec;
610 ot->poll= ED_operator_objectmode;
613 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
615 RNA_def_boolean(ot->srna, "location", 0, "Location", "");
616 RNA_def_boolean(ot->srna, "rotation", 0, "Rotation", "");
617 RNA_def_boolean(ot->srna, "scale", 0, "Scale", "");
620 /********************* Set Object Center ************************/
623 GEOMETRY_TO_ORIGIN=0,
628 static int object_origin_set_exec(bContext *C, wmOperator *op)
630 Main *bmain= CTX_data_main(C);
631 Scene *scene= CTX_data_scene(C);
632 Object *obedit= CTX_data_edit_object(C);
634 float cursor[3], cent[3], cent_neg[3], centn[3], min[3], max[3];
635 int centermode = RNA_enum_get(op->ptr, "type");
636 int around = RNA_enum_get(op->ptr, "center"); /* initialized from v3d->around */
638 /* keep track of what is changed */
639 int tot_change=0, tot_lib_error=0, tot_multiuser_arm_error=0;
641 if (obedit && centermode != GEOMETRY_TO_ORIGIN) {
642 BKE_report(op->reports, RPT_ERROR, "Operation cannot be performed in EditMode");
643 return OPERATOR_CANCELLED;
646 /* get the view settings if 'around' isnt set and the view is available */
647 View3D *v3d= CTX_wm_view3d(C);
648 copy_v3_v3(cursor, give_cursor(scene, v3d));
649 if(v3d && !RNA_struct_property_is_set(op->ptr, "center"))
656 INIT_MINMAX(min, max);
658 if(obedit->type==OB_MESH) {
659 Mesh *me= obedit->data;
660 BMEditMesh *em = me->edit_btmesh;
665 if(centermode == ORIGIN_TO_CURSOR) {
666 copy_v3_v3(cent, cursor);
667 invert_m4_m4(obedit->imat, obedit->obmat);
668 mul_m4_v3(obedit->imat, cent);
670 BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
671 if(around==V3D_CENTROID) {
673 add_v3_v3(cent, eve->co);
674 mul_v3_fl(cent, 1.0f/(float)total);
677 DO_MINMAX(eve->co, min, max);
678 mid_v3_v3v3(cent, min, max);
683 BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
684 sub_v3_v3(eve->co, cent);
687 EDBM_RecalcNormals(em);
689 DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
694 CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
695 ob->flag &= ~OB_DONE;
699 for (tob= bmain->object.first; tob; tob= tob->id.next) {
701 ((ID *)tob->data)->flag &= ~LIB_DOIT;
703 ((ID *)tob->dup_group)->flag &= ~LIB_DOIT;
706 CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
707 if((ob->flag & OB_DONE)==0) {
708 int do_inverse_offset = FALSE;
711 if(centermode == ORIGIN_TO_CURSOR) {
712 copy_v3_v3(cent, cursor);
713 invert_m4_m4(ob->imat, ob->obmat);
714 mul_m4_v3(ob->imat, cent);
717 if(ob->data == NULL) {
718 /* special support for dupligroups */
719 if((ob->transflag & OB_DUPLIGROUP) && ob->dup_group && (ob->dup_group->id.flag & LIB_DOIT)==0) {
720 if(ob->dup_group->id.lib) {
724 if(centermode == ORIGIN_TO_CURSOR) { /* done */ }
726 /* only bounds support */
727 INIT_MINMAX(min, max);
728 minmax_object_duplis(scene, ob, min, max);
729 mid_v3_v3v3(cent, min, max);
730 invert_m4_m4(ob->imat, ob->obmat);
731 mul_m4_v3(ob->imat, cent);
734 add_v3_v3(ob->dup_group->dupli_ofs, cent);
737 ob->dup_group->id.flag |= LIB_DOIT;
738 do_inverse_offset= TRUE;
742 else if (((ID *)ob->data)->lib) {
746 if(obedit==NULL && ob->type==OB_MESH) {
749 if(centermode == ORIGIN_TO_CURSOR) { /* done */ }
750 else if(around==V3D_CENTROID) { mesh_center_median(me, cent); }
751 else { mesh_center_bounds(me, cent); }
753 negate_v3_v3(cent_neg, cent);
754 mesh_translate(me, cent_neg, 1);
757 me->id.flag |= LIB_DOIT;
758 do_inverse_offset= TRUE;
760 else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
763 if(centermode == ORIGIN_TO_CURSOR) { /* done */ }
764 else if(around==V3D_CENTROID) { curve_center_median(cu, cent); }
765 else { curve_center_bounds(cu, cent); }
767 /* don't allow Z change if curve is 2D */
768 if((ob->type == OB_CURVE) && !(cu->flag & CU_3D))
771 negate_v3_v3(cent_neg, cent);
772 curve_translate(cu, cent_neg, 1);
775 cu->id.flag |= LIB_DOIT;
776 do_inverse_offset= TRUE;
779 if (centermode == GEOMETRY_TO_ORIGIN) {
780 DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
785 else if(ob->type==OB_FONT) {
790 if(cu->bb==NULL && (centermode != ORIGIN_TO_CURSOR)) {
794 if(centermode == ORIGIN_TO_CURSOR) {
798 cent[0]= 0.5f * ( cu->bb->vec[4][0] + cu->bb->vec[0][0]);
799 cent[1]= 0.5f * ( cu->bb->vec[0][1] + cu->bb->vec[2][1]) - 0.5f; /* extra 0.5 is the height o above line */
804 cu->xof= cu->xof - (cent[0] / cu->fsize);
805 cu->yof= cu->yof - (cent[1] / cu->fsize);
808 cu->id.flag |= LIB_DOIT;
809 do_inverse_offset= TRUE;
812 else if(ob->type==OB_ARMATURE) {
813 bArmature *arm = ob->data;
815 if(ID_REAL_USERS(arm) > 1) {
816 /*BKE_report(op->reports, RPT_ERROR, "Can't apply to a multi user armature");
818 tot_multiuser_arm_error++;
821 /* Function to recenter armatures in editarmature.c
822 * Bone + object locations are handled there.
824 docenter_armature(scene, ob, cursor, centermode, around);
827 arm->id.flag |= LIB_DOIT;
828 /* do_inverse_offset= TRUE; */ /* docenter_armature() handles this */
830 where_is_object(scene, ob);
831 where_is_pose(scene, ob); /* needed for bone parents */
833 ignore_parent_tx(bmain, scene, ob);
840 /* offset other selected objects */
841 if(do_inverse_offset && (centermode != GEOMETRY_TO_ORIGIN)) {
842 /* was the object data modified
843 * note: the functions above must set 'cent' */
844 copy_v3_v3(centn, cent);
845 mul_mat3_m4_v3(ob->obmat, centn); /* ommit translation part */
846 add_v3_v3(ob->loc, centn);
848 where_is_object(scene, ob);
849 if(ob->type==OB_ARMATURE) {
850 where_is_pose(scene, ob); /* needed for bone parents */
853 ignore_parent_tx(bmain, scene, ob);
856 CTX_DATA_BEGIN(C, Object*, ob_other, selected_editable_objects) {
857 if( (ob_other->flag & OB_DONE)==0 &&
858 ( (ob->data && (ob->data == ob_other->data)) ||
859 (ob->dup_group==ob_other->dup_group && (ob->transflag|ob_other->transflag) & OB_DUPLIGROUP) )
861 ob_other->flag |= OB_DONE;
862 DAG_id_tag_update(&ob_other->id, OB_RECALC_OB|OB_RECALC_DATA);
864 copy_v3_v3(centn, cent);
865 mul_mat3_m4_v3(ob_other->obmat, centn); /* ommit translation part */
866 add_v3_v3(ob_other->loc, centn);
868 where_is_object(scene, ob_other);
869 if(ob_other->type==OB_ARMATURE) {
870 where_is_pose(scene, ob_other); /* needed for bone parents */
872 ignore_parent_tx(bmain, scene, ob_other);
881 for (tob= bmain->object.first; tob; tob= tob->id.next)
882 if(tob->data && (((ID *)tob->data)->flag & LIB_DOIT))
883 DAG_id_tag_update(&tob->id, OB_RECALC_OB|OB_RECALC_DATA);
886 DAG_ids_flush_update(bmain, 0);
887 WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
890 /* Warn if any errors occurred */
891 if (tot_lib_error+tot_multiuser_arm_error) {
892 BKE_reportf(op->reports, RPT_WARNING, "%i Object(s) Not Centered, %i Changed:",tot_lib_error+tot_multiuser_arm_error, tot_change);
894 BKE_reportf(op->reports, RPT_WARNING, "|%i linked library objects",tot_lib_error);
895 if (tot_multiuser_arm_error)
896 BKE_reportf(op->reports, RPT_WARNING, "|%i multiuser armature object(s)",tot_multiuser_arm_error);
899 return OPERATOR_FINISHED;
902 void OBJECT_OT_origin_set(wmOperatorType *ot)
904 static EnumPropertyItem prop_set_center_types[] = {
905 {GEOMETRY_TO_ORIGIN, "GEOMETRY_ORIGIN", 0, "Geometry to Origin", "Move object geometry to object origin"},
906 {ORIGIN_TO_GEOMETRY, "ORIGIN_GEOMETRY", 0, "Origin to Geometry", "Move object origin to center of object geometry"},
907 {ORIGIN_TO_CURSOR, "ORIGIN_CURSOR", 0, "Origin to 3D Cursor", "Move object origin to position of the 3d cursor"},
908 {0, NULL, 0, NULL, NULL}
911 static EnumPropertyItem prop_set_bounds_types[] = {
912 {V3D_CENTROID, "MEDIAN", 0, "Median Center", ""},
913 {V3D_CENTER, "BOUNDS", 0, "Bounds Center", ""},
914 {0, NULL, 0, NULL, NULL}
918 ot->name= "Set Origin";
919 ot->description = "Set the object's origin, by either moving the data, or set to center of data, or use 3d cursor";
920 ot->idname= "OBJECT_OT_origin_set";
923 ot->invoke= WM_menu_invoke;
924 ot->exec= object_origin_set_exec;
926 ot->poll= ED_operator_scene_editable;
929 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
931 ot->prop= RNA_def_enum(ot->srna, "type", prop_set_center_types, 0, "Type", "");
932 RNA_def_enum(ot->srna, "center", prop_set_bounds_types, V3D_CENTROID, "Center", "");