PageRenderTime 25ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/plug-ins/map-object/arcball.c

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