Geo Stars Library  0.9.3
Geodetic and Astrometry library
geoPoint.c
Go to the documentation of this file.
1 /*! \file geoPoint.c
2  \brief This file contains the geo library routines for:
3  \li Conversion between coordinate systems
4  \li Angle conversions
5  \li Tangential plane calculations
6 
7 */
8 
9 #include <stdio.h>
10 #include <math.h>
11 #include <string.h>
12 #include <stdlib.h>
13 #include <ctype.h>
14 #include "geoStars.h"
15 
16 
17 //-----------------------------------------------------------------
18 /*!
19 \brief This function returns the version of the GeoStarsLib.
20 
21 \retval GEOSTARSLIB_VERSION as a double
22 
23 */
24 
26 {
27  return(GEOSTARSLIB_VERSION);
28 }
29 
30 
31 //-----------------------------------------------------------------
32 /*!
33 \brief This function returns the XYZ offset of the target point with
34  respect to the source point, given the Earth Fixed Geodetic
35  coordinates of the points. The EFG coordinates for the source
36  must appear in the GEO_LOCATION record, which must be built
37  previous to the call to this procedure.
38 
39 \param GEO_LOCATION *src_desc
40 \param GEO_LOCATION *tgt_desc
41 \param double xyz_disp[]
42 \retval GEO_OK on success
43 \retval GEO_ERROR on error
44 
45 \note This routine will allow you input site coordinates from two
46 different datums. It is up to the caller to make sure the datums are the
47 same (if it matters).
48 */
49 
51 GEO_LOCATION *tgt_desc,
52 double xyz_disp[])
53 {
54  double delta_e, delta_f, delta_g, intermed_val;
55 
56  // if(src_desc->datum != tgt_desc->datum) return(GEO_ERROR);
57 
58  delta_e = tgt_desc->e - src_desc->e;
59  delta_f = tgt_desc->f - src_desc->f;
60  delta_g = tgt_desc->g - src_desc->g;
61 
62  intermed_val = (-src_desc->clon * delta_e) -
63  ( src_desc->slon * delta_f);
64 
65  xyz_disp[GEO_X] =
66  (-src_desc->slon * delta_e) +
67  ( src_desc->clon * delta_f);
68  xyz_disp[GEO_Y] =
69  (src_desc->slat * intermed_val) +
70  (src_desc->clat * delta_g);
71  xyz_disp[GEO_Z] =
72  (-src_desc->clat * intermed_val) +
73  ( src_desc->slat * delta_g);
74 
75  return(GEO_OK);
76 
77 } /* End procedure site_xyz_diff */
78 
79 /*!
80 \brief This function returns the XYZ offset of the target point with
81  respect to the source point, given the Earth Fixed Geodetic
82  coordinates of the points. The EFG coordinates for the source
83  must appear in the GEO_LOCATION record, which must be built
84  previous to the call to this procedure.
85 
86 \param GEO_LOCATION *src_desc
87 \param GEO_LOCATION *tgt_desc
88 \param double xyz_disp[]
89 \retval GEO_OK on success
90 \retval GEO_ERROR on error
91 
92 \note This routine will allow you input site coordinates from two
93 different datums. It is up to the caller to make sure the datums are the
94 same (if it matters).
95 */
96 int DLL_CALLCONV geoEfg2XyzDiff_packed(GEO_LOCATION *src_desc, int count, double efg_xyz[])
97 {
98  double delta_e, delta_f, delta_g, intermed_val;
99 
100  double* vector;
101 
102  // calculate end
103  double* vend = efg_xyz + (3 * count);
104 
105  /* Convert all the sets. */
106  for (vector = efg_xyz; vector < vend; vector += 3)
107  {
108  delta_e = vector[GEO_E] - src_desc->e;
109  delta_f = vector[GEO_F] - src_desc->f;
110  delta_g = vector[GEO_G] - src_desc->g;
111 
112  intermed_val = (-src_desc->clon * delta_e) -
113  ( src_desc->slon * delta_f);
114 
115  vector[GEO_X] =
116  (-src_desc->slon * delta_e) +
117  ( src_desc->clon * delta_f);
118  vector[GEO_Y] =
119  (src_desc->slat * intermed_val) +
120  (src_desc->clat * delta_g);
121  vector[GEO_Z] =
122  (-src_desc->clat * intermed_val) +
123  ( src_desc->slat * delta_g);
124  }
125 
126  return(GEO_OK);
127 
128 } /* End procedure efg_xyz_diff */
129 
130 double DLL_CALLCONV geoLlh2DiffX (double lat1, double lon1, double hgt1,int datum1, double lat2, double lon2, double hgt2,int datum2)
131 {
132  double xyz[3];
133  GEO_LOCATION site1, site2;
134 
135  geoInitLocation(&site1, lat1, lon1, hgt1, datum1, "site1");
136  geoInitLocation(&site2, lat2, lon2, hgt2, datum2, "site2");
137  geoEfg2XyzDiff(&site1, &site2,xyz);
138  return(xyz[GEO_X]);
139 
140 }
141 
142 double DLL_CALLCONV geoLlh2DiffY (double lat1, double lon1, double hgt1,int datum1, double lat2, double lon2, double hgt2,int datum2)
143 {
144  double xyz[3];
145  GEO_LOCATION site1, site2;
146 
147  geoInitLocation(&site1, lat1, lon1, hgt1, datum1, "site1");
148  geoInitLocation(&site2, lat2, lon2, hgt2, datum2, "site2");
149  geoEfg2XyzDiff(&site1, &site2,xyz);
150  return(xyz[GEO_Y]);
151 
152 }
153 double DLL_CALLCONV geoLlh2DiffZ (double lat1, double lon1, double hgt1,int datum1, double lat2, double lon2, double hgt2,int datum2)
154 {
155  double xyz[3];
156  GEO_LOCATION site1, site2;
157 
158  geoInitLocation(&site1, lat1, lon1, hgt1, datum1, "site1");
159  geoInitLocation(&site2, lat2, lon2, hgt2, datum2, "site2");
160  geoEfg2XyzDiff(&site1, &site2,xyz);
161  return(xyz[GEO_Z]);
162 
163 }
164 //-----------------------------------------------------------------
165 /*!
166 \brief This routine will convert geodetic coordinates (latitude
167 \f$\phi\f$, longitude \f$\lambda\f$, and ellipsoid height \f$h\f$)
168 into earth centered Cartesian coordinates (E,F,G).
169 
170  \param double lat : Latitude in RADIANS
171  \param double lon : Longitude in RADIANS
172  \param double height : Height in METERS
173  \param int datum1
174  \param double *e : E(x) in METERS
175  \param double *f : F(y) in METERS
176  \param double *g : G(z) in METERS
177  \return nothing
178 */
179 
180 
181 void DLL_CALLCONV geoLlh2Efg (double lat, double lon, double height,int datum,
182 double *e, double *f, double *g)
183 
184 {
185  double N,a,e2,ee2, b, flat;
186  double slat, clat;
187 
188  clat = cos(lat);
189  slat = sin(lat);
190 
191  /* Get the ellipsoid parameters */
192  geoGetEllipsoid(&a,&b,&e2,&ee2,&flat,datum);
193 
194  /* Compute the radius of curvature */
195  N = a / (sqrt(1.0 - e2 * pow(slat,2.0)));
196 
197  /* Compute the EFG(XYZ) coordinates (earth centered) */
198  *e = (N + height) * clat * cos(lon);
199  *f = (N + height) * clat * sin(lon);
200  *g = (N * (1.0 - e2) + height) * sin(lat);
201 }
202 
203 /*!
204 \brief This routine will convert geodetic coordinates (latitude
205 \f$\phi\f$, longitude \f$\lambda\f$, and ellipsoid height \f$h\f$)
206 into earth centered Cartesian coordinates (E,F,G).
207 
208  \param GEO_DATUM* datum Datum of the lat/lon/height
209  \param int count Number of vertices
210  \param double llh_efg[] Pointer to the first coordinate of the first vertex of
211  the array.
212  \return nothing
213 */
214 void DLL_CALLCONV geoLlh2Efg_packed (GEO_DATUM* datum, int count, double llh_efg[])
215 {
216  double N, slat, clat, slon, clon;
217 
218  double* vector;
219 
220  // calculate end
221  double* vend = llh_efg + (3 * count);
222 
223  /* Convert all the sets. */
224  for (vector = llh_efg; vector < vend; vector += 3)
225  {
226 #ifdef HAVE_SINCOS
227  sincos(vector[GEO_LAT], &slat, &clat);
228  sincos(vector[GEO_LON], &slon, &clon);
229 
230 #else
231  slat = sin(vector[GEO_LAT]);
232  clat = cos(vector[GEO_LAT]);
233  slon = sin(vector[GEO_LON]);
234  clon = cos(vector[GEO_LON]);
235 #endif
236 
237  /* Compute the radius of curvature */
238  N = datum->a / (sqrt(1.0 - datum->e2 * slat * slat));
239 
240  /* Compute the EFG(XYZ) coordinates (earth centered) */
241  vector[GEO_E] = (N + vector[GEO_HGT]) * clat * clon;
242  vector[GEO_F] = (N + vector[GEO_HGT]) * clat * slon;
243  vector[GEO_G] = (N * (1.0 - datum->e2) + vector[GEO_HGT]) * slat;
244  }
245 }
246 
247 //-----------------------------------------------------------------
248 /*!
249 \brief This routine will convert geodetic coordinates (latitude
250 \f$\phi\f$, longitude \f$\lambda\f$, and ellipsoid height \f$h\f$)
251 into earth centered Cartesian coordinates (E,F,G). This returns the
252 E component.
253 
254  \param double lat : Latitude in RADIANS
255  \param double lon : Longitude in RADIANS
256  \param double height : Height in METERS
257  \param int datum1
258  \return double *e : E(x) in METERS
259 */
260 
261 
262 double DLL_CALLCONV geoLlh2E (double lat, double lon, double hgt,int datum)
263 
264 {
265  GEO_LOCATION site;
266 
267  geoInitLocation(&site, lat, lon, hgt, datum, "site");
268  return(site.e);
269 }
270 
271 //-----------------------------------------------------------------
272 /*!
273 \brief This routine will convert geodetic coordinates (latitude
274 \f$\phi\f$, longitude \f$\lambda\f$, and ellipsoid height \f$h\f$)
275 into earth centered Cartesian coordinates (E,F,G). This returns the
276 F component.
277 
278  \param double lat : Latitude in RADIANS
279  \param double lon : Longitude in RADIANS
280  \param double height : Height in METERS
281  \param int datum1
282  \return double *f : F(x) in METERS
283 */
284 
285 
286 double DLL_CALLCONV geoLlh2F (double lat, double lon, double hgt,int datum)
287 
288 {
289  GEO_LOCATION site;
290 
291  geoInitLocation(&site, lat, lon, hgt, datum, "site");
292  return(site.f);
293 }
294 
295 //-----------------------------------------------------------------
296 /*!
297 \brief This routine will convert geodetic coordinates (latitude
298 \f$\phi\f$, longitude \f$\lambda\f$, and ellipsoid height \f$h\f$)
299 into earth centered Cartesian coordinates (E,F,G). This returns the
300 G component.
301 
302  \param double lat : Latitude in RADIANS
303  \param double lon : Longitude in RADIANS
304  \param double height : Height in METERS
305  \param int datum1
306  \return double *g : G(x) in METERS
307 */
308 
309 
310 double DLL_CALLCONV geoLlh2G (double lat, double lon, double hgt,int datum)
311 
312 {
313  GEO_LOCATION site;
314 
315  geoInitLocation(&site, lat, lon, hgt, datum, "site");
316  return(site.g);
317 }
318 
319 
320 //-----------------------------------------------------------------
321 /*!
322  \brief Given the X, Y, and Z coordinates (in meters) of a point
323  in space, the procedure geoXyz2Rae calculates the range,
324  azimuth, and elevation to that point.
325 
326  \b Notes:
327  \li X is understood to be the east-west displacement of the
328  point, with east being the positive direction.
329  \li Y is the north-south displacement, with north being positive.
330  \li Z is the vertical displacement of the point.
331  \li Range is in meters. Azimuth and elevation are in radians
332 
333 \param double xyz_in[]
334 \param double rae_out[]
335 \return nothing
336 
337 */
338 
339 void DLL_CALLCONV geoXyz2Rae (double xyz_in[],
340 double rae_out[])
341 {
342  double horz_dist;
343 
344  /* Determine the range: */
345  rae_out[GEO_RNG] =
346  sqrt(pow(xyz_in[GEO_X],2.0) + pow(xyz_in[GEO_Y],2.0) + pow(xyz_in[GEO_Z],2.0));
347 
348  /* Determine the azimuth: */
349  rae_out[GEO_AZ] = atan2(xyz_in[GEO_X], xyz_in[GEO_Y]);
350  //if((xyz_in[GEO_X] >= 0.0) && (xyz_in[GEO_Y] < 0.0)) rae_out[GEO_AZ] += M_PI;
351  if((xyz_in[GEO_X] < 0.0) && (xyz_in[GEO_Y] < 0.0)) rae_out[GEO_AZ] += (2.0 * M_PI);
352  if((xyz_in[GEO_X] < 0.0) && (xyz_in[GEO_Y] > 0.0)) rae_out[GEO_AZ] += (2.0 * M_PI);
353 
354  /* Determine the elevation: */
355  horz_dist = sqrt(pow(xyz_in[GEO_X],2.0) + pow(xyz_in[GEO_Y],2.0));
356  rae_out[GEO_EL] = atan2(xyz_in[GEO_Z], horz_dist);
357  if(rae_out[GEO_EL] < 0.0) rae_out[GEO_EL] += (2.0 * M_PI);
358 
359 } /* End procedure xyz_to_rae */
360 //-----------------------------------------------------------------
361 /*!
362  \brief Given the X, Y, and Z coordinates (in meters) of a point
363  in space, the procedure geoXyz2Rae calculates the range,
364  azimuth, and elevation to that point.
365 
366  \b Notes:
367  \li X is understood to be the east-west displacement of the
368  point, with east being the positive direction.
369  \li Y is the north-south displacement, with north being positive.
370  \li Z is the vertical displacement of the point.
371  \li Range is in meters. Azimuth and elevation are in radians
372  \param count Number of vertices
373  \param xyz_rae[] Pointer to the first coordinate of the first vertex of
374  the array.
375 \return nothing
376 
377 */
379 double xyz_rae[])
380 {
381  double horz_dist;
382  double rng, az;
383  double* vector;
384 
385  // calculate end
386  double* vend = xyz_rae + (3 * count);
387 
388  /* Convert all the sets. */
389  for (vector = xyz_rae; vector < vend; vector += 3)
390  {
391  /* Determine the range: */
392  rng =
393  sqrt(vector[GEO_X]*vector[GEO_X] + vector[GEO_Y]*vector[GEO_Y] + vector[GEO_Z]*vector[GEO_Z]);
394 
395  /* Determine the azimuth: */
396  az = atan2(vector[GEO_X], vector[GEO_Y]);
397 
398  //if((vector[GEO_X] < 0.0) && (vector[GEO_Y] < 0.0)) az += (2.0 * M_PI);
399  //if((vector[GEO_X] < 0.0) && (vector[GEO_Y] > 0.0)) az += (2.0 * M_PI);
400  if (az < -0.0f) az += (2.0 * M_PI);
401 
402  /* Determine the elevation: */
403  horz_dist = sqrt(vector[GEO_X]*vector[GEO_X] + vector[GEO_Y]*vector[GEO_Y]);
404  vector[GEO_RNG] = rng;
405  vector[GEO_AZ] = az;
406  vector[GEO_EL] = atan2(vector[GEO_Z], horz_dist);
407  if(vector[GEO_EL] < -0.0f) vector[GEO_EL] += (2.0 * M_PI);
408  }
409 } /* End procedure xyz_to_rae */
410 
411 
412 //-----------------------------------------------------------------
413 /*!
414  \brief Given the X, Y, and Z coordinates (in meters) of a point
415  in space, the procedure geoXyz2R calculates the range to that point.
416 
417  \b Notes:
418  \li X is understood to be the east-west displacement of the
419  point, with east being the positive direction.
420  \li Y is the north-south displacement, with north being positive.
421  \li Z is the vertical displacement of the point.
422  \li Range is in meters.
423 
424 \param double xyz_in[]
425 \return double range
426 
427 */
428 double DLL_CALLCONV geoXyz2R (double x, double y, double z)
429 {
430  double rae[3],xyz[3];
431  xyz[0]=x;
432  xyz[1]=y;
433  xyz[2]=z;
434  geoXyz2Rae(xyz,rae);
435  return(rae[GEO_RNG]);
436 }
437 
438 
439 //-----------------------------------------------------------------
440 /*!
441  \brief Given the X, Y, and Z coordinates (in meters) of a point
442  in space, the procedure geoXyz2R calculates the azimuth to that point.
443 
444  \b Notes:
445  \li X is understood to be the east-west displacement of the
446  point, with east being the positive direction.
447  \li Y is the north-south displacement, with north being positive.
448  \li Z is the vertical displacement of the point.
449  \li Azimuth is in decimal degrees
450 
451 \param double xyz_in[]
452 \return double azimuth
453 
454 */
455 double DLL_CALLCONV geoXyz2A (double x, double y, double z)
456 {
457  double rae[3],xyz[3];
458  xyz[0]=x;
459  xyz[1]=y;
460  xyz[2]=z;
461  geoXyz2Rae(xyz,rae);
462  return(rae[GEO_AZ]*RAD_TO_DEG);
463 }
464 
465 //-----------------------------------------------------------------
466 /*!
467  \brief Given the X, Y, and Z coordinates (in meters) of a point
468  in space, the procedure geoXyz2R calculates the elevation angle to that point.
469 
470  \b Notes:
471  \li X is understood to be the east-west displacement of the
472  point, with east being the positive direction.
473  \li Y is the north-south displacement, with north being positive.
474  \li Z is the vertical displacement of the point.
475  \li Elevation is in decimal degrees
476 
477 \param double xyz_in[]
478 \return double elevation
479 
480 */
481 
482 double DLL_CALLCONV geoXyz2E (double x, double y, double z)
483 {
484  double rae[3],xyz[3];
485  xyz[0]=x;
486  xyz[1]=y;
487  xyz[2]=z;
488  geoXyz2Rae(xyz,rae);
489  return(rae[GEO_EL]*RAD_TO_DEG);
490 }
491 
492 //-----------------------------------------------------------------
493 /*!
494 \brief This routine converts from Range, Azimuth, and Elevation
495  into Cartesian coordinates X,Y,Z.
496 
497  \param double rae_in[]
498  \param double xyz_out[]
499  \return nothing
500 */
501 void DLL_CALLCONV geoRae2Xyz (double rae_in[],
502 double xyz_out[])
503 {
504  double r_cos_e;
505 
506  r_cos_e = rae_in[GEO_RNG] * cos(rae_in[GEO_EL]);
507 
508  xyz_out[GEO_X] = sin(rae_in[GEO_AZ]) * r_cos_e;
509  xyz_out[GEO_Y] = cos(rae_in[GEO_AZ]) * r_cos_e;
510  xyz_out[GEO_Z] = rae_in[GEO_RNG] * sin(rae_in[GEO_EL]);
511 }
512 
513 //-----------------------------------------------------------------
514 /*!
515 \brief This routine iterates over \a count vertices in the array \a rae_xyz converting it from Range, Azimuth, and Elevation into Cartesian coordinates X,Y,Z.
516 
517  \param count Number of vertices
518  \param rae_xyz[] Pointer to the first coordinate of the first vertex of
519  the array.
520  \return nothing
521 */
523 double rae_xyz[])
524 {
525  double r_cos_e;
526  double r_sin_e;
527 #ifdef HAVE_SINCOS
528  double sin_a;
529 #endif
530  double cos_a;
531  double* vector;
532 
533  // calculate end
534  double* vend = rae_xyz + (3 * count);
535 
536  /* Convert all the sets. */
537  for (vector = rae_xyz; vector < vend; vector += 3)
538  {
539 #ifdef HAVE_SINCOS
540  sincos(vector[GEO_EL], &r_sin_e, &r_cos_e);
541  sincos(vector[GEO_AZ], &sin_a, &cos_a);
542  r_cos_e *= vector[GEO_RNG];
543  r_sin_e *= vector[GEO_RNG];
544 
545  vector[GEO_X] = sin_a * r_cos_e;
546  vector[GEO_Y] = cos_a * r_cos_e;
547  vector[GEO_Z] = r_sin_e;
548 #else
549  r_cos_e = vector[GEO_RNG] * cos(vector[GEO_EL]);
550  r_sin_e *= vector[GEO_RNG] * sin(vector[GEO_EL]);
551  cos_a = cos(vector[GEO_AZ]);
552 
553  vector[GEO_X] = sin(vector[GEO_AZ]) * r_cos_e;
554  vector[GEO_Y] = cos_a * r_cos_e;
555  vector[GEO_Z] = vector[GEO_RNG] ;
556 #endif
557  }
558 }
559 
560 //-----------------------------------------------------------------
561 /*!
562  \brief Ingests X, Y, Z, and site info and returns the EFG coordinates.
563 
564  \param GEO_LOCATION *loc
565  \param double xyz_in[]
566  \param double efg_out[]
567  \return nothing
568 */
569 
571 double xyz_in[],
572 double efg_out[])
573 {
574  double c1, c2, c3;
575 
576  /* Do the matrix multiplication: */
577 
578  c1 = -loc->slon * xyz_in[GEO_X] +
579  -loc->clon * loc->slat * xyz_in[GEO_Y] +
580  loc->clon * loc->clat * xyz_in[GEO_Z];
581 
582  c2 = loc->clon * xyz_in[GEO_X] +
583  -loc->slon * loc->slat * xyz_in[GEO_Y] +
584  loc->slon * loc->clat * xyz_in[GEO_Z];
585 
586  c3 = loc->clat * xyz_in[GEO_Y] +
587  loc->slat * xyz_in[GEO_Z];
588 
589  /* Add resultant matrix to local EFG to get remote EFG: */
590  efg_out[GEO_E] = c1 + loc->e;
591  efg_out[GEO_F] = c2 + loc->f;
592  efg_out[GEO_G] = c3 + loc->g;
593 
594 } /* End procedure aer_to_efg */
595 
596 //-----------------------------------------------------------------
597 /*!
598  \brief This routine takes site info and iterates over \a count vertices in the tightly packed array \a xyz_efg converting it from cartesian XYZ into geocentric EFG coordinates.
599 
600  \param loc The location that the XYZ grid is based around
601  \param count The number of vertices in the array
602  \param xyz_efg[] Pointer to the first vertex of the array
603  \return nothing
604 */
605 
607 int count,
608 double xyz_efg[])
609 {
610  double c1, c2, c3;
611  double nclonslat = -loc->clon * loc->slat;
612  double clonclat = loc->clon * loc->clat;
613  double nslonslat = -loc->slon * loc->slat;
614  double slonclat = loc->slon * loc->clat;
615  double* vector;
616 
617  // calculate end
618  double* vend = xyz_efg + (3 * count);
619 
620  /* Convert all the sets. */
621  for (vector = xyz_efg; vector < vend; vector += 3)
622  {
623  /* Do the matrix multiplication: */
624  c1 = -loc->slon * vector[GEO_X] +
625  nclonslat * vector[GEO_Y] +
626  clonclat * vector[GEO_Z];
627 
628  c2 = loc->clon * vector[GEO_X] +
629  nslonslat * vector[GEO_Y] +
630  slonclat * vector[GEO_Z];
631 
632  c3 = loc->clat * vector[GEO_Y] +
633  loc->slat * vector[GEO_Z];
634 
635  /* Add resultant matrix to local EFG to get remote EFG: */
636  vector[GEO_E] = c1 + loc->e;
637  vector[GEO_F] = c2 + loc->f;
638  vector[GEO_G] = c3 + loc->g;
639  }
640 
641 } /* End procedure xyz_to_efg */
642 
643 //-----------------------------------------------------------------
644 /*!
645  \brief Ingests Range, Azimuth, Elevation and site info and returns the EFG coordinates
646  that the RAE points to.
647 
648  \param GEO_LOCATION *loc
649  \param double aer_in[]
650  \param double efg_out[]
651  \return nothing
652 */
653 
655 double aer_in[],
656 double efg_out[])
657 {
658  double c1, c2, c3;
659  double xyz_val[3];
660 
661  /* Convert the RAE value to XYZ: */
662  geoRae2Xyz(aer_in, xyz_val);
663 
664  /* Do the matrix multiplication: */
665 
666  c1 = -loc->slon * xyz_val[GEO_X] +
667  -loc->clon * loc->slat * xyz_val[GEO_Y] +
668  loc->clon * loc->clat * xyz_val[GEO_Z];
669 
670  c2 = loc->clon * xyz_val[GEO_X] +
671  -loc->slon * loc->slat * xyz_val[GEO_Y] +
672  loc->slon * loc->clat * xyz_val[GEO_Z];
673 
674  c3 = loc->clat * xyz_val[GEO_Y] +
675  loc->slat * xyz_val[GEO_Z];
676 
677  /* Add resultant matrix to local EFG to get remote EFG: */
678  efg_out[GEO_E] = c1 + loc->e;
679  efg_out[GEO_F] = c2 + loc->f;
680  efg_out[GEO_G] = c3 + loc->g;
681 
682 } /* End procedure aer_to_efg */
683 
684 
685 //-----------------------------------------------------------------
686 /*!
687 \brief Converts degrees minutes seconds to radians.
688 \param double deg, min, sec
689 \param char sign : N,E,S,W,-,+
690 \return radians
691 */
692 double DLL_CALLCONV geoDms2Rads(double deg, double min, double sec, char *sign)
693 {
694  double direction;
695 
696  switch (toupper(*sign))
697  {
698  case '-':
699  case 'W': /* If coordinate is West or South, returned */
700  case 'S':
701  direction = -1.0; /* radian will have negative value. */
702  break;
703  case '+':
704  case 'E': /* If coordinate is East or North, returned */
705  case 'N':
706  direction = 1.0; /* radian will have positive value. */
707  break;
708  default:
709  direction = 1.0; /* If no compass direction entered, returned*/
710  } /* radian will be assumed positive. */
711 
712  /* Return radians to calling function. */
713  return( direction * DEG_TO_RAD *
714  ( fabs(deg) + (min * MIN_TO_DEG) + (sec * SEC_TO_DEG)));
715 }
716 //-----------------------------------------------------------------
717 /*!
718 \brief Converts degrees minutes seconds to Decimal Degrees
719 \param double deg, min, sec
720 \param char sign : N,E,S,W,-,+
721 \return decimal degrees
722 */
723 double DLL_CALLCONV geoDms2DD(double deg, double min, double sec, char *sign)
724 {
725  double direction;
726 
727  switch (toupper(*sign))
728  {
729  case '-':
730  case 'W': /* If coordinate is West or South, returned */
731  case 'S':
732  direction = -1.0; /* radian will have negative value. */
733  break;
734  case '+':
735  case 'E': /* If coordinate is East or North, returned */
736  case 'N':
737  direction = 1.0; /* radian will have positive value. */
738  break;
739  default:
740  direction = 1.0; /* If no compass direction entered, returned*/
741  } /* radian will be assumed positive. */
742 
743  /* Return radians to calling function. */
744  return( direction *
745  ( fabs(deg) + (min * MIN_TO_DEG) + (sec * SEC_TO_DEG)));
746 }
747 
748 
749 
750 //-----------------------------------------------------------------
751 /*!
752 \brief Convert decimal degrees, minutes, and seconds ("dmmss.s") to radians.
753 \param double in; // decimal deg,min,sec
754 \return radians
755 */
756 double DLL_CALLCONV geoDecdms2Rads(double in) /* minutes and seconds */
757 {
758  double t1,m,d,s,sign;
759 
760  if (in < 0.0)
761  sign = -1.0;
762  else
763  sign = 1.0;
764 
765  s = modf(fabs(in)/100.0, &t1) * 100.0;
766  m = modf(t1/100.0, &d) * 100.0;
767 
768  /* Return radians to calling function. */
769  return( (d + (m/60.0) + (s/3600.0)) * sign * DEG_TO_RAD);
770 }
771 
772 //-----------------------------------------------------------------
773 /*!
774 \brief Converts radians to degrees minutes seconds.
775 \param double rads
776 \param double deg, min, sec
777 \param char dir : -1.0 or 1.0
778 \return nothing
779 */
780 
781 
782 void DLL_CALLCONV geoRads2Dms(double rads,
783 double *deg, double *min, double *sec, double *dir)
784 {
785  double temp;
786  double fraction;
787 
788  if (rads < 0.0)
789  *dir = -1.0;
790  else
791  *dir = 1.0;
792 
793  rads = fabs (rads);
794 
795  temp = RAD_TO_DEG * rads;
796  fraction = modf(temp,deg);
797 
798  temp = fraction * 60.0;
799  fraction = modf(temp,min);
800 
801  *sec = fraction * 60.0;
802 }
803 
804 //-----------------------------------------------------------------
805 /*!
806 \brief Convert radians to decimal degrees, minutes, and seconds ("dddmmss.s").
807 \param double rads
808 \return double Decimal Deg/min/sec
809  */
810 double DLL_CALLCONV geoRads2Decdms(double rads)
811 {
812  double d,m,s,sign;
813  double frac;
814 
815  if (rads < 0.0)
816  sign = -1.0;
817  else
818  sign = 1.0;
819 
820  frac = modf(fabs(rads * RAD_TO_DEG),&d);
821  frac = modf(frac * 60.0,&m);
822  s = frac * 60.0;
823 
824  /* Return dddmmss.s to calling function. */
825  return(((d*10000.0)+(m*100)+s)*sign);
826 }
827 
828 //-----------------------------------------------------------------
829 /*!
830 \brief Converts radians to Decimal Degrees
831 \param double radians
832 \return double decimal degrees
833 */
834 
835 
836 double DLL_CALLCONV geoRads2DD(double rads)
837 {
838  return(rads * RAD_TO_DEG);
839 }
840 
841 //-----------------------------------------------------------------
842 /*!
843 \brief Converts Decimal Degrees to radians
844 \param double decimal degrees
845 \return radians
846 */
847 
848 
849 double DLL_CALLCONV geoDD2Rads(double dd)
850 {
851  return(dd * DEG_TO_RAD);
852 }
853 
854 
855 //-----------------------------------------------------------------
856 /*!
857 \brief Converts Decimal Degrees to degrees minutes seconds.
858 \param double decimal degrees
859 \param double deg, min, sec
860 \param char dir : -1.0 or 1.0
861 \return nothing
862 */
863 
864 
865 void DLL_CALLCONV geoDD2Dms(double dd,
866 double *deg, double *min, double *sec, double *dir)
867 {
868  double temp;
869  double fraction;
870 
871  if (dd < 0.0)
872  *dir = -1.0;
873  else
874  *dir = 1.0;
875 
876  dd = fabs (dd);
877 
878  //temp = RAD_TO_DEG * rads;
879  fraction = modf(dd,deg);
880 
881  temp = fraction * 60.0;
882  fraction = modf(temp,min);
883 
884  *sec = fraction * 60.0;
885 }
886 
887 
888 double DLL_CALLCONV geoDD2Deg(double dd)
889 {
890  double deg, min, sec,dir;
891  geoDD2Dms(dd,&deg, &min, &sec,&dir);
892  return(deg*dir);
893 }
894 double DLL_CALLCONV geoDD2Min(double dd)
895 {
896  double deg, min, sec,dir;
897  geoDD2Dms(dd,&deg, &min, &sec,&dir);
898  return(min);
899 }
900 double DLL_CALLCONV geoDD2Sec(double dd)
901 {
902  double deg, min, sec,dir;
903  geoDD2Dms(dd,&deg, &min, &sec,&dir);
904  return(sec);
905 }
906