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