qball.c (1374B)
1 /* 2 * Ken Shoemake's Quaternion rotation controller 3 */ 4 #include <u.h> 5 #include <libc.h> 6 #include <draw.h> 7 #include <stdio.h> 8 #include <event.h> 9 #include <geometry.h> 10 #define BORDER 4 11 static Point ctlcen; /* center of qball */ 12 static int ctlrad; /* radius of qball */ 13 static Quaternion *axis; /* constraint plane orientation, 0 if none */ 14 /* 15 * Convert a mouse point into a unit quaternion, flattening if 16 * constrained to a particular plane. 17 */ 18 static Quaternion mouseq(Point p){ 19 double qx=(double)(p.x-ctlcen.x)/ctlrad; 20 double qy=(double)(p.y-ctlcen.y)/ctlrad; 21 double rsq=qx*qx+qy*qy; 22 double l; 23 Quaternion q; 24 if(rsq>1){ 25 rsq=sqrt(rsq); 26 q.r=0.; 27 q.i=qx/rsq; 28 q.j=qy/rsq; 29 q.k=0.; 30 } 31 else{ 32 q.r=0.; 33 q.i=qx; 34 q.j=qy; 35 q.k=sqrt(1.-rsq); 36 } 37 if(axis){ 38 l=q.i*axis->i+q.j*axis->j+q.k*axis->k; 39 q.i-=l*axis->i; 40 q.j-=l*axis->j; 41 q.k-=l*axis->k; 42 l=sqrt(q.i*q.i+q.j*q.j+q.k*q.k); 43 if(l!=0.){ 44 q.i/=l; 45 q.j/=l; 46 q.k/=l; 47 } 48 } 49 return q; 50 } 51 void qball(Rectangle r, Mouse *m, Quaternion *result, void (*redraw)(void), Quaternion *ap){ 52 Quaternion q, down; 53 Point rad; 54 axis=ap; 55 ctlcen=divpt(addpt(r.min, r.max), 2); 56 rad=divpt(subpt(r.max, r.min), 2); 57 ctlrad=(rad.x<rad.y?rad.x:rad.y)-BORDER; 58 down=qinv(mouseq(m->xy)); 59 q=*result; 60 for(;;){ 61 *m=emouse(); 62 if(!m->buttons) break; 63 *result=qmul(q, qmul(down, mouseq(m->xy))); 64 (*redraw)(); 65 } 66 }