svn merge -r38971:38972 https://svn.blender.org/svnroot/bf-blender/trunk/blender...
[blender-staging.git] / source / blender / editors / transform / transform_snap.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): Martin Poirier
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 /** \file blender/editors/transform/transform_snap.c
31  *  \ingroup edtransform
32  */
33
34  
35 #include <stdlib.h>
36 #include <math.h>
37 #include <float.h>
38 #include <stdio.h>
39
40 #include "PIL_time.h"
41
42 #include "DNA_armature_types.h"
43 #include "DNA_scene_types.h"
44 #include "DNA_object_types.h"
45 #include "DNA_meshdata_types.h" // Temporary, for snapping to other unselected meshes
46 #include "DNA_space_types.h"
47 #include "DNA_screen_types.h"
48 #include "DNA_view3d_types.h"
49 #include "DNA_windowmanager_types.h"
50
51 #include "RNA_access.h"
52
53 #include "BLI_math.h"
54 #include "BLI_editVert.h"
55 #include "BLI_blenlib.h"
56 #include "BLI_utildefines.h"
57
58 //#include "BDR_drawobject.h"
59 //
60 //#include "editmesh.h"
61 //#include "BIF_editsima.h"
62 #include "BIF_gl.h"
63 //#include "BIF_mywindow.h"
64 //#include "BIF_screen.h"
65 //#include "BIF_editsima.h"
66 //#include "BIF_drawimage.h"
67 //#include "BIF_editmesh.h"
68
69 #include "BKE_DerivedMesh.h"
70 #include "BKE_object.h"
71 #include "BKE_anim.h" /* for duplis */
72 #include "BKE_context.h"
73 #include "BKE_tessmesh.h"
74 #include "BKE_mesh.h"
75
76 #include "ED_armature.h"
77 #include "ED_image.h"
78 #include "ED_mesh.h"
79 #include "ED_uvedit.h"
80 #include "ED_view3d.h"
81
82 #include "WM_types.h"
83
84 #include "UI_resources.h"
85 #include "UI_view2d.h"
86
87 #include "MEM_guardedalloc.h"
88
89 #include "transform.h"
90
91 //#include "blendef.h" /* for selection modes */
92
93 #define USE_BVH_FACE_SNAP
94
95 /********************* PROTOTYPES ***********************/
96
97 void setSnappingCallback(TransInfo *t);
98
99 void ApplySnapTranslation(TransInfo *t, float vec[3]);
100 void ApplySnapRotation(TransInfo *t, float *vec);
101 void ApplySnapResize(TransInfo *t, float *vec);
102
103 void CalcSnapGrid(TransInfo *t, float *vec);
104 void CalcSnapGeometry(TransInfo *t, float *vec);
105
106 void TargetSnapMedian(TransInfo *t);
107 void TargetSnapCenter(TransInfo *t);
108 void TargetSnapClosest(TransInfo *t);
109 void TargetSnapActive(TransInfo *t);
110
111 float RotationBetween(TransInfo *t, float p1[3], float p2[3]);
112 float TranslationBetween(TransInfo *t, float p1[3], float p2[3]);
113 float ResizeBetween(TransInfo *t, float p1[3], float p2[3]);
114
115
116 /****************** IMPLEMENTATIONS *********************/
117
118 #if 0
119 int BIF_snappingSupported(Object *obedit)
120 {
121         int status = 0;
122         
123         if (obedit == NULL || ELEM4(obedit->type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE)) /* only support object mesh, armature, curves */
124         {
125                 status = 1;
126         }
127         
128         return status;
129 }
130 #endif
131
132 int validSnap(TransInfo *t)
133 {
134         return (t->tsnap.status & (POINT_INIT|TARGET_INIT)) == (POINT_INIT|TARGET_INIT) ||
135                         (t->tsnap.status & (MULTI_POINTS|TARGET_INIT)) == (MULTI_POINTS|TARGET_INIT);
136 }
137
138 int activeSnap(TransInfo *t)
139 {
140         return (t->modifiers & (MOD_SNAP|MOD_SNAP_INVERT)) == MOD_SNAP || (t->modifiers & (MOD_SNAP|MOD_SNAP_INVERT)) == MOD_SNAP_INVERT;
141 }
142
143 void drawSnapping(const struct bContext *C, TransInfo *t)
144 {
145         if (validSnap(t) && activeSnap(t))
146                 {
147                 
148                 unsigned char col[4];
149                 UI_GetThemeColor3ubv(TH_TRANSFORM, col);
150                 col[3]= 128;
151                 glColor4ubv(col);
152                 
153                 if (t->spacetype == SPACE_VIEW3D) {
154                         TransSnapPoint *p;
155                         View3D *v3d = CTX_wm_view3d(C);
156                         RegionView3D *rv3d = CTX_wm_region_view3d(C);
157                         float imat[4][4];
158                         float size;
159                         
160                         glDisable(GL_DEPTH_TEST);
161         
162                         size = 2.5f * UI_GetThemeValuef(TH_VERTEX_SIZE);
163
164                         invert_m4_m4(imat, rv3d->viewmat);
165
166                         for (p = t->tsnap.points.first; p; p = p->next) {
167                                 drawcircball(GL_LINE_LOOP, p->co, ED_view3d_pixel_size(rv3d, p->co) * size, imat);
168                         }
169
170                         if (t->tsnap.status & POINT_INIT) {
171                                 drawcircball(GL_LINE_LOOP, t->tsnap.snapPoint, ED_view3d_pixel_size(rv3d, t->tsnap.snapPoint) * size, imat);
172                         }
173                         
174                         /* draw normal if needed */
175                         if (usingSnappingNormal(t) && validSnappingNormal(t))
176                         {
177                                 glBegin(GL_LINES);
178                                         glVertex3f(t->tsnap.snapPoint[0], t->tsnap.snapPoint[1], t->tsnap.snapPoint[2]);
179                                         glVertex3f(     t->tsnap.snapPoint[0] + t->tsnap.snapNormal[0],
180                                                                 t->tsnap.snapPoint[1] + t->tsnap.snapNormal[1],
181                                                                 t->tsnap.snapPoint[2] + t->tsnap.snapNormal[2]);
182                                 glEnd();
183                         }
184                         
185                         if(v3d->zbuf)
186                                 glEnable(GL_DEPTH_TEST);
187                 }
188                 else if (t->spacetype==SPACE_IMAGE)
189                 {
190                         /*This will not draw, and Im nor sure why - campbell */
191                         
192                         /*                      
193                         float xuser_asp, yuser_asp;
194                         int wi, hi;
195                         float w, h;
196                         
197                         calc_image_view(G.sima, 'f');   // float
198                         myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax);
199                         glLoadIdentity();
200                         
201                         ED_space_image_aspect(t->sa->spacedata.first, &xuser_aspx, &yuser_asp);
202                         ED_space_image_width(t->sa->spacedata.first, &wi, &hi);
203                         w = (((float)wi)/256.0f)*G.sima->zoom * xuser_asp;
204                         h = (((float)hi)/256.0f)*G.sima->zoom * yuser_asp;
205                         
206                         cpack(0xFFFFFF);
207                         glTranslatef(t->tsnap.snapPoint[0], t->tsnap.snapPoint[1], 0.0f);
208                         
209                         //glRectf(0,0,1,1);
210                         
211                         setlinestyle(0);
212                         cpack(0x0);
213                         fdrawline(-0.020/w, 0, -0.1/w, 0);
214                         fdrawline(0.1/w, 0, .020/w, 0);
215                         fdrawline(0, -0.020/h, 0, -0.1/h);
216                         fdrawline(0, 0.1/h, 0, 0.020/h);
217                         
218                         glTranslatef(-t->tsnap.snapPoint[0], -t->tsnap.snapPoint[1], 0.0f);
219                         setlinestyle(0);
220                         */
221                         
222                 }
223         }
224 }
225
226 int  handleSnapping(TransInfo *UNUSED(t), wmEvent *UNUSED(event))
227 {
228         int status = 0;
229
230 #if 0 // XXX need a proper selector for all snap mode
231         if (BIF_snappingSupported(t->obedit) && event->type == TABKEY && event->shift)
232         {
233                 /* toggle snap and reinit */
234                 t->settings->snap_flag ^= SCE_SNAP;
235                 initSnapping(t, NULL);
236                 status = 1;
237         }
238 #endif
239         
240         return status;
241 }
242
243 void applyProject(TransInfo *t)
244 {
245         /* XXX FLICKER IN OBJECT MODE */
246         if ((t->tsnap.project) && activeSnap(t) && (t->flag & T_NO_PROJECT) == 0)
247         {
248                 TransData *td = t->data;
249                 float tvec[3];
250                 float imat[4][4];
251                 int i;
252         
253                 if(t->flag & (T_EDIT|T_POSE)) {
254                         Object *ob = t->obedit?t->obedit:t->poseobj;
255                         invert_m4_m4(imat, ob->obmat);
256                 }
257
258                 for(i = 0 ; i < t->total; i++, td++) {
259                         float iloc[3], loc[3], no[3];
260                         float mval[2];
261                         int dist = 1000;
262                         
263                         if (td->flag & TD_NOACTION)
264                                 break;
265                         
266                         if (td->flag & TD_SKIP)
267                                 continue;
268                         
269                         VECCOPY(iloc, td->loc);
270                         if (t->flag & (T_EDIT|T_POSE))
271                         {
272                                 Object *ob = t->obedit?t->obedit:t->poseobj;
273                                 mul_m4_v3(ob->obmat, iloc);
274                         }
275                         else if (t->flag & T_OBJECT)
276                         {
277                                 td->ob->recalc |= OB_RECALC_OB|OB_RECALC_DATA|OB_RECALC_TIME;
278                                 object_handle_update(t->scene, td->ob);
279                                 VECCOPY(iloc, td->ob->obmat[3]);
280                         }
281                         
282                         project_float(t->ar, iloc, mval);
283                         
284                         if (snapObjectsTransform(t, mval, &dist, loc, no, t->tsnap.modeSelect))
285                         {
286 //                              if(t->flag & (T_EDIT|T_POSE)) {
287 //                                      mul_m4_v3(imat, loc);
288 //                              }
289 //                              
290                                 sub_v3_v3v3(tvec, loc, iloc);
291                                 
292                                 mul_m3_v3(td->smtx, tvec);
293                                 
294                                 add_v3_v3(td->loc, tvec);
295                         }
296                         
297                         //XXX constraintTransLim(t, td);
298                 }
299         }
300 }
301
302 void applySnapping(TransInfo *t, float *vec)
303 {
304         /* project is not applied this way */
305         if (t->tsnap.project)
306                 return;
307         
308         if (t->tsnap.status & SNAP_FORCED)
309         {
310                 t->tsnap.targetSnap(t);
311         
312                 t->tsnap.applySnap(t, vec);
313         }
314         else if ((t->tsnap.mode != SCE_SNAP_MODE_INCREMENT) && activeSnap(t))
315         {
316                 double current = PIL_check_seconds_timer();
317                 
318                 // Time base quirky code to go around findnearest slowness
319                 /* !TODO! add exception for object mode, no need to slow it down then */
320                 if (current - t->tsnap.last  >= 0.01)
321                 {
322                         t->tsnap.calcSnap(t, vec);
323                         t->tsnap.targetSnap(t);
324         
325                         t->tsnap.last = current;
326                 }
327                 if (validSnap(t))
328                 {
329                         t->tsnap.applySnap(t, vec);
330                 }
331         }
332 }
333
334 void resetSnapping(TransInfo *t)
335 {
336         t->tsnap.status = 0;
337         t->tsnap.align = 0;
338         t->tsnap.project = 0;
339         t->tsnap.mode = 0;
340         t->tsnap.modeSelect = 0;
341         t->tsnap.target = 0;
342         t->tsnap.last = 0;
343         t->tsnap.applySnap = NULL;
344
345         t->tsnap.snapNormal[0] = 0;
346         t->tsnap.snapNormal[1] = 0;
347         t->tsnap.snapNormal[2] = 0;
348 }
349
350 int usingSnappingNormal(TransInfo *t)
351 {
352         return t->tsnap.align;
353 }
354
355 int validSnappingNormal(TransInfo *t)
356 {
357         if (validSnap(t))
358         {
359                 if (dot_v3v3(t->tsnap.snapNormal, t->tsnap.snapNormal) > 0)
360                 {
361                         return 1;
362                 }
363         }
364         
365         return 0;
366 }
367
368 static void initSnappingMode(TransInfo *t)
369 {
370         ToolSettings *ts = t->settings;
371         Object *obedit = t->obedit;
372         Scene *scene = t->scene;
373
374         /* force project off when not supported */
375         if (ts->snap_mode != SCE_SNAP_MODE_FACE)
376         {
377                 t->tsnap.project = 0;
378         }
379
380         t->tsnap.mode = ts->snap_mode;
381
382         if ((t->spacetype == SPACE_VIEW3D || t->spacetype == SPACE_IMAGE) && // Only 3D view or UV
383                         (t->flag & T_CAMERA) == 0) { // Not with camera selected in camera view
384                 setSnappingCallback(t);
385
386                 /* Edit mode */
387                 if (t->tsnap.applySnap != NULL && // A snapping function actually exist
388                         (obedit != NULL && ELEM4(obedit->type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE)) ) // Temporary limited to edit mode meshes, armature, curves
389                 {
390                         /* Exclude editmesh if using proportional edit */
391                         if ((obedit->type == OB_MESH) && (t->flag & T_PROP_EDIT))
392                         {
393                                 t->tsnap.modeSelect = SNAP_NOT_OBEDIT;
394                         }
395                         else
396                         {
397                                 t->tsnap.modeSelect = t->tsnap.snap_self ? SNAP_ALL : SNAP_NOT_OBEDIT;
398                         }
399                 }
400                 /* Particles edit mode*/
401                 else if (t->tsnap.applySnap != NULL && // A snapping function actually exist
402                         (obedit == NULL && BASACT && BASACT->object && BASACT->object->mode & OB_MODE_PARTICLE_EDIT ))
403                 {
404                         t->tsnap.modeSelect = SNAP_ALL;
405                 }
406                 /* Object mode */
407                 else if (t->tsnap.applySnap != NULL && // A snapping function actually exist
408                         (obedit == NULL) ) // Object Mode
409                 {
410                         t->tsnap.modeSelect = SNAP_NOT_SELECTED;
411                 }
412                 else
413                 {
414                         /* Grid if snap is not possible */
415                         t->tsnap.mode = SCE_SNAP_MODE_INCREMENT;
416                 }
417         }
418         else
419         {
420                 /* Always grid outside of 3D view */
421                 t->tsnap.mode = SCE_SNAP_MODE_INCREMENT;
422         }
423 }
424
425 void initSnapping(TransInfo *t, wmOperator *op)
426 {
427         ToolSettings *ts = t->settings;
428         short snap_target = t->settings->snap_target;
429         
430         resetSnapping(t);
431         
432         /* if snap property exists */
433         if (op && RNA_struct_find_property(op->ptr, "snap") && RNA_property_is_set(op->ptr, "snap"))
434         {
435                 if (RNA_boolean_get(op->ptr, "snap"))
436                 {
437                         t->modifiers |= MOD_SNAP;
438
439                         if (RNA_property_is_set(op->ptr, "snap_target"))
440                         {
441                                 snap_target = RNA_enum_get(op->ptr, "snap_target");
442                         }
443                         
444                         if (RNA_property_is_set(op->ptr, "snap_point"))
445                         {
446                                 RNA_float_get_array(op->ptr, "snap_point", t->tsnap.snapPoint);
447                                 t->tsnap.status |= SNAP_FORCED|POINT_INIT;
448                         }
449                         
450                         /* snap align only defined in specific cases */
451                         if (RNA_struct_find_property(op->ptr, "snap_align"))
452                         {
453                                 t->tsnap.align = RNA_boolean_get(op->ptr, "snap_align");
454                                 RNA_float_get_array(op->ptr, "snap_normal", t->tsnap.snapNormal);
455                                 normalize_v3(t->tsnap.snapNormal);
456                         }
457
458                         if (RNA_struct_find_property(op->ptr, "use_snap_project"))
459                         {
460                                 t->tsnap.project = RNA_boolean_get(op->ptr, "use_snap_project");
461                         }
462
463                         if (RNA_struct_find_property(op->ptr, "use_snap_self"))
464                         {
465                                 t->tsnap.snap_self = RNA_boolean_get(op->ptr, "use_snap_self");
466                         }
467                 }
468         }
469         /* use scene defaults only when transform is modal */
470         else if (t->flag & T_MODAL)
471         {
472                 if(ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE))
473                 {
474                         if (ts->snap_flag & SCE_SNAP) {
475                                 t->modifiers |= MOD_SNAP;
476                         }
477
478                         t->tsnap.align = ((t->settings->snap_flag & SCE_SNAP_ROTATE) == SCE_SNAP_ROTATE);
479                         t->tsnap.project = ((t->settings->snap_flag & SCE_SNAP_PROJECT) == SCE_SNAP_PROJECT);
480                         t->tsnap.snap_self = !((t->settings->snap_flag & SCE_SNAP_NO_SELF) == SCE_SNAP_NO_SELF);
481                         t->tsnap.peel = ((t->settings->snap_flag & SCE_SNAP_PROJECT) == SCE_SNAP_PROJECT);
482                 }
483         }
484         
485         t->tsnap.target = snap_target;
486
487         initSnappingMode(t);
488 }
489
490 void setSnappingCallback(TransInfo *t)
491 {
492         t->tsnap.calcSnap = CalcSnapGeometry;
493
494         switch(t->tsnap.target)
495         {
496                 case SCE_SNAP_TARGET_CLOSEST:
497                         t->tsnap.targetSnap = TargetSnapClosest;
498                         break;
499                 case SCE_SNAP_TARGET_CENTER:
500                         t->tsnap.targetSnap = TargetSnapCenter;
501                         break;
502                 case SCE_SNAP_TARGET_MEDIAN:
503                         t->tsnap.targetSnap = TargetSnapMedian;
504                         break;
505                 case SCE_SNAP_TARGET_ACTIVE:
506                         t->tsnap.targetSnap = TargetSnapActive;
507                         break;
508
509         }
510
511         switch (t->mode)
512         {
513         case TFM_TRANSLATION:
514                 t->tsnap.applySnap = ApplySnapTranslation;
515                 t->tsnap.distance = TranslationBetween;
516                 break;
517         case TFM_ROTATION:
518                 t->tsnap.applySnap = ApplySnapRotation;
519                 t->tsnap.distance = RotationBetween;
520                 
521                 // Can't do TARGET_CENTER with rotation, use TARGET_MEDIAN instead
522                 if (t->tsnap.target == SCE_SNAP_TARGET_CENTER) {
523                         t->tsnap.target = SCE_SNAP_TARGET_MEDIAN;
524                         t->tsnap.targetSnap = TargetSnapMedian;
525                 }
526                 break;
527         case TFM_RESIZE:
528                 t->tsnap.applySnap = ApplySnapResize;
529                 t->tsnap.distance = ResizeBetween;
530                 
531                 // Can't do TARGET_CENTER with resize, use TARGET_MEDIAN instead
532                 if (t->tsnap.target == SCE_SNAP_TARGET_CENTER) {
533                         t->tsnap.target = SCE_SNAP_TARGET_MEDIAN;
534                         t->tsnap.targetSnap = TargetSnapMedian;
535                 }
536                 break;
537         default:
538                 t->tsnap.applySnap = NULL;
539                 break;
540         }
541 }
542
543 void addSnapPoint(TransInfo *t)
544 {
545         if (t->tsnap.status & POINT_INIT) {
546                 TransSnapPoint *p = MEM_callocN(sizeof(TransSnapPoint), "SnapPoint");
547
548                 VECCOPY(p->co, t->tsnap.snapPoint);
549
550                 BLI_addtail(&t->tsnap.points, p);
551
552                 t->tsnap.status |= MULTI_POINTS;
553         }
554 }
555
556 void removeSnapPoint(TransInfo *t)
557 {
558         if (t->tsnap.status & MULTI_POINTS) {
559                 BLI_freelinkN(&t->tsnap.points, t->tsnap.points.last);
560
561                 if (t->tsnap.points.first == NULL)
562                         t->tsnap.status &= ~MULTI_POINTS;
563         }
564 }
565
566 void getSnapPoint(TransInfo *t, float vec[3])
567 {
568         if (t->tsnap.points.first) {
569                 TransSnapPoint *p;
570                 int total = 0;
571
572                 vec[0] = vec[1] = vec[2] = 0;
573
574                 for (p = t->tsnap.points.first; p; p = p->next, total++) {
575                         add_v3_v3(vec, p->co);
576                 }
577
578                 if (t->tsnap.status & POINT_INIT) {
579                         add_v3_v3(vec, t->tsnap.snapPoint);
580                         total++;
581                 }
582
583                 mul_v3_fl(vec, 1.0f / total);
584         } else {
585                 VECCOPY(vec, t->tsnap.snapPoint)
586         }
587 }
588
589 /********************** APPLY **************************/
590
591 void ApplySnapTranslation(TransInfo *t, float vec[3])
592 {
593         float point[3];
594         getSnapPoint(t, point);
595         sub_v3_v3v3(vec, point, t->tsnap.snapTarget);
596 }
597
598 void ApplySnapRotation(TransInfo *t, float *vec)
599 {
600         if (t->tsnap.target == SCE_SNAP_TARGET_CLOSEST) {
601                 *vec = t->tsnap.dist;
602         }
603         else {
604                 float point[3];
605                 getSnapPoint(t, point);
606                 *vec = RotationBetween(t, t->tsnap.snapTarget, point);
607         }
608 }
609
610 void ApplySnapResize(TransInfo *t, float vec[3])
611 {
612         if (t->tsnap.target == SCE_SNAP_TARGET_CLOSEST) {
613                 vec[0] = vec[1] = vec[2] = t->tsnap.dist;
614         }
615         else {
616                 float point[3];
617                 getSnapPoint(t, point);
618                 vec[0] = vec[1] = vec[2] = ResizeBetween(t, t->tsnap.snapTarget, point);
619         }
620 }
621
622 /********************** DISTANCE **************************/
623
624 float TranslationBetween(TransInfo *UNUSED(t), float p1[3], float p2[3])
625 {
626         return len_v3v3(p1, p2);
627 }
628
629 float RotationBetween(TransInfo *t, float p1[3], float p2[3])
630 {
631         float angle, start[3], end[3], center[3];
632         
633         VECCOPY(center, t->center);     
634         if(t->flag & (T_EDIT|T_POSE)) {
635                 Object *ob= t->obedit?t->obedit:t->poseobj;
636                 mul_m4_v3(ob->obmat, center);
637         }
638
639         sub_v3_v3v3(start, p1, center);
640         sub_v3_v3v3(end, p2, center);   
641                 
642         // Angle around a constraint axis (error prone, will need debug)
643         if (t->con.applyRot != NULL && (t->con.mode & CON_APPLY)) {
644                 float axis[3], tmp[3];
645                 
646                 t->con.applyRot(t, NULL, axis, NULL);
647
648                 project_v3_v3v3(tmp, end, axis);
649                 sub_v3_v3v3(end, end, tmp);
650                 
651                 project_v3_v3v3(tmp, start, axis);
652                 sub_v3_v3v3(start, start, tmp);
653                 
654                 normalize_v3(end);
655                 normalize_v3(start);
656                 
657                 cross_v3_v3v3(tmp, start, end);
658                 
659                 if (dot_v3v3(tmp, axis) < 0.0f)
660                         angle = -acos(dot_v3v3(start, end));
661                 else    
662                         angle = acos(dot_v3v3(start, end));
663         }
664         else {
665                 float mtx[3][3];
666                 
667                 copy_m3_m4(mtx, t->viewmat);
668
669                 mul_m3_v3(mtx, end);
670                 mul_m3_v3(mtx, start);
671                 
672                 angle = atan2(start[1],start[0]) - atan2(end[1],end[0]);
673         }
674         
675         if (angle > (float)M_PI) {
676                 angle = angle - 2 * (float)M_PI;
677         }
678         else if (angle < -((float)M_PI)) {
679                 angle = 2.0f * (float)M_PI + angle;
680         }
681         
682         return angle;
683 }
684
685 float ResizeBetween(TransInfo *t, float p1[3], float p2[3])
686 {
687         float d1[3], d2[3], center[3];
688         
689         VECCOPY(center, t->center);     
690         if(t->flag & (T_EDIT|T_POSE)) {
691                 Object *ob= t->obedit?t->obedit:t->poseobj;
692                 mul_m4_v3(ob->obmat, center);
693         }
694
695         sub_v3_v3v3(d1, p1, center);
696         sub_v3_v3v3(d2, p2, center);
697         
698         if (t->con.applyRot != NULL && (t->con.mode & CON_APPLY)) {
699                 mul_m3_v3(t->con.pmtx, d1);
700                 mul_m3_v3(t->con.pmtx, d2);
701         }
702         
703         return len_v3(d2) / len_v3(d1);
704 }
705
706 /********************** CALC **************************/
707
708 void CalcSnapGrid(TransInfo *t, float *UNUSED(vec))
709 {
710         snapGridAction(t, t->tsnap.snapPoint, BIG_GEARS);
711 }
712
713 void CalcSnapGeometry(TransInfo *t, float *UNUSED(vec))
714 {
715         if (t->spacetype == SPACE_VIEW3D)
716         {
717                 float loc[3];
718                 float no[3];
719                 float mval[2];
720                 int found = 0;
721                 int dist = SNAP_MIN_DISTANCE; // Use a user defined value here
722                 
723                 mval[0] = t->mval[0];
724                 mval[1] = t->mval[1];
725                 
726                 if (t->tsnap.mode == SCE_SNAP_MODE_VOLUME)
727                 {
728                         ListBase depth_peels;
729                         DepthPeel *p1, *p2;
730                         float *last_p = NULL;
731                         float max_dist = FLT_MAX;
732                         float p[3] = {0.0f, 0.0f, 0.0f};
733                         
734                         depth_peels.first = depth_peels.last = NULL;
735                         
736                         peelObjectsTransForm(t, &depth_peels, mval);
737                         
738 //                      if (LAST_SNAP_POINT_VALID)
739 //                      {
740 //                              last_p = LAST_SNAP_POINT;
741 //                      }
742 //                      else
743 //                      {
744                                 last_p = t->tsnap.snapPoint;
745 //                      }
746                         
747                         
748                         for (p1 = depth_peels.first; p1; p1 = p1->next)
749                         {
750                                 if (p1->flag == 0)
751                                 {
752                                         float vec[3];
753                                         float new_dist;
754                                         
755                                         p2 = NULL;
756                                         p1->flag = 1;
757                 
758                                         /* if peeling objects, take the first and last from each object */                      
759                                         if (t->settings->snap_flag & SCE_SNAP_PEEL_OBJECT)
760                                         {
761                                                 DepthPeel *peel;
762                                                 for (peel = p1->next; peel; peel = peel->next)
763                                                 {
764                                                         if (peel->ob == p1->ob)
765                                                         {
766                                                                 peel->flag = 1;
767                                                                 p2 = peel;
768                                                         }
769                                                 }
770                                         }
771                                         /* otherwise, pair first with second and so on */
772                                         else
773                                         {
774                                                 for (p2 = p1->next; p2 && p2->ob != p1->ob; p2 = p2->next)
775                                                 {
776                                                         /* nothing to do here */
777                                                 }
778                                         }
779                                         
780                                         if (p2)
781                                         {
782                                                 p2->flag = 1;
783                                                 
784                                                 add_v3_v3v3(vec, p1->p, p2->p);
785                                                 mul_v3_fl(vec, 0.5f);
786                                         }
787                                         else
788                                         {
789                                                 VECCOPY(vec, p1->p);
790                                         }
791                                         
792                                         if (last_p == NULL)
793                                         {
794                                                 VECCOPY(p, vec);
795                                                 max_dist = 0;
796                                                 break;
797                                         }
798                                         
799                                         new_dist = len_v3v3(last_p, vec);
800                                         
801                                         if (new_dist < max_dist)
802                                         {
803                                                 VECCOPY(p, vec);
804                                                 max_dist = new_dist;
805                                         }
806                                 }
807                         }
808                         
809                         if (max_dist != FLT_MAX)
810                         {
811                                 VECCOPY(loc, p);
812                                 /* XXX, is there a correct normal in this case ???, for now just z up */
813                                 no[0]= 0.0;
814                                 no[1]= 0.0;
815                                 no[2]= 1.0;
816                                 found = 1;
817                         }
818                         
819                         BLI_freelistN(&depth_peels);
820                 }
821                 else
822                 {
823                         found = snapObjectsTransform(t, mval, &dist, loc, no, t->tsnap.modeSelect);
824                 }
825                 
826                 if (found == 1)
827                 {
828                         float tangent[3];
829                         
830                         sub_v3_v3v3(tangent, loc, t->tsnap.snapPoint);
831                         tangent[2] = 0; 
832                         
833                         if (dot_v3v3(tangent, tangent) > 0)
834                         {
835                                 VECCOPY(t->tsnap.snapTangent, tangent);
836                         }
837                         
838                         VECCOPY(t->tsnap.snapPoint, loc);
839                         VECCOPY(t->tsnap.snapNormal, no);
840
841                         t->tsnap.status |=  POINT_INIT;
842                 }
843                 else
844                 {
845                         t->tsnap.status &= ~POINT_INIT;
846                 }
847         }
848         else if (t->spacetype == SPACE_IMAGE && t->obedit != NULL && t->obedit->type==OB_MESH)
849         {       /* same as above but for UV's */
850                 /* same as above but for UV's */
851                 Image *ima= ED_space_image(t->sa->spacedata.first);
852                 float aspx, aspy, co[2];
853                 
854                 UI_view2d_region_to_view(&t->ar->v2d, t->mval[0], t->mval[1], co, co+1);
855
856                 if(ED_uvedit_nearest_uv(t->scene, t->obedit, ima, co, t->tsnap.snapPoint))
857                 {
858                         ED_space_image_uv_aspect(t->sa->spacedata.first, &aspx, &aspy);
859                         t->tsnap.snapPoint[0] *= aspx;
860                         t->tsnap.snapPoint[1] *= aspy;
861
862                         t->tsnap.status |=  POINT_INIT;
863                 }
864                 else
865                 {
866                         t->tsnap.status &= ~POINT_INIT;
867                 }
868         }
869 }
870
871 /********************** TARGET **************************/
872
873 void TargetSnapCenter(TransInfo *t)
874 {
875         // Only need to calculate once
876         if ((t->tsnap.status & TARGET_INIT) == 0)
877         {
878                 VECCOPY(t->tsnap.snapTarget, t->center);        
879                 if(t->flag & (T_EDIT|T_POSE)) {
880                         Object *ob= t->obedit?t->obedit:t->poseobj;
881                         mul_m4_v3(ob->obmat, t->tsnap.snapTarget);
882                 }
883                 
884                 t->tsnap.status |= TARGET_INIT;         
885         }
886 }
887
888 void TargetSnapActive(TransInfo *t)
889 {
890         // Only need to calculate once
891         if ((t->tsnap.status & TARGET_INIT) == 0)
892         {
893                 TransData *td = NULL;
894                 TransData *active_td = NULL;
895                 int i;
896
897                 for(td = t->data, i = 0 ; i < t->total && td->flag & TD_SELECTED ; i++, td++)
898                 {
899                         if (td->flag & TD_ACTIVE)
900                         {
901                                 active_td = td;
902                                 break;
903                         }
904                 }
905
906                 if (active_td)
907                 {       
908                         VECCOPY(t->tsnap.snapTarget, active_td->center);
909                                 
910                         if(t->flag & (T_EDIT|T_POSE)) {
911                                 Object *ob= t->obedit?t->obedit:t->poseobj;
912                                 mul_m4_v3(ob->obmat, t->tsnap.snapTarget);
913                         }
914                         
915                         t->tsnap.status |= TARGET_INIT;
916                 }
917                 /* No active, default to median */
918                 else
919                 {
920                         t->tsnap.target = SCE_SNAP_TARGET_MEDIAN;
921                         t->tsnap.targetSnap = TargetSnapMedian;
922                         TargetSnapMedian(t);
923                 }               
924         }
925 }
926
927 void TargetSnapMedian(TransInfo *t)
928 {
929         // Only need to calculate once
930         if ((t->tsnap.status & TARGET_INIT) == 0)
931         {
932                 TransData *td = NULL;
933                 int i;
934
935                 t->tsnap.snapTarget[0] = 0;
936                 t->tsnap.snapTarget[1] = 0;
937                 t->tsnap.snapTarget[2] = 0;
938                 
939                 for(td = t->data, i = 0 ; i < t->total && td->flag & TD_SELECTED ; i++, td++)
940                 {
941                         add_v3_v3(t->tsnap.snapTarget, td->center);
942                 }
943                 
944                 mul_v3_fl(t->tsnap.snapTarget, 1.0 / i);
945                 
946                 if(t->flag & (T_EDIT|T_POSE)) {
947                         Object *ob= t->obedit?t->obedit:t->poseobj;
948                         mul_m4_v3(ob->obmat, t->tsnap.snapTarget);
949                 }
950                 
951                 t->tsnap.status |= TARGET_INIT;         
952         }
953 }
954
955 void TargetSnapClosest(TransInfo *t)
956 {
957         // Only valid if a snap point has been selected
958         if (t->tsnap.status & POINT_INIT)
959         {
960                 TransData *closest = NULL, *td = NULL;
961                 
962                 /* Object mode */
963                 if (t->flag & T_OBJECT)
964                 {
965                         int i;
966                         for(td = t->data, i = 0 ; i < t->total && td->flag & TD_SELECTED ; i++, td++)
967                         {
968                                 struct BoundBox *bb = object_get_boundbox(td->ob);
969                                 
970                                 /* use boundbox if possible */
971                                 if (bb)
972                                 {
973                                         int j;
974                                         
975                                         for (j = 0; j < 8; j++) {
976                                                 float loc[3];
977                                                 float dist;
978                                                 
979                                                 VECCOPY(loc, bb->vec[j]);
980                                                 mul_m4_v3(td->ext->obmat, loc);
981                                                 
982                                                 dist = t->tsnap.distance(t, loc, t->tsnap.snapPoint);
983                                                 
984                                                 if (closest == NULL || fabs(dist) < fabs(t->tsnap.dist))
985                                                 {
986                                                         VECCOPY(t->tsnap.snapTarget, loc);
987                                                         closest = td;
988                                                         t->tsnap.dist = dist; 
989                                                 }
990                                         }
991                                 }
992                                 /* use element center otherwise */
993                                 else
994                                 {
995                                         float loc[3];
996                                         float dist;
997                                         
998                                         VECCOPY(loc, td->center);
999                                         
1000                                         dist = t->tsnap.distance(t, loc, t->tsnap.snapPoint);
1001                                         
1002                                         if (closest == NULL || fabs(dist) < fabs(t->tsnap.dist))
1003                                         {
1004                                                 VECCOPY(t->tsnap.snapTarget, loc);
1005                                                 closest = td;
1006                                                 t->tsnap.dist = dist; 
1007                                         }
1008                                 }
1009                         }
1010                 }
1011                 else
1012                 {
1013                         int i;
1014                         for(td = t->data, i = 0 ; i < t->total && td->flag & TD_SELECTED ; i++, td++)
1015                         {
1016                                 float loc[3];
1017                                 float dist;
1018                                 
1019                                 VECCOPY(loc, td->center);
1020                                 
1021                                 if(t->flag & (T_EDIT|T_POSE)) {
1022                                         Object *ob= t->obedit?t->obedit:t->poseobj;
1023                                         mul_m4_v3(ob->obmat, loc);
1024                                 }
1025                                 
1026                                 dist = t->tsnap.distance(t, loc, t->tsnap.snapPoint);
1027                                 
1028                                 if (closest == NULL || fabs(dist) < fabs(t->tsnap.dist))
1029                                 {
1030                                         VECCOPY(t->tsnap.snapTarget, loc);
1031                                         closest = td;
1032                                         t->tsnap.dist = dist; 
1033                                 }
1034                         }
1035                 }
1036                 
1037                 t->tsnap.status |= TARGET_INIT;
1038         }
1039 }
1040 /*================================================================*/
1041 #ifndef USE_BVH_FACE_SNAP
1042 static int snapFace(ARegion *ar, float v1co[3], float v2co[3], float v3co[3], float *v4co, float mval[2], float ray_start[3], float ray_start_local[3], float ray_normal_local[3], float obmat[][4], float timat[][3], float *loc, float *no, int *dist, float *depth)
1043 {
1044         float lambda;
1045         int result;
1046         int retval = 0;
1047         
1048         result = isect_ray_tri_threshold_v3(ray_start_local, ray_normal_local, v1co, v2co, v3co, &lambda, NULL, 0.001);
1049         
1050         if (result) {
1051                 float location[3], normal[3];
1052                 float intersect[3];
1053                 float new_depth;
1054                 int screen_loc[2];
1055                 int new_dist;
1056                 
1057                 VECCOPY(intersect, ray_normal_local);
1058                 mul_v3_fl(intersect, lambda);
1059                 add_v3_v3(intersect, ray_start_local);
1060                 
1061                 VECCOPY(location, intersect);
1062                 
1063                 if (v4co)
1064                         normal_quad_v3( normal,v1co, v2co, v3co, v4co);
1065                 else
1066                         normal_tri_v3( normal,v1co, v2co, v3co);
1067
1068                 mul_m4_v3(obmat, location);
1069                 
1070                 new_depth = len_v3v3(location, ray_start);                                      
1071                 
1072                 project_int(ar, location, screen_loc);
1073                 new_dist = abs(screen_loc[0] - (int)mval[0]) + abs(screen_loc[1] - (int)mval[1]);
1074                 
1075                 if (new_dist <= *dist && new_depth < *depth) 
1076                 {
1077                         *depth = new_depth;
1078                         retval = 1;
1079                         
1080                         VECCOPY(loc, location);
1081                         VECCOPY(no, normal);
1082                         
1083                         mul_m3_v3(timat, no);
1084                         normalize_v3(no);
1085
1086                         *dist = new_dist;
1087                 } 
1088         }
1089         
1090         return retval;
1091 }
1092 #endif
1093
1094 static int snapEdge(ARegion *ar, float v1co[3], short v1no[3], float v2co[3], short v2no[3], float mval[2], float ray_start[3], float ray_start_local[3], float ray_normal_local[3], float obmat[][4], float timat[][3], float *loc, float *no, int *dist, float *depth)
1095 {
1096         float intersect[3] = {0, 0, 0}, ray_end[3], dvec[3];
1097         int result;
1098         int retval = 0;
1099         
1100         VECCOPY(ray_end, ray_normal_local);
1101         mul_v3_fl(ray_end, 2000);
1102         add_v3_v3v3(ray_end, ray_start_local, ray_end);
1103         
1104         result = isect_line_line_v3(v1co, v2co, ray_start_local, ray_end, intersect, dvec); /* dvec used but we don't care about result */
1105         
1106         if (result)
1107         {
1108                 float edge_loc[3], vec[3];
1109                 float mul;
1110         
1111                 /* check for behind ray_start */
1112                 sub_v3_v3v3(dvec, intersect, ray_start_local);
1113                 
1114                 sub_v3_v3v3(edge_loc, v1co, v2co);
1115                 sub_v3_v3v3(vec, intersect, v2co);
1116                 
1117                 mul = dot_v3v3(vec, edge_loc) / dot_v3v3(edge_loc, edge_loc);
1118                 
1119                 if (mul > 1) {
1120                         mul = 1;
1121                         VECCOPY(intersect, v1co);
1122                 }
1123                 else if (mul < 0) {
1124                         mul = 0;
1125                         VECCOPY(intersect, v2co);
1126                 }
1127
1128                 if (dot_v3v3(ray_normal_local, dvec) > 0)
1129                 {
1130                         float location[3];
1131                         float new_depth;
1132                         int screen_loc[2];
1133                         int new_dist;
1134                         
1135                         VECCOPY(location, intersect);
1136                         
1137                         mul_m4_v3(obmat, location);
1138                         
1139                         new_depth = len_v3v3(location, ray_start);                                      
1140                         
1141                         project_int(ar, location, screen_loc);
1142                         new_dist = abs(screen_loc[0] - (int)mval[0]) + abs(screen_loc[1] - (int)mval[1]);
1143                         
1144                         /* 10% threshold if edge is closer but a bit further
1145                          * this takes care of series of connected edges a bit slanted w.r.t the viewport
1146                          * otherwise, it would stick to the verts of the closest edge and not slide along merrily 
1147                          * */
1148                         if (new_dist <= *dist && new_depth < *depth * 1.001f)
1149                         {
1150                                 float n1[3], n2[3];
1151                                 
1152                                 *depth = new_depth;
1153                                 retval = 1;
1154                                 
1155                                 sub_v3_v3v3(edge_loc, v1co, v2co);
1156                                 sub_v3_v3v3(vec, intersect, v2co);
1157                                 
1158                                 mul = dot_v3v3(vec, edge_loc) / dot_v3v3(edge_loc, edge_loc);
1159                                 
1160                                 if (no)
1161                                 {
1162                                         normal_short_to_float_v3(n1, v1no);                                             
1163                                         normal_short_to_float_v3(n2, v2no);
1164                                         interp_v3_v3v3(no, n2, n1, mul);
1165                                         mul_m3_v3(timat, no);
1166                                         normalize_v3(no);
1167                                 }                       
1168
1169                                 VECCOPY(loc, location);
1170                                 
1171                                 *dist = new_dist;
1172                         } 
1173                 }
1174         }
1175         
1176         return retval;
1177 }
1178
1179 static int snapVertex(ARegion *ar, float vco[3], short vno[3], float mval[2], float ray_start[3], float ray_start_local[3], float ray_normal_local[3], float obmat[][4], float timat[][3], float *loc, float *no, int *dist, float *depth)
1180 {
1181         int retval = 0;
1182         float dvec[3];
1183         
1184         sub_v3_v3v3(dvec, vco, ray_start_local);
1185         
1186         if (dot_v3v3(ray_normal_local, dvec) > 0)
1187         {
1188                 float location[3];
1189                 float new_depth;
1190                 int screen_loc[2];
1191                 int new_dist;
1192                 
1193                 VECCOPY(location, vco);
1194                 
1195                 mul_m4_v3(obmat, location);
1196                 
1197                 new_depth = len_v3v3(location, ray_start);                                      
1198                 
1199                 project_int(ar, location, screen_loc);
1200                 new_dist = abs(screen_loc[0] - (int)mval[0]) + abs(screen_loc[1] - (int)mval[1]);
1201                 
1202                 if (new_dist <= *dist && new_depth < *depth)
1203                 {
1204                         *depth = new_depth;
1205                         retval = 1;
1206                         
1207                         VECCOPY(loc, location);
1208                         
1209                         if (no)
1210                         {
1211                                 normal_short_to_float_v3(no, vno);
1212                                 mul_m3_v3(timat, no);
1213                                 normalize_v3(no);
1214                         }
1215
1216                         *dist = new_dist;
1217                 } 
1218         }
1219         
1220         return retval;
1221 }
1222
1223 static int snapArmature(short snap_mode, ARegion *ar, Object *ob, bArmature *arm, float obmat[][4], float ray_start[3], float ray_normal[3], float mval[2], float *loc, float *UNUSED(no), int *dist, float *depth)
1224 {
1225         float imat[4][4];
1226         float ray_start_local[3], ray_normal_local[3];
1227         int retval = 0;
1228
1229         invert_m4_m4(imat, obmat);
1230
1231         VECCOPY(ray_start_local, ray_start);
1232         VECCOPY(ray_normal_local, ray_normal);
1233         
1234         mul_m4_v3(imat, ray_start_local);
1235         mul_mat3_m4_v3(imat, ray_normal_local);
1236
1237         if(arm->edbo)
1238         {
1239                 EditBone *eBone;
1240
1241                 for (eBone=arm->edbo->first; eBone; eBone=eBone->next) {
1242                         if (eBone->layer & arm->layer) {
1243                                 /* skip hidden or moving (selected) bones */
1244                                 if ((eBone->flag & (BONE_HIDDEN_A|BONE_ROOTSEL|BONE_TIPSEL))==0) {
1245                                         switch (snap_mode)
1246                                         {
1247                                                 case SCE_SNAP_MODE_VERTEX:
1248                                                         retval |= snapVertex(ar, eBone->head, NULL, mval, ray_start, ray_start_local, ray_normal_local, obmat, NULL, loc, NULL, dist, depth);
1249                                                         retval |= snapVertex(ar, eBone->tail, NULL, mval, ray_start, ray_start_local, ray_normal_local, obmat, NULL, loc, NULL, dist, depth);
1250                                                         break;
1251                                                 case SCE_SNAP_MODE_EDGE:
1252                                                         retval |= snapEdge(ar, eBone->head, NULL, eBone->tail, NULL, mval, ray_start, ray_start_local, ray_normal_local, obmat, NULL, loc, NULL, dist, depth);
1253                                                         break;
1254                                         }
1255                                 }
1256                         }
1257                 }
1258         }
1259         else if (ob->pose && ob->pose->chanbase.first)
1260         {
1261                 bPoseChannel *pchan;
1262                 Bone *bone;
1263                 
1264                 for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
1265                         bone= pchan->bone;
1266                         /* skip hidden bones */
1267                         if (bone && !(bone->flag & (BONE_HIDDEN_P|BONE_HIDDEN_PG))) {
1268                                 float *head_vec = pchan->pose_head;
1269                                 float *tail_vec = pchan->pose_tail;
1270                                 
1271                                 switch (snap_mode)
1272                                 {
1273                                         case SCE_SNAP_MODE_VERTEX:
1274                                                 retval |= snapVertex(ar, head_vec, NULL, mval, ray_start, ray_start_local, ray_normal_local, obmat, NULL, loc, NULL, dist, depth);
1275                                                 retval |= snapVertex(ar, tail_vec, NULL, mval, ray_start, ray_start_local, ray_normal_local, obmat, NULL, loc, NULL, dist, depth);
1276                                                 break;
1277                                         case SCE_SNAP_MODE_EDGE:
1278                                                 retval |= snapEdge(ar, head_vec, NULL, tail_vec, NULL, mval, ray_start, ray_start_local, ray_normal_local, obmat, NULL, loc, NULL, dist, depth);
1279                                                 break;
1280                                 }
1281                         }
1282                 }
1283         }
1284
1285         return retval;
1286 }
1287
1288 static int snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, 
1289                                                    DerivedMesh *dm, BMEditMesh *em, float obmat[][4], 
1290                                                    float ray_start[3], float ray_normal[3], float mval[2],
1291                                                    float *loc, float *no, int *dist, float *depth)
1292 {
1293         int retval = 0;
1294         int totvert = dm->getNumVerts(dm);
1295         int totface = dm->getNumTessFaces(dm);
1296
1297         if (totvert > 0) {
1298                 float imat[4][4];
1299                 float timat[3][3]; /* transpose inverse matrix for normals */
1300                 float ray_start_local[3], ray_normal_local[3];
1301                 int test = 1;
1302
1303                 invert_m4_m4(imat, obmat);
1304
1305                 copy_m3_m4(timat, imat);
1306                 transpose_m3(timat);
1307                 
1308                 VECCOPY(ray_start_local, ray_start);
1309                 VECCOPY(ray_normal_local, ray_normal);
1310                 
1311                 mul_m4_v3(imat, ray_start_local);
1312                 mul_mat3_m4_v3(imat, ray_normal_local);
1313                 
1314                 
1315                 /* If number of vert is more than an arbitrary limit, 
1316                  * test against boundbox first
1317                  * */
1318                 if (totface > 16) {
1319                         struct BoundBox *bb = object_get_boundbox(ob);
1320                         test = ray_hit_boundbox(bb, ray_start_local, ray_normal_local);
1321                 }
1322                 
1323                 if (test == 1) {
1324                         
1325                         switch (snap_mode)
1326                         {
1327                                 case SCE_SNAP_MODE_FACE:
1328                                 { 
1329 #ifdef USE_BVH_FACE_SNAP                                // Added for durian
1330                                         BVHTreeRayHit hit;
1331                                         BVHTreeFromMesh treeData;
1332
1333                                         /* local scale in normal direction */
1334                                         float local_scale = len_v3(ray_normal_local);
1335
1336                                         treeData.em_evil= em;
1337                                         bvhtree_from_mesh_faces(&treeData, dm, 0.0f, 4, 6);
1338
1339                                         hit.index = -1;
1340                                         hit.dist = *depth * (*depth == FLT_MAX ? 1.0f : local_scale);
1341
1342                                         if(treeData.tree && BLI_bvhtree_ray_cast(treeData.tree, ray_start_local, ray_normal_local, 0.0f, &hit, treeData.raycast_callback, &treeData) != -1)
1343                                         {
1344                                                 if(hit.dist/local_scale <= *depth) {
1345                                                         *depth= hit.dist/local_scale;
1346                                                         copy_v3_v3(loc, hit.co);
1347                                                         copy_v3_v3(no, hit.no);
1348
1349                                                         /* back to worldspace */
1350                                                         mul_m4_v3(obmat, loc);
1351                                                         copy_v3_v3(no, hit.no);
1352
1353                                                         mul_m3_v3(timat, no);
1354                                                         normalize_v3(no);
1355
1356                                                         retval |= 1;
1357                                                 }
1358                                         }
1359                                         break;
1360
1361 #else
1362                                         MVert *verts = dm->getVertArray(dm);
1363                                         MFace *faces = dm->getTessFaceArray(dm);
1364                                         int *index_array = NULL;
1365                                         int index = 0;
1366                                         int i;
1367                                         
1368                                         if (em != NULL)
1369                                         {
1370                                                 index_array = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
1371                                                 EDBM_init_index_arrays(em, 0, 0, 1);
1372                                         }
1373                                         
1374                                         for( i = 0; i < totface; i++) {
1375                                                 BMFace *efa = NULL;
1376                                                 MFace *f = faces + i;
1377                                                 
1378                                                 test = 1; /* reset for every face */
1379                                         
1380                                                 if (em != NULL)
1381                                                 {
1382                                                         if (index_array)
1383                                                         {
1384                                                                 index = index_array[i];
1385                                                         }
1386                                                         else
1387                                                         {
1388                                                                 index = i;
1389                                                         }
1390                                                         
1391                                                         if (index == ORIGINDEX_NONE)
1392                                                         {
1393                                                                 test = 0;
1394                                                         }
1395                                                         else
1396                                                         {
1397                                                                 efa = EDBM_get_face_for_index(em, index);
1398                                                                 
1399                                                                 if (efa && BM_TestHFlag(efa, BM_HIDDEN))
1400                                                                 {
1401                                                                         test = 0;
1402                                                                 } else if (efa) {
1403                                                                         BMIter iter;
1404                                                                         BMLoop *l;
1405                                                                         
1406                                                                         l = BMIter_New(&iter, em->bm, BM_LOOPS_OF_FACE, efa);
1407                                                                         for ( ; l; l=BMIter_Step(&iter)) {
1408                                                                                 if (BM_TestHFlag(l->v, BM_SELECT)) {
1409                                                                                         test = 0;
1410                                                                                         break;
1411                                                                                 }
1412                                                                         }
1413                                                                 }
1414                                                         }
1415                                                 }
1416                                                 
1417                                                 
1418                                                 if (test)
1419                                                 {
1420                                                         int result;
1421                                                         float *v4co = NULL;
1422                                                         
1423                                                         if (f->v4)
1424                                                         {
1425                                                                 v4co = verts[f->v4].co;
1426                                                         }
1427                                                         
1428                                                         result = snapFace(ar, verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, v4co, mval, ray_start, ray_start_local, ray_normal_local, obmat, timat, loc, no, dist, depth);
1429                                                         retval |= result;
1430
1431                                                         if (f->v4 && result == 0)
1432                                                         {
1433                                                                 retval |= snapFace(ar, verts[f->v3].co, verts[f->v4].co, verts[f->v1].co, verts[f->v2].co, mval, ray_start, ray_start_local, ray_normal_local, obmat, timat, loc, no, dist, depth);
1434                                                         }
1435                                                 }
1436                                         }
1437                                         
1438                                         if (em != NULL)
1439                                         {
1440                                                 EDBM_free_index_arrays(em);
1441                                         }
1442 #endif
1443                                         break;
1444                                 }
1445                                 case SCE_SNAP_MODE_VERTEX:
1446                                 {
1447                                         MVert *verts = dm->getVertArray(dm);
1448                                         int *index_array = NULL;
1449                                         int index = 0;
1450                                         int i;
1451                                         
1452                                         if (em != NULL)
1453                                         {
1454                                                 index_array = dm->getVertDataArray(dm, CD_ORIGINDEX);
1455                                                 EDBM_init_index_arrays(em, 1, 0, 0);
1456                                         }
1457                                         
1458                                         for( i = 0; i < totvert; i++) {
1459                                                 BMVert *eve = NULL;
1460                                                 MVert *v = verts + i;
1461                                                 
1462                                                 test = 1; /* reset for every vert */
1463                                         
1464                                                 if (em != NULL)
1465                                                 {
1466                                                         if (index_array)
1467                                                         {
1468                                                                 index = index_array[i];
1469                                                         }
1470                                                         else
1471                                                         {
1472                                                                 index = i;
1473                                                         }
1474                                                         
1475                                                         if (index == ORIGINDEX_NONE)
1476                                                         {
1477                                                                 test = 0;
1478                                                         }
1479                                                         else
1480                                                         {
1481                                                                 eve = EDBM_get_vert_for_index(em, index);
1482                                                                 
1483                                                                 if (eve && (BM_TestHFlag(eve, BM_HIDDEN) || BM_TestHFlag(eve, BM_SELECT)))
1484                                                                 {
1485                                                                         test = 0;
1486                                                                 }
1487                                                         }
1488                                                 }
1489                                                 
1490                                                 
1491                                                 if (test)
1492                                                 {
1493                                                         retval |= snapVertex(ar, v->co, v->no, mval, ray_start, ray_start_local, ray_normal_local, obmat, timat, loc, no, dist, depth);
1494                                                 }
1495                                         }
1496
1497                                         if (em != NULL)
1498                                         {
1499                                                 EDBM_free_index_arrays(em);
1500                                         }
1501                                         break;
1502                                 }
1503                                 case SCE_SNAP_MODE_EDGE:
1504                                 {
1505                                         MVert *verts = dm->getVertArray(dm);
1506                                         MEdge *edges = dm->getEdgeArray(dm);
1507                                         int totedge = dm->getNumEdges(dm);
1508                                         int *index_array = NULL;
1509                                         int index = 0;
1510                                         int i;
1511                                         
1512                                         if (em != NULL)
1513                                         {
1514                                                 index_array = dm->getEdgeDataArray(dm, CD_ORIGINDEX);
1515                                                 EDBM_init_index_arrays(em, 0, 1, 0);
1516                                         }
1517                                         
1518                                         for( i = 0; i < totedge; i++) {
1519                                                 BMEdge *eed = NULL;
1520                                                 MEdge *e = edges + i;
1521                                                 
1522                                                 test = 1; /* reset for every vert */
1523                                         
1524                                                 if (em != NULL)
1525                                                 {
1526                                                         if (index_array)
1527                                                         {
1528                                                                 index = index_array[i];
1529                                                         }
1530                                                         else
1531                                                         {
1532                                                                 index = i;
1533                                                         }
1534                                                         
1535                                                         if (index == ORIGINDEX_NONE)
1536                                                         {
1537                                                                 test = 0;
1538                                                         }
1539                                                         else
1540                                                         {
1541                                                                 eed = EDBM_get_edge_for_index(em, index);
1542                                                                 
1543                                                                 if (eed && (BM_TestHFlag(eed, BM_HIDDEN) ||
1544                                                                         BM_TestHFlag(eed->v1, BM_SELECT) || 
1545                                                                         BM_TestHFlag(eed->v2, BM_SELECT)))
1546                                                                 {
1547                                                                         test = 0;
1548                                                                 }
1549                                                         }
1550                                                 }
1551                                                 
1552                                                 
1553                                                 if (test)
1554                                                 {
1555                                                         retval |= snapEdge(ar, verts[e->v1].co, verts[e->v1].no, verts[e->v2].co, verts[e->v2].no, mval, ray_start, ray_start_local, ray_normal_local, obmat, timat, loc, no, dist, depth);
1556                                                 }
1557                                         }
1558
1559                                         if (em != NULL)
1560                                         {
1561                                                 EDBM_free_index_arrays(em);
1562                                         }
1563                                         break;
1564                                 }
1565                         }
1566                 }
1567         }
1568
1569         return retval;
1570
1571
1572 static int snapObject(Scene *scene, ARegion *ar, Object *ob, int editobject, float obmat[][4], float ray_start[3], float ray_normal[3], float mval[2], float *loc, float *no, int *dist, float *depth)
1573 {
1574         ToolSettings *ts= scene->toolsettings;
1575         int retval = 0;
1576         
1577         if (ob->type == OB_MESH) {
1578                 BMEditMesh *em;
1579                 DerivedMesh *dm;
1580                 
1581                 if (editobject)
1582                 {
1583                         em = ((Mesh *)ob->data)->edit_btmesh;
1584                         /* dm = editbmesh_get_derived_cage(scene, ob, em, CD_MASK_BAREMESH); */
1585                         dm = editbmesh_get_derived_base(ob, em); /* limitation, em & dm MUST have the same number of faces */
1586                 }
1587                 else
1588                 {
1589                         em = NULL;
1590                         dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
1591                 }
1592                 
1593                 retval = snapDerivedMesh(ts->snap_mode, ar, ob, dm, em, obmat, ray_start, ray_normal, mval, loc, no, dist, depth);
1594
1595                 dm->release(dm);
1596         }
1597         else if (ob->type == OB_ARMATURE)
1598         {
1599                 retval = snapArmature(ts->snap_mode, ar, ob, ob->data, obmat, ray_start, ray_normal, mval, loc, no, dist, depth);
1600         }
1601         
1602         return retval;
1603 }
1604
1605 static int snapObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, float mval[2], int *dist, float *loc, float *no, SnapMode mode) {
1606         Base *base;
1607         float depth = FLT_MAX;
1608         int retval = 0;
1609         float ray_start[3], ray_normal[3];
1610         
1611         ED_view3d_win_to_ray(ar, v3d, mval, ray_start, ray_normal);
1612
1613         if (mode == SNAP_ALL && obedit)
1614         {
1615                 Object *ob = obedit;
1616
1617                 retval |= snapObject(scene, ar, ob, 1, ob->obmat, ray_start, ray_normal, mval, loc, no, dist, &depth);
1618         }
1619
1620         /* Need an exception for particle edit because the base is flagged with BA_HAS_RECALC_DATA
1621          * which makes the loop skip it, even the derived mesh will never change
1622          *
1623          * To solve that problem, we do it first as an exception. 
1624          * */
1625         base= BASACT;
1626         if(base && base->object && base->object->mode & OB_MODE_PARTICLE_EDIT)
1627         {
1628                 Object *ob = base->object;
1629                 retval |= snapObject(scene, ar, ob, 0, ob->obmat, ray_start, ray_normal, mval, loc, no, dist, &depth);
1630         }
1631
1632         for ( base = FIRSTBASE; base != NULL; base = base->next ) {
1633                 if ( BASE_VISIBLE(v3d, base) && (base->flag & (BA_HAS_RECALC_OB|BA_HAS_RECALC_DATA)) == 0 && ((mode == SNAP_NOT_SELECTED && (base->flag & (SELECT|BA_WAS_SEL)) == 0) || (ELEM(mode, SNAP_ALL, SNAP_NOT_OBEDIT) && base != BASACT)) ) {
1634                         Object *ob = base->object;
1635                         
1636                         if (ob->transflag & OB_DUPLI)
1637                         {
1638                                 DupliObject *dupli_ob;
1639                                 ListBase *lb = object_duplilist(scene, ob);
1640                                 
1641                                 for(dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next)
1642                                 {
1643                                         Object *dob = dupli_ob->ob;
1644                                         
1645                                         retval |= snapObject(scene, ar, dob, 0, dupli_ob->mat, ray_start, ray_normal, mval, loc, no, dist, &depth);
1646                                 }
1647                                 
1648                                 free_object_duplilist(lb);
1649                         }
1650                         
1651                         retval |= snapObject(scene, ar, ob, 0, ob->obmat, ray_start, ray_normal, mval, loc, no, dist, &depth);
1652                 }
1653         }
1654         
1655         return retval;
1656 }
1657
1658 int snapObjectsTransform(TransInfo *t, float mval[2], int *dist, float *loc, float *no, SnapMode mode)
1659 {
1660         return snapObjects(t->scene, t->view, t->ar, t->obedit, mval, dist, loc, no, mode);
1661 }
1662
1663 int snapObjectsContext(bContext *C, float mval[2], int *dist, float *loc, float *no, SnapMode mode)
1664 {
1665         ScrArea *sa = CTX_wm_area(C);
1666         View3D *v3d = sa->spacedata.first;
1667
1668         return snapObjects(CTX_data_scene(C), v3d, CTX_wm_region(C), CTX_data_edit_object(C), mval, dist, loc, no, mode);
1669 }
1670
1671 /******************** PEELING *********************************/
1672
1673
1674 static int cmpPeel(void *arg1, void *arg2)
1675 {
1676         DepthPeel *p1 = arg1;
1677         DepthPeel *p2 = arg2;
1678         int val = 0;
1679         
1680         if (p1->depth < p2->depth)
1681         {
1682                 val = -1;
1683         }
1684         else if (p1->depth > p2->depth)
1685         {
1686                 val = 1;
1687         }
1688         
1689         return val;
1690 }
1691
1692 static void removeDoublesPeel(ListBase *depth_peels)
1693 {
1694         DepthPeel *peel;
1695         
1696         for (peel = depth_peels->first; peel; peel = peel->next)
1697         {
1698                 DepthPeel *next_peel = peel->next;
1699                 
1700                 if (next_peel && ABS(peel->depth - next_peel->depth) < 0.0015f)
1701                 {
1702                         peel->next = next_peel->next;
1703                         
1704                         if (next_peel->next)
1705                         {
1706                                 next_peel->next->prev = peel;
1707                         }
1708                         
1709                         MEM_freeN(next_peel);
1710                 }
1711         }
1712 }
1713
1714 static void addDepthPeel(ListBase *depth_peels, float depth, float p[3], float no[3], Object *ob)
1715 {
1716         DepthPeel *peel = MEM_callocN(sizeof(DepthPeel), "DepthPeel");
1717         
1718         peel->depth = depth;
1719         peel->ob = ob;
1720         VECCOPY(peel->p, p);
1721         VECCOPY(peel->no, no);
1722         
1723         BLI_addtail(depth_peels, peel);
1724         
1725         peel->flag = 0;
1726 }
1727
1728 static int peelDerivedMesh(Object *ob, DerivedMesh *dm, float obmat[][4], float ray_start[3], float ray_normal[3], float UNUSED(mval[2]), ListBase *depth_peels)
1729 {
1730         int retval = 0;
1731         int totvert = dm->getNumVerts(dm);
1732         int totface = dm->getNumTessFaces(dm);
1733         
1734         if (totvert > 0) {
1735                 float imat[4][4];
1736                 float timat[3][3]; /* transpose inverse matrix for normals */
1737                 float ray_start_local[3], ray_normal_local[3];
1738                 int test = 1;
1739
1740                 invert_m4_m4(imat, obmat);
1741
1742                 copy_m3_m4(timat, imat);
1743                 transpose_m3(timat);
1744                 
1745                 VECCOPY(ray_start_local, ray_start);
1746                 VECCOPY(ray_normal_local, ray_normal);
1747                 
1748                 mul_m4_v3(imat, ray_start_local);
1749                 mul_mat3_m4_v3(imat, ray_normal_local);
1750                 
1751                 
1752                 /* If number of vert is more than an arbitrary limit, 
1753                  * test against boundbox first
1754                  * */
1755                 if (totface > 16) {
1756                         struct BoundBox *bb = object_get_boundbox(ob);
1757                         test = ray_hit_boundbox(bb, ray_start_local, ray_normal_local);
1758                 }
1759                 
1760                 if (test == 1) {
1761                         MVert *verts = dm->getVertArray(dm);
1762                         MFace *faces = dm->getTessFaceArray(dm);
1763                         int i;
1764                         
1765                         for( i = 0; i < totface; i++) {
1766                                 MFace *f = faces + i;
1767                                 float lambda;
1768                                 int result;
1769                                 
1770                                 
1771                                 result = isect_ray_tri_threshold_v3(ray_start_local, ray_normal_local, verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, &lambda, NULL, 0.001);
1772                                 
1773                                 if (result) {
1774                                         float location[3], normal[3];
1775                                         float intersect[3];
1776                                         float new_depth;
1777                                         
1778                                         VECCOPY(intersect, ray_normal_local);
1779                                         mul_v3_fl(intersect, lambda);
1780                                         add_v3_v3(intersect, ray_start_local);
1781                                         
1782                                         VECCOPY(location, intersect);
1783                                         
1784                                         if (f->v4)
1785                                                 normal_quad_v3( normal,verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, verts[f->v4].co);
1786                                         else
1787                                                 normal_tri_v3( normal,verts[f->v1].co, verts[f->v2].co, verts[f->v3].co);
1788
1789                                         mul_m4_v3(obmat, location);
1790                                         
1791                                         new_depth = len_v3v3(location, ray_start);                                      
1792                                         
1793                                         mul_m3_v3(timat, normal);
1794                                         normalize_v3(normal);
1795
1796                                         addDepthPeel(depth_peels, new_depth, location, normal, ob);
1797                                 }
1798                 
1799                                 if (f->v4 && result == 0)
1800                                 {
1801                                         result = isect_ray_tri_threshold_v3(ray_start_local, ray_normal_local, verts[f->v3].co, verts[f->v4].co, verts[f->v1].co, &lambda, NULL, 0.001);
1802                                         
1803                                         if (result) {
1804                                                 float location[3], normal[3];
1805                                                 float intersect[3];
1806                                                 float new_depth;
1807                                                 
1808                                                 VECCOPY(intersect, ray_normal_local);
1809                                                 mul_v3_fl(intersect, lambda);
1810                                                 add_v3_v3(intersect, ray_start_local);
1811                                                 
1812                                                 VECCOPY(location, intersect);
1813                                                 
1814                                                 if (f->v4)
1815                                                         normal_quad_v3( normal,verts[f->v1].co, verts[f->v2].co, verts[f->v3].co, verts[f->v4].co);
1816                                                 else
1817                                                         normal_tri_v3( normal,verts[f->v1].co, verts[f->v2].co, verts[f->v3].co);
1818
1819                                                 mul_m4_v3(obmat, location);
1820                                                 
1821                                                 new_depth = len_v3v3(location, ray_start);                                      
1822                                                 
1823                                                 mul_m3_v3(timat, normal);
1824                                                 normalize_v3(normal);
1825         
1826                                                 addDepthPeel(depth_peels, new_depth, location, normal, ob);
1827                                         } 
1828                                 }
1829                         }
1830                 }
1831         }
1832
1833         return retval;
1834
1835
1836 static int peelObjects(Scene *scene, View3D *v3d, ARegion *ar, Object *obedit, ListBase *depth_peels, float mval[2])
1837 {
1838         Base *base;
1839         int retval = 0;
1840         float ray_start[3], ray_normal[3];
1841         
1842         ED_view3d_win_to_ray(ar, v3d, mval, ray_start, ray_normal);
1843
1844         for ( base = scene->base.first; base != NULL; base = base->next ) {
1845                 if ( BASE_SELECTABLE(v3d, base) ) {
1846                         Object *ob = base->object;
1847                         
1848                         if (ob->transflag & OB_DUPLI)
1849                         {
1850                                 DupliObject *dupli_ob;
1851                                 ListBase *lb = object_duplilist(scene, ob);
1852                                 
1853                                 for(dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next)
1854                                 {
1855                                         Object *dob = dupli_ob->ob;
1856                                         
1857                                         if (dob->type == OB_MESH) {
1858 #if 0 //BMESH_TODO
1859                                                 EditMesh *em;
1860                                                 DerivedMesh *dm = NULL;
1861                                                 int val;
1862
1863                                                 if (dob != obedit)
1864                                                 {
1865                                                         dm = mesh_get_derived_final(scene, dob, CD_MASK_BAREMESH);
1866                                                         
1867                                                         val = peelDerivedMesh(dob, dm, dob->obmat, ray_start, ray_normal, mval, depth_peels);
1868                                                 }
1869                                                 else
1870                                                 {
1871                                                         em = ((Mesh *)dob->data)->edit_mesh;
1872                                                         dm = editmesh_get_derived_cage(scene, obedit, em, CD_MASK_BAREMESH);
1873                                                         
1874                                                         val = peelDerivedMesh(dob, dm, dob->obmat, ray_start, ray_normal, mval, depth_peels);
1875                                                 }
1876
1877                                                 retval = retval || val;
1878                                                 
1879                                                 dm->release(dm);
1880 #endif
1881                                         }
1882                                 }
1883                                 
1884                                 free_object_duplilist(lb);
1885                         }
1886                         
1887                         if (ob->type == OB_MESH) {
1888                                 BMEditMesh *em;
1889                                 DerivedMesh *dm = NULL;
1890                                 int val;
1891
1892                                 if (ob != obedit)
1893                                 {
1894                                         dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
1895                                         
1896                                         val = peelDerivedMesh(ob, dm, ob->obmat, ray_start, ray_normal, mval, depth_peels);
1897                                 }
1898                                 else
1899                                 {
1900                                         em = ((Mesh *)ob->data)->edit_btmesh;
1901                                         dm = editbmesh_get_derived_cage(scene, obedit, em, CD_MASK_BAREMESH);
1902                                         
1903                                         val = peelDerivedMesh(ob, dm, ob->obmat, ray_start, ray_normal, mval, depth_peels);
1904                                 }
1905                                         
1906                                 retval = retval || val;
1907                                 
1908                                 dm->release(dm);
1909                         }
1910                 }
1911         }
1912         
1913         BLI_sortlist(depth_peels, cmpPeel);
1914         removeDoublesPeel(depth_peels);
1915         
1916         return retval;
1917 }
1918
1919 int peelObjectsTransForm(TransInfo *t, ListBase *depth_peels, float mval[2])
1920 {
1921         return peelObjects(t->scene, t->view, t->ar, t->obedit, depth_peels, mval);
1922 }
1923
1924 int peelObjectsContext(bContext *C, ListBase *depth_peels, float mval[2])
1925 {
1926         ScrArea *sa = CTX_wm_area(C);
1927         View3D *v3d = sa->spacedata.first;
1928
1929         return peelObjects(CTX_data_scene(C), v3d, CTX_wm_region(C), CTX_data_edit_object(C), depth_peels, mval);
1930 }
1931
1932 /*================================================================*/
1933
1934 static void applyGrid(TransInfo *t, float *val, int max_index, float fac[3], GearsType action);
1935
1936
1937 void snapGridAction(TransInfo *t, float *val, GearsType action) {
1938         float fac[3];
1939
1940         fac[NO_GEARS]    = t->snap[0];
1941         fac[BIG_GEARS]   = t->snap[1];
1942         fac[SMALL_GEARS] = t->snap[2];
1943         
1944         applyGrid(t, val, t->idx_max, fac, action);
1945 }
1946
1947
1948 void snapGrid(TransInfo *t, float *val) {
1949         GearsType action;
1950
1951         // Only do something if using Snap to Grid
1952         if (t->tsnap.mode != SCE_SNAP_MODE_INCREMENT)
1953                 return;
1954
1955         action = activeSnap(t) ? BIG_GEARS : NO_GEARS;
1956
1957         if (action == BIG_GEARS && (t->modifiers & MOD_PRECISION)) {
1958                 action = SMALL_GEARS;
1959         }
1960
1961         snapGridAction(t, val, action);
1962 }
1963
1964
1965 static void applyGrid(TransInfo *t, float *val, int max_index, float fac[3], GearsType action)
1966 {
1967         int i;
1968         float asp[3] = {1.0f, 1.0f, 1.0f}; // TODO: Remove hard coded limit here (3)
1969
1970         if(max_index > 2) {
1971                 printf("applyGrid: invalid index %d, clamping\n", max_index);
1972                 max_index= 2;
1973         }
1974
1975         // Early bailing out if no need to snap
1976         if (fac[action] == 0.0f)
1977                 return;
1978         
1979         /* evil hack - snapping needs to be adapted for image aspect ratio */
1980         if((t->spacetype==SPACE_IMAGE) && (t->mode==TFM_TRANSLATION)) {
1981                 ED_space_image_uv_aspect(t->sa->spacedata.first, asp, asp+1);
1982         }
1983
1984         for (i=0; i<=max_index; i++) {
1985                 val[i]= fac[action]*asp[i]*(float)floor(val[i]/(fac[action]*asp[i]) +0.5f);
1986         }
1987 }