summaryrefslogtreecommitdiff
path: root/src/libnml/posemath/gomath.h
blob: 1aa77a2b6261503dd69df3b36093350322bc0270 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
/********************************************************************
* Description: gomath.h
*   Library file with various functions for working with matrices
*
*   Derived from a work by Fred Proctor,
*   changed to work with emc2 and HAL
*
* Adapting Author: Alex Joni
* License: LGPL Version 2
* System: Linux
*    
*******************************************************************
    Similar to posemath, but using different functions.
    
    TODO: 
	* find the new functions, add them to posemath, convert the rest
*/

#ifndef GO_MATH_H
#define GO_MATH_H

#include <stddef.h>		/* sizeof */
#include "rtapi_math.h"		/* M_PI */
#include <float.h>		/* FLT,DBL_MIN,MAX,EPSILON */
#include "gotypes.h"		/* go_integer,real */

/*! Returns the square of \a x. */
#define go_sq(x) ((x)*(x))
/*! Returns the cube of \a x.  */
#define go_cub(x) ((x)*(x)*(x))
/*! Returns \a x to the fourth power. */
#define go_qua(x) ((x)*(x)*(x)*(x))

/*! Returns the sine and cosine of \a x (in radians) in \a s and \a c,
  respectively. Implemented as a single call when supported, to speed
  up the calculation of the two values. */
extern void go_sincos(go_real x, go_real * s, go_real * c);

/*! Returns the cube root of \a x. */
extern go_real go_cbrt(go_real x);

#ifdef M_PI
/*! The value of Pi. */
#define GO_PI M_PI
#else
/*! The value of Pi. */
#define GO_PI 3.14159265358979323846
#endif
/*! The value of twice Pi. */
#define GO_2_PI (2.0*GO_PI)

#ifdef M_PI_2
/*! The value of half of Pi. */
#define GO_PI_2 M_PI_2
#else
/*! The value of half of Pi. */
#define GO_PI_2 1.57079632679489661923
#endif

#ifdef M_PI_4
/*! The value of one-fourth of Pi. */
#define GO_PI_4 M_PI_4
#else
/*! The value of one-fourth of Pi. */
#define GO_PI_4 0.78539816339744830962
#endif

/*! Returns \a rad in radians as its value in degrees. */
#define GO_TO_DEG(rad) ((rad)*57.295779513082323)
/*! Returns \a deg in degrees as its value in radians. */
#define GO_TO_RAD(deg) ((deg)*0.0174532925199432952)

/*! How close translational quantities must be to be equal. */
#define GO_TRAN_CLOSE(x,y) (fabs((x)-(y)) < GO_REAL_EPSILON)
/*! How small a translational quantity must be to be zero. */
#define GO_TRAN_SMALL(x) (fabs(x) < GO_REAL_EPSILON)

/*! How close rotational quantities must be to be equal. */
#define GO_ROT_CLOSE(x,y) (fabs((x)-(y)) < GO_REAL_EPSILON)
/*! How small a rotational quantity must be to be zero. */
#define GO_ROT_SMALL(x) (fabs(x) < GO_REAL_EPSILON)

/*! How close general quantities must be to be equal. Use this when
  you have something other than translational or rotational quantities,
  otherwise use one of \a GO_TRAN,ROT_CLOSE. */
#define GO_CLOSE(x,y) (fabs((x)-(y)) < GO_REAL_EPSILON)
/*! How small a general quantity must be to be zero. Use this when
  you have something other than a translational or rotational quantity,
  otherwise use one of \a GO_TRAN,ROT_SMALL. */
#define GO_SMALL(x) (fabs(x) < GO_REAL_EPSILON)

/*! A point or vector in Cartesian coordinates. */
typedef struct {
  go_real x;
  go_real y;
  go_real z;
} go_cart;

/*! A point or vector in spherical coordinates, with \a phi as 
  the angle down from the zenith, not up from the XY plane. */
typedef struct {
  go_real theta;
  go_real phi;
  go_real r;
} go_sph;

