mirror of
https://github.com/9fans/plan9port.git
synced 2025-01-15 11:20:03 +00:00
66 lines
1.3 KiB
C
66 lines
1.3 KiB
C
/*
|
|
* 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)();
|
|
}
|
|
}
|