View3D: remove orbit snapping LUT, allow to snap axis but not roll

This commit is contained in:
Campbell Barton
2014-03-20 15:19:02 +11:00
parent c6252d6e60
commit e5f1c0bd63
3 changed files with 131 additions and 142 deletions

View File

@@ -311,6 +311,7 @@ struct Base *ED_view3d_give_base_under_cursor(struct bContext *C, const int mval
void ED_view3d_quadview_update(struct ScrArea *sa, struct ARegion *ar, bool do_clip);
void ED_view3d_update_viewmat(struct Scene *scene, struct View3D *v3d, struct ARegion *ar, float viewmat[4][4], float winmat[4][4]);
bool ED_view3d_quat_from_axis_view(const char view, float quat[4]);
char ED_view3d_quat_to_axis_view(const float quat[4], const float epsilon);
char ED_view3d_lock_view_from_index(int index);
bool ED_view3d_lock(struct RegionView3D *rv3d);

View File

@@ -695,56 +695,6 @@ static void viewops_data_free(bContext *C, wmOperator *op)
/* ************************** viewrotate **********************************/
#define COS45 0.7071068
#define SIN45 COS45
#define NUM_SNAP_QUATS 39
static const float snapquats[NUM_SNAP_QUATS][5] = {
/*{q0, q1, q3, q4, view}*/
{COS45, -SIN45, 0.0, 0.0, RV3D_VIEW_FRONT},
{0.0, 0.0, -SIN45, -SIN45, RV3D_VIEW_BACK},
{1.0, 0.0, 0.0, 0.0, RV3D_VIEW_TOP},
{0.0, -1.0, 0.0, 0.0, RV3D_VIEW_BOTTOM},
{0.5, -0.5, -0.5, -0.5, RV3D_VIEW_RIGHT},
{0.5, -0.5, 0.5, 0.5, RV3D_VIEW_LEFT},
/* some more 45 deg snaps */
{ 0.6532815, -0.6532815, 0.2705981, 0.2705981, 0},
{ 0.9238795, 0.0, 0.0, 0.3826834, 0},
{ 0.0, -0.9238795, 0.3826834, 0.0, 0},
{ 0.3535534, -0.8535534, 0.3535534, 0.1464466, 0},
{ 0.8535534, -0.3535534, 0.1464466, 0.3535534, 0},
{ 0.4999999, -0.4999999, 0.5, 0.5, 0},
{ 0.2705980, -0.6532815, 0.6532815, 0.2705980, 0},
{ 0.6532815, -0.2705980, 0.2705980, 0.6532815, 0},
{ 0.2705978, -0.2705980, 0.6532814, 0.6532814, 0},
{ 0.3826834, 0.0, 0.0, 0.9238794, 0},
{ 0.0, -0.3826834, 0.9238794, 0.0, 0},
{ 0.1464466, -0.3535534, 0.8535534, 0.3535534, 0},
{ 0.3535534, -0.1464466, 0.3535534, 0.8535534, 0},
{ 0.0, 0.0, 0.9238794, 0.3826834, 0},
{-0.0, 0.0, 0.3826834, 0.9238794, 0},
{-0.2705980, 0.2705980, 0.6532813, 0.6532813, 0},
{-0.3826834, 0.0, 0.0, 0.9238794, 0},
{ 0.0, 0.3826834, 0.9238794, 0.0, 0},
{-0.1464466, 0.3535534, 0.8535533, 0.3535533, 0},
{-0.3535534, 0.1464466, 0.3535533, 0.8535533, 0},
{-0.4999999, 0.4999999, 0.4999999, 0.4999999, 0},
{-0.2705980, 0.6532815, 0.6532814, 0.2705980, 0},
{-0.6532815, 0.2705980, 0.2705980, 0.6532814, 0},
{-0.6532813, 0.6532813, 0.2705979, 0.2705979, 0},
{-0.9238793, 0.0, 0.0, 0.3826833, 0},
{ 0.0, 0.9238793, 0.3826833, 0.0, 0},
{-0.3535533, 0.8535533, 0.3535533, 0.1464466, 0},
{-0.8535533, 0.3535533, 0.1464466, 0.3535533, 0},
{-0.3826833, 0.9238794, 0.0, 0.0, 0},
{-0.9238794, 0.3826833, 0.0, 0.0, 0},
{-COS45, 0.0, 0.0, SIN45, 0},
{ COS45, 0.0, 0.0, SIN45, 0},
{ 0.0, 0.0, 0.0, 1.0, 0}
};
enum {
VIEW_PASS = 0,
VIEW_APPLY,
@@ -818,6 +768,108 @@ static void viewrotate_apply_dyn_ofs(ViewOpsData *vod, const float viewquat[4])
}
}
static void viewrotate_apply_snap(ViewOpsData *vod)
{
const float axis_limit = DEG2RADF(45 / 3);
RegionView3D *rv3d = vod->rv3d;
float viewquat_inv[4];
float zaxis[3] = {0, 0, 1};
float zaxis_best[3];
int x, y, z;
bool found = false;
invert_qt_qt(viewquat_inv, vod->viewquat);
mul_qt_v3(viewquat_inv, zaxis);
normalize_v3(zaxis);
for (x = -1; x < 2; x++) {
for (y = -1; y < 2; y++) {
for (z = -1; z < 2; z++) {
if (x || y || z) {
float zaxis_test[3] = {x, y, z};
normalize_v3(zaxis_test);
if (angle_normalized_v3v3(zaxis_test, zaxis) < axis_limit) {
copy_v3_v3(zaxis_best, zaxis_test);
found = true;
}
}
}
}
}
if (found) {
/* find the best roll */
float quat_roll[4], quat_final[4], quat_best[4], quat_snap[4];
float viewquat_align[4]; /* viewquat aligned to zaxis_best */
float viewquat_align_inv[4]; /* viewquat aligned to zaxis_best */
float best_angle = axis_limit;
int j;
/* viewquat_align is the original viewquat aligned to the snapped axis
* for testing roll */
rotation_between_vecs_to_quat(viewquat_align, zaxis_best, zaxis);
normalize_qt(viewquat_align);
mul_qt_qtqt(viewquat_align, vod->viewquat, viewquat_align);
normalize_qt(viewquat_align);
invert_qt_qt(viewquat_align_inv, viewquat_align);
vec_to_quat(quat_snap, zaxis_best, OB_NEGZ, OB_POSY);
invert_qt(quat_snap);
normalize_qt(quat_snap);
/* check if we can find the roll */
found = false;
/* find best roll */
for (j = 0; j < 8; j++) {
float angle;
float xaxis1[3] = {1, 0, 0};
float xaxis2[3] = {1, 0, 0};
float quat_final_inv[4];
axis_angle_to_quat(quat_roll, zaxis_best, (float)j * DEG2RADF(45.0f));
normalize_qt(quat_roll);
mul_qt_qtqt(quat_final, quat_snap, quat_roll);
normalize_qt(quat_final);
/* compare 2 vector angles to find the least roll */
invert_qt_qt(quat_final_inv, quat_final);
mul_qt_v3(viewquat_align_inv, xaxis1);
mul_qt_v3(quat_final_inv, xaxis2);
angle = angle_v3v3(xaxis1, xaxis2);
if (angle <= best_angle) {
found = true;
best_angle = angle;
copy_qt_qt(quat_best, quat_final);
}
}
if (found) {
/* lock 'quat_best' to an axis view if we can */
rv3d->view = ED_view3d_quat_to_axis_view(quat_best, 0.01f);
if (rv3d->view != RV3D_VIEW_USER) {
ED_view3d_quat_from_axis_view(rv3d->view, quat_best);
}
}
else {
copy_qt_qt(quat_best, viewquat_align);
}
copy_qt_qt(rv3d->viewquat, quat_best);
viewrotate_apply_dyn_ofs(vod, rv3d->viewquat);
}
}
static void viewrotate_apply(ViewOpsData *vod, int x, int y)
{
RegionView3D *rv3d = vod->rv3d;
@@ -916,72 +968,7 @@ static void viewrotate_apply(ViewOpsData *vod, int x, int y)
/* check for view snap,
* note: don't apply snap to vod->viewquat so the view wont jam up */
if (vod->axis_snap) {
int i;
float viewquat_inv[4];
float zaxis[3] = {0, 0, 1};
invert_qt_qt(viewquat_inv, vod->viewquat);
mul_qt_v3(viewquat_inv, zaxis);
for (i = 0; i < NUM_SNAP_QUATS; i++) {
float view = (int)snapquats[i][4];
float viewquat_inv_test[4];
float zaxis_test[3] = {0, 0, 1};
invert_qt_qt(viewquat_inv_test, snapquats[i]);
mul_qt_v3(viewquat_inv_test, zaxis_test);
if (angle_v3v3(zaxis_test, zaxis) < DEG2RADF(45 / 3)) {
/* find the best roll */
float quat_roll[4], quat_final[4], quat_best[4];
float viewquat_align[4]; /* viewquat aligned to zaxis_test */
float viewquat_align_inv[4]; /* viewquat aligned to zaxis_test */
float best_angle = FLT_MAX;
int j;
/* viewquat_align is the original viewquat aligned to the snapped axis
* for testing roll */
rotation_between_vecs_to_quat(viewquat_align, zaxis_test, zaxis);
normalize_qt(viewquat_align);
mul_qt_qtqt(viewquat_align, vod->viewquat, viewquat_align);
normalize_qt(viewquat_align);
invert_qt_qt(viewquat_align_inv, viewquat_align);
/* find best roll */
for (j = 0; j < 8; j++) {
float angle;
float xaxis1[3] = {1, 0, 0};
float xaxis2[3] = {1, 0, 0};
float quat_final_inv[4];
axis_angle_to_quat(quat_roll, zaxis_test, (float)j * DEG2RADF(45.0f));
normalize_qt(quat_roll);
mul_qt_qtqt(quat_final, snapquats[i], quat_roll);
normalize_qt(quat_final);
/* compare 2 vector angles to find the least roll */
invert_qt_qt(quat_final_inv, quat_final);
mul_qt_v3(viewquat_align_inv, xaxis1);
mul_qt_v3(quat_final_inv, xaxis2);
angle = angle_v3v3(xaxis1, xaxis2);
if (angle <= best_angle) {
best_angle = angle;
copy_qt_qt(quat_best, quat_final);
if (j) view = 0; /* view grid assumes certain up axis */
}
}
copy_qt_qt(rv3d->viewquat, quat_best);
rv3d->view = view; /* if we snap to a rolled camera the grid is invalid */
viewrotate_apply_dyn_ofs(vod, rv3d->viewquat);
break;
}
}
viewrotate_apply_snap(vod);
}
vod->oldx = x;
vod->oldy = y;

View File

@@ -831,39 +831,40 @@ static void obmat_to_viewmat(RegionView3D *rv3d, Object *ob)
mat3_to_quat(rv3d->viewquat, tmat);
}
static float view3d_quat_axis[6][4] = {
{M_SQRT1_2, -M_SQRT1_2, 0.0f, 0.0f}, /* RV3D_VIEW_FRONT */
{0.0f, 0.0f, -M_SQRT1_2, -M_SQRT1_2}, /* RV3D_VIEW_BACK */
{0.5f, -0.5f, 0.5f, 0.5f}, /* RV3D_VIEW_LEFT */
{0.5f, -0.5f, -0.5f, -0.5f}, /* RV3D_VIEW_RIGHT */
{1.0f, 0.0f, 0.0f, 0.0f}, /* RV3D_VIEW_TOP */
{0.0f, -1.0f, 0.0f, 0.0f}, /* RV3D_VIEW_BOTTOM */
};
bool ED_view3d_quat_from_axis_view(const char view, float quat[4])
{
if (RV3D_VIEW_IS_AXIS(view)) {
copy_qt_qt(quat, view3d_quat_axis[view - RV3D_VIEW_FRONT]);
return true;
}
else {
return false;
}
}
char ED_view3d_quat_to_axis_view(const float quat[4], const float epsilon)
{
/* quat values are all unit length */
switch (view) {
case RV3D_VIEW_BOTTOM:
copy_v4_fl4(quat, 0.0, -1.0, 0.0, 0.0);
break;
char view;
case RV3D_VIEW_BACK:
copy_v4_fl4(quat, 0.0, 0.0, -M_SQRT1_2, -M_SQRT1_2);
break;
case RV3D_VIEW_LEFT:
copy_v4_fl4(quat, 0.5, -0.5, 0.5, 0.5);
break;
case RV3D_VIEW_TOP:
copy_v4_fl4(quat, 1.0, 0.0, 0.0, 0.0);
break;
case RV3D_VIEW_FRONT:
copy_v4_fl4(quat, M_SQRT1_2, -M_SQRT1_2, 0.0, 0.0);
break;
case RV3D_VIEW_RIGHT:
copy_v4_fl4(quat, 0.5, -0.5, -0.5, -0.5);
break;
default:
return false;
for (view = RV3D_VIEW_FRONT; view <= RV3D_VIEW_BOTTOM; view++) {
if (angle_qtqt(quat, view3d_quat_axis[view - RV3D_VIEW_FRONT]) < epsilon) {
return view;
}
}
return true;
return RV3D_VIEW_USER;
}
char ED_view3d_lock_view_from_index(int index)