=== Transform Snap ===

Snapping for object mode

Changes:
- Transform snap now working in object mode and not just mesh edit mode
- Shift-Tab can be used to toggle snap on/off inside transform too (no more Esc,toggle,restart)
- Object mode snap: Closest uses the bounding box corners of all selected objects, Median uses object center and Center uses transform center (same as edit mode).
- Object mode snap: all visible meshes can be used to get the snapping point (unlike edit mode snap which is limited to selected mesh: this might be adjusted to make edit mode snap use all visible too).

To Do:
- Add "Active" snap target method: use active object (or mesh element) as snap target
- Add snapping capabilities to Scale
- (Maybe) Add "Near pointer" snap target method: use selected element that is closest to mouse pointer as snap target. Active could probably accomplish that already in a less confusing manner, so I might skip this.
This commit is contained in:
2008-01-13 22:20:18 +00:00
parent d660e29365
commit e4e66c9aa4
6 changed files with 94 additions and 28 deletions

View File

@@ -90,6 +90,8 @@ void BIF_setDualAxisConstraint(float vec1[3], float vec2[3], char *text);
void BIF_setLocalAxisConstraint(char axis, char *text);
void BIF_setLocalLockConstraint(char axis, char *text);
int BIF_snappingSupported(void);
struct TransformOrientation;
void BIF_clearTransformOrientation(void);

View File

