Fix saving lists of arrays with recent versions of numpy
[qpms.git] / qpms / vectors.h
blob72678732c69dec17facfd14c6844ad60ae6d72ad
1 /*! \file vectors.h
2 * \brief Coordinate transforms and vector arithmetics.
3 */
4 #ifndef VECTORS_H
5 #define VECTORS_H
6 #include <math.h>
7 #ifndef M_PI_2
8 #define M_PI_2 (1.570796326794896619231321691639751442098584699687552910487)
9 #endif
10 #include "qpms_types.h"
11 #include "qpms_error.h"
13 //static inline double vectors_h_sq(double x) {return x*x;}
15 static const cart2_t CART2_ZERO = {0, 0};
16 static const cart3_t CART3_ZERO = {0, 0, 0};
18 /// 2D vector addition.
19 static inline cart2_t cart2_add(const cart2_t a, const cart2_t b) {
20 cart2_t res = {a.x+b.x, a.y+b.y};
21 return res;
24 /// 2D vector substraction.
25 static inline cart2_t cart2_substract(const cart2_t a, const cart2_t b) {
26 cart2_t res = {a.x-b.x, a.y-b.y};
27 return res;
30 /// 2D vector scaling.
31 static inline cart2_t cart2_scale(const double c, const cart2_t v) {
32 cart2_t res = {c * v.x, c * v.y};
33 return res;
36 /// 2D vector dot product.
37 static inline double cart2_dot(const cart2_t a, const cart2_t b) {
38 return a.x * b.x + a.y * b.y;
41 static inline double cart2_normsq(const cart2_t a) {
42 return cart2_dot(a, a);
45 /// 2D vector euclidian norm.
46 static inline double cart2norm(const cart2_t v) {
47 return hypot(v.x, v.y); //sqrt(v.x*v.x + v.y*v.y);
50 /// 2D cartesian to polar coordinates conversion. See @ref coord_conversions.
51 static inline pol_t cart2pol(const cart2_t cart) {
52 pol_t pol;
53 pol.r = cart2norm(cart);
54 pol.phi = atan2(cart.y, cart.x);
55 return pol;
58 /// Polar to spherical coordinates conversion. See @ref coord_conversions.
59 static inline sph_t pol2sph_equator(const pol_t pol) {
60 sph_t sph;
61 sph.r = pol.r;
62 sph.phi = pol.phi;
63 sph.theta = M_PI_2;
64 return sph;
67 /// 2D cartesian to spherical coordinates conversion. See @ref coord_conversions.
68 static inline sph_t cart22sph(const cart2_t cart) {
69 sph_t sph;
70 sph.r = cart2norm(cart);
71 sph.theta = M_PI_2;
72 sph.phi = atan2(cart.y, cart.x);
73 return sph;
76 /// 1D cartesian to spherical coordinates conversion. See @ref coord_conversions.
77 static inline sph_t cart12sph_zaxis(double z) {
78 sph_t sph = {fabs(z), z < 0 ? M_PI : 0, 0};
79 return sph;
82 /// 1D to 3D cartesian coordinates conversion. See @ref coord_conversions.
83 static inline cart3_t cart12cart3z(double z) {
84 cart3_t c = {0, 0, z};
85 return c;
88 /// 2D to 3D cartesian coordinates conversion. See @ref coord_conversions.
89 static inline cart3_t cart22cart3xy(const cart2_t a) {
90 cart3_t c;
91 c.x = a.x;
92 c.y = a.y;
93 c.z = 0;
94 return c;
97 static inline cart2_t cart3xy2cart2(const cart3_t a) {
98 cart2_t c = {a.x, a.y};
99 return c;
102 /// 3D vector dot product.
103 static inline double cart3_dot(const cart3_t a, const cart3_t b) {
104 return a.x * b.x + a.y * b.y + a.z * b.z;
108 /// 3D vector product a.k.a. cross product.
109 static inline cart3_t cart3_vectorprod(const cart3_t a, const cart3_t b) {
110 cart3_t c = {
111 .x = a.y * b.z - a.z * b.y,
112 .y = a.z * b.x - a.x * b.z,
113 .z = a.x * b.y - a.y * b.x,
115 return c;
118 /// Scalar triple product \f$ a \cdot ( b \times c ) \f$.
119 static inline double cart3_tripleprod(const cart3_t a, const cart3_t b, const cart3_t c) {
120 return cart3_dot(a, cart3_vectorprod(b, c));
123 /// 3D vector euclidian norm squared.
124 static inline double cart3_normsq(const cart3_t a) {
125 return cart3_dot(a, a);
128 /// 3D vector euclidian norm.
129 static inline double cart3norm(const cart3_t v) {
130 return sqrt(cart3_normsq(v));
133 /// 3D cartesian to spherical coordinates conversion. See @ref coord_conversions.
134 static inline sph_t cart2sph(const cart3_t cart) {
135 sph_t sph;
136 sph.r = cart3norm(cart);
137 sph.theta = sph.r ? acos(cart.z / sph.r) : M_PI_2;
138 sph.phi = atan2(cart.y, cart.x);
139 return sph;
142 /// Spherical to 3D cartesian coordinates conversion. See @ref coord_conversions.
143 static inline cart3_t sph2cart(const sph_t sph) {
144 cart3_t cart;
145 double sin_th =
146 #ifdef QPMS_VECTORS_NICE_TRANSFORMATIONS
147 (sph.theta == M_PI) ? 0 :
148 #endif
149 sin(sph.theta);
150 cart.x = sph.r * sin_th * cos(sph.phi);
151 cart.y = sph.r * sin_th * sin(sph.phi);
152 cart.z = sph.r * cos(sph.theta);
153 return cart;
156 /// Polar to 2D cartesian coordinates conversion. See @ref coord_conversions.
157 static inline cart2_t pol2cart(const pol_t pol) {
158 cart2_t cart;
159 cart.x = pol.r * cos(pol.phi);
160 cart.y = pol.r * sin(pol.phi);
161 return cart;
164 /// Polar to 3D cartesian coordinates conversion. See @ref coord_conversions.
165 static inline cart3_t pol2cart3_equator(const pol_t pol) {
166 cart2_t c = pol2cart(pol);
167 cart3_t cart3 = {c.x, c.y, 0};
168 return cart3;
172 /// 3D vector addition.
173 static inline cart3_t cart3_add(const cart3_t a, const cart3_t b) {
174 cart3_t res = {a.x+b.x, a.y+b.y, a.z+b.z};
175 return res;
178 /// 3D vector substraction.
179 static inline cart3_t cart3_substract(const cart3_t a, const cart3_t b) {
180 cart3_t res = {a.x-b.x, a.y-b.y, a.z-b.z};
181 return res;
184 /// 3D vector scaling
185 static inline cart3_t cart3_scale(const double c, const cart3_t v) {
186 cart3_t res = {c * v.x, c * v.y, c * v.z};
187 return res;
190 /// 3D vector division by scalar (N.B. argument order).
191 static inline cart3_t cart3_divscale( const cart3_t v, const double c) {
192 cart3_t res = {v.x / c, v.y / c, v.z / c};
193 return res;
196 /// Euclidian distance between two 3D points.
197 static inline double cart3_dist(const cart3_t a, const cart3_t b) {
198 return cart3norm(cart3_substract(a,b));
201 static inline bool cart3_isclose(const cart3_t a, const cart3_t b, double rtol, double atol) {
202 return cart3_dist(a,b) <= atol + rtol * (cart3norm(b) + cart3norm(a)) * .5;
205 /// Complex 3D vector scaling.
206 static inline ccart3_t ccart3_scale(const complex double c, const ccart3_t v) {
207 ccart3_t res = {c * v.x, c * v.y, c * v.z};
208 return res;
211 /// Complex 3D vector adition.
212 static inline ccart3_t ccart3_add(const ccart3_t a, const ccart3_t b) {
213 ccart3_t res = {a.x+b.x, a.y+b.y, a.z+b.z};
214 return res;
217 /// Complex 3D vector substraction.
218 static inline ccart3_t ccart3_substract(const ccart3_t a, const ccart3_t b) {
219 ccart3_t res = {a.x-b.x, a.y-b.y, a.z-b.z};
220 return res;
223 /// Complex 3D cartesian vector "dot product" without conjugation.
224 static inline complex double ccart3_dotnc(const ccart3_t a, const ccart3_t b) {
225 return a.x * b.x + a.y * b.y + a.z * b.z;
228 /// Convert cart3_t to ccart3_t.
229 static inline ccart3_t cart32ccart3(cart3_t c){
230 ccart3_t res = {c.x, c.y, c.z};
231 return res;
234 /// Complex 3D vector (geographic coordinates) addition.
235 static inline csphvec_t csphvec_add(const csphvec_t a, const csphvec_t b) {
236 csphvec_t res = {a.rc + b.rc, a.thetac + b.thetac, a.phic + b.phic};
237 return res;
240 /// Complex 3D vector (geographic coordinates) substraction.
241 static inline csphvec_t csphvec_substract(const csphvec_t a, const csphvec_t b) {
242 csphvec_t res = {a.rc - b.rc, a.thetac - b.thetac, a.phic - b.phic};
243 return res;
246 /// Complex 3D vector (geographic coordinates) scaling.
247 static inline csphvec_t csphvec_scale(complex double c, const csphvec_t v) {
248 csphvec_t res = {c * v.rc, c * v.thetac, c * v.phic};
249 return res;
252 /// Complex 3D vector (geographic coordinates) "dot product" without conjugation.
253 static inline complex double csphvec_dotnc(const csphvec_t a, const csphvec_t b) {
254 //N.B. no complex conjugation done here
255 return a.rc * b.rc + a.thetac * b.thetac + a.phic * b.phic;
258 /// Spherical coordinate system scaling.
259 static inline sph_t sph_scale(double c, const sph_t s) {
260 sph_t res = {c * s.r, s.theta, s.phi};
261 return res;
264 /// "Complex spherical" coordinate system scaling.
265 static inline csph_t sph_cscale(complex double c, const sph_t s) {
266 csph_t res = {c * s.r, s.theta, s.phi};
267 return res;
270 /// Coordinate transform of a vector in local geographic to global cartesian system.
271 // equivalent to sph_loccart2cart in qpms_p.py
272 static inline ccart3_t csphvec2ccart(const csphvec_t sphvec, const sph_t at) {
273 const double st = sin(at.theta);
274 const double ct = cos(at.theta);
275 const double sf = sin(at.phi);
276 const double cf = cos(at.phi);
277 const double rx = st * cf;
278 const double ry = st * sf;
279 const double rz = ct;
280 const double tx = ct * cf;
281 const double ty = ct * sf;
282 const double tz = -st;
283 const double fx = -sf;
284 const double fy = cf;
285 const double fz = 0.;
286 ccart3_t res;
287 res.x = rx * sphvec.rc + tx * sphvec.thetac + fx * sphvec.phic;
288 res.y = ry * sphvec.rc + ty * sphvec.thetac + fy * sphvec.phic;
289 res.z = rz * sphvec.rc + tz * sphvec.thetac + fz * sphvec.phic;
290 return res;
293 /// Coordinate transform of a vector in local geographic to global cartesian system.
295 * Same as csphvec2ccart, but with csph_t as second argument.
296 * (The radial part (which is the only complex part of csph_t)
297 * of the second argument does not play role in the
298 * transformation, so this is completely legit
300 static inline ccart3_t csphvec2ccart_csph(const csphvec_t sphvec, const csph_t at) {
301 const sph_t atreal = {0 /*not used*/, at.theta, at.phi};
302 return csphvec2ccart(sphvec, atreal);
305 /// Coordinate transform of a vector in global cartesian to local geographic system.
306 static inline csphvec_t ccart2csphvec(const ccart3_t cartvec, const sph_t at) {
307 // this chunk is copy-pasted from csphvec2cart, so there should be a better way...
308 const double st = sin(at.theta);
309 const double ct = cos(at.theta);
310 const double sf = sin(at.phi);
311 const double cf = cos(at.phi);
312 const double rx = st * cf;
313 const double ry = st * sf;
314 const double rz = ct;
315 const double tx = ct * cf;
316 const double ty = ct * sf;
317 const double tz = -st;
318 const double fx = -sf;
319 const double fy = cf;
320 const double fz = 0.;
321 csphvec_t res;
322 res.rc = rx * cartvec.x + ry * cartvec.y + rz * cartvec.z;
323 res.thetac = tx * cartvec.x + ty * cartvec.y + tz * cartvec.z;
324 res.phic = fx * cartvec.x + fy * cartvec.y + fz * cartvec.z;
325 return res;
328 /// Convert sph_t to csph_t.
329 static inline csph_t sph2csph(sph_t s) {
330 csph_t cs = {s.r, s.theta, s.phi};
331 return cs;
334 /// Convert csph_t to sph_t, discarding the imaginary part of radial component.
335 static inline sph_t csph2sph(csph_t s) {
336 sph_t rs = {creal(s.r), s.theta, s.phi};
337 return rs;
340 /// Lossy coordinate transform of ccart3_t to csph_t.
341 /** The angle and real part of the radial coordinate are determined
342 * from the real components of \a \cart. The imaginary part of the radial
343 * coordinate is then determined as the length of the imaginary
344 * part of \a cart *projected onto* the real part of \a cart.
346 * N.B. this obviously makes not much sense for purely imaginary vectors
347 * (and will cause NANs). TODO handle this better, as purely imaginary
348 * vectors could make sense e.g. for evanescent waves.
350 static inline csph_t ccart2csph(const ccart3_t cart) {
351 cart3_t rcart = {creal(cart.x), creal(cart.y), creal(cart.z)};
352 cart3_t icart = {cimag(cart.x), cimag(cart.y), cimag(cart.z)};
353 csph_t sph = sph2csph(cart2sph(rcart));
354 sph.r += I * cart3_dot(icart,rcart) / cart3norm(rcart);
355 return sph;
358 /// Real 3D cartesian to spherical (complex r) coordinates conversion. See @ref coord_conversions.
359 static inline csph_t cart2csph(const cart3_t cart) {
360 csph_t sph;
361 sph.r = cart3norm(cart);
362 sph.theta = sph.r ? acos(cart.z / sph.r) : M_PI_2;
363 sph.phi = atan2(cart.y, cart.x);
364 return sph;
367 /// Coordinate transform of csph_t to ccart3_t
368 static inline ccart3_t csph2ccart(const csph_t sph) {
369 ccart3_t cart;
370 double sin_th =
371 #ifdef QPMS_VECTORS_NICE_TRANSFORMATIONS
372 (sph.theta == M_PI) ? 0 :
373 #endif
374 sin(sph.theta);
375 cart.x = sph.r * sin_th * cos(sph.phi);
376 cart.y = sph.r * sin_th * sin(sph.phi);
377 cart.z = sph.r * cos(sph.theta);
378 return cart;
382 void print_csphvec(csphvec_t);
383 void print_ccart3(ccart3_t);
384 void print_cart3(cart3_t);
385 void print_sph(sph_t);
387 // kahan sums for various types... TODO make generic code using macros
389 /// Kanan sum initialisation for ccart3_t.
390 static inline void ccart3_kahaninit(ccart3_t *sum, ccart3_t *compensation) {
391 sum->x = sum->y = sum->z = compensation->x = compensation->y = compensation->z = 0;
393 /// Kanan sum initialisation for csphvec_t.
394 static inline void csphvec_kahaninit(csphvec_t *sum, csphvec_t *compensation) {
395 sum->rc = sum->thetac = sum->phic = compensation->rc = compensation->thetac = compensation->phic = 0;
398 /// Add element to Kahan sum (ccart3_t).
399 static inline void ccart3_kahanadd(ccart3_t *sum, ccart3_t *compensation, const ccart3_t input) {
400 ccart3_t comped_input = ccart3_substract(input, *compensation);
401 ccart3_t nsum = ccart3_add(*sum, comped_input);
402 *compensation = ccart3_substract(ccart3_substract(nsum, *sum), comped_input);
403 *sum = nsum;
406 /// Add element to Kahan sum (csphvec_t).
407 static inline void csphvec_kahanadd(csphvec_t *sum, csphvec_t *compensation, const csphvec_t input) {
408 csphvec_t comped_input = csphvec_substract(input, *compensation);
409 csphvec_t nsum = csphvec_add(*sum, comped_input);
410 *compensation = csphvec_substract(csphvec_substract(nsum, *sum), comped_input);
411 *sum = nsum;
414 /// Euclidian norm of a vector in geographic coordinates.
415 static inline double csphvec_norm(const csphvec_t a) {
416 return sqrt(creal(a.rc * conj(a.rc) + a.thetac * conj(a.thetac) + a.phic * conj(a.phic)));
419 static inline double csphvec_reldiff_abstol(const csphvec_t a, const csphvec_t b, double tolerance) {
420 double anorm = csphvec_norm(a);
421 double bnorm = csphvec_norm(b);
422 if (anorm <= tolerance && bnorm <= tolerance) return 0;
423 return csphvec_norm(csphvec_substract(a,b)) / (anorm + bnorm);
426 static inline double csphvec_reldiff(const csphvec_t a, const csphvec_t b) {
427 return csphvec_reldiff_abstol(a, b, 0);
431 /*! \page coord_conversions Coordinate systems and default conversions
433 * The coordinate system transformations are defined as following:
435 * \section coordtf_same_d Equal-dimension coordinate tranforms
436 * \subsection sph_cart3 Spherical and 3D cartesian coordinates
437 * * \f$ x = r \sin \theta \cos \phi \f$,
438 * * \f$ y = r \sin \theta \sin \phi \f$,
439 * * \f$ z = r \cos \theta \f$.
440 * \subsection pol_cart2 Polar and 2D cartesian coordinates
441 * * \f$ x = r \cos \phi \f$,
442 * * \f$ y = r \sin \phi \f$.
444 * \section coordtf_123 Lower to higher dimension conversions.
445 * * The 1D coordinate is identified with the \a z 3D cartesian coordinate.
446 * * The 2D cartesian coordinates \a x, \a y are identified with the \a x, \a y
447 * 3D cartesian coordinates.
448 * * For the sake of consistency, default conversion between
449 * 1D and 2D coordinates is not allowed and yields NAN values.
451 * \section coordtf_321 Higher to lower dimension conversions.
452 * Default conversions from higher to lower-dimensional coordinate
453 * systems are not allowed. Any projections have to be done explicitly.
456 /// Conversion from anycoord_point_t to explicitly spherical coordinates.
457 /** See @ref coord_conversions for the conversion definitions.
459 static inline sph_t anycoord2sph(anycoord_point_t p, qpms_coord_system_t t) {
460 switch(t & QPMS_COORDS_BITRANGE) {
461 case QPMS_COORDS_SPH:
462 return p.sph;
463 break;
464 case QPMS_COORDS_POL:
465 return pol2sph_equator(p.pol);
466 break;
467 case QPMS_COORDS_CART3:
468 return cart2sph(p.cart3);
469 break;
470 case QPMS_COORDS_CART2:
471 return cart22sph(p.cart2);
472 break;
473 case QPMS_COORDS_CART1:
474 return cart12sph_zaxis(p.z);
475 break;
477 QPMS_WTF;
481 /// Conversion from anycoord_point_t to explicitly 3D cartesian coordinates.
482 /** See @ref coord_conversions for the conversion definitions.
484 static inline cart3_t anycoord2cart3(anycoord_point_t p, qpms_coord_system_t t) {
485 switch(t & QPMS_COORDS_BITRANGE) {
486 case QPMS_COORDS_SPH:
487 return sph2cart(p.sph);
488 break;
489 case QPMS_COORDS_POL:
490 return pol2cart3_equator(p.pol);
491 break;
492 case QPMS_COORDS_CART3:
493 return p.cart3;
494 break;
495 case QPMS_COORDS_CART2:
496 return cart22cart3xy(p.cart2);
497 break;
498 case QPMS_COORDS_CART1:
499 return cart12cart3z(p.z);
500 break;
502 QPMS_WTF;
505 /// Cartesian norm of anycoord_point_t.
506 // The implementation is simple and stupid, do not use for heavy computations.
507 static inline double anycoord_norm(anycoord_point_t p, qpms_coord_system_t t) {
508 return cart3norm(anycoord2cart3(p, t));
511 #if 0
512 // Convenience identifiers for return values.
513 static const cart3_t CART3_INVALID = {NAN, NAN, NAN};
514 static const cart2_t CART2_INVALID = {NAN, NAN};
515 static const double CART1_INVALID = NAN;
516 static const sph_t SPH_INVALID = {NAN, NAN, NAN};
517 static const pol_t POL_INVALID = {NAN, NAN};
518 #endif
520 /// Conversion from anycoord_point_t to explicitly polar coordinates.
521 /** See @ref coord_conversions for the conversion definitions.
523 static inline pol_t anycoord2pol(anycoord_point_t p, qpms_coord_system_t t) {
524 switch(t & QPMS_COORDS_BITRANGE) {
525 case QPMS_COORDS_SPH:
526 case QPMS_COORDS_CART3:
527 QPMS_PR_ERROR("Implicit conversion from 3D to 2D"
528 " coordinates not allowed");
529 break;
530 case QPMS_COORDS_POL:
531 return p.pol;
532 break;
533 case QPMS_COORDS_CART2:
534 return cart2pol(p.cart2);
535 break;
536 case QPMS_COORDS_CART1:
537 QPMS_PR_ERROR("Implicit conversion from 1D to 2D"
538 " coordinates not allowed");
539 break;
541 QPMS_WTF;
545 /// Conversion from anycoord_point_t to explicitly 2D cartesian coordinates.
546 /** See @ref coord_conversions for the conversion definitions.
548 static inline cart2_t anycoord2cart2(anycoord_point_t p, qpms_coord_system_t t) {
549 switch(t & QPMS_COORDS_BITRANGE) {
550 case QPMS_COORDS_SPH:
551 case QPMS_COORDS_CART3:
552 QPMS_PR_ERROR("Implicit conversion from 3D to 2D"
553 " coordinates not allowed");
554 break;
555 case QPMS_COORDS_POL:
556 return pol2cart(p.pol);
557 break;
558 case QPMS_COORDS_CART2:
559 return p.cart2;
560 break;
561 case QPMS_COORDS_CART1:
562 QPMS_PR_ERROR("Implicit conversion from 1D to 2D"
563 " coordinates not allowed");
564 break;
566 QPMS_WTF;
570 /// Conversion from anycoord_point_t to explicitly 1D cartesian coordinates.
571 /** See @ref coord_conversions for the conversion definitions.
573 static inline double anycoord2cart1(anycoord_point_t p, qpms_coord_system_t t) {
574 if ((t & QPMS_COORDS_BITRANGE) == QPMS_COORDS_CART1)
575 return p.z;
576 else
577 QPMS_PR_ERROR("Implicit conversion from nD (n > 1)"
578 " to 1D not allowed.");
582 /// Coordinate conversion of point arrays (something to something).
583 /** The dest and src arrays must not overlap */
584 static inline void qpms_array_coord_transform(void *dest, qpms_coord_system_t tdest,
585 const void *src, qpms_coord_system_t tsrc, size_t nmemb) {
586 switch(tdest & QPMS_COORDS_BITRANGE) {
587 case QPMS_COORDS_SPH:
589 sph_t *d = (sph_t *) dest;
590 switch (tsrc & QPMS_COORDS_BITRANGE) {
591 case QPMS_COORDS_SPH: {
592 const sph_t *s = src;
593 for(size_t i = 0; i < nmemb; ++i)
594 d[i] = s[i];
595 return;
596 } break;
597 case QPMS_COORDS_CART3: {
598 const cart3_t *s = src;
599 for(size_t i = 0; i < nmemb; ++i)
600 d[i] = cart2sph(s[i]);
601 return;
602 } break;
603 case QPMS_COORDS_POL: {
604 const pol_t *s = src;
605 for(size_t i = 0; i < nmemb; ++i)
606 d[i] = pol2sph_equator(s[i]);
607 return;
608 } break;
609 case QPMS_COORDS_CART2: {
610 const cart2_t *s = src;
611 for(size_t i = 0; i < nmemb; ++i)
612 d[i] = cart22sph(s[i]);
613 return;
614 } break;
615 case QPMS_COORDS_CART1: {
616 const double *s = src;
617 for(size_t i = 0; i < nmemb; ++i)
618 d[i] = cart12sph_zaxis(s[i]);
619 return;
620 } break;
622 QPMS_WTF;
624 break;
625 case QPMS_COORDS_CART3:
627 cart3_t *d = (cart3_t *) dest;
628 switch (tsrc & QPMS_COORDS_BITRANGE) {
629 case QPMS_COORDS_SPH: {
630 const sph_t *s = src;
631 for(size_t i = 0; i < nmemb; ++i)
632 d[i] = sph2cart(s[i]);
633 return;
634 } break;
635 case QPMS_COORDS_CART3: {
636 const cart3_t *s = src;
637 for(size_t i = 0; i < nmemb; ++i)
638 d[i] = s[i];
639 return;
640 } break;
641 case QPMS_COORDS_POL: {
642 const pol_t *s = src;
643 for(size_t i = 0; i < nmemb; ++i)
644 d[i] = pol2cart3_equator(s[i]);
645 return;
646 } break;
647 case QPMS_COORDS_CART2: {
648 const cart2_t *s = src;
649 for(size_t i = 0; i < nmemb; ++i)
650 d[i] = cart22cart3xy(s[i]);
651 return;
652 } break;
653 case QPMS_COORDS_CART1: {
654 const double *s = src;
655 for(size_t i = 0; i < nmemb; ++i)
656 d[i] = cart12cart3z(s[i]);
657 return;
658 } break;
660 QPMS_WTF;
662 break;
663 case QPMS_COORDS_POL:
665 pol_t *d = (pol_t *) dest;
666 switch (tsrc & QPMS_COORDS_BITRANGE) {
667 case QPMS_COORDS_SPH:
668 case QPMS_COORDS_CART3:
669 QPMS_PR_ERROR("Implicit conversion from 3D to 2D coordinates not allowed");
670 break;
671 case QPMS_COORDS_POL: {
672 const pol_t *s = src;
673 for(size_t i = 0; i < nmemb; ++i)
674 d[i] = s[i];
675 return;
676 } break;
677 case QPMS_COORDS_CART2: {
678 const cart2_t *s = src;
679 for(size_t i = 0; i < nmemb; ++i)
680 d[i] = cart2pol(s[i]);
681 return;
682 } break;
683 case QPMS_COORDS_CART1:
684 QPMS_PR_ERROR("Implicit conversion from 3D to 1D coordinates not allowed");
685 break;
687 QPMS_WTF;
689 break;
690 case QPMS_COORDS_CART2:
692 cart2_t *d = (cart2_t *) dest;
693 switch (tsrc & QPMS_COORDS_BITRANGE) {
694 case QPMS_COORDS_SPH:
695 case QPMS_COORDS_CART3:
696 QPMS_PR_ERROR("Implicit conversion from 3D to 2D coordinates not allowed");
697 break;
698 case QPMS_COORDS_POL: {
699 const pol_t *s = src;
700 for(size_t i = 0; i < nmemb; ++i)
701 d[i] = pol2cart(s[i]);
702 return;
703 } break;
704 case QPMS_COORDS_CART2: {
705 const cart2_t *s = src;
706 for(size_t i = 0; i < nmemb; ++i)
707 d[i] = s[i];
708 return;
709 } break;
710 case QPMS_COORDS_CART1:
711 QPMS_PR_ERROR("Implicit conversion from 3D to 1D coordinates not allowed");
712 break;
714 QPMS_WTF;
716 break;
717 case QPMS_COORDS_CART1:
719 double *d = (double *) dest;
720 switch (tsrc & QPMS_COORDS_BITRANGE) {
721 case QPMS_COORDS_SPH:
722 case QPMS_COORDS_CART3:
723 QPMS_PR_ERROR("Implicit conversion from 3D to 2D coordinates not allowed");
724 break;
725 case QPMS_COORDS_POL:
726 case QPMS_COORDS_CART2:
727 QPMS_PR_ERROR("Implicit conversion from 3D to 1D coordinates not allowed");
728 break;
729 case QPMS_COORDS_CART1: {
730 const double *s = src;
731 for(size_t i = 0; i < nmemb; ++i)
732 d[i] = s[i];
733 return;
734 } break;
736 QPMS_WTF;
738 break;
740 QPMS_WTF;
744 /// Coordinate conversion of point arrays (anycoord_point_t to something).
745 /** The dest and src arrays must not overlap */
746 static inline void anycoord_arr2something(void *dest, qpms_coord_system_t tdest,
747 const anycoord_point_t *src, qpms_coord_system_t tsrc, size_t nmemb) {
748 if(nmemb) {
749 switch(tdest & QPMS_COORDS_BITRANGE) {
750 case QPMS_COORDS_SPH:
752 sph_t *d = (sph_t *) dest;
753 switch (tsrc & QPMS_COORDS_BITRANGE) {
754 case QPMS_COORDS_SPH:
755 for(size_t i = 0; i < nmemb; ++i)
756 d[i] = src[i].sph;
757 return; break;
758 case QPMS_COORDS_CART3:
759 for(size_t i = 0; i < nmemb; ++i)
760 d[i] = cart2sph(src[i].cart3);
761 return; break;
762 case QPMS_COORDS_POL:
763 for(size_t i = 0; i < nmemb; ++i)
764 d[i] = pol2sph_equator(src[i].pol);
765 return; break;
766 case QPMS_COORDS_CART2:
767 for(size_t i = 0; i < nmemb; ++i)
768 d[i] = cart22sph(src[i].cart2);
769 return; break;
770 case QPMS_COORDS_CART1:
771 for(size_t i = 0; i < nmemb; ++i)
772 d[i] = cart12sph_zaxis(src[i].z);
773 return; break;
775 QPMS_WTF;
777 break;
778 case QPMS_COORDS_CART3:
780 cart3_t *d = (cart3_t *) dest;
781 switch (tsrc & QPMS_COORDS_BITRANGE) {
782 case QPMS_COORDS_SPH:
783 for(size_t i = 0; i < nmemb; ++i)
784 d[i] = sph2cart(src[i].sph);
785 return; break;
786 case QPMS_COORDS_CART3:
787 for(size_t i = 0; i < nmemb; ++i)
788 d[i] = src[i].cart3;
789 return; break;
790 case QPMS_COORDS_POL:
791 for(size_t i = 0; i < nmemb; ++i)
792 d[i] = pol2cart3_equator(src[i].pol);
793 return; break;
794 case QPMS_COORDS_CART2:
795 for(size_t i = 0; i < nmemb; ++i)
796 d[i] = cart22cart3xy(src[i].cart2);
797 return; break;
798 case QPMS_COORDS_CART1:
799 for(size_t i = 0; i < nmemb; ++i)
800 d[i] = cart12cart3z(src[i].z);
801 return; break;
803 QPMS_WTF;
805 break;
806 case QPMS_COORDS_POL:
808 pol_t *d = (pol_t *) dest;
809 switch (tsrc & QPMS_COORDS_BITRANGE) {
810 case QPMS_COORDS_SPH:
811 case QPMS_COORDS_CART3:
812 QPMS_PR_ERROR("Implicit conversion from 3D to 2D coordinates not allowed");
813 break;
814 case QPMS_COORDS_POL:
815 for(size_t i = 0; i < nmemb; ++i)
816 d[i] = src[i].pol;
817 return; break;
818 case QPMS_COORDS_CART2:
819 for(size_t i = 0; i < nmemb; ++i)
820 d[i] = cart2pol(src[i].cart2);
821 return; break;
822 case QPMS_COORDS_CART1:
823 QPMS_PR_ERROR("Implicit conversion from 3D to 1D coordinates not allowed");
824 break;
826 QPMS_WTF;
828 break;
829 case QPMS_COORDS_CART2:
831 cart2_t *d = (cart2_t *) dest;
832 switch (tsrc & QPMS_COORDS_BITRANGE) {
833 case QPMS_COORDS_SPH:
834 case QPMS_COORDS_CART3:
835 QPMS_PR_ERROR("Implicit conversion from 3D to 2D coordinates not allowed");
836 break;
837 case QPMS_COORDS_POL:
838 for(size_t i = 0; i < nmemb; ++i)
839 d[i] = pol2cart(src[i].pol);
840 return; break;
841 case QPMS_COORDS_CART2:
842 for(size_t i = 0; i < nmemb; ++i)
843 d[i] = src[i].cart2;
844 return; break;
845 case QPMS_COORDS_CART1:
846 QPMS_PR_ERROR("Implicit conversion from 3D to 1D coordinates not allowed");
847 break;
849 QPMS_WTF;
851 break;
852 case QPMS_COORDS_CART1:
854 double *d = (double *) dest;
855 switch (tsrc & QPMS_COORDS_BITRANGE) {
856 case QPMS_COORDS_SPH:
857 case QPMS_COORDS_CART3:
858 QPMS_PR_ERROR("Implicit conversion from 3D to 2D coordinates not allowed");
859 break;
860 case QPMS_COORDS_POL:
861 case QPMS_COORDS_CART2:
862 QPMS_PR_ERROR("Implicit conversion from 3D to 1D coordinates not allowed");
863 break;
864 case QPMS_COORDS_CART1:
865 for(size_t i = 0; i < nmemb; ++i)
866 d[i] = src[i].z;
867 return; break;
869 QPMS_WTF;
871 break;
873 QPMS_WTF;
877 /// Converts cart3_t to array of doubles.
878 static inline void cart3_to_double_array(double a[], cart3_t b) {
879 a[0] = b.x; a[1] = b.y; a[2] = b.z;
882 /// Converts array of doubles to cart3_t.
883 static inline cart3_t cart3_from_double_array(const double a[]) {
884 cart3_t b = {.x = a[0], .y = a[1], .z = a[1]};
885 return b;
888 /// Converts cart2_t to array of doubles.
889 static inline void cart2_to_double_array(double a[], cart2_t b) {
890 a[0] = b.x; a[1] = b.y;
893 /// Converts array of doubles to cart2_t
894 static inline cart2_t cart2_from_double_array(const double a[]) {
895 cart2_t b = {.x = a[0], .y = a[1]};
896 return b;
900 typedef double matrix3d[3][3];
901 typedef double matrix2d[2][2];
902 typedef complex double cmatrix3d[3][3];
903 typedef complex double cmatrix2d[2][2];
904 #endif //VECTORS_H