/*! A point or vector in cylindrical coordinates. */
typedef struct {
  go_real theta;
  go_real r;
  go_real z;
} go_cyl;

/*! A rotation vector, whose direction points along the axis of positive
  rotation, and whose magnitude is the amount of rotation around this
  axis, in radians. */
typedef struct {
  go_real x;
  go_real y;
  go_real z;
} go_rvec;

/*            |  m.x.x   m.y.x   m.z.x  | */
/* go_mat m = |  m.x.y   m.y.y   m.z.y  | */
/*            |  m.x.z   m.y.z   m.z.z  | */

/*! A rotation matrix. */
typedef struct {
  go_cart x;			/*!< X unit vector */
  go_cart y;			/*!< Y unit vector */
  go_cart z;			/*!< Z unit vector */
} go_mat;

/*! A quaternion. \a s is the cosine of the half angle of rotation,
  and the \a xyz elements comprise the vector that points in the direction
  of positive rotation and whose magnitude is the sine of the half
  angle of rotation. */
typedef struct {
  go_real s;
  go_real x;
  go_real y;
  go_real z;
} go_quat;

/*! ZYZ Euler angles. \a z is the amount of the first rotation around the
  Z axis. \a y is the amount of the second rotation around the new \a Y
  axis. \a zp is the amount of the third rotation around the new \a Z axis. */
typedef struct {
  go_real z;
  go_real y;
  go_real zp;
} go_zyz;

/*! ZYX Euler angles. \a z is the amount of the first rotation around the
  Z axis. \a y is the amount of the second rotation around the new \a Y
  axis. \a x is the amount of the third rotation around the new \a X axis. */
typedef struct {
  go_real z;
  go_real y;
  go_real x;
} go_zyx;

/*! Roll-pitch-yaw angles. \a r is the amount of the first rotation
  (roll) around the X axis. \a p is the amount of the second rotation
  (pitch) around the original Y axis.  \a y is the amount of the third
  rotation (yaw) around the original Z axis. */
typedef struct {
  go_real r;
  go_real p;
  go_real y;
} go_rpy;

/*!
  A \a go_pose represents the Cartesian position vector and quaternion
  orientation of a frame.
*/
typedef struct {
  go_cart tran;
  go_quat rot;
} go_pose;

/*!
  A \a go_screw represents the linear- and angular velocity vectors
  of a frame. \a v is the Cartesian linear velocity vector.
  \a w is the Cartesian angular velocity vector, the instantaneous
  vector about which the frame is rotating.
*/
typedef struct {
  go_cart v;
  go_cart w;
} go_screw;

/*! Convenience function that returns a \a go_pose given individual
  elements. */
extern go_pose
go_pose_this(go_real x, go_real y, go_real z,
	     go_real rs, go_real rx, go_real ry, go_real rz);

/*! Returns the zero vector. */
extern go_cart
go_cart_zero(void);

/*! Returns the identity (zero) quaternion, i.e., no rotation. */
extern go_quat
go_quat_identity(void);

/*! Returns the identity pose, no translation or rotation. */
extern go_pose
go_pose_identity(void);

typedef struct {
  go_cart tran;
  go_mat rot;
} go_hom;

/* lines, planes and related functions */

/*!
  Lines are represented in point-direction form 
  (point p, direction v) as
  (x - px)/vx = (y - py)/vy = (z - pz)vz
*/
typedef struct {
  go_cart point;
  go_cart direction;		/* always a unit vector */
} go_line;

/*!
  Given a plane as Ax + By + Cz + D = 0, the normal vector
  \a normal is the Cartesian vector (A,B,C), and the number
  \a d is the value D.

  Planes have a handedness, given by the direction of the normal
  vector, so two planes that appear coincident may be different by the
  direction of their anti-parallel normal vectors.
*/
typedef struct {
  go_cart normal;
  go_real d;
} go_plane;

/*! Fills in \a line given \a point and \a direction. Returns GO_RESULT_OK
  if \a direction is non-zero, otherwise GO_RESULT_ERROR. */