@@ -122,7 +122,7 @@ typedef struct TransDataExtension {
float iquat[4]; /* Initial rotation quaternion */
float *size; /* Size of the data to transform (Faculative) */
float isize[3]; /* Initial size */
float obmat[3][3]; /* Object matrix */
float obmat[4][4]; /* Object matrix */
} TransDataExtension;
typedef struct TransData2D {

View File

@@ -1818,7 +1818,7 @@ static uiBlock *view3d_transformmenu(void *arg_unused)
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Center Cursor", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 12, "");
}
if (G.obedit != NULL && G.obedit->type==OB_MESH)
if (BIF_snappingSupported())
{
uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
@@ -5476,7 +5476,7 @@ void view3d_buttons(void)
}
/* Snap */
if(G.obedit && (G.obedit->type == OB_MESH)) { // Only Mesh for now
if (BIF_snappingSupported()) {
uiBlockBeginAlign(block);
if (G.scene->snap_flag & SCE_SNAP) {

View File

@@ -1570,8 +1570,8 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
/* Shift-Tabe handling (other cases are in toets) */
if (G.qual == LR_SHIFTKEY)
{
/* Snap toggle (only edit mesh right now) */
if (G.obedit && G.obedit->type==OB_MESH)
/* Snap toggle only when supported */
if (BIF_snappingSupported())
{
G.scene->snap_flag ^= SCE_SNAP;
allqueue(REDRAWHEADERS, 0);

View File

@@ -2861,6 +2861,8 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob)
VECCOPY(td->ext->dsize, ob->dsize);
VECCOPY(td->center, ob->obmat[3]);
Mat4CpyMat4(td->ext->obmat, ob->obmat);
/* is there a need to set the global<->data space conversion matrices? */
if (ob->parent || constinv) {

View File

@@ -90,10 +90,22 @@ float RotationBetween(TransInfo *t, float p1[3], float p2[3]);
float TranslationBetween(TransInfo *t, float p1[3], float p2[3]);
// Trickery
int findNearestVertFromObjects(int *dist, float *loc);
int findNearestVertFromObjects(int *dist, float *loc, int selected);
/****************** IMPLEMENTATIONS *********************/
int BIF_snappingSupported(void)
{
int status = 0;
if (G.obedit == NULL || G.obedit->type==OB_MESH) /* only support object or mesh */
{
status = 1;
}
return status;
}
void drawSnapping(TransInfo *t)
{
if ((t->tsnap.status & (SNAP_ON|POINT_INIT|TARGET_INIT)) == (SNAP_ON|POINT_INIT|TARGET_INIT) &&
@@ -168,7 +180,13 @@ int handleSnapping(TransInfo *t, int event)
{
int status = 0;
// Put keyhandling code here
if (BIF_snappingSupported() && event == TABKEY && (G.qual & LR_SHIFTKEY) == LR_SHIFTKEY)
{
/* toggle snap and reinit */
G.scene->snap_flag ^= SCE_SNAP;
initSnapping(t);
status = 1;
}
return status;
}
@@ -211,10 +229,19 @@ void initSnapping(TransInfo *t)
if (t->spacetype == SPACE_VIEW3D || t->spacetype == SPACE_IMAGE) { // Only 3D view or UV
setSnappingCallback(t);
/* Edit mode */
if (t->tsnap.applySnap != NULL && // A snapping function actually exist
(G.obedit != NULL && G.obedit->type==OB_MESH) && // Temporary limited to edit mode meshes
(G.scene->snap_flag & SCE_SNAP) && // Only if the snap flag is on
(t->flag & T_PROP_EDIT) == 0) // No PET, obviously
(G.obedit != NULL && G.obedit->type==OB_MESH) && // Temporary limited to edit mode meshes
((t->flag & T_PROP_EDIT) == 0) ) // No PET, obviously
{
t->tsnap.status |= SNAP_ON;
t->tsnap.modePoint = SNAP_GEO;
}
/* Object mode */
else if (t->tsnap.applySnap != NULL && // A snapping function actually exist
(G.scene->snap_flag & SCE_SNAP) && // Only if the snap flag is on
(G.obedit == NULL) ) // Object Mode
{
t->tsnap.status |= SNAP_ON;
t->tsnap.modePoint = SNAP_GEO;
@@ -364,7 +391,28 @@ void CalcSnapGrid(TransInfo *t, float *vec)
void CalcSnapGeometry(TransInfo *t, float *vec)
{
if (G.obedit != NULL && G.obedit->type==OB_MESH)
if (G.obedit == NULL)
{
if (t->spacetype == SPACE_VIEW3D)
{
float vec[3];
int found = 0;
int dist = 40; // Use a user defined value here
found = findNearestVertFromObjects(&dist, vec, 0);
if (found == 1)
{
VECCOPY(t->tsnap.snapPoint, vec);
t->tsnap.status |= POINT_INIT;
}
else
{
t->tsnap.status &= ~POINT_INIT;
}
}
}
else if (G.obedit != NULL && G.obedit->type==OB_MESH)
{
/*if (G.scene->selectmode & B_SEL_VERT)*/
@@ -378,7 +426,7 @@ void CalcSnapGeometry(TransInfo *t, float *vec)
// use findnearestverts in vert mode, others in other modes
nearest = findnearestvert(&dist, SELECT, 1);
found = findNearestVertFromObjects(&dist, vec);
found = findNearestVertFromObjects(&dist, vec, SELECT);
if (found == 1)
{
VECCOPY(t->tsnap.snapPoint, vec);
@@ -479,7 +527,7 @@ void TargetSnapMedian(TransInfo *t)
for(td = t->data, i = 0 ; i < t->total && td->flag & TD_SELECTED ; i++, td++)
{
VecAddf(t->tsnap.snapTarget, t->tsnap.snapTarget, td->iloc);
VecAddf(t->tsnap.snapTarget, t->tsnap.snapTarget, td->center);
}
VecMulf(t->tsnap.snapTarget, 1.0 / t->total);
@@ -500,28 +548,42 @@ void TargetSnapClosest(TransInfo *t)
{
TransData *closest = NULL, *td = NULL;
// Base case, only one selected item
if (t->total == 1)
/* Object mode */
if (t->flag & T_OBJECT)
{
VECCOPY(t->tsnap.snapTarget, t->data[0].iloc);
if(t->flag & (T_EDIT|T_POSE)) {
Object *ob= G.obedit?G.obedit:t->poseobj;
Mat4MulVecfl(ob->obmat, t->tsnap.snapTarget);
}
t->tsnap.dist = t->tsnap.distance(t, t->tsnap.snapTarget, t->tsnap.snapPoint);
}
// More than one selected item
else
int i;
for(td = t->data, i = 0 ; i < t->total && td->flag & TD_SELECTED ; i++, td++)
{
struct BoundBox *bb = object_get_boundbox(td->ob);
int j;
for (j = 0; j < 8; j++) {
float loc[3];
float dist;
VECCOPY(loc, bb->vec[j]);
Mat4MulVecfl(td->ext->obmat, loc);
dist = t->tsnap.distance(t, loc, t->tsnap.snapPoint);
if (closest == NULL || fabs(dist) < fabs(t->tsnap.dist))
{
VECCOPY(t->tsnap.snapTarget, loc);
closest = td;
t->tsnap.dist = dist;
}
}
}
}
else
{
int i;
for(td = t->data, i = 0 ; i < t->total && td->flag & TD_SELECTED ; i++, td++)
{
float loc[3];
float dist;
VECCOPY(loc, td->iloc);
VECCOPY(loc, td->center);
if(t->flag & (T_EDIT|T_POSE)) {
Object *ob= G.obedit?G.obedit:t->poseobj;
@@ -544,7 +606,7 @@ void TargetSnapClosest(TransInfo *t)
}
/*================================================================*/
int findNearestVertFromObjects(int *dist, float *loc) {
int findNearestVertFromObjects(int *dist, float *loc, int selected) {
Base *base;
int retval = 0;
short mval[2];
@@ -553,7 +615,7 @@ int findNearestVertFromObjects(int *dist, float *loc) {
base= FIRSTBASE;
for ( base = FIRSTBASE; base != NULL; base = base->next ) {
if ( TESTBASE(base) && base != BASACT ) {
if ( base != BASACT && BASE_SELECTABLE(base) && (base->flag & SELECT) == selected ) {
Object *ob = base->object;
if (ob->type == OB_MESH) {