Additive snap for Transform. Easy snapping between two vertices, in the middle of...
authorMartin Poirier <theeth@yahoo.com>
Tue, 1 Dec 2009 18:26:18 +0000 (18:26 +0000)
committerMartin Poirier <theeth@yahoo.com>
Tue, 1 Dec 2009 18:26:18 +0000 (18:26 +0000)
A to add the current snapping point to the list
Alt-A to remove the last one

The resulting snapping point is the average of all snap points in the list (and the one under the mouse pointer, if valid).

Snapping between two verts is a matter of moving over the first, pressing A, moving over the other, confirming transform.

source/blender/editors/transform/transform.c
source/blender/editors/transform/transform.h
source/blender/editors/transform/transform_generics.c
source/blender/editors/transform/transform_snap.c

index 2e1922d8a0727dfcb2b89d72fe21d85973f0142a..cbcb3953f49cec205fa88cf5aabb3f23b5b39cd9 100644 (file)
@@ -517,6 +517,8 @@ static char *transform_to_undostr(TransInfo *t)
 #define TFM_MODAL_PLANE_Y              13
 #define TFM_MODAL_PLANE_Z              14
 #define TFM_MODAL_CONS_OFF             15
+#define TFM_MODAL_ADD_SNAP             16
+#define TFM_MODAL_REMOVE_SNAP  17
 
 /* called in transform_ops.c, on each regeneration of keymaps */
 void transform_modal_keymap(wmKeyConfig *keyconf)
@@ -537,6 +539,8 @@ void transform_modal_keymap(wmKeyConfig *keyconf)
        {TFM_MODAL_PLANE_Y, "PLANE_Y", 0, "Orientation Y plane", ""},
        {TFM_MODAL_PLANE_Z, "PLANE_Z", 0, "Orientation Z plane", ""},
        {TFM_MODAL_CONS_OFF, "CONS_OFF", 0, "Remove Constraints", ""},
+       {TFM_MODAL_ADD_SNAP, "ADD_SNAP", 0, "Add Snap Point", ""},
+       {TFM_MODAL_REMOVE_SNAP, "REMOVE_SNAP", 0, "Remove Last Snap Point", ""},
        {0, NULL, 0, NULL, NULL}};
        
        wmKeyMap *keymap= WM_modalkeymap_get(keyconf, "Transform Modal Map");
@@ -558,6 +562,9 @@ void transform_modal_keymap(wmKeyConfig *keyconf)
        
        WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_CLICK, KM_ANY, 0, TFM_MODAL_SNAP_TOGGLE);
        
+       WM_modalkeymap_add_item(keymap, AKEY, KM_PRESS, 0, 0, TFM_MODAL_ADD_SNAP);
+       WM_modalkeymap_add_item(keymap, AKEY, KM_PRESS, KM_ALT, 0, TFM_MODAL_REMOVE_SNAP);
+
        /* assign map to operators */
        WM_modalkeymap_assign(keymap, "TFM_OT_transform");
        WM_modalkeymap_assign(keymap, "TFM_OT_translate");
@@ -743,6 +750,14 @@ int transformEvent(TransInfo *t, wmEvent *event)
                                        t->redraw = 1;
                                }
                                break;
+                       case TFM_MODAL_ADD_SNAP:
+                               addSnapPoint(t);
+                               t->redraw = 1;
+                               break;
+                       case TFM_MODAL_REMOVE_SNAP:
+                               removeSnapPoint(t);
+                               t->redraw = 1;
+                               break;
                        default:
                                handled = 0;
                                break;
index 4b7d24dc1fac304e39043ff035b9811f79a8e8b1..1577c05cc8823fdd07a85d9897089e5f1343d809 100644 (file)
@@ -32,6 +32,8 @@
 
 #include "ED_transform.h"
 
+#include "DNA_listBase.h"
+
 #include "BLI_editVert.h"
 
 /* ************************** Types ***************************** */
