BallMath.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. /**** BallMath.c - Essential routines for ArcBall. ****/
  2. #include <math.h>
  3. #include "BallMath.h"
  4. #include "BallAux.h"
  5. /* Convert window coordinates to sphere coordinates. */
  6. HVect MouseOnSphere(HVect mouse, HVect ballCenter, double ballRadius)
  7. {
  8. HVect ballMouse;
  9. register double mag;
  10. ballMouse.x = (mouse.x - ballCenter.x) / ballRadius;
  11. ballMouse.y = (mouse.y - ballCenter.y) / ballRadius;
  12. mag = ballMouse.x * ballMouse.x + ballMouse.y * ballMouse.y;
  13. if (mag > 1.0) {
  14. register double scale = 1.0 / sqrt(mag);
  15. ballMouse.x *= scale;
  16. ballMouse.y *= scale;
  17. ballMouse.z = 0.0;
  18. }
  19. else {
  20. ballMouse.z = sqrt(1 - mag);
  21. }
  22. ballMouse.w = 0.0;
  23. return (ballMouse);
  24. }
  25. #include <stdio.h>
  26. /* Construct a unit quaternion from two points on unit sphere */
  27. Quat Qt_FromBallPoints(HVect from, HVect to)
  28. {
  29. Quat qu;
  30. float mag, ang, s;
  31. qu.x = from.y * to.z - from.z * to.y;
  32. qu.y = from.z * to.x - from.x * to.z;
  33. qu.z = from.x * to.y - from.y * to.x;
  34. qu.w = from.x * to.x + from.y * to.y + from.z * to.z;
  35. mag = sqrt(qu.x * qu.x + qu.y * qu.y + qu.z * qu.z);
  36. ang = atan2(mag, qu.w) / 2.;
  37. s = sin(ang);
  38. if (mag) {
  39. qu.x *= s / mag;
  40. qu.y *= s / mag;
  41. qu.z *= s / mag;
  42. }
  43. qu.w = cos(ang);
  44. return (qu);
  45. }
  46. /* Convert a unit quaternion to two points on unit sphere */
  47. void Qt_ToBallPoints(Quat q, HVect * arcFrom, HVect * arcTo)
  48. {
  49. double s;
  50. s = sqrt(q.x * q.x + q.y * q.y);
  51. if (s == 0.0) {
  52. *arcFrom = V3_(0.0, 1.0, 0.0);
  53. }
  54. else {
  55. *arcFrom = V3_(-q.y / s, q.x / s, 0.0);
  56. }
  57. arcTo->x = q.w * arcFrom->x - q.z * arcFrom->y;
  58. arcTo->y = q.w * arcFrom->y + q.z * arcFrom->x;
  59. arcTo->z = q.x * arcFrom->y - q.y * arcFrom->x;
  60. if (q.w < 0.0)
  61. *arcFrom = V3_(-arcFrom->x, -arcFrom->y, 0.0);
  62. }
  63. /* Force sphere point to be perpendicular to axis. */
  64. HVect ConstrainToAxis(HVect loose, HVect axis)
  65. {
  66. HVect onPlane;
  67. register float norm;
  68. onPlane = V3_Sub(loose, V3_Scale(axis, V3_Dot(axis, loose)));
  69. norm = V3_Norm(onPlane);
  70. if (norm > 0.0) {
  71. if (onPlane.z < 0.0)
  72. onPlane = V3_Negate(onPlane);
  73. return (V3_Scale(onPlane, 1 / sqrt(norm)));
  74. } /* else drop through */
  75. if (axis.z == 1) {
  76. onPlane = V3_(1.0, 0.0, 0.0);
  77. }
  78. else {
  79. onPlane = V3_Unit(V3_(-axis.y, axis.x, 0.0));
  80. }
  81. return (onPlane);
  82. }
  83. /* Find the index of nearest arc of axis set. */
  84. int NearestConstraintAxis(HVect loose, HVect * axes, int nAxes)
  85. {
  86. HVect onPlane;
  87. register float max, dot;
  88. register int i, nearest;
  89. max = -1;
  90. nearest = 0;
  91. for (i = 0; i < nAxes; i++) {
  92. onPlane = ConstrainToAxis(loose, axes[i]);
  93. dot = V3_Dot(onPlane, loose);
  94. if (dot > max) {
  95. max = dot;
  96. nearest = i;
  97. }
  98. }
  99. return (nearest);
  100. }