123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566 |
- /*
- * Ken Shoemake's Quaternion rotation controller
- */
- #include <u.h>
- #include <libc.h>
- #include <draw.h>
- #include <stdio.h>
- #include <event.h>
- #include <geometry.h>
- #define BORDER 4
- static Point ctlcen; /* center of qball */
- static int ctlrad; /* radius of qball */
- static Quaternion *axis; /* constraint plane orientation, 0 if none */
- /*
- * Convert a mouse point into a unit quaternion, flattening if
- * constrained to a particular plane.
- */
- static Quaternion mouseq(Point p){
- double qx=(double)(p.x-ctlcen.x)/ctlrad;
- double qy=(double)(p.y-ctlcen.y)/ctlrad;
- double rsq=qx*qx+qy*qy;
- double l;
- Quaternion q;
- if(rsq>1){
- rsq=sqrt(rsq);
- q.r=0.;
- q.i=qx/rsq;
- q.j=qy/rsq;
- q.k=0.;
- }
- else{
- q.r=0.;
- q.i=qx;
- q.j=qy;
- q.k=sqrt(1.-rsq);
- }
- if(axis){
- l=q.i*axis->i+q.j*axis->j+q.k*axis->k;
- q.i-=l*axis->i;
- q.j-=l*axis->j;
- q.k-=l*axis->k;
- l=sqrt(q.i*q.i+q.j*q.j+q.k*q.k);
- if(l!=0.){
- q.i/=l;
- q.j/=l;
- q.k/=l;
- }
- }
- return q;
- }
- void qball(Rectangle r, Mouse *m, Quaternion *result, void (*redraw)(void), Quaternion *ap){
- Quaternion q, down;
- Point rad;
- axis=ap;
- ctlcen=divpt(addpt(r.min, r.max), 2);
- rad=divpt(subpt(r.max, r.min), 2);
- ctlrad=(rad.x<rad.y?rad.x:rad.y)-BORDER;
- down=qinv(mouseq(m->xy));
- q=*result;
- for(;;){
- *m=emouse();
- if(!m->buttons) break;
- *result=qmul(q, qmul(down, mouseq(m->xy)));
- (*redraw)();
- }
- }
|