/ecere/src/gfx/3D/Quaternion.ec

https://github.com/thexa4/sdk · C · 321 lines · 268 code · 46 blank · 7 comment · 9 complexity · 271e710e396461e87407a3cce5389ad2 MD5 · raw file

  1. namespace gfx3D;
  2. import "Display"
  3. public struct Euler
  4. {
  5. Degrees yaw, pitch, roll;
  6. property Quaternion
  7. {
  8. set
  9. {
  10. double y = 2 * ( value.y*value.z + value.w*value.x );
  11. if(fabs(y) <= 1.0 - 0.000005)
  12. {
  13. double x = 2 * ( value.x*value.z - value.w*value.y );
  14. double z = 1 - 2 * ( value.x*value.x + value.y*value.y );
  15. Angle yaw = -atan2(x, z);
  16. Angle pitch = atan2(y, sqrt(x * x + z * z));
  17. double sYaw = sin( yaw / 2 );
  18. double cYaw = cos( yaw / 2 );
  19. double sPitch = sin( pitch / 2 );
  20. double cPitch = cos( pitch / 2 );
  21. Quaternion yp = { cPitch * cYaw, sPitch * cYaw, cPitch * sYaw, sPitch * sYaw };
  22. double rollW = yp.w * value.w + yp.x * value.x + yp.y * value.y + yp.z * value.z;
  23. double rollZ = yp.w * value.z + yp.x * value.y - yp.y * value.x - yp.z * value.w;
  24. this.yaw = yaw;
  25. this.pitch = pitch;
  26. this.roll = atan2(rollZ, rollW) * 2;
  27. }
  28. else
  29. {
  30. // 90 degrees pitch case
  31. double sin45 = sin(Pi/4);
  32. double yawW = sin45 * value.w + sin45 * value.x;
  33. double yawY = sin45 * value.y + sin45 * value.z;
  34. this.yaw = atan2(yawY, yawW) * 2;
  35. this.pitch = Pi/2;
  36. this.roll = 0;
  37. }
  38. }
  39. get
  40. {
  41. double sYaw = sin( yaw / 2 );
  42. double cYaw = cos( yaw / 2 );
  43. double sPitch = sin( pitch / 2 );
  44. double cPitch = cos( pitch / 2 );
  45. double sRoll = sin( roll / 2 );
  46. double cRoll = cos( roll / 2 );
  47. Quaternion yp = { cPitch * cYaw, sPitch * cYaw, cPitch * sYaw, sPitch * sYaw };
  48. value.w = yp.w * cRoll - yp.z * sRoll;
  49. value.x = yp.x * cRoll - yp.y * sRoll;
  50. value.y = yp.y * cRoll + yp.x * sRoll;
  51. value.z = yp.z * cRoll + yp.w * sRoll;
  52. }
  53. };
  54. void Add(Euler e1, Euler e2)
  55. {
  56. yaw = e1.yaw + e2.yaw;
  57. pitch = e1.pitch + e2.pitch;
  58. roll = e1.roll + e2.roll;
  59. }
  60. };
  61. public struct Quaternion
  62. {
  63. double w, x, y, z;
  64. void Identity(void)
  65. {
  66. x = y = z = 0;
  67. w = 1;
  68. }
  69. void Normalize(Quaternion source)
  70. {
  71. double m = sqrt(source.x * source.x +
  72. source.y * source.y +
  73. source.z * source.z +
  74. source.w * source.w);
  75. if(m)
  76. {
  77. x = (double)(source.x/m);
  78. y = (double)(source.y/m);
  79. z = (double)(source.z/m);
  80. w = (double)(source.w/m);
  81. }
  82. else
  83. w = x = y = z = 0;
  84. }
  85. void Multiply(Quaternion q1, Quaternion q2)
  86. {
  87. w = q1.w * q2.w - q2.x * q1.x - q1.y * q2.y - q1.z * q2.z;
  88. x = q1.w * q2.x + q2.w * q1.x + q1.y * q2.z - q1.z * q2.y;
  89. y = q1.w * q2.y + q2.w * q1.y + q1.z * q2.x - q1.x * q2.z;
  90. z = q1.w * q2.z + q2.w * q1.z + q1.x * q2.y - q1.y * q2.x;
  91. }
  92. void Divide(Quaternion q1, Quaternion q2)
  93. {
  94. w = q2.w * q1.w + q2.x * q1.x + q2.y * q1.y + q2.z * q1.z;
  95. x = q2.w * q1.x - q2.x * q1.w + q2.y * q1.z - q2.z * q1.y;
  96. y = q2.w * q1.y - q2.x * q1.z - q2.y * q1.w + q2.z * q1.x;
  97. z = q2.w * q1.z + q2.x * q1.y - q2.y * q1.x - q2.z * q1.w;
  98. }
  99. void RotationAxis(Vector3Df axis, Degrees angle)
  100. {
  101. double sa = sin( angle / 2 );
  102. double ca = cos( angle / 2 );
  103. x = (double)(axis.x * sa);
  104. y = (double)(axis.y * sa);
  105. z = (double)(axis.z * sa);
  106. w = (double)ca;
  107. }
  108. void RotationYawPitchRoll(Euler euler)
  109. {
  110. Quaternion rotation, result;
  111. result.Yaw(euler.yaw);
  112. rotation.Pitch(euler.pitch);
  113. Multiply(rotation, result);
  114. rotation.Roll(euler.roll);
  115. result.Multiply(rotation, this);
  116. Normalize(result);
  117. }
  118. void RotationDirection(Vector3D direction)
  119. {
  120. Angle yaw = -atan2(direction.x, direction.z);
  121. Angle pitch = atan2(direction.y, sqrt(direction.x * direction.x + direction.z * direction.z));
  122. YawPitch(yaw, pitch);
  123. }
  124. void RotationMatrix(Matrix m)
  125. {
  126. double t = m.m[0][0] + m.m[1][1] + m.m[2][2] + 1.0;
  127. if(t > 0)
  128. {
  129. double s = sqrt(t) * 2;
  130. w = (double) (0.25f * s);
  131. x = (double) (( m.m[2][1] - m.m[1][2] ) / s);
  132. y = (double) (( m.m[0][2] - m.m[2][0] ) / s);
  133. z = (double) (( m.m[1][0] - m.m[0][1] ) / s);
  134. }
  135. else
  136. {
  137. double q[3];
  138. double s;
  139. int i = 0,j,k;
  140. int nxt[3] = {1,2,0};
  141. if(m.m[1][1] > m.m[0][0]) i = 1;
  142. if(m.m[2][2] > m.m[i][i]) i = 2;
  143. j = nxt[i];
  144. k = nxt[j];
  145. s = sqrt(m.m[i][i] - (m.m[j][j] + m.m[k][k]) + 1.0) * 2;
  146. w = (double) ((m.m[k][j] - m.m[j][k]) / s);
  147. q[i] = (double) (0.25f * s);
  148. q[j] = (double) ((m.m[j][i] - m.m[i][j]) / s);
  149. q[k] = (double) ((m.m[k][i] - m.m[i][k]) / s);
  150. x = q[0];
  151. y = q[1];
  152. z = q[2];
  153. }
  154. }
  155. #define DELTA 0
  156. void Slerp(Quaternion from, Quaternion to, float t)
  157. {
  158. double to1[4];
  159. double omega, cosom, sinom, scale0, scale1;
  160. cosom = from.x * to.x + from.y * to.y + from.z * to.z + from.w * to.w;
  161. if ( cosom < 0.0 )
  162. {
  163. cosom = -cosom;
  164. to1[0] = -to.x;
  165. to1[1] = -to.y;
  166. to1[2] = -to.z;
  167. to1[3] = -to.w;
  168. }
  169. else
  170. {
  171. to1[0] = to.x;
  172. to1[1] = to.y;
  173. to1[2] = to.z;
  174. to1[3] = to.w;
  175. }
  176. if ( (1.0 - cosom) > DELTA )
  177. {
  178. omega = acos(cosom);
  179. sinom = sin(omega);
  180. scale0 = sin((1.0 - t) * omega) / sinom;
  181. scale1 = sin(t * omega) / sinom;
  182. }
  183. else
  184. {
  185. scale0 = 1.0 - t;
  186. scale1 = t;
  187. }
  188. x = (double)(scale0 * from.x + scale1 * to1[0]);
  189. y = (double)(scale0 * from.y + scale1 * to1[1]);
  190. z = (double)(scale0 * from.z + scale1 * to1[2]);
  191. w = (double)(scale0 * from.w + scale1 * to1[3]);
  192. }
  193. void Yaw(Degrees angle)
  194. {
  195. double sa = sin( angle / 2 );
  196. double ca = cos( angle / 2 );
  197. x = 0;
  198. y = (double)sa;
  199. z = 0;
  200. w = (double)ca;
  201. }
  202. void YawPitch(Degrees yaw, Degrees pitch)
  203. {
  204. double sYaw = sin( yaw / 2 );
  205. double cYaw = cos( yaw / 2 );
  206. double sPitch = sin( pitch / 2 );
  207. double cPitch = cos( pitch / 2 );
  208. w = cPitch * cYaw;
  209. x = sPitch * cYaw;
  210. y = cPitch * sYaw;
  211. z = sPitch * sYaw;
  212. }
  213. void Pitch(Degrees angle)
  214. {
  215. double sa = sin( angle / 2 );
  216. double ca = cos( angle / 2 );
  217. x = (double)sa;
  218. y = 0;
  219. z = 0;
  220. w = (double)ca;
  221. }
  222. void Roll(Degrees angle)
  223. {
  224. double sa = sin( angle / 2 );
  225. double ca = cos( angle / 2 );
  226. x = 0;
  227. y = 0;
  228. z = (double)sa;
  229. w = (double)ca;
  230. }
  231. void RotatePitch(Degrees pitch)
  232. {
  233. Quaternion rotation, result;
  234. rotation.Pitch(pitch);
  235. result.Multiply(rotation, this);
  236. this = result;
  237. }
  238. void RotateYaw(Degrees yaw)
  239. {
  240. Quaternion rotation, result;
  241. rotation.Yaw(yaw);
  242. result.Multiply(rotation, this);
  243. this = result;
  244. }
  245. void RotateRoll(Degrees roll)
  246. {
  247. Quaternion rotation, result;
  248. rotation.Roll(roll);
  249. result.Multiply(rotation, this);
  250. this = result;
  251. }
  252. void RotateYawPitch(Degrees yaw, Degrees pitch)
  253. {
  254. Quaternion rotation, result;
  255. rotation.YawPitch(yaw, pitch);
  256. result.Multiply(rotation, this);
  257. this = result;
  258. }
  259. void ToDirection(Vector3D direction)
  260. {
  261. /*
  262. Vector3Df vector { 0,0,1 };
  263. Matrix mat;
  264. mat.RotationQuaternion(this);
  265. direction.Transform(vector, mat);
  266. */
  267. direction.x = (double)( 2 * ( x*z - w*y ));
  268. direction.y = (double)( 2 * ( y*z + w*x ));
  269. direction.z = (double)(1 - 2 * ( x*x + y*y ));
  270. }
  271. void Inverse(Quaternion source)
  272. {
  273. this = { -source.w, source.x, source.y, source.z };
  274. }
  275. };