1 /*
2 *+
3 *  Name:
4 *     palDafin
5 
6 *  Purpose:
7 *     Sexagesimal character string to angle
8 
9 *  Language:
10 *     Starlink ANSI C
11 
12 *  Type of Module:
13 *     Library routine
14 
15 *  Invocation:
16 *     void palDafin ( const char *string, int *ipos, double *a, int *j );
17 
18 *  Arguments:
19 *     string = const char * (Given)
20 *        String containing deg, arcmin, arcsec fields
21 *     ipos = int * (Given & Returned)
22 *        Position to start decoding "string". First character
23 *        is position 1 for compatibility with SLA. After
24 *        calling this routine "iptr" will be positioned after
25 *        the sexagesimal string.
26 *     a = double * (Returned)
27 *        Angle in radians.
28 *     j = int * (Returned)
29 *        status:  0 = OK
30 *                +1 = default, A unchanged
31 *                -1 = bad degrees      )
32 *                -2 = bad arcminutes   )  (note 3)
33 *                -3 = bad arcseconds   )
34 
35 *  Description:
36 *     Extracts an angle from a sexagesimal string with degrees, arcmin,
37 *     arcsec fields using space or comma delimiters.
38 
39 *  Authors:
40 *     TIMJ: Tim Jenness (JAC, Hawaii)
41 *     PTW: Patrick T. Wallace
42 *     {enter_new_authors_here}
43 
44 *  Example:
45 *     argument    before                           after
46 *
47 *     STRING      '-57 17 44.806  12 34 56.7'      unchanged
48 *     IPTR        1                                16 (points to 12...)
49 *     A           ?                                -1.00000D0
50 *     J           ?                                0
51 
52 *  Notes:
53 *     - The first three "fields" in STRING are degrees, arcminutes,
54 *       arcseconds, separated by spaces or commas.  The degrees field
55 *       may be signed, but not the others.  The decoding is carried
56 *       out by the palDfltin routine and is free-format.
57 *     - Successive fields may be absent, defaulting to zero.  For
58 *       zero status, the only combinations allowed are degrees alone,
59 *       degrees and arcminutes, and all three fields present.  If all
60 *       three fields are omitted, a status of +1 is returned and A is
61 *       unchanged.  In all other cases A is changed.
62 *     - Range checking:
63 *
64 *           The degrees field is not range checked.  However, it is
65 *           expected to be integral unless the other two fields are absent.
66 *
67 *           The arcminutes field is expected to be 0-59, and integral if
68 *           the arcseconds field is present.  If the arcseconds field
69 *           is absent, the arcminutes is expected to be 0-59.9999...
70 *
71 *           The arcseconds field is expected to be 0-59.9999...
72 *
73 *     - Decoding continues even when a check has failed.  Under these
74 *       circumstances the field takes the supplied value, defaulting
75 *       to zero, and the result A is computed and returned.
76 *     - Further fields after the three expected ones are not treated
77 *       as an error.  The pointer IPOS is left in the correct state
78 *       for further decoding with the present routine or with palDfltin
79 *       etc. See the example, above.
80 *     - If STRING contains hours, minutes, seconds instead of degrees
81 *       etc, or if the required units are turns (or days) instead of
82 *       radians, the result A should be multiplied as follows:
83 *
84 *           for        to obtain    multiply
85 *           STRING     A in         A by
86 *
87 *           d ' "      radians      1       =  1.0
88 *           d ' "      turns        1/2pi   =  0.1591549430918953358
89 *           h m s      radians      15      =  15.0
90 *           h m s      days         15/2pi  =  2.3873241463784300365
91 
92 *  History:
93 *     2012-03-08 (TIMJ):
94 *        Initial version from SLA/F using Fortran documentation
95 *        Adapted with permission from the Fortran SLALIB library.
96 *     2012-10-17 (TIMJ):
97 *        Fix range check on arcminute value.
98 *     {enter_further_changes_here}
99 
100 *  Copyright:
101 *     Copyright (C) 1996 Rutherford Appleton Laboratory
102 *     Copyright (C) 2012 Science and Technology Facilities Council.
103 *     All Rights Reserved.
104 
105 *  Licence:
106 *     This program is free software; you can redistribute it and/or
107 *     modify it under the terms of the GNU General Public License as
108 *     published by the Free Software Foundation; either version 3 of
109 *     the License, or (at your option) any later version.
110 *
111 *     This program is distributed in the hope that it will be
112 *     useful, but WITHOUT ANY WARRANTY; without even the implied
113 *     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
114 *     PURPOSE. See the GNU General Public License for more details.
115 *
116 *     You should have received a copy of the GNU General Public License
117 *     along with this program; if not, write to the Free Software
118 *     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
119 *     MA 02110-1301, USA.
120 
121 *  Bugs:
122 *     {note_any_bugs_here}
123 *-
124 */
125 
126 #include "pal.h"
127 #include "palmac.h"
128 #include "pal1sofa.h"
129 
130 #include <math.h>
131 
palDafin(const char * string,int * ipos,double * a,int * j)132 void palDafin ( const char *string, int *ipos, double *a, int *j ) {
133 
134   int jd = 0;    /* Status for degree parsing */
135   int jm = 0;    /* Status for arcmin parsing */
136   int js = 0;    /* Status for arcsec parsing */
137   int jf = 0;    /* Internal copy of status */
138   double deg = 0.0;
139   double arcmin = 0.0;
140   double arcsec = 0.0;
141 
142   /* Decode degrees, arcminutes, arcseconds */
143   palDfltin( string, ipos, &deg, &jd );
144   if (jd > 1) {
145     jf = -1;
146   } else {
147 
148     palDfltin( string, ipos, &arcmin, &jm );
149     if ( jm < 0 || jm > 1 ) {
150       jf = -2;
151     } else {
152 
153       palDfltin( string, ipos, &arcsec, &js );
154       if (js < 0 || js > 1) {
155         jf = -3;
156 
157       } else if (jd > 0) { /* See if combination of fields is credible */
158         /* No degrees: arcmin, arcsec ought also to be absent */
159         if (jm == 0) {
160           /* Suspect arcmin */
161           jf = -2;
162         } else if (js == 0) {
163           /* Suspect arcsec */
164           jf = -3;
165         } else {
166           /* All three fields absent */
167           jf = 1;
168         }
169 
170       } else if (jm != 0 && js == 0) { /* Deg present: if arcsec present should have arcmin */
171         jf = -3;
172 
173       /* Tests for range and integrality */
174       } else if (jm == 0 && DINT(deg) != deg) { /* Degrees */
175         jf = -1;
176 
177       } else if ( (js == 0 && DINT(arcmin) != arcmin) || arcmin >= 60.0 ) { /* Arcmin */
178         jf = -2;
179 
180       } else if (arcsec >= 60.0) { /* Arcsec */
181         jf = -3;
182       }
183     }
184   }
185 
186   /* Unless all three fields absent, compute angle value */
187   if (jf <= 0) {
188     *a = PAL__DAS2R * ( 60.0 * ( 60.0 * fabs(deg) + arcmin) + arcsec );
189     if ( jd < 0 ) *a *= -1.;
190   }
191 
192   *j = jf;
193 
194 }
195