Blender  V2.59
view3d_snap.c
Go to the documentation of this file.
00001 /*
00002  * $Id: view3d_snap.c 36596 2011-05-10 14:48:06Z campbellbarton $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00021  * All rights reserved.
00022  *
00023  * The Original Code is: all of this file.
00024  *
00025  * Contributor(s): none yet.
00026  *
00027  * ***** END GPL LICENSE BLOCK *****
00028  */
00029 
00035 #include <math.h>
00036 #include <string.h>
00037 
00038 #include "MEM_guardedalloc.h"
00039 
00040 #include "DNA_armature_types.h"
00041 #include "DNA_curve_types.h"
00042 #include "DNA_lattice_types.h"
00043 #include "DNA_meta_types.h"
00044 #include "DNA_scene_types.h"
00045 #include "DNA_object_types.h"
00046 
00047 #include "BLI_blenlib.h"
00048 #include "BLI_math.h"
00049 #include "BLI_editVert.h"
00050 #include "BLI_linklist.h"
00051 #include "BLI_utildefines.h"
00052 
00053 #include "BKE_armature.h"
00054 #include "BKE_context.h"
00055 #include "BKE_curve.h"
00056 #include "BKE_depsgraph.h"
00057 #include "BKE_lattice.h"
00058 #include "BKE_main.h"
00059 #include "BKE_object.h"
00060 
00061 #include "WM_api.h"
00062 #include "WM_types.h"
00063 
00064 
00065 
00066 #include "ED_armature.h"
00067 #include "ED_mesh.h"
00068 #include "ED_screen.h"
00069 #include "ED_curve.h" /* for ED_curve_editnurbs */
00070 
00071 #include "view3d_intern.h"
00072 
00073 extern float originmat[3][3];   /* XXX object.c */
00074 
00075 /* ************************************************** */
00076 /* ********************* old transform stuff ******** */
00077 /* *********** will get replaced with new transform * */
00078 /* ************************************************** */
00079 
00080 typedef struct TransVert {
00081         float *loc;
00082         float oldloc[3], fac;
00083         float *val, oldval;
00084         int flag;
00085         float *nor;
00086 } TransVert;
00087 
00088 static TransVert *transvmain=NULL;
00089 static int tottrans= 0;
00090 
00091 /* copied from editobject.c, now uses (almost) proper depgraph */
00092 static void special_transvert_update(Object *obedit)
00093 {
00094         
00095         if(obedit) {
00096                 
00097                 DAG_id_tag_update(obedit->data, 0);
00098                 
00099                 if(obedit->type==OB_MESH) {
00100                         Mesh *me= obedit->data;
00101                         recalc_editnormals(me->edit_mesh);      // does face centers too
00102                 }
00103                 else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
00104                         Curve *cu= obedit->data;
00105                         ListBase *nurbs= ED_curve_editnurbs(cu);
00106                         Nurb *nu= nurbs->first;
00107 
00108                         while(nu) {
00109                                 /* keep handles' vectors unchanged */
00110                                 if(nu->bezt) {
00111                                         int a= nu->pntsu;
00112                                         TransVert *tv= transvmain;
00113                                         BezTriple *bezt= nu->bezt;
00114 
00115                                         while(a--) {
00116                                                 if(bezt->f1 & SELECT) tv++;
00117 
00118                                                 if(bezt->f2 & SELECT) {
00119                                                         float v[3];
00120 
00121                                                         if(bezt->f1 & SELECT) {
00122                                                                 sub_v3_v3v3(v, (tv-1)->oldloc, tv->oldloc);
00123                                                                 add_v3_v3v3(bezt->vec[0], bezt->vec[1], v);
00124                                                         }
00125 
00126                                                         if(bezt->f3 & SELECT) {
00127                                                                 sub_v3_v3v3(v, (tv+1)->oldloc, tv->oldloc);
00128                                                                 add_v3_v3v3(bezt->vec[2], bezt->vec[1], v);
00129                                                         }
00130 
00131                                                         tv++;
00132                                                 }
00133 
00134                                                 if(bezt->f3 & SELECT) tv++;
00135 
00136                                                 bezt++;
00137                                         }
00138                                 }
00139 
00140                                 test2DNurb(nu);
00141                                 testhandlesNurb(nu); /* test for bezier too */
00142                                 nu= nu->next;
00143                         }
00144                 }
00145                 else if(obedit->type==OB_ARMATURE){
00146                         bArmature *arm= obedit->data;
00147                         EditBone *ebo;
00148                         TransVert *tv= transvmain;
00149                         int a=0;
00150                         
00151                         /* Ensure all bone tails are correctly adjusted */
00152                         for (ebo= arm->edbo->first; ebo; ebo=ebo->next) {
00153                                 /* adjust tip if both ends selected */
00154                                 if ((ebo->flag & BONE_ROOTSEL) && (ebo->flag & BONE_TIPSEL)) {
00155                                         if (tv) {
00156                                                 float diffvec[3];
00157                                                 
00158                                                 sub_v3_v3v3(diffvec, tv->loc, tv->oldloc);
00159                                                 add_v3_v3(ebo->tail, diffvec);
00160                                                 
00161                                                 a++;
00162                                                 if (a<tottrans) tv++;
00163                                         }
00164                                 }
00165                         }
00166                         
00167                         /* Ensure all bones are correctly adjusted */
00168                         for (ebo= arm->edbo->first; ebo; ebo=ebo->next) {
00169                                 if ((ebo->flag & BONE_CONNECTED) && ebo->parent){
00170                                         /* If this bone has a parent tip that has been moved */
00171                                         if (ebo->parent->flag & BONE_TIPSEL){
00172                                                 VECCOPY (ebo->head, ebo->parent->tail);
00173                                         }
00174                                         /* If this bone has a parent tip that has NOT been moved */
00175                                         else{
00176                                                 VECCOPY (ebo->parent->tail, ebo->head);
00177                                         }
00178                                 }
00179                         }
00180                         if(arm->flag & ARM_MIRROR_EDIT) 
00181                                 transform_armature_mirror_update(obedit);
00182                 }
00183                 else if(obedit->type==OB_LATTICE) {
00184                         Lattice *lt= obedit->data;
00185                         
00186                         if(lt->editlatt->latt->flag & LT_OUTSIDE)
00187                                 outside_lattice(lt->editlatt->latt);
00188                 }
00189         }
00190 }
00191 
00192 /* copied from editobject.c, needs to be replaced with new transform code still */
00193 /* mode flags: */
00194 #define TM_ALL_JOINTS           1 /* all joints (for bones only) */
00195 #define TM_SKIP_HANDLES         2 /* skip handles when control point is selected (for curves only) */
00196 static void make_trans_verts(Object *obedit, float *min, float *max, int mode)  
00197 {
00198         Nurb *nu;
00199         BezTriple *bezt;
00200         BPoint *bp;
00201         TransVert *tv=NULL;
00202         MetaElem *ml;
00203         EditVert *eve;
00204         EditBone        *ebo;
00205         float total, center[3], centroid[3];
00206         int a;
00207 
00208         tottrans= 0; // global!
00209         
00210         INIT_MINMAX(min, max);
00211         centroid[0]=centroid[1]=centroid[2]= 0.0;
00212         
00213         if(obedit->type==OB_MESH) {
00214                 Mesh *me= obedit->data;
00215                 EditMesh *em= me->edit_mesh;
00216                 
00217                 // transform now requires awareness for select mode, so we tag the f1 flags in verts
00218                 tottrans= 0;
00219                 if(em->selectmode & SCE_SELECT_VERTEX) {
00220                         for(eve= em->verts.first; eve; eve= eve->next) {
00221                                 if(eve->h==0 && (eve->f & SELECT)) {
00222                                         eve->f1= SELECT;
00223                                         tottrans++;
00224                                 }
00225                                 else eve->f1= 0;
00226                         }
00227                 }
00228                 else if(em->selectmode & SCE_SELECT_EDGE) {
00229                         EditEdge *eed;
00230                         for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
00231                         for(eed= em->edges.first; eed; eed= eed->next) {
00232                                 if(eed->h==0 && (eed->f & SELECT)) eed->v1->f1= eed->v2->f1= SELECT;
00233                         }
00234                         for(eve= em->verts.first; eve; eve= eve->next) if(eve->f1) tottrans++;
00235                 }
00236                 else {
00237                         EditFace *efa;
00238                         for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
00239                         for(efa= em->faces.first; efa; efa= efa->next) {
00240                                 if(efa->h==0 && (efa->f & SELECT)) {
00241                                         efa->v1->f1= efa->v2->f1= efa->v3->f1= SELECT;
00242                                         if(efa->v4) efa->v4->f1= SELECT;
00243                                 }
00244                         }
00245                         for(eve= em->verts.first; eve; eve= eve->next) if(eve->f1) tottrans++;
00246                 }
00247                 
00248                 /* and now make transverts */
00249                 if(tottrans) {
00250                         tv=transvmain= MEM_callocN(tottrans*sizeof(TransVert), "maketransverts");
00251 
00252                         for(eve= em->verts.first; eve; eve= eve->next) {
00253                                 if(eve->f1) {
00254                                         VECCOPY(tv->oldloc, eve->co);
00255                                         tv->loc= eve->co;
00256                                         if(eve->no[0] != 0.0f || eve->no[1] != 0.0f ||eve->no[2] != 0.0f)
00257                                                 tv->nor= eve->no; // note this is a hackish signal (ton)
00258                                         tv->flag= eve->f1 & SELECT;
00259                                         tv++;
00260                                 }
00261                         }
00262                 }
00263         }
00264         else if (obedit->type==OB_ARMATURE){
00265                 bArmature *arm= obedit->data;
00266                 int totmalloc= BLI_countlist(arm->edbo);
00267 
00268                 totmalloc *= 2;  /* probably overkill but bones can have 2 trans verts each */
00269 
00270                 tv=transvmain= MEM_callocN(totmalloc*sizeof(TransVert), "maketransverts armature");
00271                 
00272                 for (ebo= arm->edbo->first; ebo; ebo=ebo->next){
00273                         if(ebo->layer & arm->layer) {
00274                                 short tipsel= (ebo->flag & BONE_TIPSEL);
00275                                 short rootsel= (ebo->flag & BONE_ROOTSEL);
00276                                 short rootok= (!(ebo->parent && (ebo->flag & BONE_CONNECTED) && ebo->parent->flag & BONE_TIPSEL));
00277                                 
00278                                 if ((tipsel && rootsel) || (rootsel)) {
00279                                         /* Don't add the tip (unless mode & TM_ALL_JOINTS, for getting all joints),
00280                                          * otherwise we get zero-length bones as tips will snap to the same
00281                                          * location as heads. 
00282                                          */
00283                                         if (rootok) {
00284                                                 VECCOPY (tv->oldloc, ebo->head);
00285                                                 tv->loc= ebo->head;
00286                                                 tv->nor= NULL;
00287                                                 tv->flag= 1;
00288                                                 tv++;
00289                                                 tottrans++;
00290                                         }       
00291                                         
00292                                         if ((mode & TM_ALL_JOINTS) && (tipsel)) {
00293                                                 VECCOPY (tv->oldloc, ebo->tail);
00294                                                 tv->loc= ebo->tail;
00295                                                 tv->nor= NULL;
00296                                                 tv->flag= 1;
00297                                                 tv++;
00298                                                 tottrans++;
00299                                         }                                       
00300                                 }
00301                                 else if (tipsel) {
00302                                         VECCOPY (tv->oldloc, ebo->tail);
00303                                         tv->loc= ebo->tail;
00304                                         tv->nor= NULL;
00305                                         tv->flag= 1;
00306                                         tv++;
00307                                         tottrans++;
00308                                 }
00309                         }                       
00310                 }
00311         }
00312         else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
00313                 Curve *cu= obedit->data;
00314                 int totmalloc= 0;
00315                 ListBase *nurbs= ED_curve_editnurbs(cu);
00316 
00317                 for(nu= nurbs->first; nu; nu= nu->next) {
00318                         if(nu->type == CU_BEZIER)
00319                                 totmalloc += 3*nu->pntsu;
00320                         else
00321                                 totmalloc += nu->pntsu*nu->pntsv;
00322                 }
00323                 tv=transvmain= MEM_callocN(totmalloc*sizeof(TransVert), "maketransverts curve");
00324 
00325                 nu= nurbs->first;
00326                 while(nu) {
00327                         if(nu->type == CU_BEZIER) {
00328                                 a= nu->pntsu;
00329                                 bezt= nu->bezt;
00330                                 while(a--) {
00331                                         if(bezt->hide==0) {
00332                                                 int skip_handle= 0;
00333                                                 if(bezt->f2 & SELECT)
00334                                                         skip_handle= mode & TM_SKIP_HANDLES;
00335 
00336                                                 if((bezt->f1 & SELECT) && !skip_handle) {
00337                                                         VECCOPY(tv->oldloc, bezt->vec[0]);
00338                                                         tv->loc= bezt->vec[0];
00339                                                         tv->flag= bezt->f1 & SELECT;
00340                                                         tv++;
00341                                                         tottrans++;
00342                                                 }
00343                                                 if(bezt->f2 & SELECT) {
00344                                                         VECCOPY(tv->oldloc, bezt->vec[1]);
00345                                                         tv->loc= bezt->vec[1];
00346                                                         tv->val= &(bezt->alfa);
00347                                                         tv->oldval= bezt->alfa;
00348                                                         tv->flag= bezt->f2 & SELECT;
00349                                                         tv++;
00350                                                         tottrans++;
00351                                                 }
00352                                                 if((bezt->f3 & SELECT) && !skip_handle) {
00353                                                         VECCOPY(tv->oldloc, bezt->vec[2]);
00354                                                         tv->loc= bezt->vec[2];
00355                                                         tv->flag= bezt->f3 & SELECT;
00356                                                         tv++;
00357                                                         tottrans++;
00358                                                 }
00359                                         }
00360                                         bezt++;
00361                                 }
00362                         }
00363                         else {
00364                                 a= nu->pntsu*nu->pntsv;
00365                                 bp= nu->bp;
00366                                 while(a--) {
00367                                         if(bp->hide==0) {
00368                                                 if(bp->f1 & SELECT) {
00369                                                         VECCOPY(tv->oldloc, bp->vec);
00370                                                         tv->loc= bp->vec;
00371                                                         tv->val= &(bp->alfa);
00372                                                         tv->oldval= bp->alfa;
00373                                                         tv->flag= bp->f1 & SELECT;
00374                                                         tv++;
00375                                                         tottrans++;
00376                                                 }
00377                                         }
00378                                         bp++;
00379                                 }
00380                         }
00381                         nu= nu->next;
00382                 }
00383         }
00384         else if(obedit->type==OB_MBALL) {
00385                 MetaBall *mb= obedit->data;
00386                 int totmalloc= BLI_countlist(mb->editelems);
00387                 
00388                 tv=transvmain= MEM_callocN(totmalloc*sizeof(TransVert), "maketransverts mball");
00389                 
00390                 ml= mb->editelems->first;
00391                 while(ml) {
00392                         if(ml->flag & SELECT) {
00393                                 tv->loc= &ml->x;
00394                                 copy_v3_v3(tv->oldloc, tv->loc);
00395                                 tv->val= &(ml->rad);
00396                                 tv->oldval= ml->rad;
00397                                 tv->flag= 1;
00398                                 tv++;
00399                                 tottrans++;
00400                         }
00401                         ml= ml->next;
00402                 }
00403         }
00404         else if(obedit->type==OB_LATTICE) {
00405                 Lattice *lt= obedit->data;
00406                 
00407                 bp= lt->editlatt->latt->def;
00408                 
00409                 a= lt->editlatt->latt->pntsu*lt->editlatt->latt->pntsv*lt->editlatt->latt->pntsw;
00410                 
00411                 tv=transvmain= MEM_callocN(a*sizeof(TransVert), "maketransverts latt");
00412                 
00413                 while(a--) {
00414                         if(bp->f1 & SELECT) {
00415                                 if(bp->hide==0) {
00416                                         copy_v3_v3(tv->oldloc, bp->vec);
00417                                         tv->loc= bp->vec;
00418                                         tv->flag= bp->f1 & SELECT;
00419                                         tv++;
00420                                         tottrans++;
00421                                 }
00422                         }
00423                         bp++;
00424                 }
00425         }
00426         
00427         if(!tottrans && transvmain) {
00428                 /* prevent memory leak. happens for curves/latticies due to */
00429                 /* difficult condition of adding points to trans data */
00430                 MEM_freeN(transvmain);
00431                 transvmain= NULL;
00432         }
00433 
00434         /* cent etc */
00435         tv= transvmain;
00436         total= 0.0;
00437         for(a=0; a<tottrans; a++, tv++) {
00438                 if(tv->flag & SELECT) {
00439                         add_v3_v3(centroid, tv->oldloc);
00440                         total += 1.0f;
00441                         DO_MINMAX(tv->oldloc, min, max);
00442                 }
00443         }
00444         if(total != 0.0f) {
00445                 mul_v3_fl(centroid, 1.0f/total);
00446         }
00447 
00448         mid_v3_v3v3(center, min, max);
00449 }
00450 
00451 /* *********************** operators ******************** */
00452 
00453 static int snap_sel_to_grid(bContext *C, wmOperator *UNUSED(op))
00454 {
00455         Main *bmain= CTX_data_main(C);
00456         Object *obedit= CTX_data_edit_object(C);
00457         Scene *scene= CTX_data_scene(C);
00458         RegionView3D *rv3d= CTX_wm_region_data(C);
00459         TransVert *tv;
00460         float gridf, imat[3][3], bmat[3][3], vec[3];
00461         int a;
00462 
00463         gridf= rv3d->gridview;
00464 
00465         if(obedit) {
00466                 tottrans= 0;
00467                 
00468                 if ELEM6(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL) 
00469                         make_trans_verts(obedit, bmat[0], bmat[1], 0);
00470                 if(tottrans==0) return OPERATOR_CANCELLED;
00471                 
00472                 copy_m3_m4(bmat, obedit->obmat);
00473                 invert_m3_m3(imat, bmat);
00474                 
00475                 tv= transvmain;
00476                 for(a=0; a<tottrans; a++, tv++) {
00477                         
00478                         VECCOPY(vec, tv->loc);
00479                         mul_m3_v3(bmat, vec);
00480                         add_v3_v3(vec, obedit->obmat[3]);
00481                         vec[0]= gridf*floorf(0.5f+ vec[0]/gridf);
00482                         vec[1]= gridf*floorf(0.5f+ vec[1]/gridf);
00483                         vec[2]= gridf*floorf(0.5f+ vec[2]/gridf);
00484                         sub_v3_v3(vec, obedit->obmat[3]);
00485                         
00486                         mul_m3_v3(imat, vec);
00487                         VECCOPY(tv->loc, vec);
00488                 }
00489                 
00490                 special_transvert_update(obedit);
00491                 
00492                 MEM_freeN(transvmain);
00493                 transvmain= NULL;
00494         
00495         }
00496         else {
00497 
00498                 CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
00499                         if(ob->mode & OB_MODE_POSE) {
00500                                 bPoseChannel *pchan;
00501                                 bArmature *arm= ob->data;
00502                                 
00503                                 for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
00504                                         if(pchan->bone->flag & BONE_SELECTED) {
00505                                                 if(pchan->bone->layer & arm->layer) {
00506                                                         if((pchan->bone->flag & BONE_CONNECTED)==0) { 
00507                                                                 float vecN[3], nLoc[3]; 
00508                                                                 
00509                                                                 /* get nearest grid point to snap to */
00510                                                                 VECCOPY(nLoc, pchan->pose_mat[3]);
00511                                                                 vec[0]= gridf * (float)(floor(0.5f+ nLoc[0]/gridf));
00512                                                                 vec[1]= gridf * (float)(floor(0.5f+ nLoc[1]/gridf));
00513                                                                 vec[2]= gridf * (float)(floor(0.5f+ nLoc[2]/gridf));
00514                                                                 
00515                                                                 /* get bone-space location of grid point */
00516                                                                 armature_loc_pose_to_bone(pchan, vec, vecN);
00517                                                                 
00518                                                                 /* adjust location */
00519                                                                 if ((pchan->protectflag & OB_LOCK_LOCX)==0)     
00520                                                                         pchan->loc[0]= vecN[0];
00521                                                                 if ((pchan->protectflag & OB_LOCK_LOCY)==0)     
00522                                                                         pchan->loc[0]= vecN[1];
00523                                                                 if ((pchan->protectflag & OB_LOCK_LOCZ)==0)     
00524                                                                         pchan->loc[0]= vecN[2];
00525                                                         }
00526                                                         /* if the bone has a parent and is connected to the parent, 
00527                                                          * don't do anything - will break chain unless we do auto-ik. 
00528                                                          */
00529                                                 }
00530                                         }
00531                                 }
00532                                 ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK);
00533                                 
00534                                 /* auto-keyframing */
00535 // XXX                          autokeyframe_pose_cb_func(ob, TFM_TRANSLATION, 0);
00536                                 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
00537                         }
00538                         else {
00539                                 ob->recalc |= OB_RECALC_OB;
00540                                 
00541                                 vec[0]= -ob->obmat[3][0]+gridf*floorf(0.5f+ ob->obmat[3][0]/gridf);
00542                                 vec[1]= -ob->obmat[3][1]+gridf*floorf(0.5f+ ob->obmat[3][1]/gridf);
00543                                 vec[2]= -ob->obmat[3][2]+gridf*floorf(0.5f+ ob->obmat[3][2]/gridf);
00544                                 
00545                                 if(ob->parent) {
00546                                         where_is_object(scene, ob);
00547                                         
00548                                         invert_m3_m3(imat, originmat);
00549                                         mul_m3_v3(imat, vec);
00550                                 }
00551                                 if ((ob->protectflag & OB_LOCK_LOCX)==0)
00552                                         ob->loc[0]+= vec[0];
00553                                 if ((ob->protectflag & OB_LOCK_LOCY)==0)
00554                                         ob->loc[1]+= vec[1];
00555                                 if ((ob->protectflag & OB_LOCK_LOCZ)==0)
00556                                         ob->loc[2]+= vec[2];
00557                                 
00558                                 /* auto-keyframing */
00559 // XXX                          autokeyframe_ob_cb_func(ob, TFM_TRANSLATION);
00560                         }
00561                 }
00562                 CTX_DATA_END;
00563         }
00564 
00565         DAG_ids_flush_update(bmain, 0);
00566         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
00567         
00568         return OPERATOR_FINISHED;
00569 }
00570 
00571 void VIEW3D_OT_snap_selected_to_grid(wmOperatorType *ot)
00572 {
00573         
00574         /* identifiers */
00575         ot->name= "Snap Selection to Grid";
00576         ot->description= "Snap selected item(s) to nearest grid node";
00577         ot->idname= "VIEW3D_OT_snap_selected_to_grid";
00578         
00579         /* api callbacks */
00580         ot->exec= snap_sel_to_grid;
00581         ot->poll= ED_operator_region_view3d_active;
00582         
00583         /* flags */
00584         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00585 }
00586 
00587 /* *************************************************** */
00588 
00589 static int snap_sel_to_curs(bContext *C, wmOperator *UNUSED(op))
00590 {
00591         Main *bmain= CTX_data_main(C);
00592         Object *obedit= CTX_data_edit_object(C);
00593         Scene *scene= CTX_data_scene(C);
00594         View3D *v3d= CTX_wm_view3d(C);
00595         TransVert *tv;
00596         float *curs, imat[3][3], bmat[3][3], vec[3];
00597         int a;
00598 
00599         curs= give_cursor(scene, v3d);
00600 
00601         if(obedit) {
00602                 tottrans= 0;
00603                 
00604                 if ELEM6(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL) 
00605                         make_trans_verts(obedit, bmat[0], bmat[1], 0);
00606                 if(tottrans==0) return OPERATOR_CANCELLED;
00607                 
00608                 copy_m3_m4(bmat, obedit->obmat);
00609                 invert_m3_m3(imat, bmat);
00610                 
00611                 tv= transvmain;
00612                 for(a=0; a<tottrans; a++, tv++) {
00613                         sub_v3_v3v3(vec, curs, obedit->obmat[3]);
00614                         mul_m3_v3(imat, vec);
00615                         copy_v3_v3(tv->loc, vec);
00616                 }
00617                 
00618                 special_transvert_update(obedit);
00619                 
00620                 MEM_freeN(transvmain);
00621                 transvmain= NULL;
00622                 
00623         }
00624         else {
00625                 CTX_DATA_BEGIN(C, Object*, ob, selected_editable_objects) {
00626                         if(ob->mode & OB_MODE_POSE) {
00627                                 bPoseChannel *pchan;
00628                                 bArmature *arm= ob->data;
00629                                 float cursp[3];
00630                                 
00631                                 invert_m4_m4(ob->imat, ob->obmat);
00632                                 VECCOPY(cursp, curs);
00633                                 mul_m4_v3(ob->imat, cursp);
00634                                 
00635                                 for (pchan = ob->pose->chanbase.first; pchan; pchan=pchan->next) {
00636                                         if(pchan->bone->flag & BONE_SELECTED) {
00637                                                 if(pchan->bone->layer & arm->layer) {
00638                                                         if((pchan->bone->flag & BONE_CONNECTED)==0) { 
00639                                                                 float curspn[3];
00640                                                                 
00641                                                                 /* get location of cursor in bone-space */
00642                                                                 armature_loc_pose_to_bone(pchan, cursp, curspn);
00643                                                                 
00644                                                                 /* copy new position */
00645                                                                 if ((pchan->protectflag & OB_LOCK_LOCX)==0)     
00646                                                                         pchan->loc[0]= curspn[0];
00647                                                                 if ((pchan->protectflag & OB_LOCK_LOCY)==0)     
00648                                                                         pchan->loc[1]= curspn[1];
00649                                                                 if ((pchan->protectflag & OB_LOCK_LOCZ)==0)     
00650                                                                         pchan->loc[2]= curspn[2];
00651                                                         }
00652                                                         /* if the bone has a parent and is connected to the parent, 
00653                                                          * don't do anything - will break chain unless we do auto-ik. 
00654                                                          */
00655                                                 }
00656                                         }
00657                                 }
00658                                 ob->pose->flag |= (POSE_LOCKED|POSE_DO_UNLOCK);
00659                                 
00660                                 /* auto-keyframing */
00661 // XXX                          autokeyframe_pose_cb_func(ob, TFM_TRANSLATION, 0);
00662                                 DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
00663                         }
00664                         else {
00665                                 ob->recalc |= OB_RECALC_OB;
00666                                 
00667                                 vec[0]= -ob->obmat[3][0] + curs[0];
00668                                 vec[1]= -ob->obmat[3][1] + curs[1];
00669                                 vec[2]= -ob->obmat[3][2] + curs[2];
00670                                 
00671                                 if(ob->parent) {
00672                                         where_is_object(scene, ob);
00673                                         
00674                                         invert_m3_m3(imat, originmat);
00675                                         mul_m3_v3(imat, vec);
00676                                 }
00677                                 if ((ob->protectflag & OB_LOCK_LOCX)==0)
00678                                         ob->loc[0]+= vec[0];
00679                                 if ((ob->protectflag & OB_LOCK_LOCY)==0)
00680                                         ob->loc[1]+= vec[1];
00681                                 if ((ob->protectflag & OB_LOCK_LOCZ)==0)
00682                                         ob->loc[2]+= vec[2];
00683                                 
00684                                 /* auto-keyframing */
00685 // XXX                          autokeyframe_ob_cb_func(ob, TFM_TRANSLATION);
00686                         }
00687                 }
00688                 CTX_DATA_END;
00689         }
00690 
00691         DAG_ids_flush_update(bmain, 0);
00692         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, NULL);
00693         
00694         return OPERATOR_FINISHED;
00695 }
00696 
00697 void VIEW3D_OT_snap_selected_to_cursor(wmOperatorType *ot)
00698 {
00699         
00700         /* identifiers */
00701         ot->name= "Snap Selection to Cursor";
00702         ot->description= "Snap selected item(s) to cursor";
00703         ot->idname= "VIEW3D_OT_snap_selected_to_cursor";
00704         
00705         /* api callbacks */
00706         ot->exec= snap_sel_to_curs;
00707         ot->poll= ED_operator_view3d_active;
00708         
00709         /* flags */
00710         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00711 }
00712 
00713 /* *************************************************** */
00714 
00715 static int snap_curs_to_grid(bContext *C, wmOperator *UNUSED(op))
00716 {
00717         Scene *scene= CTX_data_scene(C);
00718         RegionView3D *rv3d= CTX_wm_region_data(C);
00719         View3D *v3d= CTX_wm_view3d(C);
00720         float gridf, *curs;
00721 
00722         gridf= rv3d->gridview;
00723         curs= give_cursor(scene, v3d);
00724 
00725         curs[0]= gridf*floorf(0.5f+curs[0]/gridf);
00726         curs[1]= gridf*floorf(0.5f+curs[1]/gridf);
00727         curs[2]= gridf*floorf(0.5f+curs[2]/gridf);
00728         
00729         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);        // hrm
00730         
00731         return OPERATOR_FINISHED;
00732 }
00733 
00734 void VIEW3D_OT_snap_cursor_to_grid(wmOperatorType *ot)
00735 {
00736         
00737         /* identifiers */
00738         ot->name= "Snap Cursor to Grid";
00739         ot->description= "Snap cursor to nearest grid node";
00740         ot->idname= "VIEW3D_OT_snap_cursor_to_grid";
00741         
00742         /* api callbacks */
00743         ot->exec= snap_curs_to_grid;
00744         ot->poll= ED_operator_region_view3d_active;
00745         
00746         /* flags */
00747         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00748 }
00749 
00750 /* **************************************************** */
00751 
00752 static int snap_curs_to_sel(bContext *C, wmOperator *UNUSED(op))
00753 {
00754         Object *obedit= CTX_data_edit_object(C);
00755         Scene *scene= CTX_data_scene(C);
00756         View3D *v3d= CTX_wm_view3d(C);
00757         TransVert *tv;
00758         float *curs, bmat[3][3], vec[3], min[3], max[3], centroid[3];
00759         int count, a;
00760 
00761         curs= give_cursor(scene, v3d);
00762 
00763         count= 0;
00764         INIT_MINMAX(min, max);
00765         centroid[0]= centroid[1]= centroid[2]= 0.0;
00766 
00767         if(obedit) {
00768                 tottrans=0;
00769                 
00770                 if ELEM6(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL) 
00771                         make_trans_verts(obedit, bmat[0], bmat[1], TM_ALL_JOINTS|TM_SKIP_HANDLES);
00772                 if(tottrans==0) return OPERATOR_CANCELLED;
00773                 
00774                 copy_m3_m4(bmat, obedit->obmat);
00775                 
00776                 tv= transvmain;
00777                 for(a=0; a<tottrans; a++, tv++) {
00778                         VECCOPY(vec, tv->loc);
00779                         mul_m3_v3(bmat, vec);
00780                         add_v3_v3(vec, obedit->obmat[3]);
00781                         add_v3_v3(centroid, vec);
00782                         DO_MINMAX(vec, min, max);
00783                 }
00784                 
00785                 if(v3d->around==V3D_CENTROID) {
00786                         mul_v3_fl(centroid, 1.0f/(float)tottrans);
00787                         VECCOPY(curs, centroid);
00788                 }
00789                 else {
00790                         mid_v3_v3v3(curs, min, max);
00791                 }
00792                 MEM_freeN(transvmain);
00793                 transvmain= NULL;
00794         }
00795         else {
00796                 Object *obact= CTX_data_active_object(C);
00797                 
00798                 if(obact && (obact->mode & OB_MODE_POSE)) {
00799                         bArmature *arm= obact->data;
00800                         bPoseChannel *pchan;
00801                         for (pchan = obact->pose->chanbase.first; pchan; pchan=pchan->next) {
00802                                 if(arm->layer & pchan->bone->layer) {
00803                                         if(pchan->bone->flag & BONE_SELECTED) {
00804                                                 VECCOPY(vec, pchan->pose_head);
00805                                                 mul_m4_v3(obact->obmat, vec);
00806                                                 add_v3_v3(centroid, vec);
00807                                                 DO_MINMAX(vec, min, max);
00808                                                 count++;
00809                                         }
00810                                 }
00811                         }
00812                 }
00813                 else {
00814                         CTX_DATA_BEGIN(C, Object*, ob, selected_objects) {
00815                                 VECCOPY(vec, ob->obmat[3]);
00816                                 add_v3_v3(centroid, vec);
00817                                 DO_MINMAX(vec, min, max);
00818                                 count++;
00819                         }
00820                         CTX_DATA_END;
00821                 }
00822                 if(count) {
00823                         if(v3d->around==V3D_CENTROID) {
00824                                 mul_v3_fl(centroid, 1.0f/(float)count);
00825                                 VECCOPY(curs, centroid);
00826                         }
00827                         else {
00828                                 mid_v3_v3v3(curs, min, max);
00829                         }
00830                 }
00831         }
00832         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);
00833         
00834         return OPERATOR_FINISHED;
00835 }
00836 
00837 void VIEW3D_OT_snap_cursor_to_selected(wmOperatorType *ot)
00838 {
00839         
00840         /* identifiers */
00841         ot->name= "Snap Cursor to Selected";
00842         ot->description= "Snap cursor to center of selected item(s)"; 
00843         ot->idname= "VIEW3D_OT_snap_cursor_to_selected";
00844         
00845         /* api callbacks */
00846         ot->exec= snap_curs_to_sel;
00847         ot->poll= ED_operator_view3d_active;
00848         
00849         /* flags */
00850         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00851 }
00852 
00853 /* ********************************************** */
00854 
00855 static int snap_curs_to_active(bContext *C, wmOperator *UNUSED(op))
00856 {
00857         Object *obedit= CTX_data_edit_object(C);
00858         Object *obact= CTX_data_active_object(C);
00859         Scene *scene= CTX_data_scene(C);
00860         View3D *v3d= CTX_wm_view3d(C);
00861         float *curs;
00862         
00863         curs = give_cursor(scene, v3d);
00864 
00865         if (obedit)  {
00866                 if (obedit->type == OB_MESH) {
00867                         /* check active */
00868                         Mesh *me= obedit->data;
00869                         EditSelection ese;
00870                         
00871                         if (EM_get_actSelection(me->edit_mesh, &ese)) {
00872                                 EM_editselection_center(curs, &ese);
00873                         }
00874                         
00875                         mul_m4_v3(obedit->obmat, curs);
00876                 }
00877         }
00878         else {
00879                 if (obact) {
00880                         VECCOPY(curs, obact->obmat[3]);
00881                 }
00882         }
00883         
00884         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);
00885         return OPERATOR_FINISHED;
00886 }
00887 
00888 void VIEW3D_OT_snap_cursor_to_active(wmOperatorType *ot)
00889 {
00890         
00891         /* identifiers */
00892         ot->name= "Snap Cursor to Active";
00893         ot->description= "Snap cursor to active item";
00894         ot->idname= "VIEW3D_OT_snap_cursor_to_active";
00895         
00896         /* api callbacks */
00897         ot->exec= snap_curs_to_active;
00898         ot->poll= ED_operator_view3d_active;
00899         
00900         /* flags */
00901         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00902 }
00903 
00904 /* **************************************************** */
00905 /*New Code - Snap Cursor to Center -*/
00906 static int snap_curs_to_center(bContext *C, wmOperator *UNUSED(op))
00907 {
00908         Scene *scene= CTX_data_scene(C);
00909         View3D *v3d= CTX_wm_view3d(C);
00910         float *curs;
00911         curs= give_cursor(scene, v3d);
00912 
00913         curs[0]= 0.0;
00914         curs[1]= 0.0;
00915         curs[2]= 0.0;
00916         
00917         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);
00918         
00919         return OPERATOR_FINISHED;
00920 }
00921 
00922 void VIEW3D_OT_snap_cursor_to_center(wmOperatorType *ot)
00923 {
00924         
00925         /* identifiers */
00926         ot->name= "Snap Cursor to Center";
00927         ot->description= "Snap cursor to the Center";
00928         ot->idname= "VIEW3D_OT_snap_cursor_to_center";
00929         
00930         /* api callbacks */ 
00931         ot->exec= snap_curs_to_center;
00932         ot->poll= ED_operator_view3d_active;
00933         
00934         /* flags */
00935            ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00936 }
00937 
00938 /* **************************************************** */
00939 
00940 
00941 int minmax_verts(Object *obedit, float *min, float *max)
00942 {
00943         TransVert *tv;
00944         float centroid[3], vec[3], bmat[3][3];
00945         int a;
00946 
00947         tottrans=0;
00948         if ELEM5(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE) 
00949                 make_trans_verts(obedit, bmat[0], bmat[1], TM_ALL_JOINTS);
00950         
00951         if(tottrans==0) return 0;
00952 
00953         copy_m3_m4(bmat, obedit->obmat);
00954         
00955         tv= transvmain;
00956         for(a=0; a<tottrans; a++, tv++) {               
00957                 VECCOPY(vec, tv->loc);
00958                 mul_m3_v3(bmat, vec);
00959                 add_v3_v3(vec, obedit->obmat[3]);
00960                 add_v3_v3(centroid, vec);
00961                 DO_MINMAX(vec, min, max);               
00962         }
00963         
00964         MEM_freeN(transvmain);
00965         transvmain= NULL;
00966         
00967         return 1;
00968 }
00969