extern int go_line_from_point_direction(const go_cart * point, const go_cart * direction, go_line * line);

/*! Fills in \a line given two points. Returns GO_RESULT_OK if the points
  are different, otherwise GO_RESULT_ERROR. */
extern int go_line_from_points(const go_cart * point1, const go_cart * point2, go_line * line);

/*! Fill in \a line with the intersection of the two planes. Returns GO_RESULT_OK if the planes are not parallel, otherwise GO_RESULT_ERROR. */
extern int go_line_from_planes(const go_plane * plane1, const go_plane * plane2, go_line * line);

/*! Returns non-zero if the lines are the same, otherwise zero. */
extern go_flag go_line_line_compare(const go_line * line1, const go_line * line2);

/*! Fills in \a point with the point located distance \a d along \a line */
extern int go_line_evaluate(const go_line * line, go_real d, go_cart * point);

/*! Fills in \a distance with the distance from \a point to \a line */
extern int go_point_line_distance(const go_cart * point, const go_line * line, go_real * distance);

/*! Fills in \a pout with the nearest point on \a line to \a point */
extern int go_point_line_proj(const go_cart * point, const go_line * line, go_cart * pout);

/*! Fills in \a proj with the projection of \a point onto \a plane */
extern int go_point_plane_proj(const go_cart * point, const go_plane * plane, go_cart * proj);

/*! Fills in \a proj with the projection of \a line onto \a plane */
extern int go_line_plane_proj(const go_line * line, const go_plane * plane, go_line * proj);

/*! Fills in \a plane give a \a point on the plane and the normal \a direction. */
extern int go_plane_from_point_normal(const go_cart * point, const go_cart * normal, go_plane * plane);

/*! Fills in \a plane given the A, B, C and D values in the canonical
  form Ax + By + Cz + D = 0. Returns GO_RESULT_OK
  if not all of A, B and C are zero, otherwise GO_RESULT_ERROR. */
extern int go_plane_from_abcd(go_real A, go_real B, go_real C, go_real D, go_plane * plane);

/*! Fills in \a plane given three points. Returns GO_RESULT_OK
  if the points are distinct, otherwise GO_RESULT_ERROR. */
extern int go_plane_from_points(const go_cart * point1, const go_cart * point2, const go_cart * point3, go_plane * plane);

/*! Fills in \a plane given a \a point on the plane and a \a line
  in the plane. Returns GO_RESULT_OK if the point is not on the line,
  GO_RESULT_ERROR otherwise. */
extern int go_plane_from_point_line(const go_cart * point, const go_line * line, go_plane * plane);

/*! Returns non-zero if the planes are coincident and have the same
  normal direction, otherwise zero. */
extern go_flag go_plane_plane_compare(const go_plane * plane1, const go_plane * plane2);

/*! Fills in the \a distance from the \a point to the \a plane.  */
extern int go_point_plane_distance(const go_cart * point, const go_plane * plane, go_real * distance);

/*! Fills in \a point with the point located distances \a u and \a v along
  some othogonal planar coordinate system in \a plane */
extern int go_plane_evaluate(const go_plane * plane, go_real u, go_real v, go_cart * point);

/*! Fills in \a point with the intersection point of
 \a line with \a plane, and \a distance with the distance along the
 line to the intersection point. Returns GO_RESULT_ERROR if the line
 is parallel to the plane and not lying in the plane, otherwise
 GO_RESULT_OK. */
extern int go_line_plane_intersect(const go_line * line, const go_plane * plane, go_cart * point, go_real * distance);

/*
  struct arguments are passed to functions as const pointers since the
  speed is at least as fast for all but structs of one or two elements.
*/

/* translation rep conversion functions */

extern int go_cart_sph_convert(const go_cart *, go_sph *);
extern int go_cart_cyl_convert(const go_cart *, go_cyl *);
extern int go_sph_cart_convert(const go_sph *, go_cart *);
extern int go_sph_cyl_convert(const go_sph *, go_cyl *);
extern int go_cyl_cart_convert(const go_cyl *, go_cart *);
extern int go_cyl_sph_convert(const go_cyl *, go_sph *);

