=== 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)
This commit is contained in:
2006-12-23 00:52:34 +00:00
parent 48b62511bf
commit 1ad1522d10
4 changed files with 141 additions and 58 deletions

View File

@@ -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);

View File

@@ -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];

View File

@@ -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 */

View File

@@ -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,29 +155,55 @@ 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)
{
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.calcSnap = CalcSnapGeometry;
t->tsnap.distance = TranslationBetween;
break;
case TFM_ROTATION:
t->tsnap.applySnap = NULL;
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;
@@ -181,20 +212,6 @@ void setSnappingCallback(TransInfo *t)
t->tsnap.applySnap = NULL;
break;
}
switch(G.vd->flag2 & V3D_SNAP_TARGET)
{
case V3D_SNAP_TARGET_CLOSEST:
t->tsnap.targetSnap = TargetSnapClosest;
break;
case V3D_SNAP_TARGET_CENTER:
t->tsnap.targetSnap = TargetSnapCenter;
break;
case V3D_SNAP_TARGET_MEDIAN:
t->tsnap.targetSnap = TargetSnapMedian;
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)
{
// FOO
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])
{
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);
if (closest == NULL || dist < closestDist)
dist = t->tsnap.distance(t, td->iloc, t->tsnap.snapPoint);
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)