SINFONI Pipeline Reference Manual  2.5.2
irplib_wcs.c
1 /* $Id: irplib_wcs.c,v 1.8 2010-10-07 14:10:55 llundin Exp $
2  *
3  * This file is part of the irplib package
4  * Copyright (C) 2002,2003 European Southern Observatory
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1307 USA
19  */
20 
21 /*
22  * $Author: llundin $
23  * $Date: 2010-10-07 14:10:55 $
24  * $Revision: 1.8 $
25  * $Name: not supported by cvs2svn $
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 
32 /*-----------------------------------------------------------------------------
33  Includes
34  -----------------------------------------------------------------------------*/
35 
36 #include <math.h>
37 #include <cpl.h>
38 
39 #include "irplib_wcs.h"
40 
41 /*----------------------------------------------------------------------------*/
45 /*----------------------------------------------------------------------------*/
46 
47 static cpl_error_code irplib_wcs_is_iso8601(int, int, int, int, int, double);
48 
51 /*----------------------------------------------------------------------------*/
62 /*----------------------------------------------------------------------------*/
63 cpl_error_code irplib_wcs_xytoradec(const cpl_wcs *wcs,
64  double x,
65  double y,
66  double *ra,
67  double *dec)
68 {
69  cpl_matrix * xy;
70  cpl_matrix * radec = NULL;
71  cpl_array * status = NULL;
72  cpl_error_code error;
73 
74  cpl_ensure_code(ra != NULL, CPL_ERROR_NULL_INPUT);
75  cpl_ensure_code(dec != NULL, CPL_ERROR_NULL_INPUT);
76 
77  /* Load up the information */
78  xy = cpl_matrix_new(1, 2);
79  cpl_matrix_set(xy, 0, 0, x);
80  cpl_matrix_set(xy, 0, 1, y);
81 
82  /* Call the conversion routine */
83  error = cpl_wcs_convert(wcs, xy, &radec, &status, CPL_WCS_PHYS2WORLD);
84 
85  cpl_matrix_delete(xy);
86 
87  if (!error) {
88 
89  /* Pass it back now */
90  *ra = cpl_matrix_get(radec, 0, 0);
91  *dec = cpl_matrix_get(radec, 0, 1);
92 
93  }
94 
95  /* Tidy and propagate error, if any */
96  cpl_matrix_delete(radec);
97  cpl_array_delete(status);
98 
99  return cpl_error_set_where(cpl_func);
100 }
101 
102 /*----------------------------------------------------------------------------*/
113 /*----------------------------------------------------------------------------*/
114 cpl_error_code irplib_wcs_radectoxy(const cpl_wcs * wcs,
115  double ra,
116  double dec,
117  double * x,
118  double * y)
119 {
120  cpl_matrix * radec;
121  cpl_matrix * xy = NULL;
122  cpl_array * status = NULL;
123  cpl_error_code error;
124 
125  cpl_ensure_code(x != NULL, CPL_ERROR_NULL_INPUT);
126  cpl_ensure_code(y != NULL, CPL_ERROR_NULL_INPUT);
127 
128  /* Feed the matrix with RA, DEC */
129  radec = cpl_matrix_new(1, 2);
130  cpl_matrix_set(radec, 0, 0, ra);
131  cpl_matrix_set(radec, 0, 1, dec);
132 
133  error = cpl_wcs_convert(wcs, radec, &xy, &status, CPL_WCS_WORLD2PHYS);
134 
135  cpl_matrix_delete(radec);
136 
137  if (!error) {
138 
139  *x = cpl_matrix_get(xy, 0, 0);
140  *y = cpl_matrix_get(xy, 0, 1);
141 
142  }
143 
144  /* Tidy and propagate error, if any */
145  cpl_array_delete(status);
146  cpl_matrix_delete(xy);
147 
148  return cpl_error_set_where(cpl_func);
149 
150 }
151 
152 /*----------------------------------------------------------------------------*/
162 /*----------------------------------------------------------------------------*/
163 double irplib_wcs_great_circle_dist(double ra1,
164  double dec1,
165  double ra2,
166  double dec2)
167 {
168 
169  /* Convert all input from degrees to radian - and back for the result */
170  const double dra = sin( CPL_MATH_RAD_DEG * (ra2 - ra1 )/2.0 );
171  const double ddec = sin( CPL_MATH_RAD_DEG * (dec2 - dec1)/2.0 );
172 
173  dec1 *= CPL_MATH_RAD_DEG;
174  dec2 *= CPL_MATH_RAD_DEG;
175 
176  return 2.0 * asin(sqrt( ddec*ddec + cos(dec1)*cos(dec2)*dra*dra))
177  * CPL_MATH_DEG_RAD;
178 }
179 
180 
181 /*----------------------------------------------------------------------------*/
195 /*----------------------------------------------------------------------------*/
196 cpl_error_code irplib_wcs_mjd_from_iso8601(double * pmjd, int year, int month,
197  int day, int hour, int minute,
198  double second)
199 {
200 
201  cpl_ensure_code(pmjd != NULL, CPL_ERROR_NULL_INPUT);
202  cpl_ensure_code(!irplib_wcs_is_iso8601(year, month, day, hour, minute,
203  second), cpl_error_get_code());
204 
205  /* Compute MJD. */
206  *pmjd = (double)((1461*(year - (12-month)/10 + 4712))/4
207  + (306*((month+9)%12) + 5)/10
208  - (3*((year - (12-month)/10 + 4900)/100))/4
209  + day - 2399904)
210  + (hour + (minute + second/60.0)/60.0)/24.0;
211 
212  return CPL_ERROR_NONE;
213 
214 }
215 
216 
217 /*----------------------------------------------------------------------------*/
233 /*----------------------------------------------------------------------------*/
234 cpl_error_code irplib_wcs_iso8601_from_string(int * pyear, int * pmonth,
235  int * pday, int * phour,
236  int * pminute, double * psecond,
237  const char * iso8601)
238 {
239 
240  /* Standard year-2000 form: CCYY-MM-DD[Thh:mm:ss[.sss...]] */
241  const char * iso8601format = "%4d-%2d-%2dT%2d:%2d:%lf";
242 
243  cpl_ensure_code(pyear != NULL, CPL_ERROR_NULL_INPUT);
244  cpl_ensure_code(pmonth != NULL, CPL_ERROR_NULL_INPUT);
245  cpl_ensure_code(pday != NULL, CPL_ERROR_NULL_INPUT);
246  cpl_ensure_code(phour != NULL, CPL_ERROR_NULL_INPUT);
247  cpl_ensure_code(pminute != NULL, CPL_ERROR_NULL_INPUT);
248  cpl_ensure_code(psecond != NULL, CPL_ERROR_NULL_INPUT);
249  cpl_ensure_code(iso8601 != NULL, CPL_ERROR_NULL_INPUT);
250 
251  cpl_error_ensure(sscanf(iso8601, iso8601format, pyear, pmonth,
252  pday, phour, pminute, psecond) == 6,
253  CPL_ERROR_ILLEGAL_INPUT, return cpl_error_get_code(),
254  "%s is not formatted as %s", iso8601, iso8601format);
255 
256  cpl_ensure_code(!irplib_wcs_is_iso8601(*pyear, *pmonth, *pday, *phour,
257  *pminute, *psecond),
258  cpl_error_get_code());
259 
260  return CPL_ERROR_NONE;
261 }
262 
263 
264 /*----------------------------------------------------------------------------*/
273 /*----------------------------------------------------------------------------*/
274 cpl_error_code irplib_wcs_mjd_from_string(double * pmjd, const char * iso8601)
275 {
276 
277 
278  int year, day, month, hour, minute;
279  double second;
280 
281  return irplib_wcs_iso8601_from_string(&year, &month, &day, &hour,
282  &minute, &second, iso8601)
283  || irplib_wcs_mjd_from_iso8601(pmjd, year, month, day, hour, minute,
284  second)
285  ? cpl_error_set_where(cpl_func) : CPL_ERROR_NONE;
286 }
287 
288 
289 
290 /*----------------------------------------------------------------------------*/
304 /*----------------------------------------------------------------------------*/
305 cpl_error_code irplib_wcs_iso8601_from_mjd(int * pyear, int * pmonth,
306  int * pday, int * phour,
307  int * pminute, double * psecond,
308  double mjd)
309 {
310 
311  int jd, n4, dd;
312  double t;
313 
314  cpl_ensure_code(pyear != NULL, CPL_ERROR_NULL_INPUT);
315  cpl_ensure_code(pmonth != NULL, CPL_ERROR_NULL_INPUT);
316  cpl_ensure_code(pday != NULL, CPL_ERROR_NULL_INPUT);
317  cpl_ensure_code(phour != NULL, CPL_ERROR_NULL_INPUT);
318  cpl_ensure_code(pminute != NULL, CPL_ERROR_NULL_INPUT);
319  cpl_ensure_code(psecond != NULL, CPL_ERROR_NULL_INPUT);
320 
321  /* Copied from datfix() in wcslib (v. 4.4.4) */
322 
323  jd = 2400001 + (int)mjd;
324 
325  n4 = 4*(jd + ((2*((4*jd - 17918)/146097)*3)/4 + 1)/2 - 37);
326  dd = 10*(((n4-237)%1461)/4) + 5;
327 
328  *pyear = n4/1461 - 4712;
329  *pmonth = (2 + dd/306)%12 + 1;
330  *pday = (dd%306)/10 + 1;
331 
332  t = mjd - (int)mjd; /* t is now days */
333 
334  t *= 24.0; /* t is now hours */
335  *phour = (int)t;
336  t = 60.0 * (t - *phour); /* t is now minutes */
337  *pminute = (int)t;
338  *psecond = 60.0 * (t - *pminute);
339 
340  /* A failure here implies that this code has a bug */
341  cpl_ensure_code(!irplib_wcs_is_iso8601(*pyear, *pmonth, *pday, *phour,
342  *pminute, *psecond),
343  CPL_ERROR_UNSPECIFIED);
344 
345  return CPL_ERROR_NONE;
346 }
347 
348 
351 /*----------------------------------------------------------------------------*/
363 /*----------------------------------------------------------------------------*/
364 static cpl_error_code irplib_wcs_is_iso8601(int year, int month,
365  int day, int hour,
366  int minute, double second)
367 {
368 
369  const cpl_boolean is_leap = year % 4 ? CPL_FALSE : CPL_TRUE;
370  const int mlen[] = {0, 31, is_leap ? 29 : 28, 31, 30, 31, 30, 31, 31, 30,
371  31, 30, 31};
372 
373  cpl_ensure_code(month > 0, CPL_ERROR_ILLEGAL_INPUT);
374  cpl_ensure_code(month <= 12, CPL_ERROR_ILLEGAL_INPUT);
375 
376  cpl_ensure_code(day > 0, CPL_ERROR_ILLEGAL_INPUT);
377  cpl_ensure_code(day <= mlen[month], CPL_ERROR_ILLEGAL_INPUT);
378 
379  cpl_ensure_code(minute < 60, CPL_ERROR_ILLEGAL_INPUT);
380  cpl_ensure_code(minute >= 0, CPL_ERROR_ILLEGAL_INPUT);
381 
382  cpl_ensure_code(second < 60.0, CPL_ERROR_ILLEGAL_INPUT);
383  cpl_ensure_code(second >= 0.0, CPL_ERROR_ILLEGAL_INPUT);
384 
385  cpl_ensure_code(hour >= 0, CPL_ERROR_ILLEGAL_INPUT);
386  /* 24:00:00 is valid ISO-8601 */
387  cpl_ensure_code(hour <= (minute > 0 || second > 0.0 ? 23 : 24),
388  CPL_ERROR_ILLEGAL_INPUT);
389 
390  return CPL_ERROR_NONE;
391 }