PageRenderTime 39ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/src/libnml/posemath/_posemath.c

https://github.com/araisrobo/linuxcnc
C | 1740 lines | 1285 code | 342 blank | 113 comment | 164 complexity | 29d70c9cb35ce7686124ae4f7c902763 MD5 | raw file
  1. /********************************************************************
  2. * Description: _posemath.c
  3. * C definitions for pose math library data types and manipulation
  4. * functions.
  5. *
  6. * Derived from a work by Fred Proctor & Will Shackleford
  7. *
  8. * Author:
  9. * License: LGPL Version 2
  10. * System: Linux
  11. *
  12. * Copyright (c) 2004 All rights reserved.
  13. *
  14. * Last change:
  15. ********************************************************************/
  16. #if defined(PM_PRINT_ERROR) && defined(rtai)
  17. #undef PM_PRINT_ERROR
  18. #endif
  19. #if defined(PM_DEBUG) && defined(rtai)
  20. #undef PM_DEBUG
  21. #endif
  22. #ifdef PM_PRINT_ERROR
  23. #define PM_DEBUG /* have to have debug with printing */
  24. #include <stdio.h>
  25. #include <stdarg.h>
  26. #endif
  27. #include "posemath.h"
  28. #include "rtapi_math.h"
  29. #include <float.h>
  30. #include "sincos.h"
  31. /* global error number */
  32. int pmErrno = 0;
  33. #ifdef PM_PRINT_ERROR
  34. void pmPrintError(const char *fmt, ...)
  35. {
  36. va_list args;
  37. va_start(args, fmt);
  38. vfprintf(stderr, fmt, args);
  39. va_end(args);
  40. }
  41. /* error printing function */
  42. void pmPerror(const char *s)
  43. {
  44. char *pmErrnoString;
  45. switch (pmErrno) {
  46. case 0:
  47. /* no error */
  48. return;
  49. case PM_ERR:
  50. pmErrnoString = "unspecified error";
  51. break;
  52. case PM_IMPL_ERR:
  53. pmErrnoString = "not implemented";
  54. break;
  55. case PM_NORM_ERR:
  56. pmErrnoString = "expected normalized value";
  57. break;
  58. case PM_DIV_ERR:
  59. pmErrnoString = "divide by zero";
  60. break;
  61. default:
  62. pmErrnoString = "unassigned error";
  63. break;
  64. }
  65. if (s != 0 && s[0] != 0) {
  66. fprintf(stderr, "%s: %s\n", s, pmErrnoString);
  67. } else {
  68. fprintf(stderr, "%s\n", pmErrnoString);
  69. }
  70. }
  71. #endif /* PM_PRINT_ERROR */
  72. /* fuzz checker */
  73. #define IS_FUZZ(a,fuzz) (fabs(a) < (fuzz) ? 1 : 0)
  74. /* Pose Math Basis Functions */
  75. /* Scalar functions */
  76. double pmSqrt(double x)
  77. {
  78. if (x > 0.0) {
  79. return sqrt(x);
  80. }
  81. if (x > SQRT_FUZZ) {
  82. return 0.0;
  83. }
  84. #ifdef PM_PRINT_ERROR
  85. pmPrintError("sqrt of large negative number\n");
  86. #endif
  87. return 0.0;
  88. }
  89. /* Translation rep conversion functions */
  90. int pmCartSphConvert(PmCartesian v, PmSpherical * s)
  91. {
  92. double _r;
  93. s->theta = atan2(v.y, v.x);
  94. s->r = pmSqrt(pmSq(v.x) + pmSq(v.y) + pmSq(v.z));
  95. _r = pmSqrt(pmSq(v.x) + pmSq(v.y));
  96. s->phi = atan2(_r, v.z);
  97. return pmErrno = 0;
  98. }
  99. int pmCartCylConvert(PmCartesian v, PmCylindrical * c)
  100. {
  101. c->theta = atan2(v.y, v.x);
  102. c->r = pmSqrt(pmSq(v.x) + pmSq(v.y));
  103. c->z = v.z;
  104. return pmErrno = 0;
  105. }
  106. int pmSphCartConvert(PmSpherical s, PmCartesian * v)
  107. {
  108. double _r;
  109. _r = s.r * sin(s.phi);
  110. v->z = s.r * cos(s.phi);
  111. v->x = _r * cos(s.theta);
  112. v->y = _r * sin(s.theta);
  113. return pmErrno = 0;
  114. }
  115. int pmSphCylConvert(PmSpherical s, PmCylindrical * c)
  116. {
  117. c->theta = s.theta;
  118. c->r = s.r * cos(s.phi);
  119. c->z = s.r * sin(s.phi);
  120. return pmErrno = 0;
  121. }
  122. int pmCylCartConvert(PmCylindrical c, PmCartesian * v)
  123. {
  124. v->x = c.r * cos(c.theta);
  125. v->y = c.r * sin(c.theta);
  126. v->z = c.z;
  127. return pmErrno = 0;
  128. }
  129. int pmCylSphConvert(PmCylindrical c, PmSpherical * s)
  130. {
  131. s->theta = c.theta;
  132. s->r = pmSqrt(pmSq(c.r) + pmSq(c.z));
  133. s->phi = atan2(c.z, c.r);
  134. return pmErrno = 0;
  135. }
  136. /* Rotation rep conversion functions */
  137. int pmAxisAngleQuatConvert(PmAxis axis, double a, PmQuaternion * q)
  138. {
  139. double sh;
  140. a *= 0.5;
  141. sincos(a, &sh, &(q->s));
  142. switch (axis) {
  143. case PM_X:
  144. q->x = sh;
  145. q->y = 0.0;
  146. q->z = 0.0;
  147. break;
  148. case PM_Y:
  149. q->x = 0.0;
  150. q->y = sh;
  151. q->z = 0.0;
  152. break;
  153. case PM_Z:
  154. q->x = 0.0;
  155. q->y = 0.0;
  156. q->z = sh;
  157. break;
  158. default:
  159. #ifdef PM_PRINT_ERROR
  160. pmPrintError("error: bad axis in pmAxisAngleQuatConvert\n");
  161. #endif
  162. return -1;
  163. }
  164. if (q->s < 0.0) {
  165. q->s *= -1.0;
  166. q->x *= -1.0;
  167. q->y *= -1.0;
  168. q->z *= -1.0;
  169. }
  170. return 0;
  171. }
  172. int pmRotQuatConvert(PmRotationVector r, PmQuaternion * q)
  173. {
  174. double sh;
  175. #ifdef PM_DEBUG
  176. /* make sure r is normalized */
  177. if (0 != pmRotNorm(r, &r)) {
  178. #ifdef PM_PRINT_ERROR
  179. pmPrintError
  180. ("error: pmRotQuatConvert rotation vector not normalized\n");
  181. #endif
  182. return pmErrno = PM_NORM_ERR;
  183. }
  184. #endif
  185. if (pmClose(r.s, 0.0, QS_FUZZ)) {
  186. q->s = 1.0;
  187. q->x = q->y = q->z = 0.0;
  188. return pmErrno = 0;
  189. }
  190. sincos(r.s / 2.0, &sh, &(q->s));
  191. if (q->s >= 0.0) {
  192. q->x = r.x * sh;
  193. q->y = r.y * sh;
  194. q->z = r.z * sh;
  195. } else {
  196. q->s *= -1;
  197. q->x = -r.x * sh;
  198. q->y = -r.y * sh;
  199. q->z = -r.z * sh;
  200. }
  201. return pmErrno = 0;
  202. }
  203. int pmRotMatConvert(PmRotationVector r, PmRotationMatrix * m)
  204. {
  205. double s, c, omc;
  206. #ifdef PM_DEBUG
  207. if (!pmRotIsNorm(r)) {
  208. #ifdef PM_PRINT_ERROR
  209. pmPrintError("Bad vector in pmRotMatConvert\n");
  210. #endif
  211. return pmErrno = PM_NORM_ERR;
  212. }
  213. #endif
  214. sincos(r.s, &s, &c);
  215. /* from space book */
  216. m->x.x = c + pmSq(r.x) * (omc = 1 - c); /* omc = One Minus Cos */
  217. m->y.x = -r.z * s + r.x * r.y * omc;
  218. m->z.x = r.y * s + r.x * r.z * omc;
  219. m->x.y = r.z * s + r.y * r.x * omc;
  220. m->y.y = c + pmSq(r.y) * omc;
  221. m->z.y = -r.x * s + r.y * r.z * omc;
  222. m->x.z = -r.y * s + r.z * r.x * omc;
  223. m->y.z = r.x * s + r.z * r.y * omc;
  224. m->z.z = c + pmSq(r.z) * omc;
  225. return pmErrno = 0;
  226. }
  227. int pmRotZyzConvert(PmRotationVector r, PmEulerZyz * zyz)
  228. {
  229. #ifdef PM_DEBUG
  230. #ifdef PM_PRINT_ERROR
  231. pmPrintError("error: pmRotZyzConvert not implemented\n");
  232. #endif
  233. return pmErrno = PM_IMPL_ERR;
  234. #else
  235. return PM_IMPL_ERR;
  236. #endif
  237. }
  238. int pmRotZyxConvert(PmRotationVector r, PmEulerZyx * zyx)
  239. {
  240. PmRotationMatrix m;
  241. int r1, r2;
  242. r1 = pmRotMatConvert(r, &m);
  243. r2 = pmMatZyxConvert(m, zyx);
  244. return pmErrno = r1 || r2 ? PM_NORM_ERR : 0;
  245. }
  246. int pmRotRpyConvert(PmRotationVector r, PmRpy * rpy)
  247. {
  248. PmQuaternion q;
  249. int r1, r2;
  250. q.s = q.x = q.y = q.z = 0.0;
  251. r1 = pmRotQuatConvert(r, &q);
  252. r2 = pmQuatRpyConvert(q, rpy);
  253. return r1 || r2 ? pmErrno : 0;
  254. }
  255. int pmQuatRotConvert(PmQuaternion q, PmRotationVector * r)
  256. {
  257. double sh;
  258. #ifdef PM_DEBUG
  259. if (!pmQuatIsNorm(q)) {
  260. #ifdef PM_PRINT_ERROR
  261. pmPrintError("Bad quaternion in pmQuatRotConvert\n");
  262. #endif
  263. return pmErrno = PM_NORM_ERR;
  264. }
  265. #endif
  266. if (r == 0) {
  267. return (pmErrno = PM_ERR);
  268. }
  269. sh = pmSqrt(pmSq(q.x) + pmSq(q.y) + pmSq(q.z));
  270. if (sh > QSIN_FUZZ) {
  271. r->s = 2.0 * atan2(sh, q.s);
  272. r->x = q.x / sh;
  273. r->y = q.y / sh;
  274. r->z = q.z / sh;
  275. } else {
  276. r->s = 0.0;
  277. r->x = 0.0;
  278. r->y = 0.0;
  279. r->z = 0.0;
  280. }
  281. return pmErrno = 0;
  282. }
  283. int pmQuatMatConvert(PmQuaternion q, PmRotationMatrix * m)
  284. {
  285. #ifdef PM_DEBUG
  286. if (!pmQuatIsNorm(q)) {
  287. #ifdef PM_PRINT_ERROR
  288. pmPrintError("Bad quaternion in pmQuatMatConvert\n");
  289. #endif
  290. return pmErrno = PM_NORM_ERR;
  291. }
  292. #endif
  293. /* from space book where e1=q.x e2=q.y e3=q.z e4=q.s */
  294. m->x.x = 1 - 2 * (pmSq(q.y) + pmSq(q.z));
  295. m->y.x = 2 * (q.x * q.y - q.z * q.s);
  296. m->z.x = 2 * (q.z * q.x + q.y * q.s);
  297. m->x.y = 2 * (q.x * q.y + q.z * q.s);
  298. m->y.y = 1 - 2 * (pmSq(q.z) + pmSq(q.x));
  299. m->z.y = 2 * (q.y * q.z - q.x * q.s);
  300. m->x.z = 2 * (q.z * q.x - q.y * q.s);
  301. m->y.z = 2 * (q.y * q.z + q.x * q.s);
  302. m->z.z = 1 - 2 * (pmSq(q.x) + pmSq(q.y));
  303. return pmErrno = 0;
  304. }
  305. int pmQuatZyzConvert(PmQuaternion q, PmEulerZyz * zyz)
  306. {
  307. PmRotationMatrix m;
  308. int r1, r2;
  309. /*! \todo FIXME-- need direct equations */
  310. r1 = pmQuatMatConvert(q, &m);
  311. r2 = pmMatZyzConvert(m, zyz);
  312. return pmErrno = r1 || r2 ? PM_NORM_ERR : 0;
  313. }
  314. int pmQuatZyxConvert(PmQuaternion q, PmEulerZyx * zyx)
  315. {
  316. PmRotationMatrix m;
  317. int r1, r2;
  318. /*! \todo FIXME-- need direct equations */
  319. r1 = pmQuatMatConvert(q, &m);
  320. r2 = pmMatZyxConvert(m, zyx);
  321. return pmErrno = r1 || r2 ? PM_NORM_ERR : 0;
  322. }
  323. int pmQuatRpyConvert(PmQuaternion q, PmRpy * rpy)
  324. {
  325. PmRotationMatrix m;
  326. int r1, r2;
  327. /*! \todo FIXME-- need direct equations */
  328. r1 = pmQuatMatConvert(q, &m);
  329. r2 = pmMatRpyConvert(m, rpy);
  330. return pmErrno = r1 || r2 ? PM_NORM_ERR : 0;
  331. }
  332. int pmMatRotConvert(PmRotationMatrix m, PmRotationVector * r)
  333. {
  334. PmQuaternion q;
  335. int r1, r2;
  336. /*! \todo FIXME-- need direct equations */
  337. r1 = pmMatQuatConvert(m, &q);
  338. r2 = pmQuatRotConvert(q, r);
  339. return pmErrno = r1 || r2 ? PM_NORM_ERR : 0;
  340. }
  341. int pmMatQuatConvert(PmRotationMatrix m, PmQuaternion * q)
  342. {
  343. /*
  344. from Stephe's "space" book e1 = (c32 - c23) / 4*e4 e2 = (c13 - c31) /
  345. 4*e4 e3 = (c21 - c12) / 4*e4 e4 = sqrt(1 + c11 + c22 + c33) / 2
  346. if e4 == 0 e1 = sqrt(1 + c11 - c33 - c22) / 2 e2 = sqrt(1 + c22 - c33
  347. - c11) / 2 e3 = sqrt(1 + c33 - c11 - c22) / 2 to determine whether to
  348. take the positive or negative sqrt value since e4 == 0 indicates a
  349. 180* rotation then (0 x y z) = (0 -x -y -z). Thus some generallities
  350. can be used: 1) find which of e1, e2, or e3 has the largest magnitude
  351. and leave it pos. 2) if e1 is largest then if c21 < 0 then take the
  352. negative for e2 if c31 < 0 then take the negative for e3 3) else if e2
  353. is largest then if c21 < 0 then take the negative for e1 if c32 < 0
  354. then take the negative for e3 4) else if e3 is larget then if c31 < 0
  355. then take the negative for e1 if c32 < 0 then take the negative for e2
  356. Note: c21 in the space book is m.x.y in this C code */
  357. double a;
  358. #ifdef PM_DEBUG
  359. if (!pmMatIsNorm(m)) {
  360. #ifdef PM_PRINT_ERROR
  361. pmPrintError("Bad matrix in pmMatQuatConvert\n");
  362. #endif
  363. return pmErrno = PM_NORM_ERR;
  364. }
  365. #endif
  366. q->s = 0.5 * pmSqrt(1.0 + m.x.x + m.y.y + m.z.z);
  367. if (fabs(q->s) > QS_FUZZ) {
  368. q->x = (m.y.z - m.z.y) / (a = 4 * q->s);
  369. q->y = (m.z.x - m.x.z) / a;
  370. q->z = (m.x.y - m.y.x) / a;
  371. } else {
  372. q->s = 0;
  373. q->x = pmSqrt(1.0 + m.x.x - m.y.y - m.z.z) / 2.0;
  374. q->y = pmSqrt(1.0 + m.y.y - m.x.x - m.z.z) / 2.0;
  375. q->z = pmSqrt(1.0 + m.z.z - m.y.y - m.x.x) / 2.0;
  376. if (q->x > q->y && q->x > q->z) {
  377. if (m.x.y < 0.0) {
  378. q->y *= -1;
  379. }
  380. if (m.x.z < 0.0) {
  381. q->z *= -1;
  382. }
  383. } else if (q->y > q->z) {
  384. if (m.x.y < 0.0) {
  385. q->x *= -1;
  386. }
  387. if (m.y.z < 0.0) {
  388. q->z *= -1;
  389. }
  390. } else {
  391. if (m.x.z < 0.0) {
  392. q->x *= -1;
  393. }
  394. if (m.y.z < 0.0) {
  395. q->y *= -1;
  396. }
  397. }
  398. }
  399. return pmQuatNorm(*q, q);
  400. }
  401. int pmMatZyzConvert(PmRotationMatrix m, PmEulerZyz * zyz)
  402. {
  403. zyz->y = atan2(pmSqrt(pmSq(m.x.z) + pmSq(m.y.z)), m.z.z);
  404. if (fabs(zyz->y) < ZYZ_Y_FUZZ) {
  405. zyz->z = 0.0;
  406. zyz->y = 0.0; /* force Y to 0 */
  407. zyz->zp = atan2(-m.y.x, m.x.x);
  408. } else if (fabs(zyz->y - PM_PI) < ZYZ_Y_FUZZ) {
  409. zyz->z = 0.0;
  410. zyz->y = PM_PI; /* force Y to 180 */
  411. zyz->zp = atan2(m.y.x, -m.x.x);
  412. } else {
  413. zyz->z = atan2(m.z.y, m.z.x);
  414. zyz->zp = atan2(m.y.z, -m.x.z);
  415. }
  416. return pmErrno = 0;
  417. }
  418. int pmMatZyxConvert(PmRotationMatrix m, PmEulerZyx * zyx)
  419. {
  420. zyx->y = atan2(-m.x.z, pmSqrt(pmSq(m.x.x) + pmSq(m.x.y)));
  421. if (fabs(zyx->y - (2 * PM_PI)) < ZYX_Y_FUZZ) {
  422. zyx->z = 0.0;
  423. zyx->y = (2 * PM_PI); /* force it */
  424. zyx->x = atan2(m.y.x, m.y.y);
  425. } else if (fabs(zyx->y + (2 * PM_PI)) < ZYX_Y_FUZZ) {
  426. zyx->z = 0.0;
  427. zyx->y = -(2 * PM_PI); /* force it */
  428. zyx->x = -atan2(m.y.z, m.y.y);
  429. } else {
  430. zyx->z = atan2(m.x.y, m.x.x);
  431. zyx->x = atan2(m.y.z, m.z.z);
  432. }
  433. return pmErrno = 0;
  434. }
  435. int pmMatRpyConvert(PmRotationMatrix m, PmRpy * rpy)
  436. {
  437. rpy->p = atan2(-m.x.z, pmSqrt(pmSq(m.x.x) + pmSq(m.x.y)));
  438. if (fabs(rpy->p - (2 * PM_PI)) < RPY_P_FUZZ) {
  439. rpy->r = atan2(m.y.x, m.y.y);
  440. rpy->p = (2 * PM_PI); /* force it */
  441. rpy->y = 0.0;
  442. } else if (fabs(rpy->p + (2 * PM_PI)) < RPY_P_FUZZ) {
  443. rpy->r = -atan2(m.y.z, m.y.y);
  444. rpy->p = -(2 * PM_PI); /* force it */
  445. rpy->y = 0.0;
  446. } else {
  447. rpy->r = atan2(m.y.z, m.z.z);
  448. rpy->y = atan2(m.x.y, m.x.x);
  449. }
  450. return pmErrno = 0;
  451. }
  452. int pmZyzRotConvert(PmEulerZyz zyz, PmRotationVector * r)
  453. {
  454. #ifdef PM_PRINT_ERROR
  455. pmPrintError("error: pmZyzRotConvert not implemented\n");
  456. #endif
  457. return pmErrno = PM_IMPL_ERR;
  458. }
  459. int pmZyzQuatConvert(PmEulerZyz zyz, PmQuaternion * q)
  460. {
  461. PmRotationMatrix m;
  462. int r1, r2;
  463. /*! \todo FIXME-- need direct equations */
  464. r1 = pmZyzMatConvert(zyz, &m);
  465. r2 = pmMatQuatConvert(m, q);
  466. return pmErrno = r1 || r2 ? PM_NORM_ERR : 0;
  467. }
  468. int pmZyzMatConvert(PmEulerZyz zyz, PmRotationMatrix * m)
  469. {
  470. double sa, sb, sg;
  471. double ca, cb, cg;
  472. sa = sin(zyz.z);
  473. sb = sin(zyz.y);
  474. sg = sin(zyz.zp);
  475. ca = cos(zyz.z);
  476. cb = cos(zyz.y);
  477. cg = cos(zyz.zp);
  478. m->x.x = ca * cb * cg - sa * sg;
  479. m->y.x = -ca * cb * sg - sa * cg;
  480. m->z.x = ca * sb;
  481. m->x.y = sa * cb * cg + ca * sg;
  482. m->y.y = -sa * cb * sg + ca * cg;
  483. m->z.y = sa * sb;
  484. m->x.z = -sb * cg;
  485. m->y.z = sb * sg;
  486. m->z.z = cb;
  487. return pmErrno = 0;
  488. }
  489. int pmZyzRpyConvert(PmEulerZyz zyz, PmRpy * rpy)
  490. {
  491. #ifdef PM_PRINT_ERROR
  492. pmPrintError("error: pmZyzRpyConvert not implemented\n");
  493. #endif
  494. return pmErrno = PM_IMPL_ERR;
  495. }
  496. int pmZyxRotConvert(PmEulerZyx zyx, PmRotationVector * r)
  497. {
  498. PmRotationMatrix m;
  499. int r1, r2;
  500. /*! \todo FIXME-- need direct equations */
  501. r1 = pmZyxMatConvert(zyx, &m);
  502. r2 = pmMatRotConvert(m, r);
  503. return pmErrno = r1 || r2 ? PM_NORM_ERR : 0;
  504. }
  505. int pmZyxQuatConvert(PmEulerZyx zyx, PmQuaternion * q)
  506. {
  507. PmRotationMatrix m;
  508. int r1, r2;
  509. /*! \todo FIXME-- need direct equations */
  510. r1 = pmZyxMatConvert(zyx, &m);
  511. r2 = pmMatQuatConvert(m, q);
  512. return pmErrno = r1 || r2 ? PM_NORM_ERR : 0;
  513. }
  514. int pmZyxMatConvert(PmEulerZyx zyx, PmRotationMatrix * m)
  515. {
  516. double sa, sb, sg;
  517. double ca, cb, cg;
  518. sa = sin(zyx.z);
  519. sb = sin(zyx.y);
  520. sg = sin(zyx.x);
  521. ca = cos(zyx.z);
  522. cb = cos(zyx.y);
  523. cg = cos(zyx.x);
  524. m->x.x = ca * cb;
  525. m->y.x = ca * sb * sg - sa * cg;
  526. m->z.x = ca * sb * cg + sa * sg;
  527. m->x.y = sa * cb;
  528. m->y.y = sa * sb * sg + ca * cg;
  529. m->z.y = sa * sb * cg - ca * sg;
  530. m->x.z = -sb;
  531. m->y.z = cb * sg;
  532. m->z.z = cb * cg;
  533. return pmErrno = 0;
  534. }
  535. int pmZyxZyzConvert(PmEulerZyx zyx, PmEulerZyz * zyz)
  536. {
  537. #ifdef PM_PRINT_ERROR
  538. pmPrintError("error: pmZyxZyzConvert not implemented\n");
  539. #endif
  540. return pmErrno = PM_IMPL_ERR;
  541. }
  542. int pmZyxRpyConvert(PmEulerZyx zyx, PmRpy * rpy)
  543. {
  544. #ifdef PM_PRINT_ERROR
  545. pmPrintError("error: pmZyxRpyConvert not implemented\n");
  546. #endif
  547. return pmErrno = PM_IMPL_ERR;
  548. }
  549. int pmRpyRotConvert(PmRpy rpy, PmRotationVector * r)
  550. {
  551. PmQuaternion q;
  552. int r1, r2;
  553. q.s = q.x = q.y = q.z = 0.0;
  554. r->s = r->x = r->y = r->z = 0.0;
  555. r1 = pmRpyQuatConvert(rpy, &q);
  556. r2 = pmQuatRotConvert(q, r);
  557. return r1 || r2 ? pmErrno : 0;
  558. }
  559. int pmRpyQuatConvert(PmRpy rpy, PmQuaternion * q)
  560. {
  561. PmRotationMatrix m;
  562. int r1, r2;
  563. /*! \todo FIXME-- need direct equations */
  564. r1 = pmRpyMatConvert(rpy, &m);
  565. r2 = pmMatQuatConvert(m, q);
  566. return pmErrno = r1 || r2 ? PM_NORM_ERR : 0;
  567. }
  568. int pmRpyMatConvert(PmRpy rpy, PmRotationMatrix * m)
  569. {
  570. double sa, sb, sg;
  571. double ca, cb, cg;
  572. sa = sin(rpy.y);
  573. sb = sin(rpy.p);
  574. sg = sin(rpy.r);
  575. ca = cos(rpy.y);
  576. cb = cos(rpy.p);
  577. cg = cos(rpy.r);
  578. m->x.x = ca * cb;
  579. m->y.x = ca * sb * sg - sa * cg;
  580. m->z.x = ca * sb * cg + sa * sg;
  581. m->x.y = sa * cb;
  582. m->y.y = sa * sb * sg + ca * cg;
  583. m->z.y = sa * sb * cg - ca * sg;
  584. m->x.z = -sb;
  585. m->y.z = cb * sg;
  586. m->z.z = cb * cg;
  587. return pmErrno = 0;
  588. }
  589. int pmRpyZyzConvert(PmRpy rpy, PmEulerZyz * zyz)
  590. {
  591. #ifdef PM_PRINT_ERROR
  592. pmPrintError("error: pmRpyZyzConvert not implemented\n");
  593. #endif
  594. return pmErrno = PM_IMPL_ERR;
  595. }
  596. int pmRpyZyxConvert(PmRpy rpy, PmEulerZyx * zyx)
  597. {
  598. #ifdef PM_PRINT_ERROR
  599. pmPrintError("error: pmRpyZyxConvert not implemented\n");
  600. #endif
  601. return pmErrno = PM_IMPL_ERR;
  602. }
  603. int pmPoseHomConvert(PmPose p, PmHomogeneous * h)
  604. {
  605. int r1;
  606. h->tran = p.tran;
  607. r1 = pmQuatMatConvert(p.rot, &h->rot);
  608. return pmErrno = r1;
  609. }
  610. int pmHomPoseConvert(PmHomogeneous h, PmPose * p)
  611. {
  612. int r1;
  613. p->tran = h.tran;
  614. r1 = pmMatQuatConvert(h.rot, &p->rot);
  615. return pmErrno = r1;
  616. }
  617. /* PmCartesian functions */
  618. int pmCartCartCompare(PmCartesian v1, PmCartesian v2)
  619. {
  620. if (fabs(v1.x - v2.x) >= V_FUZZ ||
  621. fabs(v1.y - v2.y) >= V_FUZZ || fabs(v1.z - v2.z) >= V_FUZZ) {
  622. return 0;
  623. }
  624. return 1;
  625. }
  626. int pmCartCartDot(PmCartesian v1, PmCartesian v2, double *d)
  627. {
  628. *d = v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
  629. return pmErrno = 0;
  630. }
  631. int pmCartCartCross(PmCartesian v1, PmCartesian v2, PmCartesian * vout)
  632. {
  633. vout->x = v1.y * v2.z - v1.z * v2.y;
  634. vout->y = v1.z * v2.x - v1.x * v2.z;
  635. vout->z = v1.x * v2.y - v1.y * v2.x;
  636. return pmErrno = 0;
  637. }
  638. int pmCartMag(PmCartesian v, double *d)
  639. {
  640. *d = pmSqrt(pmSq(v.x) + pmSq(v.y) + pmSq(v.z));
  641. return pmErrno = 0;
  642. }
  643. int pmCartCartDisp(PmCartesian v1, PmCartesian v2, double *d)
  644. {
  645. *d = pmSqrt(pmSq(v2.x - v1.x) + pmSq(v2.y - v1.y) + pmSq(v2.z - v1.z));
  646. return pmErrno = 0;
  647. }
  648. int pmCartCartAdd(PmCartesian v1, PmCartesian v2, PmCartesian * vout)
  649. {
  650. vout->x = v1.x + v2.x;
  651. vout->y = v1.y + v2.y;
  652. vout->z = v1.z + v2.z;
  653. return pmErrno = 0;
  654. }
  655. int pmCartCartSub(PmCartesian v1, PmCartesian v2, PmCartesian * vout)
  656. {
  657. vout->x = v1.x - v2.x;
  658. vout->y = v1.y - v2.y;
  659. vout->z = v1.z - v2.z;
  660. return pmErrno = 0;
  661. }
  662. int pmCartScalMult(PmCartesian v1, double d, PmCartesian * vout)
  663. {
  664. vout->x = v1.x * d;
  665. vout->y = v1.y * d;
  666. vout->z = v1.z * d;
  667. return pmErrno = 0;
  668. }
  669. int pmCartScalDiv(PmCartesian v1, double d, PmCartesian * vout)
  670. {
  671. if (d == 0.0) {
  672. #ifdef PM_PRINT_ERROR
  673. pmPrintError("Divide by 0 in pmCartScalDiv\n");
  674. #endif
  675. vout->x = DBL_MAX;
  676. vout->y = DBL_MAX;
  677. vout->z = DBL_MAX;
  678. return pmErrno = PM_DIV_ERR;
  679. }
  680. vout->x = v1.x / d;
  681. vout->y = v1.y / d;
  682. vout->z = v1.z / d;
  683. return pmErrno = 0;
  684. }
  685. int pmCartNeg(PmCartesian v1, PmCartesian * vout)
  686. {
  687. vout->x = -v1.x;
  688. vout->y = -v1.y;
  689. vout->z = -v1.z;
  690. return pmErrno = 0;
  691. }
  692. int pmCartInv(PmCartesian v1, PmCartesian * vout)
  693. {
  694. double size_sq = pmSq(v1.x) + pmSq(v1.y) + pmSq(v1.z);
  695. if (size_sq == 0.0) {
  696. #ifdef PM_PRINT_ERROR
  697. pmPrintError("Zero vector in pmCartInv\n");
  698. #endif
  699. vout->x = DBL_MAX;
  700. vout->y = DBL_MAX;
  701. vout->z = DBL_MAX;
  702. return pmErrno = PM_NORM_ERR;
  703. }
  704. vout->x = v1.x / size_sq;
  705. vout->y = v1.y / size_sq;
  706. vout->z = v1.z / size_sq;
  707. return pmErrno = 0;
  708. }
  709. // This used to be called pmCartNorm.
  710. int pmCartUnit(PmCartesian v, PmCartesian * vout)
  711. {
  712. double size = pmSqrt(pmSq(v.x) + pmSq(v.y) + pmSq(v.z));
  713. if (size == 0.0) {
  714. #ifdef PM_PRINT_ERROR
  715. pmPrintError("Zero vector in pmCartUnit\n");
  716. #endif
  717. vout->x = DBL_MAX;
  718. vout->y = DBL_MAX;
  719. vout->z = DBL_MAX;
  720. return pmErrno = PM_NORM_ERR;
  721. }
  722. vout->x = v.x / size;
  723. vout->y = v.y / size;
  724. vout->z = v.z / size;
  725. return pmErrno = 0;
  726. }
  727. /*! \todo This is if 0'd out so we can find all the pmCartNorm calls that should
  728. be renamed pmCartUnit.
  729. Later we'll put this back. */
  730. #if 0
  731. int pmCartNorm(PmCartesian v, PmCartesian * vout)
  732. {
  733. vout->x = v.x;
  734. vout->y = v.y;
  735. vout->z = v.z;
  736. return pmErrno = 0;
  737. }
  738. #endif
  739. int pmCartIsNorm(PmCartesian v)
  740. {
  741. return pmSqrt(pmSq(v.x) + pmSq(v.y) + pmSq(v.z)) - 1.0 <
  742. UNIT_VEC_FUZZ ? 1 : 0;
  743. }
  744. int pmCartCartProj(PmCartesian v1, PmCartesian v2, PmCartesian * vout)
  745. {
  746. int r1, r2, r3;
  747. double d;
  748. r1 = pmCartUnit(v2, &v2);
  749. r2 = pmCartCartDot(v1, v2, &d);
  750. r3 = pmCartScalMult(v2, d, vout);
  751. return pmErrno = r1 || r2 || r3 ? PM_NORM_ERR : 0;
  752. }
  753. int pmCartPlaneProj(PmCartesian v, PmCartesian normal, PmCartesian * vout)
  754. {
  755. int r1, r2;
  756. PmCartesian par;
  757. r1 = pmCartCartProj(v, normal, &par);
  758. r2 = pmCartCartSub(v, par, vout);
  759. return pmErrno = r1 || r2 ? PM_NORM_ERR : 0;
  760. }
  761. /* angle-axis functions */
  762. int pmQuatAxisAngleMult(PmQuaternion q, PmAxis axis, double angle,
  763. PmQuaternion * pq)
  764. {
  765. double sh, ch;
  766. #ifdef PM_DEBUG
  767. if (!pmQuatIsNorm(q)) {
  768. #ifdef PM_PRINT_ERROR
  769. pmPrintError("error: non-unit quaternion in pmQuatAxisAngleMult\n");
  770. #endif
  771. return -1;
  772. }
  773. #endif
  774. angle *= 0.5;
  775. sincos(angle, &sh, &ch);
  776. switch (axis) {
  777. case PM_X:
  778. pq->s = ch * q.s - sh * q.x;
  779. pq->x = ch * q.x + sh * q.s;
  780. pq->y = ch * q.y + sh * q.z;
  781. pq->z = ch * q.z - sh * q.y;
  782. break;
  783. case PM_Y:
  784. pq->s = ch * q.s - sh * q.y;
  785. pq->x = ch * q.x - sh * q.z;
  786. pq->y = ch * q.y + sh * q.s;
  787. pq->z = ch * q.z + sh * q.x;
  788. break;
  789. case PM_Z:
  790. pq->s = ch * q.s - sh * q.z;
  791. pq->x = ch * q.x + sh * q.y;
  792. pq->y = ch * q.y - sh * q.x;
  793. pq->z = ch * q.z + sh * q.s;
  794. break;
  795. default:
  796. #ifdef PM_PRINT_ERROR
  797. pmPrintError("error: bad axis in pmQuatAxisAngleMult\n");
  798. #endif
  799. return -1;
  800. }
  801. if (pq->s < 0.0) {
  802. pq->s *= -1.0;
  803. pq->x *= -1.0;
  804. pq->y *= -1.0;
  805. pq->z *= -1.0;
  806. }
  807. return 0;
  808. }
  809. /* PmRotationVector functions */
  810. int pmRotScalMult(PmRotationVector r, double s, PmRotationVector * rout)
  811. {
  812. rout->s = r.s * s;
  813. rout->x = r.x;
  814. rout->y = r.y;
  815. rout->z = r.z;
  816. return pmErrno = 0;
  817. }
  818. int pmRotScalDiv(PmRotationVector r, double s, PmRotationVector * rout)
  819. {
  820. if (s == 0.0) {
  821. #ifdef PM_PRINT_ERROR
  822. pmPrintError("Divide by zero in pmRotScalDiv\n");
  823. #endif
  824. rout->s = DBL_MAX;
  825. rout->x = r.x;
  826. rout->y = r.y;
  827. rout->z = r.z;
  828. return pmErrno = PM_NORM_ERR;
  829. }
  830. rout->s = r.s / s;
  831. rout->x = r.x;
  832. rout->y = r.y;
  833. rout->z = r.z;
  834. return pmErrno = 0;
  835. }
  836. int pmRotIsNorm(PmRotationVector r)
  837. {
  838. if (fabs(r.s) < RS_FUZZ ||
  839. fabs(pmSqrt(pmSq(r.x) + pmSq(r.y) + pmSq(r.z))) - 1.0 < UNIT_VEC_FUZZ)
  840. {
  841. return 1;
  842. }
  843. return 0;
  844. }
  845. int pmRotNorm(PmRotationVector r, PmRotationVector * rout)
  846. {
  847. double size;
  848. size = pmSqrt(pmSq(r.x) + pmSq(r.y) + pmSq(r.z));
  849. if (fabs(r.s) < RS_FUZZ) {
  850. rout->s = 0.0;
  851. rout->x = 0.0;
  852. rout->y = 0.0;
  853. rout->z = 0.0;
  854. return pmErrno = 0;
  855. }
  856. if (size == 0.0) {
  857. #ifdef PM_PRINT_ERROR
  858. pmPrintError("error: pmRotNorm size is zero\n");
  859. #endif
  860. rout->s = 0.0;
  861. rout->x = 0.0;
  862. rout->y = 0.0;
  863. rout->z = 0.0;
  864. return pmErrno = PM_NORM_ERR;
  865. }
  866. rout->s = r.s;
  867. rout->x = r.x / size;
  868. rout->y = r.y / size;
  869. rout->z = r.z / size;
  870. return pmErrno = 0;
  871. }
  872. /* PmRotationMatrix functions */
  873. int pmMatNorm(PmRotationMatrix m, PmRotationMatrix * mout)
  874. {
  875. /*! \todo FIXME */
  876. *mout = m;
  877. #ifdef PM_PRINT_ERROR
  878. pmPrintError("error: pmMatNorm not implemented\n");
  879. #endif
  880. return pmErrno = PM_IMPL_ERR;
  881. }
  882. int pmMatIsNorm(PmRotationMatrix m)
  883. {
  884. PmCartesian u;
  885. pmCartCartCross(m.x, m.y, &u);
  886. return (pmCartIsNorm(m.x) &&
  887. pmCartIsNorm(m.y) && pmCartIsNorm(m.z) && pmCartCartCompare(u, m.z));
  888. }
  889. int pmMatInv(PmRotationMatrix m, PmRotationMatrix * mout)
  890. {
  891. /* inverse of a rotation matrix is the transpose */
  892. mout->x.x = m.x.x;
  893. mout->x.y = m.y.x;
  894. mout->x.z = m.z.x;
  895. mout->y.x = m.x.y;
  896. mout->y.y = m.y.y;
  897. mout->y.z = m.z.y;
  898. mout->z.x = m.x.z;
  899. mout->z.y = m.y.z;
  900. mout->z.z = m.z.z;
  901. return pmErrno = 0;
  902. }
  903. int pmMatCartMult(PmRotationMatrix m, PmCartesian v, PmCartesian * vout)
  904. {
  905. vout->x = m.x.x * v.x + m.y.x * v.y + m.z.x * v.z;
  906. vout->y = m.x.y * v.x + m.y.y * v.y + m.z.y * v.z;
  907. vout->z = m.x.z * v.x + m.y.z * v.y + m.z.z * v.z;
  908. return pmErrno = 0;
  909. }
  910. int pmMatMatMult(PmRotationMatrix m1, PmRotationMatrix m2,
  911. PmRotationMatrix * mout)
  912. {
  913. mout->x.x = m1.x.x * m2.x.x + m1.y.x * m2.x.y + m1.z.x * m2.x.z;
  914. mout->x.y = m1.x.y * m2.x.x + m1.y.y * m2.x.y + m1.z.y * m2.x.z;
  915. mout->x.z = m1.x.z * m2.x.x + m1.y.z * m2.x.y + m1.z.z * m2.x.z;
  916. mout->y.x = m1.x.x * m2.y.x + m1.y.x * m2.y.y + m1.z.x * m2.y.z;
  917. mout->y.y = m1.x.y * m2.y.x + m1.y.y * m2.y.y + m1.z.y * m2.y.z;
  918. mout->y.z = m1.x.z * m2.y.x + m1.y.z * m2.y.y + m1.z.z * m2.y.z;
  919. mout->z.x = m1.x.x * m2.z.x + m1.y.x * m2.z.y + m1.z.x * m2.z.z;
  920. mout->z.y = m1.x.y * m2.z.x + m1.y.y * m2.z.y + m1.z.y * m2.z.z;
  921. mout->z.z = m1.x.z * m2.z.x + m1.y.z * m2.z.y + m1.z.z * m2.z.z;
  922. return pmErrno = 0;
  923. }
  924. /* PmQuaternion functions */
  925. int pmQuatQuatCompare(PmQuaternion q1, PmQuaternion q2)
  926. {
  927. #ifdef PM_DEBUG
  928. if (!pmQuatIsNorm(q1) || !pmQuatIsNorm(q2)) {
  929. #ifdef PM_PRINT_ERROR
  930. pmPrintError("Bad quaternion in pmQuatQuatCompare\n");
  931. #endif
  932. }
  933. #endif
  934. if (fabs(q1.s - q2.s) < Q_FUZZ &&
  935. fabs(q1.x - q2.x) < Q_FUZZ &&
  936. fabs(q1.y - q2.y) < Q_FUZZ && fabs(q1.z - q2.z) < Q_FUZZ) {
  937. return 1;
  938. }
  939. /* note (0, x, y, z) = (0, -x, -y, -z) */
  940. if (fabs(q1.s) >= QS_FUZZ ||
  941. fabs(q1.x + q2.x) >= Q_FUZZ ||
  942. fabs(q1.y + q2.y) >= Q_FUZZ || fabs(q1.z + q2.z) >= Q_FUZZ) {
  943. return 0;
  944. }
  945. return 1;
  946. }
  947. int pmQuatMag(PmQuaternion q, double *d)
  948. {
  949. PmRotationVector r;
  950. int r1;
  951. if (0 == d) {
  952. return (pmErrno = PM_ERR);
  953. }
  954. r1 = pmQuatRotConvert(q, &r);
  955. *d = r.s;
  956. return pmErrno = r1;
  957. }
  958. int pmQuatNorm(PmQuaternion q1, PmQuaternion * qout)
  959. {
  960. double size = pmSqrt(pmSq(q1.s) + pmSq(q1.x) + pmSq(q1.y) + pmSq(q1.z));
  961. if (size == 0.0) {
  962. #ifdef PM_PRINT_ERROR
  963. pmPrintError("Bad quaternion in pmQuatNorm\n");
  964. #endif
  965. qout->s = 1;
  966. qout->x = 0;
  967. qout->y = 0;
  968. qout->z = 0;
  969. return pmErrno = PM_NORM_ERR;
  970. }
  971. if (q1.s >= 0.0) {
  972. qout->s = q1.s / size;
  973. qout->x = q1.x / size;
  974. qout->y = q1.y / size;
  975. qout->z = q1.z / size;
  976. return pmErrno = 0;
  977. } else {
  978. qout->s = -q1.s / size;
  979. qout->x = -q1.x / size;
  980. qout->y = -q1.y / size;
  981. qout->z = -q1.z / size;
  982. return pmErrno = 0;
  983. }
  984. }
  985. int pmQuatInv(PmQuaternion q1, PmQuaternion * qout)
  986. {
  987. if (qout == 0) {
  988. return pmErrno = PM_ERR;
  989. }
  990. qout->s = q1.s;
  991. qout->x = -q1.x;
  992. qout->y = -q1.y;
  993. qout->z = -q1.z;
  994. #ifdef PM_DEBUG
  995. if (!pmQuatIsNorm(q1)) {
  996. #ifdef PM_PRINT_ERROR
  997. pmPrintError("Bad quaternion in pmQuatInv\n");
  998. #endif
  999. return pmErrno = PM_NORM_ERR;
  1000. }
  1001. #endif
  1002. return pmErrno = 0;
  1003. }
  1004. int pmQuatIsNorm(PmQuaternion q1)
  1005. {
  1006. return (fabs(pmSq(q1.s) + pmSq(q1.x) + pmSq(q1.y) + pmSq(q1.z) - 1.0) <
  1007. UNIT_QUAT_FUZZ);
  1008. }
  1009. int pmQuatScalMult(PmQuaternion q, double s, PmQuaternion * qout)
  1010. {
  1011. /*! \todo FIXME-- need a native version; this goes through a rotation vector */
  1012. PmRotationVector r;
  1013. int r1, r2, r3;
  1014. r1 = pmQuatRotConvert(q, &r);
  1015. r2 = pmRotScalMult(r, s, &r);
  1016. r3 = pmRotQuatConvert(r, qout);
  1017. return pmErrno = (r1 || r2 || r3) ? PM_NORM_ERR : 0;
  1018. }
  1019. int pmQuatScalDiv(PmQuaternion q, double s, PmQuaternion * qout)
  1020. {
  1021. /*! \todo FIXME-- need a native version; this goes through a rotation vector */
  1022. PmRotationVector r;
  1023. int r1, r2, r3;
  1024. r1 = pmQuatRotConvert(q, &r);
  1025. r2 = pmRotScalDiv(r, s, &r);
  1026. r3 = pmRotQuatConvert(r, qout);
  1027. return pmErrno = (r1 || r2 || r3) ? PM_NORM_ERR : 0;
  1028. }
  1029. int pmQuatQuatMult(PmQuaternion q1, PmQuaternion q2, PmQuaternion * qout)
  1030. {
  1031. if (qout == 0) {
  1032. return pmErrno = PM_ERR;
  1033. }
  1034. qout->s = q1.s * q2.s - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z;
  1035. if (qout->s >= 0.0) {
  1036. qout->x = q1.s * q2.x + q1.x * q2.s + q1.y * q2.z - q1.z * q2.y;
  1037. qout->y = q1.s * q2.y - q1.x * q2.z + q1.y * q2.s + q1.z * q2.x;
  1038. qout->z = q1.s * q2.z + q1.x * q2.y - q1.y * q2.x + q1.z * q2.s;
  1039. } else {
  1040. qout->s *= -1;
  1041. qout->x = -q1.s * q2.x - q1.x * q2.s - q1.y * q2.z + q1.z * q2.y;
  1042. qout->y = -q1.s * q2.y + q1.x * q2.z - q1.y * q2.s - q1.z * q2.x;
  1043. qout->z = -q1.s * q2.z - q1.x * q2.y + q1.y * q2.x - q1.z * q2.s;
  1044. }
  1045. #ifdef PM_DEBUG
  1046. if (!pmQuatIsNorm(q1) || !pmQuatIsNorm(q2)) {
  1047. #ifdef PM_PRINT_ERROR
  1048. pmPrintError("Bad quaternion in pmQuatQuatMult\n");
  1049. #endif
  1050. return pmErrno = PM_NORM_ERR;
  1051. }
  1052. #endif
  1053. return pmErrno = 0;
  1054. }
  1055. int pmQuatCartMult(PmQuaternion q1, PmCartesian v2, PmCartesian * vout)
  1056. {
  1057. PmCartesian c;
  1058. c.x = q1.y * v2.z - q1.z * v2.y;
  1059. c.y = q1.z * v2.x - q1.x * v2.z;
  1060. c.z = q1.x * v2.y - q1.y * v2.x;
  1061. vout->x = v2.x + 2.0 * (q1.s * c.x + q1.y * c.z - q1.z * c.y);
  1062. vout->y = v2.y + 2.0 * (q1.s * c.y + q1.z * c.x - q1.x * c.z);
  1063. vout->z = v2.z + 2.0 * (q1.s * c.z + q1.x * c.y - q1.y * c.x);
  1064. #ifdef PM_DEBUG
  1065. if (!pmQuatIsNorm(q1)) {
  1066. #ifdef PM_PRINT_ERROR
  1067. pmPrintError("Bad quaternion in pmQuatCartMult\n");
  1068. #endif
  1069. return pmErrno = PM_NORM_ERR;
  1070. }
  1071. #endif
  1072. return pmErrno = 0;
  1073. }
  1074. /* PmPose functions*/
  1075. int pmPosePoseCompare(PmPose p1, PmPose p2)
  1076. {
  1077. #ifdef PM_DEBUG
  1078. if (!pmQuatIsNorm(p1.rot) || !pmQuatIsNorm(p2.rot)) {
  1079. #ifdef PM_PRINT_ERROR
  1080. pmPrintError("Bad quaternion in pmPosePoseCompare\n");
  1081. #endif
  1082. }
  1083. #endif
  1084. return pmErrno = (pmQuatQuatCompare(p1.rot, p2.rot) &&
  1085. pmCartCartCompare(p1.tran, p2.tran));
  1086. }
  1087. int pmPoseInv(PmPose p1, PmPose * p2)
  1088. {
  1089. int r1, r2;
  1090. #ifdef PM_DEBUG
  1091. if (!pmQuatIsNorm(p1.rot)) {
  1092. #ifdef PM_PRINT_ERROR
  1093. pmPrintError("Bad quaternion in pmPoseInv\n");
  1094. #endif
  1095. }
  1096. #endif
  1097. r1 = pmQuatInv(p1.rot, &p2->rot);
  1098. r2 = pmQuatCartMult(p2->rot, p1.tran, &p2->tran);
  1099. p2->tran.x *= -1.0;
  1100. p2->tran.y *= -1.0;
  1101. p2->tran.z *= -1.0;
  1102. return pmErrno = (r1 || r2) ? PM_NORM_ERR : 0;
  1103. }
  1104. int pmPoseCartMult(PmPose p1, PmCartesian v2, PmCartesian * vout)
  1105. {
  1106. int r1, r2;
  1107. #ifdef PM_DEBUG
  1108. if (!pmQuatIsNorm(p1.rot)) {
  1109. #ifdef PM_PRINT_ERROR
  1110. pmPrintError("Bad quaternion in pmPoseCartMult\n");
  1111. #endif
  1112. return pmErrno = PM_NORM_ERR;
  1113. }
  1114. #endif
  1115. r1 = pmQuatCartMult(p1.rot, v2, vout);
  1116. r2 = pmCartCartAdd(p1.tran, *vout, vout);
  1117. return pmErrno = (r1 || r2) ? PM_NORM_ERR : 0;
  1118. }
  1119. int pmPosePoseMult(PmPose p1, PmPose p2, PmPose * pout)
  1120. {
  1121. int r1, r2, r3;
  1122. #ifdef PM_DEBUG
  1123. if (!pmQuatIsNorm(p1.rot) || !pmQuatIsNorm(p2.rot)) {
  1124. #ifdef PM_PRINT_ERROR
  1125. pmPrintError("Bad quaternion in pmPosePoseMult\n");
  1126. #endif
  1127. return pmErrno = PM_NORM_ERR;
  1128. }
  1129. #endif
  1130. r1 = pmQuatCartMult(p1.rot, p2.tran, &pout->tran);
  1131. r2 = pmCartCartAdd(p1.tran, pout->tran, &pout->tran);
  1132. r3 = pmQuatQuatMult(p1.rot, p2.rot, &pout->rot);
  1133. return pmErrno = (r1 || r2 || r3) ? PM_NORM_ERR : 0;
  1134. }
  1135. /* homogeneous transform functions */
  1136. int pmHomInv(PmHomogeneous h1, PmHomogeneous * h2)
  1137. {
  1138. int r1, r2;
  1139. #ifdef PM_DEBUG
  1140. if (!pmMatIsNorm(h1.rot)) {
  1141. #ifdef PM_PRINT_ERROR
  1142. pmPrintError("Bad rotation matrix in pmHomInv\n");
  1143. #endif
  1144. }
  1145. #endif
  1146. r1 = pmMatInv(h1.rot, &h2->rot);
  1147. r2 = pmMatCartMult(h2->rot, h1.tran, &h2->tran);
  1148. h2->tran.x *= -1.0;
  1149. h2->tran.y *= -1.0;
  1150. h2->tran.z *= -1.0;
  1151. return pmErrno = (r1 || r2) ? PM_NORM_ERR : 0;
  1152. }
  1153. /* line functions */
  1154. int pmLineInit(PmLine * line, PmPose start, PmPose end)
  1155. {
  1156. int r1 = 0, r2 = 0, r3 = 0, r4 = 0, r5 = 0;
  1157. double tmag = 0.0;
  1158. double rmag = 0.0;
  1159. PmQuaternion startQuatInverse;
  1160. if (0 == line) {
  1161. return (pmErrno = PM_ERR);
  1162. }
  1163. r3 = pmQuatInv(start.rot, &startQuatInverse);
  1164. if (r3) {
  1165. return r3;
  1166. }
  1167. r4 = pmQuatQuatMult(startQuatInverse, end.rot, &line->qVec);
  1168. if (r4) {
  1169. return r4;
  1170. }
  1171. pmQuatMag(line->qVec, &rmag);
  1172. if (rmag > Q_FUZZ) {
  1173. r5 = pmQuatScalMult(line->qVec, 1 / rmag, &(line->qVec));
  1174. if (r5) {
  1175. return r5;
  1176. }
  1177. }
  1178. line->start = start;
  1179. line->end = end;
  1180. r1 = pmCartCartSub(end.tran, start.tran, &line->uVec);
  1181. if (r1) {
  1182. return r1;
  1183. }
  1184. pmCartMag(line->uVec, &tmag);
  1185. if (IS_FUZZ(tmag, CART_FUZZ)) {
  1186. line->uVec.x = 1.0;
  1187. line->uVec.y = 0.0;
  1188. line->uVec.z = 0.0;
  1189. } else {
  1190. r2 = pmCartUnit(line->uVec, &line->uVec);
  1191. }
  1192. line->tmag = tmag;
  1193. line->rmag = rmag;
  1194. line->tmag_zero = (line->tmag <= CART_FUZZ);
  1195. line->rmag_zero = (line->rmag <= Q_FUZZ);
  1196. /* return PM_NORM_ERR if uVec has been set to 1, 0, 0 */
  1197. return pmErrno = (r1 || r2 || r3 || r4 || r5) ? PM_NORM_ERR : 0;
  1198. }
  1199. int pmLinePoint(PmLine * line, double len, PmPose * point)
  1200. {
  1201. int r1 = 0, r2 = 0, r3 = 0, r4 = 0;
  1202. if (line->tmag_zero) {
  1203. point->tran = line->end.tran;
  1204. } else {
  1205. /* return start + len * uVec */
  1206. r1 = pmCartScalMult(line->uVec, len, &point->tran);
  1207. r2 = pmCartCartAdd(line->start.tran, point->tran, &point->tran);
  1208. }
  1209. if (line->rmag_zero) {
  1210. point->rot = line->end.rot;
  1211. } else {
  1212. if (line->tmag_zero) {
  1213. r3 = pmQuatScalMult(line->qVec, len, &point->rot);
  1214. } else {
  1215. r3 = pmQuatScalMult(line->qVec, len * line->rmag / line->tmag,
  1216. &point->rot);
  1217. }
  1218. r4 = pmQuatQuatMult(line->start.rot, point->rot, &point->rot);
  1219. }
  1220. return pmErrno = (r1 || r2 || r3 || r4) ? PM_NORM_ERR : 0;
  1221. }
  1222. /* circle functions */
  1223. /*
  1224. pmCircleInit() takes the defining parameters of a generalized circle
  1225. and sticks them in the structure. It also computes the radius and vectors
  1226. in the plane that are useful for other functions and that don't need
  1227. to be recomputed every time.
  1228. Note that the end can be placed arbitrarily, resulting in a combination of
  1229. spiral and helical motion. There is an overconstraint between the start,
  1230. center, and normal vector: the center vector and start vector are assumed
  1231. to be in the plane defined by the normal vector. If this is not true, then
  1232. it will be made true by moving the center vector onto the plane.
  1233. */
  1234. int pmCircleInit(PmCircle * circle,
  1235. PmPose start, PmPose end,
  1236. PmCartesian center, PmCartesian normal, int turn)
  1237. {
  1238. double dot;
  1239. PmCartesian rEnd;
  1240. PmCartesian v;
  1241. double d;
  1242. int r1;
  1243. #ifdef PM_DEBUG
  1244. if (0 == circle) {
  1245. #ifdef PM_PRINT_ERROR
  1246. pmPrintError("error: pmCircleInit cirle pointer is null\n");
  1247. #endif
  1248. return pmErrno = PM_ERR;
  1249. }
  1250. #endif
  1251. /* adjust center */
  1252. pmCartCartSub(start.tran, center, &v);
  1253. r1 = pmCartCartProj(v, normal, &v);
  1254. if (PM_NORM_ERR == r1) {
  1255. /* bad normal vector-- abort */
  1256. #ifdef PM_PRINT_ERROR
  1257. pmPrintError("error: pmCircleInit normal vector is 0\n");
  1258. #endif
  1259. return -1;
  1260. }
  1261. pmCartCartAdd(v, center, &circle->center);
  1262. /* normalize and redirect normal vector based on turns. If turn is less
  1263. than 0, point normal vector in other direction and make turn positive,
  1264. -1 -> 0, -2 -> 1, etc. */
  1265. pmCartUnit(normal, &circle->normal);
  1266. if (turn < 0) {
  1267. turn = -1 - turn;
  1268. pmCartScalMult(circle->normal, -1.0, &circle->normal);
  1269. }
  1270. /* radius */
  1271. pmCartCartDisp(start.tran, circle->center, &circle->radius);
  1272. /* vector in plane of circle from center to start, magnitude radius */
  1273. pmCartCartSub(start.tran, circle->center, &circle->rTan);
  1274. /* vector in plane of circle perpendicular to rTan, magnitude radius */
  1275. pmCartCartCross(circle->normal, circle->rTan, &circle->rPerp);
  1276. /* do rHelix, rEnd */
  1277. pmCartCartSub(end.tran, circle->center, &circle->rHelix);
  1278. pmCartPlaneProj(circle->rHelix, circle->normal, &rEnd);
  1279. pmCartMag(rEnd, &circle->spiral);
  1280. circle->spiral -= circle->radius;
  1281. pmCartCartSub(circle->rHelix, rEnd, &circle->rHelix);
  1282. pmCartUnit(rEnd, &rEnd);
  1283. /* unit vector in plane of circle perpendicular to rEnd */
  1284. /* utvOut: unit tangent vector outward */
  1285. pmCartCartCross(circle->normal, rEnd, &circle->utvOut);
  1286. /* utvIn: unit tangent vector inward */
  1287. pmCartUnit(circle->rPerp, &circle->utvIn);
  1288. pmCartScalMult(rEnd, circle->radius, &rEnd);
  1289. /* Patch for error spiral end same as spiral center */
  1290. pmCartMag(rEnd, &d);
  1291. if (d == 0.0) {
  1292. pmCartScalMult(circle->normal, DOUBLE_FUZZ, &v);
  1293. pmCartCartAdd(rEnd, v, &rEnd);
  1294. }
  1295. /* end patch 03-mar-1999 Dirk Maij */
  1296. /* angle */
  1297. pmCartCartDot(circle->rTan, rEnd, &dot);
  1298. dot = dot / (circle->radius * circle->radius);
  1299. if (dot > 1.0) {
  1300. circle->angle = 0.0;
  1301. } else if (dot < -1.0) {
  1302. circle->angle = PM_PI;
  1303. } else {
  1304. circle->angle = acos(dot);
  1305. }
  1306. /* now angle is in range 0..PI . Check if cross is antiparallel to
  1307. normal. If so, true angle is between PI..2PI. Need to subtract from
  1308. 2PI. */
  1309. pmCartCartCross(circle->rTan, rEnd, &v);
  1310. pmCartCartDot(v, circle->normal, &d);
  1311. if (d < 0.0) {
  1312. circle->angle = PM_2_PI - circle->angle;
  1313. }
  1314. if (circle->angle > -(CIRCLE_FUZZ) && circle->angle < (CIRCLE_FUZZ)) {
  1315. circle->angle = PM_2_PI;
  1316. }
  1317. /* now add more angle for multi turns */
  1318. if (turn > 0) {
  1319. circle->angle += turn * 2.0 * PM_PI;
  1320. }
  1321. /* if 0'ed out while not debugging*/
  1322. #if 0
  1323. printf("\n\n");
  1324. printf("pmCircleInit:\n");
  1325. printf(" \t start : \t{x=%9.9f, y=%9.9f, z=%9.9f}\n",
  1326. start.tran.x, start.tran.y, start.tran.z);
  1327. printf(" \t end : \t{x=%9.9f, y=%9.9f, z=%9.9f}\n",
  1328. end.tran.x, end.tran.y, end.tran.z);
  1329. printf(" \t center : \t{x=%9.9f, y=%9.9f, z=%9.9f}\n",
  1330. center.x, center.y, center.z);
  1331. printf(" \t normal : \t{x=%9.9f, y=%9.9f, z=%9.9f}\n",
  1332. normal.x, normal.y, normal.z);
  1333. printf(" \t rEnd : \t{x=%9.9f, y=%9.9f, z=%9.9f}\n",
  1334. rEnd.x, rEnd.y, rEnd.z);
  1335. printf(" \t turn=%d\n", turn);
  1336. printf(" \t dot=%9.9f\n", dot);
  1337. printf(" \t d=%9.9f\n", d);
  1338. printf(" \t circle \t{angle=%9.9f, radius=%9.9f, spiral=%9.9f}\n",
  1339. circle->angle, circle->radius, circle->spiral);
  1340. printf(" \t circle->normal : \t{x=%9.9f, y=%9.9f, z=%9.9f}\n",
  1341. circle->normal.x, circle->normal.y, circle->normal.z);
  1342. printf(" \t circle->center : \t{x=%9.9f, y=%9.9f, z=%9.9f}\n",
  1343. circle->center.x, circle->center.y, circle->center.z);
  1344. printf(" \t circle->rTan : \t{x=%9.9f, y=%9.9f, z=%9.9f}\n",
  1345. circle->rTan.x, circle->rTan.y, circle->rTan.z);
  1346. printf(" \t circle->rPerp : \t{x=%9.9f, y=%9.9f, z=%9.9f}\n",
  1347. circle->rPerp.x, circle->rPerp.y, circle->rPerp.z);
  1348. printf(" \t circle->rHelix : \t{x=%9.9f, y=%9.9f, z=%9.9f}\n",
  1349. circle->rHelix.x, circle->rHelix.y, circle->rHelix.z);
  1350. printf("\n\n");
  1351. #endif
  1352. return pmErrno = 0;
  1353. }
  1354. /*
  1355. pmCirclePoint() returns the point at the given angle along
  1356. the circle. If the circle is a helix or spiral or combination, the
  1357. point will include interpolation off the actual circle.
  1358. */
  1359. int pmCirclePoint(PmCircle * circle, double angle, PmPose * point)
  1360. {
  1361. PmCartesian par, perp;
  1362. double scale;
  1363. #ifdef PM_DEBUG
  1364. if (0 == circle || 0 == point) {
  1365. #ifdef PM_PRINT_ERROR
  1366. pmPrintError
  1367. ("error: pmCirclePoint circle or point pointer is null\n");
  1368. #endif
  1369. return pmErrno = PM_ERR;
  1370. }
  1371. #endif
  1372. /* compute components rel to center */
  1373. pmCartScalMult(circle->rTan, cos(angle), &par);
  1374. pmCartScalMult(circle->rPerp, sin(angle), &perp);
  1375. /* add to get radius vector rel to center */
  1376. pmCartCartAdd(par, perp, &point->tran);
  1377. /* get scale for spiral, helix interpolation */
  1378. if (circle->angle == 0.0) {
  1379. #ifdef PM_PRINT_ERROR
  1380. pmPrintError("error: pmCirclePoint angle is zero\n");
  1381. #endif
  1382. return pmErrno = PM_DIV_ERR;
  1383. }
  1384. scale = angle / circle->angle;
  1385. /* add scaled vector in radial dir for spiral */
  1386. pmCartUnit(point->tran, &par);
  1387. pmCartScalMult(par, scale * circle->spiral, &par);
  1388. pmCartCartAdd(point->tran, par, &point->tran);
  1389. /* add scaled vector in helix dir */
  1390. pmCartScalMult(circle->rHelix, scale, &perp);
  1391. pmCartCartAdd(point->tran, perp, &point->tran);
  1392. /* add to center vector for final result */
  1393. pmCartCartAdd(circle->center, point->tran, &point->tran);
  1394. return pmErrno = 0;
  1395. }