From: Ian Jackson Date: Mon, 31 Dec 2007 17:03:41 +0000 (+0000) Subject: better rotations X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=moebius2.git;a=commitdiff_plain;h=82fc0fa604179b3c5627dcd652010270a114476f better rotations --- diff --git a/common.h b/common.h index cb45e81..ebc34d1 100644 --- a/common.h +++ b/common.h @@ -50,6 +50,9 @@ void gsldie(int l, const char *what, int status); #define GSL_VECTOR(x) gsl_vector x##_gsl= { D3,1,&x[0] }; #define GSL_MATRIX(x) gsl_matrix x##_gsl= { D3,D3,D3,&x[0][0] }; +#define MIN(a,b) ((a) <= (b) ? (a) : (b)) +#define MAX(a,b) ((a) >= (b) ? (a) : (b)) + #ifdef FP_FAST_FMA # define fma_fast fma #else diff --git a/view.c b/view.c index 712623c..e269e25 100644 --- a/view.c +++ b/view.c @@ -249,7 +249,7 @@ static void show(void) { typedef struct { const char *name; - void (*start)(void); + void (*start)(const XButtonEvent *e); void (*delta)(double dx, double dy); void (*conclude)(void); void (*abandon)(void); @@ -261,10 +261,11 @@ typedef struct { drag_##x##_conclude, drag_##x##_abandon \ } -#define DRAG_SAVING(x, thing) \ +#define DRAG_SAVING(x, thing, hook) \ static typeof(thing) original_##thing; \ - static void drag_##x##_start(void) { \ + static void drag_##x##_start(const XButtonEvent *e) { \ memcpy(&original_##thing, &thing, sizeof(thing)); \ + hook; \ } \ static void drag_##x##_conclude(void) { } \ static void drag_##x##_abandon(void) { \ @@ -273,7 +274,7 @@ typedef struct { } \ DRAG(x) -static void drag_none_start(void) { } +static void drag_none_start(const XButtonEvent *e) { } static void drag_none_delta(double dx, double dy) { } static void drag_none_conclude(void) { } static void drag_none_abandon(void) { } @@ -296,6 +297,25 @@ static void pmatrix(const char *n, double m[D3][D3]) { } #define PMATRIX(x) pmatrix(#x,x); +static double drag_transform_conv_x_z= 0; +static double drag_transform_conv_y_z= 0; + +static void drag_transform_prep(const XButtonEvent *e) { + static const double factor= 2.5; + drag_transform_conv_x_z= MAX( MIN(e->y * factor / wheight - (factor/2), + 1.0), -1.0); + drag_transform_conv_y_z= MAX( MIN(e->x * factor / wwidth - (factor/2), + 1.0), -1.0); + printf("drag_transform_conv_{x,y}_z = %g,%g\n", + drag_transform_conv_x_z, drag_transform_conv_y_z); +} + +static void make_z_rotation(double rotz[D3][D3], double cz, double sz) { + rotz[0][0]= cz; rotz[0][1]= sz; rotz[0][2]= 0; + rotz[1][0]= -sz; rotz[1][1]= cz; rotz[1][2]= 0; + rotz[2][0]= 0; rotz[2][1]= 0; rotz[2][2]= 1; +} + static void drag_rotate_delta(double dx, double dy) { /* We multiple our transformation matrix by a matrix: * @@ -310,31 +330,56 @@ static void drag_rotate_delta(double dx, double dy) { * we make cy and sy be cos() and sin(hypot(x,y)) and use * with cr,sr as cos() and sin(atan2(y,y)): * - * Ie we would do T' = R^T X R T where - * or T' = C T where C = R^T X R and + * Ie we would do T' = Z R^T X R T where + * or T' = Z C T where C = R^T X R and * * adjustment R = [ cr sr 0 ] * [ -sr cr 0 ] - * [ 0 0 1 ] + * [ 0 0 1 ] or make_z_rotation(cr,sr) + * + * rotation Z = [ cz sz 0 ] + * [ -sz cz 0 ] + * [ 0 0 1 ] or make_z_rotation(cz,sz) */ - double rotx[D3][D3], adjr[D3][D3]; + double rotx[D3][D3], adjr[D3][D3], rotz[D3][D3]; GSL_MATRIX(rotx); GSL_MATRIX(adjr); + GSL_MATRIX(rotz); static double temp[D3][D3], change[D3][D3]; static GSL_MATRIX(temp); static GSL_MATRIX(change); + printf("\nTRANSFORM %g, %g\n", dx,dy); + + double dz= -drag_transform_conv_x_z * dx + + drag_transform_conv_y_z * dy; + + dx *= (1 - fabs(drag_transform_conv_x_z)); + dy *= (1 - fabs(drag_transform_conv_y_z)); + double d= hypot(dx,dy); - if (d < 1e-6) return; + + printf(" dx,dy,dz = %g, %g, %g d = %g\n", dx,dy,dz, d); + + if (hypot(d,dz) < 1e-6) return; + + printf(" no xy rotation\n"); double ang= d*2.0; double cy= cos(ang); double sy= sin(ang); - double cr= -dy / d; - double sr= dx / d; + + double cr, sr; + if (d > 1e-6) { + cr= -dy / d; + sr= dx / d; + } else { + cr= 1; + sr= 0; + } printf("\n d=%g cy,sy=%g,%g cr,sr=%g,%g\n\n", d,cy,sy,cr,sr); rotx[0][0]= 1; rotx[0][1]= 0; rotx[0][2]= 0; @@ -342,26 +387,33 @@ static void drag_rotate_delta(double dx, double dy) { rotx[2][0]= 0; rotx[2][1]= -sy; rotx[2][2]= cy; PMATRIX(rotx); - adjr[0][0]= cr; adjr[0][1]= sr; adjr[0][2]= 0; - adjr[1][0]= -sr; adjr[1][1]= cr; adjr[1][2]= 0; - adjr[2][0]= 0; adjr[2][1]= 0; adjr[2][2]= 1; + make_z_rotation(adjr,cr,sr); PMATRIX(adjr); GA( gsl_blas_dgemm(CblasNoTrans,CblasNoTrans, 1.0, &rotx_gsl,&adjr_gsl, 0.0, &temp_gsl) ); - PMATRIX(temp); + pmatrix("X R", temp); GA( gsl_blas_dgemm(CblasTrans,CblasNoTrans, 1.0, &adjr_gsl,&temp_gsl, 0.0, &change_gsl) ); PMATRIX(change); + double angz= dz*2.0; + make_z_rotation(rotz,cos(angz),sin(angz)); + PMATRIX(rotz); + + GA( gsl_blas_dgemm(CblasTrans,CblasNoTrans, 1.0, + &rotz_gsl,&change_gsl, + 0.0, &temp_gsl) ); + pmatrix("Z C", temp); + static double skew[D3][D3]; static GSL_MATRIX(skew); GA( gsl_blas_dgemm(CblasNoTrans,CblasNoTrans, 1.0, - &change_gsl,&transform_gsl, + &temp_gsl, &transform_gsl, 0.0, &skew_gsl) ); PMATRIX(skew); @@ -403,13 +455,13 @@ static void drag_rotate_delta(double dx, double dy) { printf("drag_rotate_delta...\n"); show(); } -DRAG_SAVING(rotate, transform); +DRAG_SAVING(rotate, transform, drag_transform_prep(e)); static void drag_sizeadj_delta(double dx, double dy) { sizeadj_scale *= pow(3.0, -dy); show(); } -DRAG_SAVING(sizeadj, sizeadj_scale); +DRAG_SAVING(sizeadj, sizeadj_scale, ); static void drag_3d_delta(double dx, double dy) { eyes_apart += dx * 0.1; @@ -417,7 +469,7 @@ static void drag_3d_delta(double dx, double dy) { printf("sizeadj eyes_apart %g\n", eyes_apart); show(); } -DRAG_SAVING(3d, eyes_apart); +DRAG_SAVING(3d, eyes_apart, ); static const Drag *drag= &drag_none; @@ -450,7 +502,7 @@ static void event_button(XButtonEvent *e) { drag->name, (unsigned long)e->button, e->x, e->y); drag_last_x= e->x; drag_last_y= e->y; - drag->start(); + drag->start(e); } if (e->type == ButtonRelease) { printf("drag=%s release %d,%d\n", drag->name, e->x, e->y);