home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / plug-ins / MapObject / arcball.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-02-23  |  12.5 KB  |  529 lines

  1. /************************************/
  2. /* ArcBall.c (c) Ken Shoemake, 1993 */
  3. /* Modified by Tom Bech, 1996       */
  4. /************************************/
  5.  
  6. #include <gdk/gdk.h>
  7.  
  8. #include <libgimp/gimp.h>
  9.  
  10. #include "arcball.h"
  11.  
  12. /* Gloval variables */
  13. /* ================ */
  14.  
  15. Quat qOne = { 0, 0, 0, 1 };
  16.  
  17. static HVect         center;
  18. static double        radius;
  19. static Quat          qNow, qDown, qDrag;
  20. static HVect         vNow, vDown, vFrom, vTo, vrFrom, vrTo;
  21. static HMatrix       mNow, mDown;
  22. static unsigned int  showResult, dragging;
  23. static ConstraintSet sets[NSets];
  24. static int           setSizes[NSets];
  25. static AxisSet       axisSet;
  26. static int           axisIndex;
  27.  
  28. static HMatrix mId =
  29. {
  30.   { 1, 0, 0, 0 },
  31.   { 0, 1, 0, 0 },
  32.   { 0, 0, 1, 0 },
  33.   { 0, 0, 0, 1 }
  34. };
  35.  
  36. static double otherAxis[][4] =
  37. {
  38.   {-0.48, 0.80, 0.36, 1}
  39. };
  40.  
  41. /* Externally visible methods */
  42. /* ========================== */
  43.  
  44. void     ArcBall_Init      (void);
  45. void     ArcBall_Place     (HVect    Center,
  46.                 double   Radius);
  47. void     ArcBall_UseSet    (AxisSet  axis_Set);
  48. void     ArcBall_Update    (void);
  49. void     ArcBall_Value     (HMatrix  m_Now);
  50. void     ArcBall_Values    (double  *alpha,
  51.                 double  *beta,
  52.                 double  *gamma);
  53. void     ArcBall_BeginDrag (void);
  54. void     ArcBall_EndDrag   (void);
  55. void     ArcBall_Mouse     (HVect    v_Now);
  56. void     ArcBall_CopyMat   (HMatrix  inm,
  57.                 HMatrix  outm);
  58.  
  59. /* Internal methods */
  60. /* ================ */
  61.  
  62. static void     Qt_ToMatrix(Quat q,HMatrix out);
  63. static Quat     Qt_Conj(Quat q);
  64. static Quat     Qt_Mul(Quat qL, Quat qR);
  65. static Quat     Qt_FromBallPoints(HVect from, HVect to);
  66. static void     Qt_ToBallPoints(Quat q, HVect *arcFrom, HVect *arcTo);
  67.  
  68. static HVect    V3_(double x, double y, double z);
  69. static double   V3_Norm(HVect v);
  70. static HVect    V3_Unit(HVect v);
  71. static HVect    V3_Scale(HVect v, double s);
  72. static HVect    V3_Negate(HVect v);
  73. /*
  74. static HVect    V3_Add(HVect v1, HVect v2);
  75. */
  76. static HVect    V3_Sub(HVect v1, HVect v2);
  77. static double   V3_Dot(HVect v1, HVect v2);
  78. /*
  79. static HVect    V3_Cross(HVect v1, HVect v2);
  80. static HVect    V3_Bisect(HVect v0, HVect v1);
  81. */
  82.  
  83. static HVect    MouseOnSphere(HVect mouse, HVect ballCenter, double ballRadius);
  84. static HVect    ConstrainToAxis(HVect loose, HVect axis);
  85. static int      NearestConstraintAxis(HVect loose, HVect *axes, int nAxes);
  86.  
  87. /* Establish reasonable initial values for controller. */
  88. /* =================================================== */
  89.  
  90. void
  91. ArcBall_Init (void)
  92. {
  93.   int i;
  94.   
  95.   center = qOne;
  96.   radius = 1.0;
  97.   vDown = vNow = qOne;
  98.   qDown = qNow = qOne;
  99.   for (i=15; i>=0; i--)
  100.     ((double *)mNow)[i] = ((double *)mDown)[i] = ((double *)mId)[i];
  101.  
  102.   showResult = dragging = FALSE;
  103.   axisSet = NoAxes;
  104.   sets[CameraAxes] = mId[X];
  105.   setSizes[CameraAxes] = 3;
  106.   sets[BodyAxes] = mDown[X];
  107.   setSizes[BodyAxes] = 3;
  108.   sets[OtherAxes] = otherAxis[X];
  109.   setSizes[OtherAxes] = 1;
  110. }
  111.  
  112. /* Set the center and size of the controller. */
  113. /* ========================================== */
  114.  
  115. void
  116. ArcBall_Place (HVect  Center,
  117.            double Radius)
  118. {
  119.   center = Center;
  120.   radius = Radius;
  121. }
  122.  
  123. /* Incorporate new mouse position. */
  124. /* =============================== */
  125.  
  126. void
  127. ArcBall_Mouse (HVect v_Now)
  128. {
  129.   vNow = v_Now;
  130. }
  131.  
  132. /* Choose a constraint set, or none. */
  133. /* ================================= */
  134.  
  135. void
  136. ArcBall_UseSet (AxisSet axis_Set)
  137. {
  138.   if (!dragging) axisSet = axis_Set;
  139. }
  140.  
  141. /* Using vDown, vNow, dragging, and axisSet, compute rotation etc. */
  142. /* =============================================================== */
  143.  
  144. void
  145. ArcBall_Update (void)
  146. {
  147.   int setSize = setSizes[axisSet];
  148.   HVect *set = (HVect *)(sets[axisSet]);
  149.  
  150.   vFrom = MouseOnSphere(vDown, center, radius);
  151.   vTo = MouseOnSphere(vNow, center, radius);
  152.   if (dragging)
  153.     {
  154.       if (axisSet!=NoAxes)
  155.     {
  156.       vFrom = ConstrainToAxis(vFrom, set[axisIndex]);
  157.       vTo = ConstrainToAxis(vTo, set[axisIndex]);
  158.     }
  159.       qDrag = Qt_FromBallPoints(vFrom, vTo);
  160.       qNow = Qt_Mul(qDrag, qDown);
  161.     }
  162.   else
  163.     {
  164.       if (axisSet!=NoAxes) axisIndex = NearestConstraintAxis(vTo, set, setSize);
  165.     }
  166.   Qt_ToBallPoints(qDown, &vrFrom, &vrTo);
  167.   Qt_ToMatrix(Qt_Conj(qNow), mNow); /* Gives transpose for GL. */
  168. }
  169.  
  170. /* Return rotation matrix defined by controller use. */
  171. /* ================================================= */
  172.  
  173. void
  174. ArcBall_Value (HMatrix m_Now)
  175. {
  176.   ArcBall_CopyMat (mNow, m_Now);
  177. }
  178.  
  179. /* Extract rotation angles from matrix */
  180. /* =================================== */
  181.  
  182. void
  183. ArcBall_Values (double *alpha,
  184.         double *beta,
  185.         double *gamma)
  186. {
  187.   if ((*beta=asin(-mNow[0][2]))!=0.0)
  188.     {
  189.       *gamma=atan2(mNow[1][2],mNow[2][2]);
  190.       *alpha=atan2(mNow[0][1],mNow[0][0]);
  191.     }
  192.   else
  193.     {
  194.       *gamma=atan2(mNow[1][0],mNow[1][1]);
  195.       *alpha=0.0;     
  196.     }
  197. }
  198.  
  199. /* Begin drag sequence. */
  200. /* ==================== */
  201.  
  202. void
  203. ArcBall_BeginDrag (void)
  204. {
  205.   dragging = TRUE;
  206.   vDown = vNow;
  207. }
  208.  
  209. /* Stop drag sequence. */
  210. /* =================== */
  211.  
  212. void
  213. ArcBall_EndDrag (void)
  214. {
  215.   dragging = FALSE;
  216.   qDown = qNow;
  217.  
  218.   ArcBall_CopyMat (mNow, mDown);
  219. }
  220.  
  221. /*===================*/
  222. /***** BallAux.c *****/
  223. /*===================*/
  224.  
  225. /* Return quaternion product qL * qR.  Note: order is important! */
  226. /* To combine rotations, use the product Mul(qSecond, qFirst),   */
  227. /* which gives the effect of rotating by qFirst then qSecond.    */
  228. /* ============================================================= */
  229.  
  230. static Quat
  231. Qt_Mul (Quat qL,
  232.     Quat qR)
  233. {
  234.   Quat qq;
  235.   qq.w = qL.w*qR.w - qL.x*qR.x - qL.y*qR.y - qL.z*qR.z;
  236.   qq.x = qL.w*qR.x + qL.x*qR.w + qL.y*qR.z - qL.z*qR.y;
  237.   qq.y = qL.w*qR.y + qL.y*qR.w + qL.z*qR.x - qL.x*qR.z;
  238.   qq.z = qL.w*qR.z + qL.z*qR.w + qL.x*qR.y - qL.y*qR.x;
  239.   return (qq);
  240. }
  241.  
  242. /* Construct rotation matrix from (possibly non-unit) quaternion. */
  243. /* Assumes matrix is used to multiply column vector on the left:  */
  244. /* vnew = mat vold.  Works correctly for right-handed coordinate  */
  245. /* system and right-handed rotations.                             */
  246. /* ============================================================== */
  247.  
  248. static void
  249. Qt_ToMatrix (Quat    q,
  250.          HMatrix out)
  251. {
  252.   double Nq = q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w;
  253.   double s = (Nq > 0.0) ? (2.0 / Nq) : 0.0;
  254.   double xs = q.x*s,          ys = q.y*s,      zs = q.z*s;
  255.   double wx = q.w*xs,          wy = q.w*ys,      wz = q.w*zs;
  256.   double xx = q.x*xs,          xy = q.x*ys,      xz = q.x*zs;
  257.   double yy = q.y*ys,          yz = q.y*zs,      zz = q.z*zs;
  258.   out[X][X] = 1.0 - (yy + zz); out[Y][X] = xy + wz; out[Z][X] = xz - wy;
  259.   out[X][Y] = xy - wz; out[Y][Y] = 1.0 - (xx + zz); out[Z][Y] = yz + wx;
  260.   out[X][Z] = xz + wy; out[Y][Z] = yz - wx; out[Z][Z] = 1.0 - (xx + yy);
  261.   out[X][W] = out[Y][W] = out[Z][W] = out[W][X] = out[W][Y] = out[W][Z] = 0.0;
  262.   out[W][W] = 1.0;
  263. }
  264.  
  265. /* Return conjugate of quaternion. */
  266. /* =============================== */
  267.  
  268. static Quat
  269. Qt_Conj (Quat q)
  270. {
  271.   Quat qq;
  272.   qq.x = -q.x; qq.y = -q.y; qq.z = -q.z; qq.w = q.w;
  273.   return (qq);
  274. }
  275.  
  276. /* Return vector formed from components */
  277. /* ==================================== */
  278.  
  279. static HVect
  280. V3_ (double x,
  281.      double y,
  282.      double z)
  283. {
  284.   HVect v;
  285.   v.x = x; v.y = y; v.z = z; v.w = 0;
  286.   return (v);
  287. }
  288.  
  289. /* Return norm of v, defined as sum of squares of components */
  290. /* ========================================================= */
  291.  
  292. static double
  293. V3_Norm (HVect v)
  294. {
  295.   return ( v.x*v.x + v.y*v.y + v.z*v.z );
  296. }
  297.  
  298. /* Return unit magnitude vector in direction of v */
  299. /* ============================================== */
  300.  
  301. static HVect
  302. V3_Unit (HVect v)
  303. {
  304.   static HVect u = {0, 0, 0, 0};
  305.   double vlen = sqrt(V3_Norm(v));
  306.   
  307.   if (vlen != 0.0) u.x = v.x/vlen; u.y = v.y/vlen; u.z = v.z/vlen;
  308.   return (u);
  309. }
  310.  
  311. /* Return version of v scaled by s */
  312. /* =============================== */
  313.  
  314. static HVect
  315. V3_Scale (HVect v,
  316.       double s)
  317. {
  318.   HVect u;
  319.   u.x = s*v.x; u.y = s*v.y; u.z = s*v.z; u.w = v.w;
  320.   return (u);
  321. }
  322.  
  323. /* Return negative of v */
  324. /* ==================== */
  325.  
  326. static HVect
  327. V3_Negate (HVect v)
  328. {
  329.   static HVect u = {0, 0, 0, 0};
  330.   u.x = -v.x; u.y = -v.y; u.z = -v.z;
  331.   return (u);
  332. }
  333.  
  334. /* Return sum of v1 and v2 */
  335. /* ======================= */
  336. /*
  337. static HVect
  338. V3_Add (HVect v1,
  339.     HVect v2)
  340. {
  341.   static HVect v = {0, 0, 0, 0};
  342.   v.x = v1.x+v2.x; v.y = v1.y+v2.y; v.z = v1.z+v2.z;
  343.   return (v);
  344. }
  345. */
  346. /* Return difference of v1 minus v2 */
  347. /* ================================ */
  348.  
  349. static HVect
  350. V3_Sub (HVect v1,
  351.     HVect v2)
  352. {
  353.   static HVect v = {0, 0, 0, 0};
  354.   v.x = v1.x-v2.x; v.y = v1.y-v2.y; v.z = v1.z-v2.z;
  355.   return (v);
  356. }
  357.  
  358. /* Halve arc between unit vectors v0 and v1. */
  359. /* ========================================= */
  360. /*
  361. static HVect
  362. V3_Bisect (HVect v0,
  363.        HVect v1)
  364. {
  365.   HVect v = {0, 0, 0, 0};
  366.   double Nv;
  367.  
  368.   v = V3_Add(v0, v1);
  369.   Nv = V3_Norm(v);
  370.   if (Nv < 1.0e-5) v = V3_(0, 0, 1);
  371.   else v = V3_Scale(v, 1/sqrt(Nv));
  372.   return (v);
  373. }
  374. */
  375.  
  376. /* Return dot product of v1 and v2 */
  377. /* =============================== */
  378.  
  379. static double
  380. V3_Dot (HVect v1,
  381.     HVect v2)
  382. {
  383.   return (v1.x*v2.x + v1.y*v2.y + v1.z*v2.z);
  384. }
  385.  
  386.  
  387. /* Return cross product, v1 x v2 */
  388. /* ============================= */
  389. /*
  390. static HVect
  391. V3_Cross (HVect v1,
  392.       HVect v2)
  393. {
  394.   static HVect v = {0, 0, 0, 0};
  395.   v.x = v1.y*v2.z-v1.z*v2.y;
  396.   v.y = v1.z*v2.x-v1.x*v2.z;
  397.   v.z = v1.x*v2.y-v1.y*v2.x;
  398.   return (v);
  399. }
  400. */
  401.  
  402. void
  403. ArcBall_CopyMat (HMatrix inm,
  404.          HMatrix outm)
  405. {
  406.   int x=0,y=0;
  407.  
  408.   for (x=0;x<4;x++)
  409.     {
  410.       for (y=0;y<4;y++)
  411.     {
  412.       outm[y][x]=inm[y][x];
  413.     }
  414.     }
  415. }
  416.  
  417. /*=====================================================*/
  418. /**** BallMath.c - Essential routines for ArcBall.  ****/
  419. /*=====================================================*/
  420.  
  421. /* Convert window coordinates to sphere coordinates. */
  422. /* ================================================= */
  423.  
  424. static HVect
  425. MouseOnSphere (HVect  mouse,
  426.            HVect  ballCenter,
  427.            double ballRadius)
  428. {
  429.   HVect ballMouse;
  430.   register double mag;
  431.   
  432.   ballMouse.x = (mouse.x - ballCenter.x) / ballRadius;
  433.   ballMouse.y = (mouse.y - ballCenter.y) / ballRadius;
  434.   mag = ballMouse.x*ballMouse.x + ballMouse.y*ballMouse.y;
  435.   if (mag > 1.0)
  436.     {
  437.       register double scale = 1.0/sqrt(mag);
  438.       ballMouse.x *= scale; ballMouse.y *= scale;
  439.       ballMouse.z = 0.0;
  440.     }
  441.   else ballMouse.z = sqrt(1 - mag);
  442.   ballMouse.w = 0.0;
  443.   return (ballMouse);
  444. }
  445.  
  446. /* Construct a unit quaternion from two points on unit sphere */
  447. /* ========================================================== */
  448.  
  449. static Quat
  450. Qt_FromBallPoints (HVect from,
  451.            HVect to)
  452. {
  453.   Quat qu;
  454.   qu.x = from.y*to.z - from.z*to.y;
  455.   qu.y = from.z*to.x - from.x*to.z;
  456.   qu.z = from.x*to.y - from.y*to.x;
  457.   qu.w = from.x*to.x + from.y*to.y + from.z*to.z;
  458.   return (qu);
  459. }
  460.  
  461. /* Convert a unit quaternion to two points on unit sphere */
  462. /* ====================================================== */
  463.  
  464. static void
  465. Qt_ToBallPoints (Quat   q,
  466.          HVect *arcFrom,
  467.          HVect *arcTo)
  468. {
  469.   double s;
  470.   
  471.   s = sqrt(q.x*q.x + q.y*q.y);
  472.   if (s == 0.0) *arcFrom = V3_(0.0, 1.0, 0.0);
  473.   else          *arcFrom = V3_(-q.y/s, q.x/s, 0.0);
  474.   arcTo->x = q.w*arcFrom->x - q.z*arcFrom->y;
  475.   arcTo->y = q.w*arcFrom->y + q.z*arcFrom->x;
  476.   arcTo->z = q.x*arcFrom->y - q.y*arcFrom->x;
  477.   if (q.w < 0.0) *arcFrom = V3_(-arcFrom->x, -arcFrom->y, 0.0);
  478. }
  479.  
  480. /* Force sphere point to be perpendicular to axis. */
  481. /* =============================================== */
  482.  
  483. static HVect
  484. ConstrainToAxis (HVect loose,
  485.          HVect axis)
  486. {
  487.   HVect onPlane;
  488.   register double norm;
  489.   
  490.   onPlane = V3_Sub(loose, V3_Scale(axis, V3_Dot(axis, loose)));
  491.   norm = V3_Norm(onPlane);
  492.   if (norm > 0.0)
  493.     {
  494.       if (onPlane.z < 0.0) onPlane = V3_Negate(onPlane);
  495.       return ( V3_Scale(onPlane, 1/sqrt(norm)) );
  496.     }
  497.   /* else drop through */
  498.   /* ================= */
  499.  
  500.   if (axis.z == 1) onPlane = V3_(1.0, 0.0, 0.0);
  501.   else             onPlane = V3_Unit(V3_(-axis.y, axis.x, 0.0));
  502.   return (onPlane);
  503. }
  504.  
  505. /* Find the index of nearest arc of axis set. */
  506. /* ========================================== */
  507.  
  508. static int
  509. NearestConstraintAxis (HVect  loose,
  510.                HVect *axes,
  511.                int    nAxes)
  512. {
  513.   HVect onPlane;
  514.   register double max, dot;
  515.   register int i, nearest;
  516.   max = -1; nearest = 0;
  517.   
  518.   for (i=0; i<nAxes; i++)
  519.     {
  520.       onPlane = ConstrainToAxis(loose, axes[i]);
  521.       dot = V3_Dot(onPlane, loose);
  522.       if (dot>max)
  523.     {
  524.       max = dot; nearest = i;
  525.     }
  526.     }
  527.   return (nearest);
  528. }
  529.