/* rotation rep conversion functions */

extern int go_rvec_quat_convert(const go_rvec *, go_quat *);
extern int go_rvec_mat_convert(const go_rvec *, go_mat *);
extern int go_rvec_zyz_convert(const go_rvec *, go_zyz *);
extern int go_rvec_zyx_convert(const go_rvec *, go_zyx *);
extern int go_rvec_rpy_convert(const go_rvec *, go_rpy *);

extern int go_quat_rvec_convert(const go_quat *, go_rvec *);
extern int go_quat_mat_convert(const go_quat *, go_mat *);
extern int go_quat_zyz_convert(const go_quat *, go_zyz *);
extern int go_quat_zyx_convert(const go_quat *, go_zyx *);
extern int go_quat_rpy_convert(const go_quat *, go_rpy *);

extern int go_mat_rvec_convert(const go_mat *, go_rvec *);
extern int go_mat_quat_convert(const go_mat *, go_quat *);
extern int go_mat_zyz_convert(const go_mat *, go_zyz *);
extern int go_mat_zyx_convert(const go_mat *, go_zyx *);
extern int go_mat_rpy_convert(const go_mat *, go_rpy *);

extern int go_zyz_rvec_convert(const go_zyz *, go_rvec *);
extern int go_zyz_quat_convert(const go_zyz *, go_quat *);
extern int go_zyz_mat_convert(const go_zyz *, go_mat *);
extern int go_zyz_zyx_convert(const go_zyz *, go_zyx *);
extern int go_zyz_rpy_convert(const go_zyz *, go_rpy *);

extern int go_zyx_rvec_convert(const go_zyx *, go_rvec *);
extern int go_zyx_quat_convert(const go_zyx *, go_quat *);
extern int go_zyx_mat_convert(const go_zyx *, go_mat *);
extern int go_zyx_zyz_convert(const go_zyx *, go_zyz *);
extern int go_zyx_rpy_convert(const go_zyx *, go_rpy *);

extern int go_rpy_rvec_convert(const go_rpy *, go_rvec *);
extern int go_rpy_quat_convert(const go_rpy *, go_quat *);
extern int go_rpy_mat_convert(const go_rpy *, go_mat *);
extern int go_rpy_zyz_convert(const go_rpy *, go_zyz *);
extern int go_rpy_zyx_convert(const go_rpy *, go_zyx *);

/* combined rep conversion functions */

extern int go_pose_hom_convert(const go_pose *, go_hom *);
extern int go_hom_pose_convert(const go_hom *, go_pose *);

/* misc conversion functions */
/*!
  go_cart_rvec_convert and go_rvec_cart_convert convert between
  Cartesian vectors and rotation vectors. The conversion is trivial
  but keeps types distinct.
*/
extern int go_cart_rvec_convert(const go_cart * cart, go_rvec * rvec);
extern int go_rvec_cart_convert(const go_rvec * rvec, go_cart * cart);

/* translation functions, that work only with the preferred
   go_cart type. Other types must be converted to go_cart
   to use these, e.g., there's no go_sph_cyl_compare() */

extern go_flag go_cart_cart_compare(const go_cart *, const go_cart *);
extern int go_cart_cart_dot(const go_cart *, const go_cart *,
				  go_real *);
extern int go_cart_cart_cross(const go_cart *, const go_cart *,
				    go_cart *);
extern int go_cart_mag(const go_cart *, go_real *);
extern int go_cart_magsq(const go_cart *, go_real *);
extern go_flag go_cart_cart_par(const go_cart *, const go_cart *);
extern go_flag go_cart_cart_perp(const go_cart *, const go_cart *);

/*! Places the Cartesian displacement between two vectors \a v1 and
 \a v2 in \a disp, returning \a GO_RESULT_OK. */
extern int go_cart_cart_disp(const go_cart * v1,
				   const go_cart * v2,
				   go_real * disp);

