diff options
author | Martin Poirier <theeth@yahoo.com> | 2006-12-23 03:52:34 +0300 |
---|---|---|
committer | Martin Poirier <theeth@yahoo.com> | 2006-12-23 03:52:34 +0300 |
commit | 1ad1522d10a0efbb5929826af4801724adf4a357 (patch) | |
tree | 298d8e6b9d75707e410d2fb59e756291350499d0 | |
parent | 48b62511bf9535dcaf484f5324c1776975b8791f (diff) |
=== Transform Snap ===
==== Rotation Snap ====
Snap is no longer limited to Translation, it works in Rotation too.
There's some bugs left with rotation snap when using constraints, I'll be ironing that next.
==== Bug Fixes ====
* Fix manipulators to always use Grid.
* Fix initialization bug (took two transform call to do a correct snap init when changing between Grid and Snap)
-rwxr-xr-x | source/blender/include/transform.h | 30 | ||||
-rwxr-xr-x | source/blender/src/transform.c | 6 | ||||
-rwxr-xr-x | source/blender/src/transform_generics.c | 1 | ||||
-rw-r--r-- | source/blender/src/transform_snap.c | 162 |
4 files changed, 141 insertions, 58 deletions
diff --git a/source/blender/include/transform.h b/source/blender/include/transform.h index 2ce022a650a..7a29f15ce0b 100755 --- a/source/blender/include/transform.h +++ b/source/blender/include/transform.h @@ -60,14 +60,17 @@ typedef struct NumInput { */ typedef struct TransSnap { - int mode; - int status; - float snapPoint[3]; - float snapTarget[3]; - double last; - void (*applySnap)(struct TransInfo *, float *); - void (*calcSnap)(struct TransInfo *, float *); - void (*targetSnap)(struct TransInfo *); + short modePoint; + short modeTarget; + int status; + float snapPoint[3]; + float snapTarget[3]; + float dist; // Distance from snapPoint to snapTarget + double last; + void (*applySnap)(struct TransInfo *, float *); + void (*calcSnap)(struct TransInfo *, float *); + void (*targetSnap)(struct TransInfo *); + float (*distance)(struct TransInfo *, float p1[3], float p2[3]); // Get the transform distance between two points (used by Closest snap) } TransSnap; typedef struct TransCon { @@ -257,9 +260,14 @@ typedef struct TransInfo { #define TARGET_INIT 2 #define POINT_INIT 4 -/* transsnap->mode */ -#define SNAP_GRID 1 -#define SNAP_GEO 2 +/* transsnap->modePoint */ +#define SNAP_GRID 0 +#define SNAP_GEO 1 + +/* transsnap->modeTarget */ +#define SNAP_CLOSEST 0 +#define SNAP_CENTER 1 +#define SNAP_MEDIAN 2 void checkFirstTime(void); diff --git a/source/blender/src/transform.c b/source/blender/src/transform.c index 7a9efd723ae..facee8ed8d9 100755 --- a/source/blender/src/transform.c +++ b/source/blender/src/transform.c @@ -756,6 +756,8 @@ void initTransform(int mode, int context) { createTransData(&Trans); // make TransData structs from selection + initSnapping(&Trans); // Initialize snapping data AFTER mode flags + if (Trans.total == 0) { postTrans(&Trans); return; @@ -940,6 +942,8 @@ void initManipulator(int mode) } Trans.flag |= T_USES_MANIPULATOR; + + Trans.tsnap.modePoint = SNAP_GRID; // Always use snap to grid with manipulators } void ManipulatorTransform() @@ -1896,6 +1900,8 @@ int Rotation(TransInfo *t, short mval[2]) if (t->con.applyRot) { t->con.applyRot(t, NULL, axis); } + + applySnapping(t, &final); if (hasNumInput(&t->num)) { char c[20]; diff --git a/source/blender/src/transform_generics.c b/source/blender/src/transform_generics.c index 1746daae7f2..bdb2075b65c 100755 --- a/source/blender/src/transform_generics.c +++ b/source/blender/src/transform_generics.c @@ -494,7 +494,6 @@ void initTrans (TransInfo *t) t->around = V3D_CENTRE; setTransformViewMatrices(t); - initSnapping(t); } /* Here I would suggest only TransInfo related issues, like free data & reset vars. Not redraws */ diff --git a/source/blender/src/transform_snap.c b/source/blender/src/transform_snap.c index 3a4bb5087a4..2ba69d8d524 100644 --- a/source/blender/src/transform_snap.c +++ b/source/blender/src/transform_snap.c @@ -75,6 +75,9 @@ void TargetSnapMedian(TransInfo *t); void TargetSnapCenter(TransInfo *t); void TargetSnapClosest(TransInfo *t); +float RotationBetween(TransInfo *t, float p1[3], float p2[3]); +float TranslationBetween(TransInfo *t, float p1[3], float p2[3]); + /****************** IMPLEMENTATIONS *********************/ void drawSnapping(TransInfo *t) @@ -139,6 +142,8 @@ void applySnapping(TransInfo *t, float *vec) void resetSnapping(TransInfo *t) { t->tsnap.status = 0; + t->tsnap.modePoint = 0; + t->tsnap.modeTarget = 0; t->tsnap.last = 0; t->tsnap.applySnap = NULL; } @@ -150,51 +155,63 @@ void initSnapping(TransInfo *t) if (t->tsnap.applySnap != NULL && // A snapping function actually exist (G.obedit != NULL && G.obedit->type==OB_MESH) && // Temporary limited to edit mode meshes - (t->spacetype==SPACE_VIEW3D) && // Only 3D view (not UV) + (t->spacetype == SPACE_VIEW3D) && // Only 3D view (not UV) (G.vd->flag2 & V3D_TRANSFORM_SNAP) && // Only if the snap flag is on (t->flag & T_PROP_EDIT) == 0) // No PET, obviously { t->tsnap.status |= SNAP_ON; - t->tsnap.mode = SNAP_GEO; + t->tsnap.modePoint = SNAP_GEO; } else { - t->tsnap.mode = SNAP_GRID; + t->tsnap.modePoint = SNAP_GRID; } } void setSnappingCallback(TransInfo *t) { - switch (t->mode) - { - case TFM_TRANSLATION: - t->tsnap.applySnap = ApplySnapTranslation; - t->tsnap.calcSnap = CalcSnapGeometry; - break; - case TFM_ROTATION: - t->tsnap.applySnap = NULL; - break; - case TFM_RESIZE: - t->tsnap.applySnap = NULL; - break; - default: - t->tsnap.applySnap = NULL; - break; - } + t->tsnap.calcSnap = CalcSnapGeometry; + switch(G.vd->flag2 & V3D_SNAP_TARGET) { case V3D_SNAP_TARGET_CLOSEST: + t->tsnap.modeTarget = SNAP_CLOSEST; t->tsnap.targetSnap = TargetSnapClosest; break; case V3D_SNAP_TARGET_CENTER: + t->tsnap.modeTarget = SNAP_CENTER; t->tsnap.targetSnap = TargetSnapCenter; break; case V3D_SNAP_TARGET_MEDIAN: + t->tsnap.modeTarget = SNAP_MEDIAN; t->tsnap.targetSnap = TargetSnapMedian; break; } + switch (t->mode) + { + case TFM_TRANSLATION: + t->tsnap.applySnap = ApplySnapTranslation; + t->tsnap.distance = TranslationBetween; + break; + case TFM_ROTATION: + t->tsnap.applySnap = ApplySnapRotation; + t->tsnap.distance = RotationBetween; + + // Can't do TARGET_CENTER with rotation, use TARGET_MEDIAN instead + if ((G.vd->flag2 & V3D_SNAP_TARGET) == V3D_SNAP_TARGET_CENTER) { + t->tsnap.modeTarget = SNAP_MEDIAN; + t->tsnap.targetSnap = TargetSnapMedian; + } + break; + case TFM_RESIZE: + t->tsnap.applySnap = NULL; + break; + default: + t->tsnap.applySnap = NULL; + break; + } } /********************** APPLY **************************/ @@ -204,9 +221,78 @@ void ApplySnapTranslation(TransInfo *t, float vec[3]) VecSubf(vec, t->tsnap.snapPoint, t->tsnap.snapTarget); } -void ApplySnapRotation(TransInfo *t, float vec[3]) +void ApplySnapRotation(TransInfo *t, float *vec) +{ + if (t->tsnap.modeTarget == SNAP_CLOSEST) { + *vec = t->tsnap.dist; + } + else { + *vec = RotationBetween(t, t->tsnap.snapTarget, t->tsnap.snapPoint); + } +} + + +/********************** DISTANCE **************************/ + +float TranslationBetween(TransInfo *t, float p1[3], float p2[3]) +{ + return VecLenf(p1, p2); +} + +float RotationBetween(TransInfo *t, float p1[3], float p2[3]) { - // FOO + float angle, start[3], end[3], center[3]; + + VECCOPY(center, t->center); + if(t->flag & (T_EDIT|T_POSE)) { + Object *ob= G.obedit?G.obedit:t->poseobj; + Mat4MulVecfl(ob->obmat, center); + } + + VecSubf(start, p1, center); + VecSubf(end, p2, center); + + // Angle around a constraint axis (error prone, will need debug) + if (t->con.applyRot != NULL && (t->con.mode & CON_APPLY)) { + float axis[3], tmp[3]; + + t->con.applyRot(t, NULL, axis); + + Projf(tmp, end, axis); + VecSubf(end, end, tmp); + + Projf(tmp, start, axis); + VecSubf(start, start, tmp); + + Normalise(end); + Normalise(start); + + Crossf(tmp, start, end); + + if (Inpf(tmp, axis) < 0.0) + angle = -acos(Inpf(start, end)); + else + angle = acos(Inpf(start, end)); + } + else { + float mtx[3][3]; + + Mat3CpyMat4(mtx, t->viewinv); + + Mat3MulVecfl(mtx, end); + Mat3MulVecfl(mtx, start); + + angle = atan2(end[1],end[0]) - atan2(start[1],start[0]); + } + + if (angle > M_PI) { + angle = 2 * M_PI - angle; + } + else if (angle < -(M_PI)) { + angle = 2 * M_PI + angle; + } + + return angle; } /********************** CALC **************************/ @@ -319,7 +405,6 @@ void TargetSnapClosest(TransInfo *t) if (t->tsnap.status & POINT_INIT) { TransData *closest = NULL, *td = NULL; - float closestDist = 0; // Base case, only one selected item if (t->total == 1) @@ -329,40 +414,25 @@ void TargetSnapClosest(TransInfo *t) // More than one selected item else { - float point[3]; - - VECCOPY(point, t->tsnap.snapPoint); - - if(t->flag & (T_EDIT|T_POSE)) { - Object *ob= G.obedit?G.obedit:t->poseobj; - float imat[4][4]; - Mat4Invert(imat, ob->obmat); - Mat4MulVecfl(imat, point); - } - for (td = t->data; td != NULL && td->flag & TD_SELECTED ; td++) { - float vdist[3]; + float loc[3]; float dist; - VecSubf(vdist, td->iloc, point); - dist = Inpf(vdist, vdist); + VECCOPY(loc, td->iloc); + Mat4MulVecfl(G.obedit->obmat, loc); + + dist = t->tsnap.distance(t, td->iloc, t->tsnap.snapPoint); - if (closest == NULL || dist < closestDist) + if (closest == NULL || fabs(dist) < fabs(t->tsnap.dist)) { + VECCOPY(t->tsnap.snapTarget, loc); closest = td; - closestDist = dist; + t->tsnap.dist = dist; } } } - VECCOPY(t->tsnap.snapTarget, closest->iloc); - - if(t->flag & (T_EDIT|T_POSE)) { - Object *ob= G.obedit?G.obedit:t->poseobj; - Mat4MulVecfl(ob->obmat, t->tsnap.snapTarget); - } - t->tsnap.status |= TARGET_INIT; } } @@ -388,7 +458,7 @@ void snapGrid(TransInfo *t, float *val) { GearsType action; // Only do something if using Snap to Grid - if ((t->tsnap.mode & SNAP_GRID) == 0) + if (t->tsnap.modePoint != SNAP_GRID) return; if(t->mode==TFM_ROTATION || t->mode==TFM_WARP || t->mode==TFM_TILT || t->mode==TFM_TRACKBALL || t->mode==TFM_BONE_ROLL) |