2 * \brief Coordinate transforms and vector arithmetics.
8 #define M_PI_2 (1.570796326794896619231321691639751442098584699687552910487)
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
};
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
};
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
};
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
) {
53 pol
.r
= cart2norm(cart
);
54 pol
.phi
= atan2(cart
.y
, cart
.x
);
58 /// Polar to spherical coordinates conversion. See @ref coord_conversions.
59 static inline sph_t
pol2sph_equator(const pol_t pol
) {
67 /// 2D cartesian to spherical coordinates conversion. See @ref coord_conversions.
68 static inline sph_t
cart22sph(const cart2_t cart
) {
70 sph
.r
= cart2norm(cart
);
72 sph
.phi
= atan2(cart
.y
, cart
.x
);
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};
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
};
88 /// 2D to 3D cartesian coordinates conversion. See @ref coord_conversions.
89 static inline cart3_t
cart22cart3xy(const cart2_t a
) {
97 static inline cart2_t
cart3xy2cart2(const cart3_t a
) {
98 cart2_t c
= {a
.x
, a
.y
};
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
) {
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
,
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
) {
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
);
142 /// Spherical to 3D cartesian coordinates conversion. See @ref coord_conversions.
143 static inline cart3_t
sph2cart(const sph_t sph
) {
146 #ifdef QPMS_VECTORS_NICE_TRANSFORMATIONS
147 (sph
.theta
== M_PI
) ? 0 :
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
);
156 /// Polar to 2D cartesian coordinates conversion. See @ref coord_conversions.
157 static inline cart2_t
pol2cart(const pol_t pol
) {
159 cart
.x
= pol
.r
* cos(pol
.phi
);
160 cart
.y
= pol
.r
* sin(pol
.phi
);
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};
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
};
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
};
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
};
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
};
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
};
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
};
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
};
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
};
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
};
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
};
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
};
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
};
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
};
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.;
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
;
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.;
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
;
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
};
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
};
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
);
358 /// Real 3D cartesian to spherical (complex r) coordinates conversion. See @ref coord_conversions.
359 static inline csph_t
cart2csph(const cart3_t cart
) {
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
);
367 /// Coordinate transform of csph_t to ccart3_t
368 static inline ccart3_t
csph2ccart(const csph_t sph
) {
371 #ifdef QPMS_VECTORS_NICE_TRANSFORMATIONS
372 (sph
.theta
== M_PI
) ? 0 :
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
);
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
);
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
);
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
:
464 case QPMS_COORDS_POL
:
465 return pol2sph_equator(p
.pol
);
467 case QPMS_COORDS_CART3
:
468 return cart2sph(p
.cart3
);
470 case QPMS_COORDS_CART2
:
471 return cart22sph(p
.cart2
);
473 case QPMS_COORDS_CART1
:
474 return cart12sph_zaxis(p
.z
);
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
);
489 case QPMS_COORDS_POL
:
490 return pol2cart3_equator(p
.pol
);
492 case QPMS_COORDS_CART3
:
495 case QPMS_COORDS_CART2
:
496 return cart22cart3xy(p
.cart2
);
498 case QPMS_COORDS_CART1
:
499 return cart12cart3z(p
.z
);
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
));
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
};
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");
530 case QPMS_COORDS_POL
:
533 case QPMS_COORDS_CART2
:
534 return cart2pol(p
.cart2
);
536 case QPMS_COORDS_CART1
:
537 QPMS_PR_ERROR("Implicit conversion from 1D to 2D"
538 " coordinates not allowed");
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");
555 case QPMS_COORDS_POL
:
556 return pol2cart(p
.pol
);
558 case QPMS_COORDS_CART2
:
561 case QPMS_COORDS_CART1
:
562 QPMS_PR_ERROR("Implicit conversion from 1D to 2D"
563 " coordinates not allowed");
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
)
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
)
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
]);
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
]);
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
]);
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
]);
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
]);
635 case QPMS_COORDS_CART3
: {
636 const cart3_t
*s
= src
;
637 for(size_t i
= 0; i
< nmemb
; ++i
)
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
]);
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
]);
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
]);
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");
671 case QPMS_COORDS_POL
: {
672 const pol_t
*s
= src
;
673 for(size_t i
= 0; i
< nmemb
; ++i
)
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
]);
683 case QPMS_COORDS_CART1
:
684 QPMS_PR_ERROR("Implicit conversion from 3D to 1D coordinates not allowed");
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");
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
]);
704 case QPMS_COORDS_CART2
: {
705 const cart2_t
*s
= src
;
706 for(size_t i
= 0; i
< nmemb
; ++i
)
710 case QPMS_COORDS_CART1
:
711 QPMS_PR_ERROR("Implicit conversion from 3D to 1D coordinates not allowed");
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");
725 case QPMS_COORDS_POL
:
726 case QPMS_COORDS_CART2
:
727 QPMS_PR_ERROR("Implicit conversion from 3D to 1D coordinates not allowed");
729 case QPMS_COORDS_CART1
: {
730 const double *s
= src
;
731 for(size_t i
= 0; i
< nmemb
; ++i
)
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
) {
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
)
758 case QPMS_COORDS_CART3
:
759 for(size_t i
= 0; i
< nmemb
; ++i
)
760 d
[i
] = cart2sph(src
[i
].cart3
);
762 case QPMS_COORDS_POL
:
763 for(size_t i
= 0; i
< nmemb
; ++i
)
764 d
[i
] = pol2sph_equator(src
[i
].pol
);
766 case QPMS_COORDS_CART2
:
767 for(size_t i
= 0; i
< nmemb
; ++i
)
768 d
[i
] = cart22sph(src
[i
].cart2
);
770 case QPMS_COORDS_CART1
:
771 for(size_t i
= 0; i
< nmemb
; ++i
)
772 d
[i
] = cart12sph_zaxis(src
[i
].z
);
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
);
786 case QPMS_COORDS_CART3
:
787 for(size_t i
= 0; i
< nmemb
; ++i
)
790 case QPMS_COORDS_POL
:
791 for(size_t i
= 0; i
< nmemb
; ++i
)
792 d
[i
] = pol2cart3_equator(src
[i
].pol
);
794 case QPMS_COORDS_CART2
:
795 for(size_t i
= 0; i
< nmemb
; ++i
)
796 d
[i
] = cart22cart3xy(src
[i
].cart2
);
798 case QPMS_COORDS_CART1
:
799 for(size_t i
= 0; i
< nmemb
; ++i
)
800 d
[i
] = cart12cart3z(src
[i
].z
);
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");
814 case QPMS_COORDS_POL
:
815 for(size_t i
= 0; i
< nmemb
; ++i
)
818 case QPMS_COORDS_CART2
:
819 for(size_t i
= 0; i
< nmemb
; ++i
)
820 d
[i
] = cart2pol(src
[i
].cart2
);
822 case QPMS_COORDS_CART1
:
823 QPMS_PR_ERROR("Implicit conversion from 3D to 1D coordinates not allowed");
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");
837 case QPMS_COORDS_POL
:
838 for(size_t i
= 0; i
< nmemb
; ++i
)
839 d
[i
] = pol2cart(src
[i
].pol
);
841 case QPMS_COORDS_CART2
:
842 for(size_t i
= 0; i
< nmemb
; ++i
)
845 case QPMS_COORDS_CART1
:
846 QPMS_PR_ERROR("Implicit conversion from 3D to 1D coordinates not allowed");
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");
860 case QPMS_COORDS_POL
:
861 case QPMS_COORDS_CART2
:
862 QPMS_PR_ERROR("Implicit conversion from 3D to 1D coordinates not allowed");
864 case QPMS_COORDS_CART1
:
865 for(size_t i
= 0; i
< nmemb
; ++i
)
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]};
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]};
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];