extern int go_cart_cart_add(const go_cart *, const go_cart *,
				  go_cart *);
extern int go_cart_cart_sub(const go_cart *, const go_cart *,
				  go_cart *);
extern int go_cart_scale_mult(const go_cart *, go_real, go_cart *);
extern int go_cart_neg(const go_cart *, go_cart *);
extern int go_cart_unit(const go_cart *, go_cart *);

/*!
  Given two non-zero vectors \a v1 and \a v2, fill in \a quat with
  the minimum rotation that brings \a v1 to \a v2.
 */
extern int go_cart_cart_rot(const go_cart * v1,
				  const go_cart * v2,
				  go_quat * quat);

/*!
  Project vector \a v1 onto \a v2, with the resulting vector placed
  into \a vout. Returns GO_RESULT_OK if it can be done, otherwise
  something else.
*/
extern int go_cart_cart_proj(const go_cart * v1, const go_cart * v2,
				   go_cart * vout);
extern int go_cart_plane_proj(const go_cart *, const go_cart *,
				    go_cart *);
extern int go_cart_cart_angle(const go_cart *, const go_cart *,
				    go_real *);
/*!
  go_cart_normal finds one of the infinite vectors perpendicular
  to \a v, putting the result in \a vout.
 */
extern int go_cart_normal(const go_cart * v, go_cart * vout);
extern int go_cart_centroid(const go_cart * varray,
				  go_integer num,
				  go_cart * centroid);
extern int go_cart_centroidize(const go_cart * vinarray,
				     go_integer num,
				     go_cart * centroid,
				     go_cart * voutarray);
extern int go_cart_cart_pose(const go_cart *, const go_cart *,
				   go_cart *, go_cart *,
				   go_integer, go_pose *);

/*!
  Returns the Cartesian point \a p whose distances from three other points
  \a c1, \a c2 and \a c3 are \a l1, \a l2 and \a l3, respectively. In
  general there are 0, 1 or two points possible. If no point is possible,
  this returns GO_RESULT_ERROR, otherwise the points are returned in \a
  p1 and \a p2, which may be the same point.
*/

int go_cart_trilaterate(const go_cart * c1, 
			      const go_cart * c2,
			      const go_cart * c3,
			      go_real l1,
			      go_real l2,
			      go_real l3,
			      go_cart * p1,
			      go_cart * p2);

/* quat functions */

extern go_flag go_quat_quat_compare(const go_quat *, const go_quat *);
extern int go_quat_mag(const go_quat *, go_real *);

/*!
  go_quat_unit takes a quaternion rotation \a q and converts it into
  a unit rotation about the same axis, \a qout.
*/
extern int go_quat_unit(const go_quat * q, go_quat * qout);
extern int go_quat_norm(const go_quat *, go_quat *);
extern int go_quat_inv(const go_quat *, go_quat *);
extern go_flag go_quat_is_norm(const go_quat *);
extern int go_quat_scale_mult(const go_quat *, go_real, go_quat *);
extern int go_quat_quat_mult(const go_quat *, const go_quat *,
				   go_quat *);
extern int go_quat_cart_mult(const go_quat *, const go_cart *,
				   go_cart *);

/* rotation vector functions */

extern go_flag go_rvec_rvec_compare(const go_rvec * r1, const go_rvec * r2);
extern int go_rvec_scale_mult(const go_rvec *, go_real, go_rvec *);

/* rotation matrix functions */

/*        |  m.x.x   m.y.x   m.z.x  |   */
/*   M =  |  m.x.y   m.y.y   m.z.y  |   */
/*        |  m.x.z   m.y.z   m.z.z  |   */

/*!
  Normalizes rotation matrix \a m so that all columns are mutually
  perpendicular unit vectors, placing the result in \a mout.
*/
extern int go_mat_norm(const go_mat * m, go_mat * mout);

extern go_flag go_mat_is_norm(const go_mat *);
extern int go_mat_inv(const go_mat *, go_mat *);
extern int go_mat_cart_mult(const go_mat *, const go_cart *, go_cart *);
extern int go_mat_mat_mult(const go_mat *, const go_mat *, go_mat *);

