_posemath.c
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 17 #if defined(PM_PRINT_ERROR) && defined(rtai) 18 #undef PM_PRINT_ERROR 19 #endif 20 21 #if defined(PM_DEBUG) && defined(rtai) 22 #undef PM_DEBUG 23 #endif 24 25 #ifdef PM_PRINT_ERROR 26 #define PM_DEBUG /* have to have debug with printing */ 27 #include <stdio.h> 28 #include <stdarg.h> 29 #endif 30 #include "posemath.h" 31 32 #include "rtapi_math.h" 33 #include <float.h> 34 35 #include "sincos.h" 36 37 /* global error number */ 38 int pmErrno = 0; 39 40 #ifdef PM_PRINT_ERROR 41 42 void pmPrintError(const char *fmt, ...) 43 { 44 va_list args; 45 46 va_start(args, fmt); 47 vfprintf(stderr, fmt, args); 48 va_end(args); 49 } 50 51 /* error printing function */ 52 void pmPerror(const char *s) 53 { 54 char *pmErrnoString; 55 56 switch (pmErrno) { 57 case 0: 58 /* no error */ 59 return; 60 61 case PM_ERR: 62 pmErrnoString = "unspecified error"; 63 break; 64 65 case PM_IMPL_ERR: 66 pmErrnoString = "not implemented"; 67 break; 68 69 case PM_NORM_ERR: 70 pmErrnoString = "expected normalized value"; 71 break; 72 73 case PM_DIV_ERR: 74 pmErrnoString = "divide by zero"; 75 break; 76 77 default: 78 pmErrnoString = "unassigned error"; 79 break; 80 } 81 82 if (s != 0 && s[0] != 0) { 83 fprintf(stderr, "%s: %s\n", s, pmErrnoString); 84 } else { 85 fprintf(stderr, "%s\n", pmErrnoString); 86 } 87 } 88 89 #endif /* PM_PRINT_ERROR */ 90 91 /* fuzz checker */ 92 #define IS_FUZZ(a,fuzz) (fabs(a) < (fuzz) ? 1 : 0) 93 94 /* Pose Math Basis Functions */ 95 96 /* Scalar functions */ 97 98 double pmSqrt(double x) 99 { 100 if (x > 0.0) { 101 return sqrt(x); 102 } 103 104 if (x > SQRT_FUZZ) { 105 return 0.0; 106 } 107 #ifdef PM_PRINT_ERROR 108 pmPrintError("sqrt of large negative number\n"); 109 #endif 110 111 return 0.0; 112 } 113 114 /* Translation rep conversion functions */ 115 116 int pmCartSphConvert(PmCartesian const * const v, PmSpherical * const s) 117 { 118 double _r; 119 120 s->theta = atan2(v->y, v->x); 121 s->r = pmSqrt(pmSq(v->x) + pmSq(v->y) + pmSq(v->z)); 122 _r = pmSqrt(pmSq(v->x) + pmSq(v->y)); 123 s->phi = atan2(_r, v->z); 124 125 return pmErrno = 0; 126 } 127 128 int pmCartCylConvert(PmCartesian const * const v, PmCylindrical * const c) 129 { 130 c->theta = atan2(v->y, v->x); 131 c->r = pmSqrt(pmSq(v->x) + pmSq(v->y)); 132 c->z = v->z; 133 134 return pmErrno = 0; 135 } 136 137 int pmSphCartConvert(PmSpherical const * const s, PmCartesian * const v) 138 { 139 double _r; 140 141 _r = s->r * sin(s->phi); 142 v->z = s->r * cos(s->phi); 143 v->x = _r * cos(s->theta); 144 v->y = _r * sin(s->theta); 145 146 return pmErrno = 0; 147 } 148 149 int pmSphCylConvert(PmSpherical const * const s, PmCylindrical * const c) 150 { 151 c->theta = s->theta; 152 c->r = s->r * cos(s->phi); 153 c->z = s->r * sin(s->phi); 154 return pmErrno = 0; 155 } 156 157 int pmCylCartConvert(PmCylindrical const * const c, PmCartesian * const v) 158 { 159 v->x = c->r * cos(c->theta); 160 v->y = c->r * sin(c->theta); 161 v->z = c->z; 162 return pmErrno = 0; 163 } 164 165 int pmCylSphConvert(PmCylindrical const * const c, PmSpherical * const s) 166 { 167 s->theta = c->theta; 168 s->r = pmSqrt(pmSq(c->r) + pmSq(c->z)); 169 s->phi = atan2(c->z, c->r); 170 return pmErrno = 0; 171 } 172 173 /* Rotation rep conversion functions */ 174 175 int pmAxisAngleQuatConvert(PmAxis axis, double a, PmQuaternion * const q) 176 { 177 double sh; 178 179 a *= 0.5; 180 sincos(a, &sh, &(q->s)); 181 182 switch (axis) { 183 case PM_X: 184 q->x = sh; 185 q->y = 0.0; 186 q->z = 0.0; 187 break; 188 189 case PM_Y: 190 q->x = 0.0; 191 q->y = sh; 192 q->z = 0.0; 193 break; 194 195 case PM_Z: 196 q->x = 0.0; 197 q->y = 0.0; 198 q->z = sh; 199 break; 200 201 default: 202 #ifdef PM_PRINT_ERROR 203 pmPrintError("error: bad axis in pmAxisAngleQuatConvert\n"); 204 #endif 205 return -1; 206 } 207 208 if (q->s < 0.0) { 209 q->s *= -1.0; 210 q->x *= -1.0; 211 q->y *= -1.0; 212 q->z *= -1.0; 213 } 214 215 return 0; 216 } 217 218 int pmRotQuatConvert(PmRotationVector const * const r, PmQuaternion * const q) 219 { 220 double sh; 221 222 #ifdef PM_DEBUG 223 /* make sure r is normalized */ 224 //FIXME breaks const promise 225 PmRotationVector r_raw = *r; 226 if (0 != pmRotNorm(&r_raw, r)) { 227 #ifdef PM_PRINT_ERROR 228 pmPrintError 229 ("error: pmRotQuatConvert rotation vector not normalized\n"); 230 #endif 231 return pmErrno = PM_NORM_ERR; 232 } 233 #endif 234 235 if (pmClose(r->s, 0.0, QS_FUZZ)) { 236 q->s = 1.0; 237 q->x = q->y = q->z = 0.0; 238 239 return pmErrno = 0; 240 } 241 242 sincos(r->s / 2.0, &sh, &(q->s)); 243 244 if (q->s >= 0.0) { 245 q->x = r->x * sh; 246 q->y = r->y * sh; 247 q->z = r->z * sh; 248 } else { 249 q->s *= -1; 250 q->x = -r->x * sh; 251 q->y = -r->y * sh; 252 q->z = -r->z * sh; 253 } 254 255 return pmErrno = 0; 256 } 257 258 int pmRotMatConvert(PmRotationVector const * const r, PmRotationMatrix * const m) 259 { 260 double s, c, omc; 261 262 #ifdef PM_DEBUG 263 if (!pmRotIsNorm(r)) { 264 #ifdef PM_PRINT_ERROR 265 pmPrintError("Bad vector in pmRotMatConvert\n"); 266 #endif 267 return pmErrno = PM_NORM_ERR; 268 } 269 #endif 270 271 sincos(r->s, &s, &c); 272 273 /* from space book */ 274 m->x.x = c + pmSq(r->x) * (omc = 1 - c); /* omc = One Minus Cos */ 275 m->y.x = -r->z * s + r->x * r->y * omc; 276 m->z.x = r->y * s + r->x * r->z * omc; 277 278 m->x.y = r->z * s + r->y * r->x * omc; 279 m->y.y = c + pmSq(r->y) * omc; 280 m->z.y = -r->x * s + r->y * r->z * omc; 281 282 m->x.z = -r->y * s + r->z * r->x * omc; 283 m->y.z = r->x * s + r->z * r->y * omc; 284 m->z.z = c + pmSq(r->z) * omc; 285 286 return pmErrno = 0; 287 } 288 289 int pmRotZyzConvert(PmRotationVector const * const r, PmEulerZyz * const zyz) 290 { 291 #ifdef PM_DEBUG 292 #ifdef PM_PRINT_ERROR 293 pmPrintError("error: pmRotZyzConvert not implemented\n"); 294 #endif 295 return pmErrno = PM_IMPL_ERR; 296 #else 297 return PM_IMPL_ERR; 298 #endif 299 } 300 301 int pmRotZyxConvert(PmRotationVector const * const r, PmEulerZyx * const zyx) 302 { 303 PmRotationMatrix m; 304 int r1, r2; 305 306 r1 = pmRotMatConvert(r, &m); 307 r2 = pmMatZyxConvert(&m, zyx); 308 309 return pmErrno = r1 || r2 ? PM_NORM_ERR : 0; 310 } 311 312 int pmRotRpyConvert(PmRotationVector const * const r, PmRpy * const rpy) 313 { 314 PmQuaternion q; 315 int r1, r2; 316 317 q.s = q.x = q.y = q.z = 0.0; 318 319 r1 = pmRotQuatConvert(r, &q); 320 r2 = pmQuatRpyConvert(&q, rpy); 321 322 return r1 || r2 ? pmErrno : 0; 323 } 324 325 int pmQuatRotConvert(PmQuaternion const * const q, PmRotationVector * const r) 326 { 327 double sh; 328 329 #ifdef PM_DEBUG 330 if (!pmQuatIsNorm(q)) { 331 #ifdef PM_PRINT_ERROR 332 pmPrintError("Bad quaternion in pmQuatRotConvert\n"); 333 #endif 334 return pmErrno = PM_NORM_ERR; 335 } 336 #endif 337 if (r == 0) { 338 return (pmErrno = PM_ERR); 339 } 340 341 sh = pmSqrt(pmSq(q->x) + pmSq(q->y) + pmSq(q->z)); 342 343 if (sh > QSIN_FUZZ) { 344 r->s = 2.0 * atan2(sh, q->s); 345 r->x = q->x / sh; 346 r->y = q->y / sh; 347 r->z = q->z / sh; 348 } else { 349 r->s = 0.0; 350 r->x = 0.0; 351 r->y = 0.0; 352 r->z = 0.0; 353 } 354 355 return pmErrno = 0; 356 } 357 358 int pmQuatMatConvert(PmQuaternion const * const q, PmRotationMatrix * const m) 359 { 360 #ifdef PM_DEBUG 361 if (!pmQuatIsNorm(q)) { 362 #ifdef PM_PRINT_ERROR 363 pmPrintError("Bad quaternion in pmQuatMatConvert\n"); 364 #endif 365 return pmErrno = PM_NORM_ERR; 366 } 367 #endif 368 369 /* from space book where e1=q->x e2=q->y e3=q->z e4=q->s */ 370 m->x.x = 1.0 - 2.0 * (pmSq(q->y) + pmSq(q->z)); 371 m->y.x = 2.0 * (q->x * q->y - q->z * q->s); 372 m->z.x = 2.0 * (q->z * q->x + q->y * q->s); 373 374 m->x.y = 2.0 * (q->x * q->y + q->z * q->s); 375 m->y.y = 1.0 - 2.0 * (pmSq(q->z) + pmSq(q->x)); 376 m->z.y = 2.0 * (q->y * q->z - q->x * q->s); 377 378 m->x.z = 2.0 * (q->z * q->x - q->y * q->s); 379 m->y.z = 2.0 * (q->y * q->z + q->x * q->s); 380 m->z.z = 1.0 - 2.0 * (pmSq(q->x) + pmSq(q->y)); 381 382 return pmErrno = 0; 383 } 384 385 int pmQuatZyzConvert(PmQuaternion const * const q, PmEulerZyz * const zyz) 386 { 387 PmRotationMatrix m; 388 int r1, r2; 389 390 /*! \todo FIXME-- need direct equations */ 391 r1 = pmQuatMatConvert(q, &m); 392 r2 = pmMatZyzConvert(&m, zyz); 393 394 return pmErrno = r1 || r2 ? PM_NORM_ERR : 0; 395 } 396 397 int pmQuatZyxConvert(PmQuaternion const * const q, PmEulerZyx * const zyx) 398 { 399 PmRotationMatrix m; 400 int r1, r2; 401 402 /*! \todo FIXME-- need direct equations */ 403 r1 = pmQuatMatConvert(q, &m); 404 r2 = pmMatZyxConvert(&m, zyx); 405 406 return pmErrno = r1 || r2 ? PM_NORM_ERR : 0; 407 } 408 409 int pmQuatRpyConvert(PmQuaternion const * const q, PmRpy * const rpy) 410 { 411 PmRotationMatrix m; 412 int r1, r2; 413 414 /*! \todo FIXME-- need direct equations */ 415 r1 = pmQuatMatConvert(q, &m); 416 r2 = pmMatRpyConvert(&m, rpy); 417 418 return pmErrno = r1 || r2 ? PM_NORM_ERR : 0; 419 } 420 421 int pmMatRotConvert(PmRotationMatrix const * const m, PmRotationVector * const r) 422 { 423 PmQuaternion q; 424 int r1, r2; 425 426 /*! \todo FIXME-- need direct equations */ 427 r1 = pmMatQuatConvert(m, &q); 428 r2 = pmQuatRotConvert(&q, r); 429 430 return pmErrno = r1 || r2 ? PM_NORM_ERR : 0; 431 } 432 433 int pmMatQuatConvert(PmRotationMatrix const * const m, PmQuaternion * const q) 434 { 435 /* 436 from Stephe's "space" book e1 = (c32 - c23) / 4*e4 e2 = (c13 - c31) / 437 4*e4 e3 = (c21 - c12) / 4*e4 e4 = sqrt(1 + c11 + c22 + c33) / 2 438 439 if e4 == 0 e1 = sqrt(1 + c11 - c33 - c22) / 2 e2 = sqrt(1 + c22 - c33 440 - c11) / 2 e3 = sqrt(1 + c33 - c11 - c22) / 2 to determine whether to 441 take the positive or negative sqrt value since e4 == 0 indicates a 442 180* rotation then (0 x y z) = (0 -x -y -z). Thus some generallities 443 can be used: 1) find which of e1, e2, or e3 has the largest magnitude 444 and leave it pos. 2) if e1 is largest then if c21 < 0 then take the 445 negative for e2 if c31 < 0 then take the negative for e3 3) else if e2 446 is largest then if c21 < 0 then take the negative for e1 if c32 < 0 447 then take the negative for e3 4) else if e3 is larget then if c31 < 0 448 then take the negative for e1 if c32 < 0 then take the negative for e2 449 450 Note: c21 in the space book is m->x.y in this C code */ 451 452 double a; 453 454 #ifdef PM_DEBUG 455 if (!pmMatIsNorm(m)) { 456 #ifdef PM_PRINT_ERROR 457 pmPrintError("Bad matrix in pmMatQuatConvert\n"); 458 #endif 459 return pmErrno = PM_NORM_ERR; 460 } 461 #endif 462 463 q->s = 0.5 * pmSqrt(1.0 + m->x.x + m->y.y + m->z.z); 464 465 if (fabs(q->s) > QS_FUZZ) { 466 q->x = (m->y.z - m->z.y) / (a = 4 * q->s); 467 q->y = (m->z.x - m->x.z) / a; 468 q->z = (m->x.y - m->y.x) / a; 469 } else { 470 q->s = 0; 471 q->x = pmSqrt(1.0 + m->x.x - m->y.y - m->z.z) / 2.0; 472 q->y = pmSqrt(1.0 + m->y.y - m->x.x - m->z.z) / 2.0; 473 q->z = pmSqrt(1.0 + m->z.z - m->y.y - m->x.x) / 2.0; 474 475 if (q->x > q->y && q->x > q->z) { 476 if (m->x.y < 0.0) { 477 q->y *= -1; 478 } 479 if (m->x.z < 0.0) { 480 q->z *= -1; 481 } 482 } else if (q->y > q->z) { 483 if (m->x.y < 0.0) { 484 q->x *= -1; 485 } 486 if (m->y.z < 0.0) { 487 q->z *= -1; 488 } 489 } else { 490 if (m->x.z < 0.0) { 491 q->x *= -1; 492 } 493 if (m->y.z < 0.0) { 494 q->y *= -1; 495 } 496 } 497 } 498 499 return pmQuatNorm(q, q); 500 } 501 502 int pmMatZyzConvert(PmRotationMatrix const * const m, PmEulerZyz * const zyz) 503 { 504 zyz->y = atan2(pmSqrt(pmSq(m->x.z) + pmSq(m->y.z)), m->z.z); 505 506 if (fabs(zyz->y) < ZYZ_Y_FUZZ) { 507 zyz->z = 0.0; 508 zyz->y = 0.0; /* force Y to 0 */ 509 zyz->zp = atan2(-m->y.x, m->x.x); 510 } else if (fabs(zyz->y - PM_PI) < ZYZ_Y_FUZZ) { 511 zyz->z = 0.0; 512 zyz->y = PM_PI; /* force Y to 180 */ 513 zyz->zp = atan2(m->y.x, -m->x.x); 514 } else { 515 zyz->z = atan2(m->z.y, m->z.x); 516 zyz->zp = atan2(m->y.z, -m->x.z); 517 } 518 519 return pmErrno = 0; 520 } 521 522 int pmMatZyxConvert(PmRotationMatrix const * const m, PmEulerZyx * const zyx) 523 { 524 zyx->y = atan2(-m->x.z, pmSqrt(pmSq(m->x.x) + pmSq(m->x.y))); 525 526 if (fabs(zyx->y - PM_PI_2) < ZYX_Y_FUZZ) { 527 zyx->z = 0.0; 528 zyx->y = PM_PI_2; /* force it */ 529 zyx->x = atan2(m->y.x, m->y.y); 530 } else if (fabs(zyx->y + PM_PI_2) < ZYX_Y_FUZZ) { 531 zyx->z = 0.0; 532 zyx->y = -PM_PI_2; /* force it */ 533 zyx->x = -atan2(m->y.z, m->y.y); 534 } else { 535 zyx->z = atan2(m->x.y, m->x.x); 536 zyx->x = atan2(m->y.z, m->z.z); 537 } 538 539 return pmErrno = 0; 540 } 541 542 int pmMatRpyConvert(PmRotationMatrix const * const m, PmRpy * const rpy) 543 { 544 rpy->p = atan2(-m->x.z, pmSqrt(pmSq(m->x.x) + pmSq(m->x.y))); 545 546 if (fabs(rpy->p - PM_PI_2) < RPY_P_FUZZ) { 547 rpy->r = atan2(m->y.x, m->y.y); 548 rpy->p = PM_PI_2; /* force it */ 549 rpy->y = 0.0; 550 } else if (fabs(rpy->p + PM_PI_2) < RPY_P_FUZZ) { 551 rpy->r = -atan2(m->y.x, m->y.y); 552 rpy->p = -PM_PI_2; /* force it */ 553 rpy->y = 0.0; 554 } else { 555 rpy->r = atan2(m->y.z, m->z.z); 556 rpy->y = atan2(m->x.y, m->x.x); 557 } 558 559 return pmErrno = 0; 560 } 561 562 int pmZyzRotConvert(PmEulerZyz const * const zyz, PmRotationVector * const r) 563 { 564 #ifdef PM_PRINT_ERROR 565 pmPrintError("error: pmZyzRotConvert not implemented\n"); 566 #endif 567 return pmErrno = PM_IMPL_ERR; 568 } 569 570 int pmZyzQuatConvert(PmEulerZyz const * const zyz, PmQuaternion * const q) 571 { 572 PmRotationMatrix m; 573 int r1, r2; 574 575 /*! \todo FIXME-- need direct equations */ 576 r1 = pmZyzMatConvert(zyz, &m); 577 r2 = pmMatQuatConvert(&m, q); 578 579 return pmErrno = r1 || r2 ? PM_NORM_ERR : 0; 580 } 581 582 int pmZyzMatConvert(PmEulerZyz const * const zyz, PmRotationMatrix * const m) 583 { 584 double sa, sb, sg; 585 double ca, cb, cg; 586 587 sa = sin(zyz->z); 588 sb = sin(zyz->y); 589 sg = sin(zyz->zp); 590 591 ca = cos(zyz->z); 592 cb = cos(zyz->y); 593 cg = cos(zyz->zp); 594 595 m->x.x = ca * cb * cg - sa * sg; 596 m->y.x = -ca * cb * sg - sa * cg; 597 m->z.x = ca * sb; 598 599 m->x.y = sa * cb * cg + ca * sg; 600 m->y.y = -sa * cb * sg + ca * cg; 601 m->z.y = sa * sb; 602 603 m->x.z = -sb * cg; 604 m->y.z = sb * sg; 605 m->z.z = cb; 606 607 return pmErrno = 0; 608 } 609 610 int pmZyzRpyConvert(PmEulerZyz const * const zyz, PmRpy * const rpy) 611 { 612 #ifdef PM_PRINT_ERROR 613 pmPrintError("error: pmZyzRpyConvert not implemented\n"); 614 #endif 615 return pmErrno = PM_IMPL_ERR; 616 } 617 618 int pmZyxRotConvert(PmEulerZyx const * const zyx, PmRotationVector * const r) 619 { 620 PmRotationMatrix m; 621 int r1, r2; 622 623 /*! \todo FIXME-- need direct equations */ 624 r1 = pmZyxMatConvert(zyx, &m); 625 r2 = pmMatRotConvert(&m, r); 626 627 return pmErrno = r1 || r2 ? PM_NORM_ERR : 0; 628 } 629 630 int pmZyxQuatConvert(PmEulerZyx const * const zyx, PmQuaternion * const q) 631 { 632 PmRotationMatrix m; 633 int r1, r2; 634 635 /*! \todo FIXME-- need direct equations */ 636 r1 = pmZyxMatConvert(zyx, &m); 637 r2 = pmMatQuatConvert(&m, q); 638 639 return pmErrno = r1 || r2 ? PM_NORM_ERR : 0; 640 } 641 642 int pmZyxMatConvert(PmEulerZyx const * const zyx, PmRotationMatrix * const m) 643 { 644 double sa, sb, sg; 645 double ca, cb, cg; 646 647 sa = sin(zyx->z); 648 sb = sin(zyx->y); 649 sg = sin(zyx->x); 650 651 ca = cos(zyx->z); 652 cb = cos(zyx->y); 653 cg = cos(zyx->x); 654 655 m->x.x = ca * cb; 656 m->y.x = ca * sb * sg - sa * cg; 657 m->z.x = ca * sb * cg + sa * sg; 658 659 m->x.y = sa * cb; 660 m->y.y = sa * sb * sg + ca * cg; 661 m->z.y = sa * sb * cg - ca * sg; 662 663 m->x.z = -sb; 664 m->y.z = cb * sg; 665 m->z.z = cb * cg; 666 667 return pmErrno = 0; 668 } 669 670 int pmZyxZyzConvert(PmEulerZyx const * const zyx, PmEulerZyz * const zyz) 671 { 672 #ifdef PM_PRINT_ERROR 673 pmPrintError("error: pmZyxZyzConvert not implemented\n"); 674 #endif 675 return pmErrno = PM_IMPL_ERR; 676 } 677 678 int pmZyxRpyConvert(PmEulerZyx const * const zyx, PmRpy * const rpy) 679 { 680 #ifdef PM_PRINT_ERROR 681 pmPrintError("error: pmZyxRpyConvert not implemented\n"); 682 #endif 683 return pmErrno = PM_IMPL_ERR; 684 } 685 686 int pmRpyRotConvert(PmRpy const * const rpy, PmRotationVector * const r) 687 { 688 PmQuaternion q; 689 int r1, r2; 690 691 q.s = q.x = q.y = q.z = 0.0; 692 r->s = r->x = r->y = r->z = 0.0; 693 694 r1 = pmRpyQuatConvert(rpy, &q); 695 r2 = pmQuatRotConvert(&q, r); 696 697 return r1 || r2 ? pmErrno : 0; 698 } 699 700 int pmRpyQuatConvert(PmRpy const * const rpy, PmQuaternion * const q) 701 { 702 PmRotationMatrix m; 703 int r1, r2; 704 705 /*! \todo FIXME-- need direct equations */ 706 r1 = pmRpyMatConvert(rpy, &m); 707 r2 = pmMatQuatConvert(&m, q); 708 709 return pmErrno = r1 || r2 ? PM_NORM_ERR : 0; 710 } 711 712 int pmRpyMatConvert(PmRpy const * const rpy, PmRotationMatrix * const m) 713 { 714 double sa, sb, sg; 715 double ca, cb, cg; 716 717 sa = sin(rpy->y); 718 sb = sin(rpy->p); 719 sg = sin(rpy->r); 720 721 ca = cos(rpy->y); 722 cb = cos(rpy->p); 723 cg = cos(rpy->r); 724 725 m->x.x = ca * cb; 726 m->y.x = ca * sb * sg - sa * cg; 727 m->z.x = ca * sb * cg + sa * sg; 728 729 m->x.y = sa * cb; 730 m->y.y = sa * sb * sg + ca * cg; 731 m->z.y = sa * sb * cg - ca * sg; 732 733 m->x.z = -sb; 734 m->y.z = cb * sg; 735 m->z.z = cb * cg; 736 737 return pmErrno = 0; 738 } 739 740 int pmRpyZyzConvert(PmRpy const * const rpy, PmEulerZyz * const zyz) 741 { 742 #ifdef PM_PRINT_ERROR 743 pmPrintError("error: pmRpyZyzConvert not implemented\n"); 744 #endif 745 return pmErrno = PM_IMPL_ERR; 746 } 747 748 int pmRpyZyxConvert(PmRpy const * const rpy, PmEulerZyx * const zyx) 749 { 750 #ifdef PM_PRINT_ERROR 751 pmPrintError("error: pmRpyZyxConvert not implemented\n"); 752 #endif 753 return pmErrno = PM_IMPL_ERR; 754 } 755 756 int pmPoseHomConvert(PmPose const * const p, PmHomogeneous * const h) 757 { 758 int r1; 759 760 h->tran = p->tran; 761 r1 = pmQuatMatConvert(&p->rot, &h->rot); 762 763 return pmErrno = r1; 764 } 765 766 int pmHomPoseConvert(PmHomogeneous const * const h, PmPose * const p) 767 { 768 int r1; 769 770 p->tran = h->tran; 771 r1 = pmMatQuatConvert(&h->rot, &p->rot); 772 773 return pmErrno = r1; 774 } 775 776 /* PmCartesian functions */ 777 778 int pmCartCartCompare(PmCartesian const * const v1, PmCartesian const * const v2) 779 { 780 if (fabs(v1->x - v2->x) >= V_FUZZ || 781 fabs(v1->y - v2->y) >= V_FUZZ || fabs(v1->z - v2->z) >= V_FUZZ) { 782 return 0; 783 } 784 785 return 1; 786 } 787 788 int pmCartCartDot(PmCartesian const * const v1, PmCartesian const * const v2, double *d) 789 { 790 *d = v1->x * v2->x + v1->y * v2->y + v1->z * v2->z; 791 792 return pmErrno = 0; 793 } 794 795 int pmCartCartMult(PmCartesian const * const v1, PmCartesian const * const v2, 796 PmCartesian * const out) 797 { 798 out->x = v1->x * v2->x; 799 out->y = v1->y * v2->y; 800 out->z = v1->z * v2->z; 801 802 return pmErrno = 0; 803 } 804 805 int pmCartCartDiv(PmCartesian const * const v1, PmCartesian const * const v2, 806 PmCartesian * const out) 807 { 808 out->x = v1->x / v2->x; 809 out->y = v1->y / v2->y; 810 out->z = v1->z / v2->z; 811 812 return pmErrno = 0; 813 } 814 815 int pmCartCartCross(PmCartesian const * const v1, PmCartesian const * const v2, 816 PmCartesian * const vout) 817 { 818 if (vout == v1 || vout == v2) { 819 return pmErrno = PM_IMPL_ERR; 820 } 821 vout->x = v1->y * v2->z - v1->z * v2->y; 822 vout->y = v1->z * v2->x - v1->x * v2->z; 823 vout->z = v1->x * v2->y - v1->y * v2->x; 824 825 return pmErrno = 0; 826 } 827 828 int pmCartInfNorm(PmCartesian const * v, double * out) 829 { 830 *out = fmax(fabs(v->x),fmax(fabs(v->y),fabs(v->z))); 831 return pmErrno = 0; 832 } 833 834 int pmCartMag(PmCartesian const * const v, double *d) 835 { 836 *d = pmSqrt(pmSq(v->x) + pmSq(v->y) + pmSq(v->z)); 837 838 return pmErrno = 0; 839 } 840 841 /** Find square of magnitude of a vector (useful for some calculations to save a sqrt).*/ 842 int pmCartMagSq(PmCartesian const * const v, double *d) 843 { 844 *d = pmSq(v->x) + pmSq(v->y) + pmSq(v->z); 845 846 return pmErrno = 0; 847 } 848 849 int pmCartCartDisp(PmCartesian const * const v1, PmCartesian const * const v2, 850 double *d) 851 { 852 *d = pmSqrt(pmSq(v2->x - v1->x) + pmSq(v2->y - v1->y) + pmSq(v2->z - v1->z)); 853 854 return pmErrno = 0; 855 } 856 857 int pmCartCartAdd(PmCartesian const * const v1, PmCartesian const * const v2, 858 PmCartesian * const vout) 859 { 860 vout->x = v1->x + v2->x; 861 vout->y = v1->y + v2->y; 862 vout->z = v1->z + v2->z; 863 864 return pmErrno = 0; 865 } 866 867 int pmCartCartSub(PmCartesian const * const v1, PmCartesian const * const v2, 868 PmCartesian * const vout) 869 { 870 vout->x = v1->x - v2->x; 871 vout->y = v1->y - v2->y; 872 vout->z = v1->z - v2->z; 873 874 return pmErrno = 0; 875 } 876 877 int pmCartScalMult(PmCartesian const * const v1, double d, PmCartesian * const vout) 878 { 879 if (v1 != vout) { 880 *vout = *v1; 881 } 882 return pmCartScalMultEq(vout, d); 883 } 884 885 int pmCartScalDiv(PmCartesian const * const v1, double d, PmCartesian * const vout) 886 { 887 if (v1 != vout) { 888 *vout = *v1; 889 } 890 return pmCartScalDivEq(vout, d); 891 } 892 893 int pmCartNeg(PmCartesian const * const v1, PmCartesian * const vout) 894 { 895 if (v1 != vout) { 896 *vout = *v1; 897 } 898 899 return pmCartNegEq(vout); 900 } 901 902 int pmCartNegEq(PmCartesian * const v1) 903 { 904 v1->x = -v1->x; 905 v1->y = -v1->y; 906 v1->z = -v1->z; 907 908 return pmErrno = 0; 909 } 910 911 int pmCartInv(PmCartesian const * const v1, PmCartesian * const vout) 912 { 913 if (v1 != vout) { 914 *vout = *v1; 915 } 916 917 return pmCartInvEq(vout); 918 } 919 920 int pmCartInvEq(PmCartesian * const v) 921 { 922 double size_sq; 923 pmCartMagSq(v,&size_sq); 924 925 if (size_sq == 0.0) { 926 #ifdef PM_PRINT_ERROR 927 pmPrintError(&"Zero vector in pmCartInv\n"); 928 #endif 929 return pmErrno = PM_NORM_ERR; 930 } 931 932 v->x /= size_sq; 933 v->y /= size_sq; 934 v->z /= size_sq; 935 936 return pmErrno = 0; 937 } 938 939 // This used to be called pmCartNorm. 940 941 int pmCartUnit(PmCartesian const * const v, PmCartesian * const vout) 942 { 943 if (vout != v) { 944 *vout = *v; 945 } 946 return pmCartUnitEq(vout); 947 } 948 949 int pmCartAbs(PmCartesian const * const v, PmCartesian * const vout) 950 { 951 952 vout->x = fabs(v->x); 953 vout->y = fabs(v->y); 954 vout->z = fabs(v->z); 955 956 return pmErrno = 0; 957 } 958 959 /* Compound assign operator equivalent functions. These are to prevent issues with passing the same variable as both input (const) and output */ 960 961 int pmCartCartAddEq(PmCartesian * const v, PmCartesian const * const v_add) 962 { 963 v->x += v_add->x; 964 v->y += v_add->y; 965 v->z += v_add->z; 966 967 return pmErrno = 0; 968 } 969 970 int pmCartCartSubEq(PmCartesian * const v, PmCartesian const * const v_sub) 971 { 972 v->x -= v_sub->x; 973 v->y -= v_sub->y; 974 v->z -= v_sub->z; 975 976 return pmErrno = 0; 977 } 978 979 int pmCartScalMultEq(PmCartesian * const v, double d) 980 { 981 982 v->x *= d; 983 v->y *= d; 984 v->z *= d; 985 986 return pmErrno = 0; 987 } 988 989 int pmCartScalDivEq(PmCartesian * const v, double d) 990 { 991 992 if (d == 0.0) { 993 #ifdef PM_PRINT_ERROR 994 pmPrintError(&"Divide by 0 in pmCartScalDiv\n"); 995 #endif 996 997 return pmErrno = PM_DIV_ERR; 998 } 999 1000 v->x /= d; 1001 v->y /= d; 1002 v->z /= d; 1003 1004 return pmErrno = 0; 1005 } 1006 1007 int pmCartUnitEq(PmCartesian * const v) 1008 { 1009 double size = pmSqrt(pmSq(v->x) + pmSq(v->y) + pmSq(v->z)); 1010 1011 if (size == 0.0) { 1012 #ifdef PM_PRINT_ERROR 1013 pmPrintError("Zero vector in pmCartUnit\n"); 1014 #endif 1015 return pmErrno = PM_NORM_ERR; 1016 } 1017 1018 v->x /= size; 1019 v->y /= size; 1020 v->z /= size; 1021 1022 return pmErrno = 0; 1023 } 1024 1025 /*! \todo This is if 0'd out so we can find all the pmCartNorm calls that should 1026 be renamed pmCartUnit. 1027 Later we'll put this back. */ 1028 #if 0 1029 1030 int pmCartNorm(PmCartesian const * const v, PmCartesian * const vout) 1031 { 1032 1033 vout->x = v->x; 1034 vout->y = v->y; 1035 vout->z = v->z; 1036 1037 return pmErrno = 0; 1038 } 1039 #endif 1040 1041 int pmCartIsNorm(PmCartesian const * const v) 1042 { 1043 return pmSqrt(pmSq(v->x) + pmSq(v->y) + pmSq(v->z)) - 1.0 < UNIT_VEC_FUZZ ? 1 : 0; 1044 } 1045 1046 int pmCartCartProj(PmCartesian const * const v1, PmCartesian const * const v2, PmCartesian * const vout) 1047 { 1048 int r1, r2; 1049 int r3=1; 1050 double d12; 1051 double d22; 1052 1053 r1 = pmCartCartDot(v1, v2, &d12); 1054 r2 = pmCartCartDot(v2, v2, &d22); 1055 if (!(r1 || r1)){ 1056 r3 = pmCartScalMult(v2, d12/d22, vout); 1057 } 1058 1059 return pmErrno = r1 || r2 || r3 ? PM_NORM_ERR : 0; 1060 } 1061 1062 int pmCartPlaneProj(PmCartesian const * const v, PmCartesian const * const normal, PmCartesian * const vout) 1063 { 1064 int r1, r2; 1065 PmCartesian par; 1066 1067 r1 = pmCartCartProj(v, normal, &par); 1068 r2 = pmCartCartSub(v, &par, vout); 1069 1070 return pmErrno = r1 || r2 ? PM_NORM_ERR : 0; 1071 } 1072 1073 /* angle-axis functions */ 1074 1075 int pmQuatAxisAngleMult(PmQuaternion const * const q, PmAxis axis, double angle, 1076 PmQuaternion * const pq) 1077 { 1078 double sh, ch; 1079 1080 #ifdef PM_DEBUG 1081 if (!pmQuatIsNorm(q)) { 1082 #ifdef PM_PRINT_ERROR 1083 pmPrintError("error: non-unit quaternion in pmQuatAxisAngleMult\n"); 1084 #endif 1085 return -1; 1086 } 1087 #endif 1088 1089 angle *= 0.5; 1090 sincos(angle, &sh, &ch); 1091 1092 switch (axis) { 1093 case PM_X: 1094 pq->s = ch * q->s - sh * q->x; 1095 pq->x = ch * q->x + sh * q->s; 1096 pq->y = ch * q->y + sh * q->z; 1097 pq->z = ch * q->z - sh * q->y; 1098 break; 1099 1100 case PM_Y: 1101 pq->s = ch * q->s - sh * q->y; 1102 pq->x = ch * q->x - sh * q->z; 1103 pq->y = ch * q->y + sh * q->s; 1104 pq->z = ch * q->z + sh * q->x; 1105 break; 1106 1107 case PM_Z: 1108 pq->s = ch * q->s - sh * q->z; 1109 pq->x = ch * q->x + sh * q->y; 1110 pq->y = ch * q->y - sh * q->x; 1111 pq->z = ch * q->z + sh * q->s; 1112 break; 1113 1114 default: 1115 #ifdef PM_PRINT_ERROR 1116 pmPrintError("error: bad axis in pmQuatAxisAngleMult\n"); 1117 #endif 1118 return -1; 1119 } 1120 1121 if (pq->s < 0.0) { 1122 pq->s *= -1.0; 1123 pq->x *= -1.0; 1124 pq->y *= -1.0; 1125 pq->z *= -1.0; 1126 } 1127 1128 return 0; 1129 } 1130 1131 /* PmRotationVector functions */ 1132 1133 int pmRotScalMult(PmRotationVector const * const r, double s, PmRotationVector * const rout) 1134 { 1135 rout->s = r->s * s; 1136 rout->x = r->x; 1137 rout->y = r->y; 1138 rout->z = r->z; 1139 1140 return pmErrno = 0; 1141 } 1142 1143 int pmRotScalDiv(PmRotationVector const * const r, double s, PmRotationVector * const rout) 1144 { 1145 if (s == 0.0) { 1146 #ifdef PM_PRINT_ERROR 1147 pmPrintError("Divide by zero in pmRotScalDiv\n"); 1148 #endif 1149 1150 rout->s = DBL_MAX; 1151 rout->x = r->x; 1152 rout->y = r->y; 1153 rout->z = r->z; 1154 1155 return pmErrno = PM_NORM_ERR; 1156 } 1157 1158 rout->s = r->s / s; 1159 rout->x = r->x; 1160 rout->y = r->y; 1161 rout->z = r->z; 1162 1163 return pmErrno = 0; 1164 } 1165 1166 int pmRotIsNorm(PmRotationVector const * const r) 1167 { 1168 if (fabs(r->s) < RS_FUZZ || 1169 fabs(pmSqrt(pmSq(r->x) + pmSq(r->y) + pmSq(r->z))) - 1.0 < UNIT_VEC_FUZZ) 1170 { 1171 return 1; 1172 } 1173 1174 return 0; 1175 } 1176 1177 int pmRotNorm(PmRotationVector const * const r, PmRotationVector * const rout) 1178 { 1179 double size; 1180 1181 size = pmSqrt(pmSq(r->x) + pmSq(r->y) + pmSq(r->z)); 1182 1183 if (fabs(r->s) < RS_FUZZ) { 1184 rout->s = 0.0; 1185 rout->x = 0.0; 1186 rout->y = 0.0; 1187 rout->z = 0.0; 1188 1189 return pmErrno = 0; 1190 } 1191 1192 if (size == 0.0) { 1193 #ifdef PM_PRINT_ERROR 1194 pmPrintError("error: pmRotNorm size is zero\n"); 1195 #endif 1196 1197 rout->s = 0.0; 1198 rout->x = 0.0; 1199 rout->y = 0.0; 1200 rout->z = 0.0; 1201 1202 return pmErrno = PM_NORM_ERR; 1203 } 1204 1205 rout->s = r->s; 1206 rout->x = r->x / size; 1207 rout->y = r->y / size; 1208 rout->z = r->z / size; 1209 1210 return pmErrno = 0; 1211 } 1212 1213 /* PmRotationMatrix functions */ 1214 1215 int pmMatNorm(PmRotationMatrix const * const m, PmRotationMatrix * const mout) 1216 { 1217 /*! \todo FIXME */ 1218 *mout = *m; 1219 1220 #ifdef PM_PRINT_ERROR 1221 pmPrintError("error: pmMatNorm not implemented\n"); 1222 #endif 1223 return pmErrno = PM_IMPL_ERR; 1224 } 1225 1226 int pmMatIsNorm(PmRotationMatrix const * const m) 1227 { 1228 PmCartesian u; 1229 1230 pmCartCartCross(&m->x, &m->y, &u); 1231 1232 return (pmCartIsNorm(&m->x) && pmCartIsNorm(&m->y) && pmCartIsNorm(&m->z) && pmCartCartCompare(&u, &m->z)); 1233 } 1234 1235 int pmMatInv(PmRotationMatrix const * const m, PmRotationMatrix * const mout) 1236 { 1237 /* inverse of a rotation matrix is the transpose */ 1238 1239 mout->x.x = m->x.x; 1240 mout->x.y = m->y.x; 1241 mout->x.z = m->z.x; 1242 1243 mout->y.x = m->x.y; 1244 mout->y.y = m->y.y; 1245 mout->y.z = m->z.y; 1246 1247 mout->z.x = m->x.z; 1248 mout->z.y = m->y.z; 1249 mout->z.z = m->z.z; 1250 1251 return pmErrno = 0; 1252 } 1253 1254 int pmMatCartMult(PmRotationMatrix const * const m, PmCartesian const * const v, PmCartesian * const vout) 1255 { 1256 vout->x = m->x.x * v->x + m->y.x * v->y + m->z.x * v->z; 1257 vout->y = m->x.y * v->x + m->y.y * v->y + m->z.y * v->z; 1258 vout->z = m->x.z * v->x + m->y.z * v->y + m->z.z * v->z; 1259 1260 return pmErrno = 0; 1261 } 1262 1263 int pmMatMatMult(PmRotationMatrix const * const m1, PmRotationMatrix const * const m2, 1264 PmRotationMatrix * const mout) 1265 { 1266 mout->x.x = m1->x.x * m2->x.x + m1->y.x * m2->x.y + m1->z.x * m2->x.z; 1267 mout->x.y = m1->x.y * m2->x.x + m1->y.y * m2->x.y + m1->z.y * m2->x.z; 1268 mout->x.z = m1->x.z * m2->x.x + m1->y.z * m2->x.y + m1->z.z * m2->x.z; 1269 1270 mout->y.x = m1->x.x * m2->y.x + m1->y.x * m2->y.y + m1->z.x * m2->y.z; 1271 mout->y.y = m1->x.y * m2->y.x + m1->y.y * m2->y.y + m1->z.y * m2->y.z; 1272 mout->y.z = m1->x.z * m2->y.x + m1->y.z * m2->y.y + m1->z.z * m2->y.z; 1273 1274 mout->z.x = m1->x.x * m2->z.x + m1->y.x * m2->z.y + m1->z.x * m2->z.z; 1275 mout->z.y = m1->x.y * m2->z.x + m1->y.y * m2->z.y + m1->z.y * m2->z.z; 1276 mout->z.z = m1->x.z * m2->z.x + m1->y.z * m2->z.y + m1->z.z * m2->z.z; 1277 1278 return pmErrno = 0; 1279 } 1280 1281 /* PmQuaternion functions */ 1282 1283 int pmQuatQuatCompare(PmQuaternion const * const q1, PmQuaternion const * const q2) 1284 { 1285 #ifdef PM_DEBUG 1286 if (!pmQuatIsNorm(q1) || !pmQuatIsNorm(q2)) { 1287 #ifdef PM_PRINT_ERROR 1288 pmPrintError("Bad quaternion in pmQuatQuatCompare\n"); 1289 #endif 1290 } 1291 #endif 1292 1293 if (fabs(q1->s - q2->s) < Q_FUZZ && 1294 fabs(q1->x - q2->x) < Q_FUZZ && 1295 fabs(q1->y - q2->y) < Q_FUZZ && fabs(q1->z - q2->z) < Q_FUZZ) { 1296 return 1; 1297 } 1298 1299 /* note (0, x, y, z) = (0, -x, -y, -z) */ 1300 if (fabs(q1->s) >= QS_FUZZ || 1301 fabs(q1->x + q2->x) >= Q_FUZZ || 1302 fabs(q1->y + q2->y) >= Q_FUZZ || fabs(q1->z + q2->z) >= Q_FUZZ) { 1303 return 0; 1304 } 1305 1306 return 1; 1307 } 1308 1309 int pmQuatMag(PmQuaternion const * const q, double *d) 1310 { 1311 PmRotationVector r; 1312 int r1; 1313 1314 if (0 == d) { 1315 return (pmErrno = PM_ERR); 1316 } 1317 1318 r1 = pmQuatRotConvert(q, &r); 1319 *d = r.s; 1320 1321 return pmErrno = r1; 1322 } 1323 1324 int pmQuatNorm(PmQuaternion const * const q1, PmQuaternion * const qout) 1325 { 1326 double size = pmSqrt(pmSq(q1->s) + pmSq(q1->x) + pmSq(q1->y) + pmSq(q1->z)); 1327 1328 if (size == 0.0) { 1329 #ifdef PM_PRINT_ERROR 1330 pmPrintError("Bad quaternion in pmQuatNorm\n"); 1331 #endif 1332 qout->s = 1; 1333 qout->x = 0; 1334 qout->y = 0; 1335 qout->z = 0; 1336 1337 return pmErrno = PM_NORM_ERR; 1338 } 1339 1340 if (q1->s >= 0.0) { 1341 qout->s = q1->s / size; 1342 qout->x = q1->x / size; 1343 qout->y = q1->y / size; 1344 qout->z = q1->z / size; 1345 1346 return pmErrno = 0; 1347 } else { 1348 qout->s = -q1->s / size; 1349 qout->x = -q1->x / size; 1350 qout->y = -q1->y / size; 1351 qout->z = -q1->z / size; 1352 1353 return pmErrno = 0; 1354 } 1355 } 1356 1357 int pmQuatInv(PmQuaternion const * const q1, PmQuaternion * const qout) 1358 { 1359 if (qout == 0) { 1360 return pmErrno = PM_ERR; 1361 } 1362 1363 qout->s = q1->s; 1364 qout->x = -q1->x; 1365 qout->y = -q1->y; 1366 qout->z = -q1->z; 1367 1368 #ifdef PM_DEBUG 1369 if (!pmQuatIsNorm(q1)) { 1370 #ifdef PM_PRINT_ERROR 1371 pmPrintError("Bad quaternion in pmQuatInv\n"); 1372 #endif 1373 return pmErrno = PM_NORM_ERR; 1374 } 1375 #endif 1376 1377 return pmErrno = 0; 1378 } 1379 1380 int pmQuatIsNorm(PmQuaternion const * const q1) 1381 { 1382 return (fabs(pmSq(q1->s) + pmSq(q1->x) + pmSq(q1->y) + pmSq(q1->z) - 1.0) < 1383 UNIT_QUAT_FUZZ); 1384 } 1385 1386 int pmQuatScalMult(PmQuaternion const * const q, double s, PmQuaternion * const qout) 1387 { 1388 /*! \todo FIXME-- need a native version; this goes through a rotation vector */ 1389 PmRotationVector r; 1390 int r1, r2, r3; 1391 1392 r1 = pmQuatRotConvert(q, &r); 1393 r2 = pmRotScalMult(&r, s, &r); 1394 r3 = pmRotQuatConvert(&r, qout); 1395 1396 return pmErrno = (r1 || r2 || r3) ? PM_NORM_ERR : 0; 1397 } 1398 1399 int pmQuatScalDiv(PmQuaternion const * const q, double s, PmQuaternion * const qout) 1400 { 1401 /*! \todo FIXME-- need a native version; this goes through a rotation vector */ 1402 PmRotationVector r; 1403 int r1, r2, r3; 1404 1405 r1 = pmQuatRotConvert(q, &r); 1406 r2 = pmRotScalDiv(&r, s, &r); 1407 r3 = pmRotQuatConvert(&r, qout); 1408 1409 return pmErrno = (r1 || r2 || r3) ? PM_NORM_ERR : 0; 1410 } 1411 1412 int pmQuatQuatMult(PmQuaternion const * const q1, PmQuaternion const * const q2, PmQuaternion * const qout) 1413 { 1414 if (qout == 0) { 1415 return pmErrno = PM_ERR; 1416 } 1417 1418 qout->s = q1->s * q2->s - q1->x * q2->x - q1->y * q2->y - q1->z * q2->z; 1419 1420 if (qout->s >= 0.0) { 1421 qout->x = q1->s * q2->x + q1->x * q2->s + q1->y * q2->z - q1->z * q2->y; 1422 qout->y = q1->s * q2->y - q1->x * q2->z + q1->y * q2->s + q1->z * q2->x; 1423 qout->z = q1->s * q2->z + q1->x * q2->y - q1->y * q2->x + q1->z * q2->s; 1424 } else { 1425 qout->s *= -1; 1426 qout->x = -q1->s * q2->x - q1->x * q2->s - q1->y * q2->z + q1->z * q2->y; 1427 qout->y = -q1->s * q2->y + q1->x * q2->z - q1->y * q2->s - q1->z * q2->x; 1428 qout->z = -q1->s * q2->z - q1->x * q2->y + q1->y * q2->x - q1->z * q2->s; 1429 } 1430 1431 #ifdef PM_DEBUG 1432 if (!pmQuatIsNorm(q1) || !pmQuatIsNorm(q2)) { 1433 #ifdef PM_PRINT_ERROR 1434 pmPrintError("Bad quaternion in pmQuatQuatMult\n"); 1435 #endif 1436 return pmErrno = PM_NORM_ERR; 1437 } 1438 #endif 1439 1440 return pmErrno = 0; 1441 } 1442 1443 int pmQuatCartMult(PmQuaternion const * const q1, PmCartesian const * const v2, PmCartesian * const vout) 1444 { 1445 PmCartesian c; 1446 1447 c.x = q1->y * v2->z - q1->z * v2->y; 1448 c.y = q1->z * v2->x - q1->x * v2->z; 1449 c.z = q1->x * v2->y - q1->y * v2->x; 1450 1451 vout->x = v2->x + 2.0 * (q1->s * c.x + q1->y * c.z - q1->z * c.y); 1452 vout->y = v2->y + 2.0 * (q1->s * c.y + q1->z * c.x - q1->x * c.z); 1453 vout->z = v2->z + 2.0 * (q1->s * c.z + q1->x * c.y - q1->y * c.x); 1454 1455 #ifdef PM_DEBUG 1456 if (!pmQuatIsNorm(q1)) { 1457 #ifdef PM_PRINT_ERROR 1458 pmPrintError(&"Bad quaternion in pmQuatCartMult\n"); 1459 #endif 1460 return pmErrno = PM_NORM_ERR; 1461 } 1462 #endif 1463 1464 return pmErrno = 0; 1465 } 1466 1467 /* PmPose functions*/ 1468 1469 int pmPosePoseCompare(PmPose const * const p1, PmPose const * const p2) 1470 { 1471 #ifdef PM_DEBUG 1472 if (!pmQuatIsNorm(&p1->rot) || !pmQuatIsNorm(&p2->rot)) { 1473 #ifdef PM_PRINT_ERROR 1474 pmPrintError("Bad quaternion in pmPosePoseCompare\n"); 1475 #endif 1476 } 1477 #endif 1478 1479 return pmErrno = (pmQuatQuatCompare(&p1->rot, &p2->rot) && pmCartCartCompare(&p1->tran, &p2->tran)); 1480 } 1481 1482 int pmPoseInv(PmPose const * const p1, PmPose * const p2) 1483 { 1484 int r1, r2; 1485 1486 #ifdef PM_DEBUG 1487 if (!pmQuatIsNorm(&p1->rot)) { 1488 #ifdef PM_PRINT_ERROR 1489 pmPrintError("Bad quaternion in pmPoseInv\n"); 1490 #endif 1491 } 1492 #endif 1493 1494 r1 = pmQuatInv(&p1->rot, &p2->rot); 1495 r2 = pmQuatCartMult(&p2->rot, &p1->tran, &p2->tran); 1496 1497 p2->tran.x *= -1.0; 1498 p2->tran.y *= -1.0; 1499 p2->tran.z *= -1.0; 1500 1501 return pmErrno = (r1 || r2) ? PM_NORM_ERR : 0; 1502 } 1503 1504 int pmPoseCartMult(PmPose const * const p1, PmCartesian const * const v2, PmCartesian * const vout) 1505 { 1506 int r1, r2; 1507 1508 #ifdef PM_DEBUG 1509 if (!pmQuatIsNorm(&p1->rot)) { 1510 #ifdef PM_PRINT_ERROR 1511 pmPrintError(&"Bad quaternion in pmPoseCartMult\n"); 1512 #endif 1513 return pmErrno = PM_NORM_ERR; 1514 } 1515 #endif 1516 1517 r1 = pmQuatCartMult(&p1->rot, v2, vout); 1518 r2 = pmCartCartAdd(&p1->tran, vout, vout); 1519 1520 return pmErrno = (r1 || r2) ? PM_NORM_ERR : 0; 1521 } 1522 1523 int pmPosePoseMult(PmPose const * const p1, PmPose const * const p2, PmPose * const pout) 1524 { 1525 int r1, r2, r3; 1526 1527 #ifdef PM_DEBUG 1528 if (!pmQuatIsNorm(&p1->rot) || !pmQuatIsNorm(&p2->rot)) { 1529 #ifdef PM_PRINT_ERROR 1530 pmPrintError("Bad quaternion in pmPosePoseMult\n"); 1531 #endif 1532 return pmErrno = PM_NORM_ERR; 1533 } 1534 #endif 1535 1536 r1 = pmQuatCartMult(&p1->rot, &p2->tran, &pout->tran); 1537 r2 = pmCartCartAdd(&p1->tran, &pout->tran, &pout->tran); 1538 r3 = pmQuatQuatMult(&p1->rot, &p2->rot, &pout->rot); 1539 1540 return pmErrno = (r1 || r2 || r3) ? PM_NORM_ERR : 0; 1541 } 1542 1543 /* homogeneous transform functions */ 1544 1545 int pmHomInv(PmHomogeneous const * const h1, PmHomogeneous * const h2) 1546 { 1547 int r1, r2; 1548 1549 #ifdef PM_DEBUG 1550 if (!pmMatIsNorm(&h1->rot)) { 1551 #ifdef PM_PRINT_ERROR 1552 pmPrintError("Bad rotation matrix in pmHomInv\n"); 1553 #endif 1554 } 1555 #endif 1556 1557 r1 = pmMatInv(&h1->rot, &h2->rot); 1558 r2 = pmMatCartMult(&h2->rot, &h1->tran, &h2->tran); 1559 1560 h2->tran.x *= -1.0; 1561 h2->tran.y *= -1.0; 1562 h2->tran.z *= -1.0; 1563 1564 return pmErrno = (r1 || r2) ? PM_NORM_ERR : 0; 1565 } 1566 1567 /* line functions */ 1568 1569 int pmLineInit(PmLine * const line, PmPose const * const start, PmPose const * const end) 1570 { 1571 int r1 = 0, r2 = 0, r3 = 0, r4 = 0, r5 = 0; 1572 double tmag = 0.0; 1573 double rmag = 0.0; 1574 PmQuaternion startQuatInverse; 1575 1576 if (0 == line) { 1577 return (pmErrno = PM_ERR); 1578 } 1579 1580 r3 = pmQuatInv(&start->rot, &startQuatInverse); 1581 if (r3) { 1582 return r3; 1583 } 1584 1585 r4 = pmQuatQuatMult(&startQuatInverse, &end->rot, &line->qVec); 1586 if (r4) { 1587 return r4; 1588 } 1589 1590 pmQuatMag(&line->qVec, &rmag); 1591 if (rmag > Q_FUZZ) { 1592 r5 = pmQuatScalMult(&line->qVec, 1 / rmag, &(line->qVec)); 1593 if (r5) { 1594 return r5; 1595 } 1596 } 1597 1598 line->start = *start; 1599 line->end = *end; 1600 r1 = pmCartCartSub(&end->tran, &start->tran, &line->uVec); 1601 if (r1) { 1602 return r1; 1603 } 1604 1605 pmCartMag(&line->uVec, &tmag); 1606 if (IS_FUZZ(tmag, CART_FUZZ)) { 1607 line->uVec.x = 1.0; 1608 line->uVec.y = 0.0; 1609 line->uVec.z = 0.0; 1610 } else { 1611 r2 = pmCartUnit(&line->uVec, &line->uVec); 1612 } 1613 line->tmag = tmag; 1614 line->rmag = rmag; 1615 line->tmag_zero = (line->tmag <= CART_FUZZ); 1616 line->rmag_zero = (line->rmag <= Q_FUZZ); 1617 1618 /* return PM_NORM_ERR if uVec has been set to 1, 0, 0 */ 1619 return pmErrno = (r1 || r2 || r3 || r4 || r5) ? PM_NORM_ERR : 0; 1620 } 1621 1622 int pmLinePoint(PmLine const * const line, double len, PmPose * const point) 1623 { 1624 int r1 = 0, r2 = 0, r3 = 0, r4 = 0; 1625 1626 if (line->tmag_zero) { 1627 point->tran = line->end.tran; 1628 } else { 1629 /* return start + len * uVec */ 1630 r1 = pmCartScalMult(&line->uVec, len, &point->tran); 1631 r2 = pmCartCartAdd(&line->start.tran, &point->tran, &point->tran); 1632 } 1633 1634 if (line->rmag_zero) { 1635 point->rot = line->end.rot; 1636 } else { 1637 if (line->tmag_zero) { 1638 r3 = pmQuatScalMult(&line->qVec, len, &point->rot); 1639 } else { 1640 r3 = pmQuatScalMult(&line->qVec, len * line->rmag / line->tmag, 1641 &point->rot); 1642 } 1643 r4 = pmQuatQuatMult(&line->start.rot, &point->rot, &point->rot); 1644 } 1645 1646 return pmErrno = (r1 || r2 || r3 || r4) ? PM_NORM_ERR : 0; 1647 } 1648 1649 1650 /* pure cartesian line functions */ 1651 1652 int pmCartLineInit(PmCartLine * const line, PmCartesian const * const start, PmCartesian const * const end) 1653 { 1654 int r1 = 0, r2 = 0; 1655 1656 if (0 == line) { 1657 return (pmErrno = PM_ERR); 1658 } 1659 1660 line->start = *start; 1661 line->end = *end; 1662 r1 = pmCartCartSub(end, start, &line->uVec); 1663 if (r1) { 1664 return r1; 1665 } 1666 1667 pmCartMag(&line->uVec, &line->tmag); 1668 // NOTE: use the same criteria for "zero" length vectors as used by canon 1669 double max_xyz=0; 1670 pmCartInfNorm(&line->uVec, &max_xyz); 1671 1672 if (IS_FUZZ(max_xyz, CART_FUZZ)) { 1673 line->uVec.x = 1.0; 1674 line->uVec.y = 0.0; 1675 line->uVec.z = 0.0; 1676 line->tmag_zero = 1; 1677 } else { 1678 r2 = pmCartUnitEq(&line->uVec); 1679 line->tmag_zero = 0; 1680 } 1681 1682 /* return PM_NORM_ERR if uVec has been set to 1, 0, 0 */ 1683 return pmErrno = (r1 || r2) ? PM_NORM_ERR : 0; 1684 } 1685 1686 int pmCartLinePoint(PmCartLine const * const line, double len, PmCartesian * const point) 1687 { 1688 int r1 = 0, r2 = 0; 1689 1690 if (line->tmag_zero) { 1691 *point = line->end; 1692 } else { 1693 /* return start + len * uVec */ 1694 r1 = pmCartScalMult(&line->uVec, len, point); 1695 r2 = pmCartCartAdd(&line->start, point, point); 1696 } 1697 1698 return pmErrno = (r1 || r2) ? PM_NORM_ERR : 0; 1699 } 1700 1701 1702 int pmCartLineStretch(PmCartLine * const line, double new_len, int from_end) 1703 { 1704 int r1 = 0, r2 = 0; 1705 1706 if (!line || line->tmag_zero || new_len <= DOUBLE_FUZZ) { 1707 return PM_ERR; 1708 } 1709 1710 if (from_end) { 1711 // Store the new relative position from end in the start point 1712 r1 = pmCartScalMult(&line->uVec, -new_len, &line->start); 1713 // Offset the new start point by the current end point 1714 r2 = pmCartCartAddEq(&line->start, &line->end); 1715 } else { 1716 // Store the new relative position from start in the end point: 1717 r1 = pmCartScalMult(&line->uVec, new_len, &line->end); 1718 // Offset the new end point by the current start point 1719 r2 = pmCartCartAdd(&line->start, &line->end, &line->end); 1720 } 1721 line->tmag = new_len; 1722 1723 return pmErrno = (r1 || r2) ? PM_NORM_ERR : 0; 1724 } 1725 1726 /* circle functions */ 1727 1728 /* 1729 pmCircleInit() takes the defining parameters of a generalized circle 1730 and sticks them in the structure. It also computes the radius and vectors 1731 in the plane that are useful for other functions and that don't need 1732 to be recomputed every time. 1733 1734 Note that the end can be placed arbitrarily, resulting in a combination of 1735 spiral and helical motion. There is an overconstraint between the start, 1736 center, and normal vector: the center vector and start vector are assumed 1737 to be in the plane defined by the normal vector. If this is not true, then 1738 it will be made true by moving the center vector onto the plane. 1739 */ 1740 int pmCircleInit(PmCircle * const circle, 1741 PmCartesian const * const start, PmCartesian const * const end, 1742 PmCartesian const * const center, PmCartesian const * const normal, int turn) 1743 { 1744 double dot; 1745 PmCartesian rEnd; 1746 PmCartesian v; 1747 double d; 1748 int r1; 1749 1750 #ifdef PM_DEBUG 1751 if (0 == circle) { 1752 #ifdef PM_PRINT_ERROR 1753 pmPrintError("error: pmCircleInit cirle pointer is null\n"); 1754 #endif 1755 return pmErrno = PM_ERR; 1756 } 1757 #endif 1758 1759 /* adjust center */ 1760 pmCartCartSub(start, center, &v); 1761 r1 = pmCartCartProj(&v, normal, &v); 1762 if (PM_NORM_ERR == r1) { 1763 /* bad normal vector-- abort */ 1764 #ifdef PM_PRINT_ERROR 1765 pmPrintError("error: pmCircleInit normal vector is 0\n"); 1766 #endif 1767 return -1; 1768 } 1769 pmCartCartAdd(&v, center, &circle->center); 1770 1771 /* normalize and redirect normal vector based on turns. If turn is less 1772 than 0, point normal vector in other direction and make turn positive, 1773 -1 -> 0, -2 -> 1, etc. */ 1774 pmCartUnit(normal, &circle->normal); 1775 if (turn < 0) { 1776 turn = -1 - turn; 1777 pmCartScalMult(&circle->normal, -1.0, &circle->normal); 1778 } 1779 1780 /* radius */ 1781 pmCartCartDisp(start, &circle->center, &circle->radius); 1782 1783 /* vector in plane of circle from center to start, magnitude radius */ 1784 pmCartCartSub(start, &circle->center, &circle->rTan); 1785 /* vector in plane of circle perpendicular to rTan, magnitude radius */ 1786 pmCartCartCross(&circle->normal, &circle->rTan, &circle->rPerp); 1787 1788 /* do rHelix, rEnd */ 1789 pmCartCartSub(end, &circle->center, &circle->rHelix); 1790 pmCartPlaneProj(&circle->rHelix, &circle->normal, &rEnd); 1791 pmCartMag(&rEnd, &circle->spiral); 1792 circle->spiral -= circle->radius; 1793 pmCartCartSub(&circle->rHelix, &rEnd, &circle->rHelix); 1794 pmCartUnit(&rEnd, &rEnd); 1795 pmCartScalMult(&rEnd, circle->radius, &rEnd); 1796 1797 /* Patch for error spiral end same as spiral center */ 1798 pmCartMag(&rEnd, &d); 1799 if (d == 0.0) { 1800 pmCartScalMult(&circle->normal, DOUBLE_FUZZ, &v); 1801 pmCartCartAdd(&rEnd, &v, &rEnd); 1802 } 1803 /* end patch 03-mar-1999 Dirk Maij */ 1804 1805 /* angle */ 1806 pmCartCartDot(&circle->rTan, &rEnd, &dot); 1807 dot = dot / (circle->radius * circle->radius); 1808 if (dot > 1.0) { 1809 circle->angle = 0.0; 1810 } else if (dot < -1.0) { 1811 circle->angle = PM_PI; 1812 } else { 1813 circle->angle = acos(dot); 1814 } 1815 /* now angle is in range 0..PI . Check if cross is antiparallel to 1816 normal. If so, true angle is between PI..2PI. Need to subtract from 1817 2PI. */ 1818 pmCartCartCross(&circle->rTan, &rEnd, &v); 1819 pmCartCartDot(&v, &circle->normal, &d); 1820 if (d < 0.0) { 1821 circle->angle = PM_2_PI - circle->angle; 1822 } 1823 1824 if (circle->angle > -(CIRCLE_FUZZ) && circle->angle < (CIRCLE_FUZZ)) { 1825 circle->angle = PM_2_PI; 1826 } 1827 1828 /* now add more angle for multi turns */ 1829 if (turn > 0) { 1830 circle->angle += turn * 2.0 * PM_PI; 1831 } 1832 1833 //Default to invalid 1834 /* if 0'ed out while not debugging*/ 1835 #if 0 1836 printf("\n\n"); 1837 printf("pmCircleInit:\n"); 1838 printf(" \t start : \t{x=%9.9f, y=%9.9f, z=%9.9f}\n", 1839 start->x, start->y, start->z); 1840 printf(" \t end : \t{x=%9.9f, y=%9.9f, z=%9.9f}\n", 1841 end->x, end->y, end->z); 1842 printf(" \t center : \t{x=%9.9f, y=%9.9f, z=%9.9f}\n", 1843 center->x, center->y, center->z); 1844 printf(" \t normal : \t{x=%9.9f, y=%9.9f, z=%9.9f}\n", 1845 normal->x, normal->y, normal->z); 1846 printf(" \t rEnd : \t{x=%9.9f, y=%9.9f, z=%9.9f}\n", 1847 rEnd.x, rEnd.y, rEnd.z); 1848 printf(" \t turn=%d\n", turn); 1849 printf(" \t dot=%9.9f\n", dot); 1850 printf(" \t d=%9.9f\n", d); 1851 printf(" \t circle \t{angle=%9.9f, radius=%9.9f, spiral=%9.9f}\n", 1852 circle->angle, circle->radius, circle->spiral); 1853 printf(" \t circle->normal : \t{x=%9.9f, y=%9.9f, z=%9.9f}\n", 1854 circle->normal.x, circle->normal.y, circle->normal.z); 1855 printf(" \t circle->center : \t{x=%9.9f, y=%9.9f, z=%9.9f}\n", 1856 circle->center.x, circle->center.y, circle->center.z); 1857 printf(" \t circle->rTan : \t{x=%9.9f, y=%9.9f, z=%9.9f}\n", 1858 circle->rTan.x, circle->rTan.y, circle->rTan.z); 1859 printf(" \t circle->rPerp : \t{x=%9.9f, y=%9.9f, z=%9.9f}\n", 1860 circle->rPerp.x, circle->rPerp.y, circle->rPerp.z); 1861 printf(" \t circle->rHelix : \t{x=%9.9f, y=%9.9f, z=%9.9f}\n", 1862 circle->rHelix.x, circle->rHelix.y, circle->rHelix.z); 1863 printf("\n\n"); 1864 #endif 1865 1866 return pmErrno = 0; 1867 } 1868 1869 1870 /* 1871 pmCirclePoint() returns the point at the given angle along 1872 the circle. If the circle is a helix or spiral or combination, the 1873 point will include interpolation off the actual circle. 1874 */ 1875 int pmCirclePoint(PmCircle const * const circle, double angle, PmCartesian * const point) 1876 { 1877 PmCartesian par, perp; 1878 double scale; 1879 1880 #ifdef PM_DEBUG 1881 if (0 == circle || 0 == point) { 1882 #ifdef PM_PRINT_ERROR 1883 pmPrintError 1884 ("error: pmCirclePoint circle or point pointer is null\n"); 1885 #endif 1886 return pmErrno = PM_ERR; 1887 } 1888 #endif 1889 1890 /* compute components rel to center */ 1891 pmCartScalMult(&circle->rTan, cos(angle), &par); 1892 pmCartScalMult(&circle->rPerp, sin(angle), &perp); 1893 1894 /* add to get radius vector rel to center */ 1895 pmCartCartAdd(&par, &perp, point); 1896 1897 /* get scale for spiral, helix interpolation */ 1898 if (circle->angle == 0.0) { 1899 #ifdef PM_PRINT_ERROR 1900 pmPrintError("error: pmCirclePoint angle is zero\n"); 1901 #endif 1902 return pmErrno = PM_DIV_ERR; 1903 } 1904 scale = angle / circle->angle; 1905 1906 /* add scaled vector in radial dir for spiral */ 1907 pmCartUnit(point, &par); 1908 pmCartScalMult(&par, scale * circle->spiral, &par); 1909 pmCartCartAdd(point, &par, point); 1910 1911 /* add scaled vector in helix dir */ 1912 pmCartScalMult(&circle->rHelix, scale, &perp); 1913 pmCartCartAdd(point, &perp, point); 1914 1915 /* add to center vector for final result */ 1916 pmCartCartAdd(&circle->center, point, point); 1917 1918 return pmErrno = 0; 1919 } 1920 1921 int pmCircleStretch(PmCircle * const circ, double new_angle, int from_end) 1922 { 1923 if (!circ || new_angle <= DOUBLE_FUZZ) { 1924 return PM_ERR; 1925 } 1926 1927 double mag = 0; 1928 pmCartMagSq(&circ->rHelix, &mag); 1929 if ( mag > 1e-6 ) { 1930 //Can't handle helices 1931 return PM_ERR; 1932 } 1933 //TODO handle spiral? 1934 if (from_end) { 1935 //Not implemented yet, way more reprocessing... 1936 PmCartesian new_start; 1937 double start_angle = circ->angle - new_angle; 1938 pmCirclePoint(circ, start_angle, &new_start); 1939 pmCartCartSub(&new_start, &circ->center, &circ->rTan); 1940 pmCartCartCross(&circ->normal, &circ->rTan, &circ->rPerp); 1941 pmCartMag(&circ->rTan, &circ->radius); 1942 } 1943 //Reduce the spiral proportionally 1944 circ->spiral *= (new_angle / circ->angle); 1945 // Easy to grow / shrink from start 1946 circ->angle = new_angle; 1947 1948 return 0; 1949 }