@@ -82,6 +84,11 @@ typedef struct NumInput {
                Negative        : number is negative
 */
 
+typedef struct TransSnapPoint {
+       struct TransSnapPoint *next,*prev;
+       float co[3];
+} TransSnapPoint;
+
 typedef struct TransSnap {
        short   mode;
        short   modePoint;
@@ -95,6 +102,7 @@ typedef struct TransSnap {
        float   snapTarget[3]; /* to this point */
        float   snapNormal[3];
        float   snapTangent[3];
+       ListBase points;
        float   dist; // Distance from snapPoint to snapTarget
        double  last;
        void  (*applySnap)(struct TransInfo *, float *);
@@ -417,6 +425,7 @@ typedef struct TransInfo {
 #define SNAP_FORCED            1
 #define TARGET_INIT            2
 #define POINT_INIT             4
+#define MULTI_POINTS   8
 
 /* transsnap->modeTarget */
 #define SNAP_CLOSEST           0
@@ -597,6 +606,10 @@ void drawSnapping(const struct bContext *C, TransInfo *t);
 int usingSnappingNormal(TransInfo *t);
 int validSnappingNormal(TransInfo *t);
 
+void getSnapPoint(TransInfo *t, float vec[3]);
+void addSnapPoint(TransInfo *t);
+void removeSnapPoint(TransInfo *t);
+
 /********************** Mouse Input ******************************/
 
 typedef enum {
index 8b7c4b7503b7f5a1c7b84f451306ddfd6644daf6..71a5affb57372294bdf260e4ee5630c274f2acbe 100644 (file)
@@ -1095,6 +1095,8 @@ void postTrans (TransInfo *t)
                MEM_freeN(t->data);
        }
        
+       BLI_freelistN(&t->tsnap.points);
+
        if (t->ext) MEM_freeN(t->ext);
        if (t->data2d) {
                MEM_freeN(t->data2d);
index d36b7c9b903454bffa0f7dcaa14f75d00f7b3c82..7f1e67b62aceec2c9e17973abae3142bd6fb4b7d 100644 (file)
@@ -123,9 +123,14 @@ int BIF_snappingSupported(Object *obedit)
        return status;
 }
 
+int validSnap(TransInfo *t) {
+       return (t->tsnap.status & (POINT_INIT|TARGET_INIT)) == (POINT_INIT|TARGET_INIT) ||
+                       (t->tsnap.status & (MULTI_POINTS|TARGET_INIT)) == (MULTI_POINTS|TARGET_INIT);
+}
+
 void drawSnapping(const struct bContext *C, TransInfo *t)
 {
-       if ((t->tsnap.status & (POINT_INIT|TARGET_INIT)) == (POINT_INIT|TARGET_INIT) &&
+       if (validSnap(t) &&
                (t->modifiers & MOD_SNAP))
                {
                
@@ -134,6 +139,7 @@ void drawSnapping(const struct bContext *C, TransInfo *t)
                glColor4ub(col[0], col[1], col[2], 128);
                
                if (t->spacetype == SPACE_VIEW3D) {
+                       TransSnapPoint *p;
                        View3D *v3d = CTX_wm_view3d(C);
                        RegionView3D *rv3d = CTX_wm_region_view3d(C);
                        float tmat[4][4], imat[4][4];
@@ -141,14 +147,18 @@ void drawSnapping(const struct bContext *C, TransInfo *t)
                        
                        glDisable(GL_DEPTH_TEST);
        
-                       size = get_drawsize(t->ar, t->tsnap.snapPoint);
-                       
-                       size *= 0.5f * UI_GetThemeValuef(TH_VERTEX_SIZE);
+                       size = 0.5f * UI_GetThemeValuef(TH_VERTEX_SIZE);
                        
                        copy_m4_m4(tmat, rv3d->viewmat);
                        invert_m4_m4(imat, tmat);
 
-                       drawcircball(GL_LINE_LOOP, t->tsnap.snapPoint, size, imat);
+                       for (p = t->tsnap.points.first; p; p = p->next) {
+                               drawcircball(GL_LINE_LOOP, p->co, size * get_drawsize(t->ar, p->co), imat);
+                       }
+
+                       if (t->tsnap.status & POINT_INIT) {
+                               drawcircball(GL_LINE_LOOP, t->tsnap.snapPoint, size * get_drawsize(t->ar, t->tsnap.snapPoint), imat);
+                       }
                        
                        /* draw normal if needed */
                        if (usingSnappingNormal(t) && validSnappingNormal(t))
@@ -302,7 +312,7 @@ void applySnapping(TransInfo *t, float *vec)
        
                        t->tsnap.last = current;
                }
-               if ((t->tsnap.status & (POINT_INIT|TARGET_INIT)) == (POINT_INIT|TARGET_INIT))
+               if (validSnap(t))
                {
                        t->tsnap.applySnap(t, vec);
                }
@@ -331,7 +341,7 @@ int usingSnappingNormal(TransInfo *t)
 
 int validSnappingNormal(TransInfo *t)
 {
-       if ((t->tsnap.status & (POINT_INIT|TARGET_INIT)) == (POINT_INIT|TARGET_INIT))
+       if (validSnap(t))
        {
                if (dot_v3v3(t->tsnap.snapNormal, t->tsnap.snapNormal) > 0)
                {
@@ -502,11 +512,59 @@ void setSnappingCallback(TransInfo *t, short snap_target)
        }
 }
 
+void addSnapPoint(TransInfo *t)
+{
+       if (t->tsnap.status & POINT_INIT) {
+               TransSnapPoint *p = MEM_callocN(sizeof(TransSnapPoint), "SnapPoint");
+
+               VECCOPY(p->co, t->tsnap.snapPoint);
+
+               BLI_addtail(&t->tsnap.points, p);
+
+               t->tsnap.status |= MULTI_POINTS;
+       }
+}
+
+void removeSnapPoint(TransInfo *t)
+{
+       if (t->tsnap.status & MULTI_POINTS) {
+               BLI_freelinkN(&t->tsnap.points, t->tsnap.points.last);
+
+               if (t->tsnap.points.first == NULL)
+                       t->tsnap.status &= ~MULTI_POINTS;
+       }
+}
+
+void getSnapPoint(TransInfo *t, float vec[3])
+{
+       if (t->tsnap.points.first) {
+               TransSnapPoint *p;
+               int total = 0;
+
+               vec[0] = vec[1] = vec[2] = 0;
+
+               for (p = t->tsnap.points.first; p; p = p->next, total++) {
+                       add_v3_v3(vec, p->co);
+               }
+
+               if (t->tsnap.status & POINT_INIT) {
+                       add_v3_v3(vec, t->tsnap.snapPoint);
+                       total++;
+               }
+
+               mul_v3_fl(vec, 1.0f / total);
+       } else {
+               VECCOPY(vec, t->tsnap.snapPoint)
+       }
+}
+
 /********************** APPLY **************************/
 
 void ApplySnapTranslation(TransInfo *t, float vec[3])
 {
-       sub_v3_v3v3(vec, t->tsnap.snapPoint, t->tsnap.snapTarget);
+       float point[3];
+       getSnapPoint(t, point);
+       sub_v3_v3v3(vec, point, t->tsnap.snapTarget);
 }
 
 void ApplySnapRotation(TransInfo *t, float *vec)
@@ -515,7 +573,9 @@ void ApplySnapRotation(TransInfo *t, float *vec)
                *vec = t->tsnap.dist;
        }
        else {
-               *vec = RotationBetween(t, t->tsnap.snapTarget, t->tsnap.snapPoint);
+               float point[3];
+               getSnapPoint(t, point);
+               *vec = RotationBetween(t, t->tsnap.snapTarget, point);
        }
 }
 
@@ -525,7 +585,9 @@ void ApplySnapResize(TransInfo *t, float vec[3])
                vec[0] = vec[1] = vec[2] = t->tsnap.dist;
        }
        else {
-               vec[0] = vec[1] = vec[2] = ResizeBetween(t, t->tsnap.snapTarget, t->tsnap.snapPoint);
+               float point[3];
+               getSnapPoint(t, point);
+               vec[0] = vec[1] = vec[2] = ResizeBetween(t, t->tsnap.snapTarget, point);
        }
 }