/* pose functions*/

extern go_flag go_pose_pose_compare(const go_pose *, const go_pose *);
extern int go_pose_inv(const go_pose *, go_pose *);
extern int go_pose_cart_mult(const go_pose *, const go_cart *, go_cart *);
extern int go_pose_pose_mult(const go_pose *, const go_pose *, go_pose *);
extern int go_pose_scale_mult(const go_pose *, go_real, go_pose *);

/*! Given two times \a t1 and \a t2, and associated poses \a p1 and \a
  p2, interpolates (or extrapolates) to find pose \a p3 at time \a
  t3. The result is stored in \a p3. Returns GO_RESULT_OK if \a t1 and
  \a t2 are distinct and \a p1 and \a p2 are valid poses, otherwise it
  can't interpolate and returns a relevant error. */
extern int
go_pose_pose_interp(go_real t1,
		    const go_pose * p1,
		    go_real t2, 
		    const go_pose * p2,
		    go_real t3, 
		    go_pose * p3);

/* homogeneous transform functions */

extern int go_hom_inv(const go_hom *, go_hom *);

/* screw functions */

/*! Given \a pose transformation from frame A to B, and a screw \a screw
  in frame A, transform the screw into frame B and place in \a out. */
extern int go_pose_screw_mult(const go_pose * pose, const go_screw * screw, go_screw * out);

/* declarations for general MxN matrices */

/*!
  Declare a matrix variable \a m with \a rows rows and \a cols columns.
  Allocates \a rows X \a columns of space in \a mspace.
*/

typedef go_real go_vector;

typedef struct {
  go_integer rows;
  go_integer cols;
  go_real ** el;
  go_real ** elcpy;
  go_real * v;
  go_integer * index;
} go_matrix;

#define GO_MATRIX_DECLARE(M,Mspace,_rows,_cols) \
go_matrix M = {0, 0, 0, 0, 0, 0}; \
struct { \
  go_real * el[_rows]; \
  go_real * elcpy[_rows]; \
  go_real stg[_rows][_cols]; \
  go_real stgcpy[_rows][_cols]; \
  go_real v[_rows]; \
  go_integer index[_rows]; \
} Mspace

#define go_matrix_init(M,Mspace,_rows,_cols) \
M.el = Mspace.el;				    \
M.elcpy = Mspace.elcpy;				    \
for (M.rows = 0; M.rows < (_rows); M.rows++) { \
  M.el[M.rows] = Mspace.stg[M.rows];	    \
  M.elcpy[M.rows] = Mspace.stgcpy[M.rows];	    \
} \
M.rows = (_rows); \
M.cols = (_cols); \
M.v = Mspace.v; \
M.index = Mspace.index

extern go_real
go_get_singular_epsilon(void);

extern int
go_set_singular_epsilon(go_real epsilon);

extern int
ludcmp(go_real ** a,
       go_real * scratchrow,
       go_integer n,
       go_integer * indx,
       go_real * d);

extern int
lubksb(go_real ** a,
       go_integer n,
       go_integer * indx,
       go_real * b);

/* MxN matrix, Mx1 vector functions */

extern int
go_cart_vector_convert(const go_cart * c,
		       go_vector * v);
extern int
go_vector_cart_convert(const go_real * v,
		       go_cart * c);

extern int
go_quat_matrix_convert(const go_quat * quat,
		      go_matrix * matrix);

extern int
go_mat_matrix_convert(const go_mat * mat,
		      go_matrix * matrix);

extern int
go_matrix_matrix_add(const go_matrix * a,
		     const go_matrix * b,
		     go_matrix * apb);

extern int
go_matrix_matrix_copy(const go_matrix * src,
		      go_matrix * dst);

extern int
go_matrix_matrix_mult(const go_matrix * a,
		      const go_matrix * b,
		      go_matrix * ab);

extern int
go_matrix_vector_mult(const go_matrix * a,
		      const go_vector * v,
		      go_vector * av);

/*!
  The matrix-vector cross product is a matrix of the same dimension,
  whose columns are the column-wise cross products of the matrix
  and the vector. The matrices must be 3xN, the vector 3x1.
*/
extern int
go_matrix_vector_cross(const go_matrix * a,
		       const go_vector * v,
		       go_matrix * axv);

extern int
go_matrix_transpose(const go_matrix * a,
		    go_matrix * at);

extern int
go_matrix_inv(const go_matrix * a,
	      go_matrix * ainv);

/* Square matrix functions, where matN is an NxN matrix, and vecN
   is an Nx1 vector */

/* Optimized 3x3 functions */
extern int go_mat3_inv(const go_real a[3][3],
			     go_real ainv[3][3]);
extern int go_mat3_mat3_mult(const go_real a[3][3],
				   const go_real b[3][3],
				   go_real axb[3][3]);
extern int go_mat3_vec3_mult(const go_real a[3][3],
				   const go_real v[3],
				   go_real axv[3]);

/* Optimized 4x4 functions */
extern int go_mat4_inv(const go_real a[4][4],
			     go_real ainv[4][4]);
extern int go_mat4_mat4_mult(const go_real a[4][4],
				   const go_real b[4][4],
				   go_real axb[4][4]);
extern int go_mat4_vec4_mult(const go_real a[4][4],
				   const go_real v[4],
				   go_real axv[4]);

/*!
  Given a 6x6 matrix \a a, computes the inverse and returns it in
  \a ainv. Leaves \a a untouched. Returns GO_RESULT_OK if there is an
  inverse, else GO_RESULT_SINGULAR if the matrix is singular.
*/
extern int go_mat6_inv(const go_real a[6][6],
			     go_real ainv[6][6]);

/*!
  Given two 6x6 matrices \a a and \a b, multiplies them and returns
  the result in \a axb. Leaves \a a and \a b untouched.
  Returns GO_RESULT_OK.
*/
extern int go_mat6_mat6_mult(const go_real a[6][6],
				   const go_real b[6][6],
				   go_real axb[6][6]);

/*!
  Given a 6x6 matrix \a a and a 6x1 vector \a v, multiplies them
  and returns the result in \a axv. Leaves \a a and \a v untouched.
  Returns GO_RESULT_OK.
*/
extern int go_mat6_vec6_mult(const go_real a[6][6],
				   const go_real v[6],
				   go_real axv[6]);

/* Denavit-Hartenberg to pose conversions */

/*
  The link frams is assumed to be

  | i-1
  |    T
  |   i

  that is, elements of the link frame expressed wrt the
  previous link frame.
*/

/*!
  These DH parameters follow the convention in John J. Craig,
  _Introduction to Robotics: Mechanics and Control_.
*/
typedef struct {
  go_real a;			/*< a[i-1] */
  go_real alpha;		/*< alpha[i-1] */
  /* either d or theta are the free variable, depending on quantity */
  go_real d;			/*< d[i] */
  go_real theta;		/*< theta[i] */
} go_dh;

/*!
  PK parameters are used for parallel kinematic mechanisms, and
  represent the Cartesian positions of the ends of the link in the
  stationary base frame and the moving platform frame. Currently this
  only supports prismatic links.
 */
typedef struct {
  go_cart base;			/*< position of fixed end in base frame */
  go_cart platform;		/*< position of moving end in platform frame  */
  go_real d;			/*< the length of the link */
} go_pk;

/*!
  PP parameters represent the pose of the link with respect to the
  previous link. Revolute joints rotate about the Z axis, prismatic
  joints slide along the Z axis.
 */
typedef struct {
  go_pose pose;		/*< the pose of the link wrt to the previous link */
} go_pp;

/*! Types of link parameter representations  */
enum {
  GO_LINK_DH = 1,		/*< for Denavit-Hartenberg params  */
  GO_LINK_PK,			/*< for parallel kinematics  */
  GO_LINK_PP			/*< for serial kinematics */
};

#define go_link_to_string(L)		\
(L) == GO_LINK_DH ? "DH" :		\
(L) == GO_LINK_PK ? "PK" :		\
(L) == GO_LINK_PP ? "PP" : "None"

/*!
  This is the generic link structure for PKM sliding/cable links and 
  serial revolute/prismatic links.
 */
typedef struct {
  union {
    go_dh dh; /*< if you have DH params and don't want to convert to PP */
    go_pk pk; /*< if you have a parallel machine, e.g., hexapod or robot crane */
    go_pp pp; /*< if you have a serial machine, e.g., an industrial robot  */
  } u;
  go_flag type;			/*< one of GO_LINK_DH,PK,PP  */
  go_flag quantity;		/*< one of GO_QUANTITY_LENGTH,ANGLE */
} go_link;

/*!
  Converts DH parameters in \a dh to their pose equivalent, stored
  in \a pose.
 */
extern int go_dh_pose_convert(const go_dh * dh, go_pose * pose);

/*!
  Converts \a pose to the equivalent DH parameters, stored in \a dh.
  Warning! Conversion from these DH parameters back to a pose via \a
  go_dh_pose_convert will NOT in general result in the same
  pose. Poses have 6 degrees of freedom, DH parameters have 4, and
  conversion to DH parameters loses some information. The source of
  this information loss is the convention imposed on DH parameters for
  choice of X-Y-Z axis directions. With poses, there is no such
  convention, and poses are thus freer than DH parameters.
 */
extern int go_pose_dh_convert(const go_pose * pose, go_dh * dh);

/*!
  Fixes the link in \a link to its value when the joint
  variable is \a joint, storing the result in \a linkout.
*/
extern int go_link_joint_set(const go_link * link, go_real joint, go_link * linkout);

/*!
  Takes the link description of the device in \a links, and the number
  of these in \a num, and builds the pose of the device and stores in
  \a pose. \a links should have the value of the free link parameter
  filled in with the current joint value, e.g., with a prior call to
  go_link_joint_set.
*/
extern int go_link_pose_build(const go_link * links, go_integer num, go_pose * pose);

typedef struct {
  go_real re;
  go_real im;
} go_complex;

extern go_complex go_complex_add(go_complex z1, go_complex z2);
extern go_complex go_complex_sub(go_complex z1, go_complex z2);
extern go_complex go_complex_mult(go_complex z1, go_complex z2);
extern go_complex go_complex_div(go_complex z1, go_complex z2, int * result);
extern go_complex go_complex_scale(go_complex z, go_real scale);
extern go_real go_complex_mag(go_complex z);
extern go_real go_complex_arg(go_complex z);
extern void go_complex_sqrt(go_complex z, go_complex * z1, go_complex * z2);
extern void go_complex_cbrt(go_complex z, go_complex * z1, go_complex * z2, go_complex * z3);

typedef struct {
  /* leading coefficient is 1, x^2 + ax + b = 0 */
  go_real a;
  go_real b;
} go_quadratic;

typedef struct {
  /* leading coefficient is 1, x^3 + ax^2 + bx + c = 0 */
  go_real a;
  go_real b;
  go_real c;
} go_cubic;

typedef struct {
  /* leading coefficient is 1, x^4 + ax^3 + bx^2 + cx + d = 0 */
  go_real a;
  go_real b;
  go_real c;
  go_real d;
} go_quartic;

extern int go_quadratic_solve(const go_quadratic * quad,
				    go_complex * z1,
				    go_complex * z2);

extern int go_cubic_solve(const go_cubic * cub,
				go_complex * z1,
				go_complex * z2,
				go_complex * z3);

extern int go_quartic_solve(const go_quartic * quart,
				  go_complex * z1,
				  go_complex * z2,
				  go_complex * z3,
				  go_complex * z4);

extern int go_tridiag_reduce(go_real ** a,
				   go_integer n,
				   go_real * d,
				   go_real * e);

extern int go_tridiag_ql(go_real * d,
			       go_real * e,
			       go_integer n,
			       go_real ** z);

#endif /* GO_MATH_H */