1 /*
2  # This file is part of the Astrometry.net suite.
3  # Licensed under a 3-clause BSD style license - see LICENSE
4  */
5 #include <unistd.h>
6 #include <stdio.h>
7 #include <string.h>
8 #include <math.h>
9 #include <assert.h>
10 
11 /**
12 
13  wget "http://antwrp.gsfc.nasa.gov/apod/image/0403/cmsky_cortner_full.jpg"
14  solve-field --backend-config backend.cfg -v --keep-xylist %s.xy --continue --scale-low 10 --scale-units degwidth --no-tweak cmsky_cortner_full.jpg
15  # index-219 ==> 159 index objs.
16  cp cmsky_cortner_full.xy 1.xy
17  cp cmsky_cortner_full.rdls 1.rd
18  cp cmsky_cortner_full.wcs 1.wcs
19  cp cmsky_cortner_full.jpg 1.jpg
20  # or:
21  # wget "http://live.astrometry.net/status.php?job=alpha-201003-01883980&get=wcs.fits" -O 1.wcs
22  # wget "http://live.astrometry.net/status.php?job=alpha-201003-01883980&get=index.rd.fits" -O 1.rd
23  verify -w 1.wcs -x 1.xy -r 1.rd -v
24 
25  **/
26 
27 #include "starutil.h"
28 #include "mathutil.h"
29 #include "bl.h"
30 #include "matchobj.h"
31 #include "xylist.h"
32 #include "rdlist.h"
33 #include "ioutils.h"
34 #include "starkd.h"
35 #include "boilerplate.h"
36 #include "sip.h"
37 #include "sip_qfits.h"
38 #include "log.h"
39 #include "fitsioutils.h"
40 #include "fit-wcs.h"
41 #include "verify.h"
42 #include "histogram2d.h"
43 
44 #include "plotstuff.h"
45 #include "plotimage.h"
46 #include "cairoutils.h"
47 
48 static const char* OPTIONS = "hx:w:r:vj:p:";
49 
print_help(char * progname)50 void print_help(char* progname) {
51     BOILERPLATE_HELP_HEADER(stdout);
52     printf("\nUsage: %s\n"
53            "   -w <WCS input file>\n"
54            "   -x <xyls input file>\n"
55            "   -r <rdls input file>\n"
56            "   [-p <plot output file>]\n"
57            "   [-v]: verbose\n"
58            "   [-j <pixel-jitter>]: set pixel jitter (default 1.0)\n"
59            "\n", progname);
60 }
61 
62 
main(int argc,char ** args)63 int main(int argc, char** args) {
64     int c;
65     char* xylsfn = NULL;
66     char* wcsfn = NULL;
67     char* rdlsfn = NULL;
68     char* plotfn = NULL;
69 
70     xylist_t* xyls = NULL;
71     rdlist_t* rdls = NULL;
72     sip_t sip;
73     int i;
74     int W, H;
75     double pixeljitter = 1.0;
76     int loglvl = LOG_MSG;
77     double wcsscale;
78 
79     fits_use_error_system();
80 
81     while ((c = getopt(argc, args, OPTIONS)) != -1) {
82         switch (c) {
83         case 'p':
84             plotfn = optarg;
85             break;
86         case 'j':
87             pixeljitter = atof(optarg);
88             break;
89         case 'h':
90             print_help(args[0]);
91             exit(0);
92         case 'r':
93             rdlsfn = optarg;
94             break;
95         case 'x':
96             xylsfn = optarg;
97             break;
98         case 'w':
99             wcsfn = optarg;
100             break;
101         case 'v':
102             loglvl++;
103             break;
104         }
105     }
106     if (optind != argc) {
107         print_help(args[0]);
108         exit(-1);
109     }
110     if (!xylsfn || !wcsfn || !rdlsfn) {
111         print_help(args[0]);
112         exit(-1);
113     }
114     log_init(loglvl);
115 
116     // read WCS.
117     logmsg("Trying to parse SIP header from %s...\n", wcsfn);
118     if (!sip_read_header_file(wcsfn, &sip)) {
119         logmsg("Failed to parse SIP header from %s.\n", wcsfn);
120     }
121     // image W, H
122     W = sip.wcstan.imagew;
123     H = sip.wcstan.imageh;
124     if ((W == 0.0) || (H == 0.0)) {
125         logmsg("WCS file %s didn't contain IMAGEW and IMAGEH headers.\n", wcsfn);
126         // FIXME - use bounds of xylist?
127         exit(-1);
128     }
129     wcsscale = sip_pixel_scale(&sip);
130     logmsg("WCS scale: %g arcsec/pixel\n", wcsscale);
131 
132     // read XYLS.
133     xyls = xylist_open(xylsfn);
134     if (!xyls) {
135         logmsg("Failed to read an xylist from file %s.\n", xylsfn);
136         exit(-1);
137     }
138 
139     // read RDLS.
140     rdls = rdlist_open(rdlsfn);
141     if (!rdls) {
142         logmsg("Failed to read an rdlist from file %s.\n", rdlsfn);
143         exit(-1);
144     }
145 
146     {
147         // (x,y) positions of field stars.
148         double* fieldpix;
149         int Nfield;
150         double* indexpix;
151         starxy_t* xy;
152         rd_t* rd;
153         int Nindex;
154 
155         xy = xylist_read_field(xyls, NULL);
156         if (!xy) {
157             logmsg("Failed to read xyls entries.\n");
158             exit(-1);
159         }
160         Nfield = starxy_n(xy);
161         fieldpix = starxy_to_xy_array(xy, NULL);
162         logmsg("Found %i field objects\n", Nfield);
163 
164         // Project RDLS into pixel space.
165         rd = rdlist_read_field(rdls, NULL);
166         if (!rd) {
167             logmsg("Failed to read rdls entries.\n");
168             exit(-1);
169         }
170         Nindex = rd_n(rd);
171         logmsg("Found %i indx objects\n", Nindex);
172         indexpix = malloc(2 * Nindex * sizeof(double));
173         for (i=0; i<Nindex; i++) {
174             anbool ok;
175             double ra = rd_getra(rd, i);
176             double dec = rd_getdec(rd, i);
177             ok = sip_radec2pixelxy(&sip, ra, dec, indexpix + i*2, indexpix + i*2 + 1);
178             assert(ok);
179         }
180 
181         logmsg("CRPIX is (%g,%g)\n", sip.wcstan.crpix[0], sip.wcstan.crpix[1]);
182 
183         {
184             double* fieldsigma2s = malloc(Nfield * sizeof(double));
185             int besti;
186             int* theta;
187             double logodds;
188             double Q2, R2;
189             double qc[2];
190             double gamma;
191 
192             // HACK -- quad radius-squared
193             Q2 = square(100.0);
194             qc[0] = sip.wcstan.crpix[0];
195             qc[1] = sip.wcstan.crpix[1];
196             // HACK -- variance growth rate wrt radius.
197             gamma = 1.0;
198 
199             for (i=0; i<Nfield; i++) {
200                 R2 = distsq(qc, fieldpix + 2*i, 2);
201                 fieldsigma2s[i] = square(pixeljitter) * (1.0 + gamma * R2/Q2);
202             }
203 
204             logodds = verify_star_lists(indexpix, Nindex,
205                                         fieldpix, fieldsigma2s, Nfield,
206                                         W*H,
207                                         0.25,
208                                         log(1e-100),
209                                         log(1e100),
210                                         &besti, NULL, &theta, NULL);
211 
212             logmsg("Logodds: %g\n", logodds);
213 
214             if (TRUE) {
215                 for (i=0; i<Nfield; i++) {
216                     if (theta[i] < 0)
217                         continue;
218                     printf("%g %g %g %g\n", fieldpix[2*i+0], fieldpix[2*i+1],
219                            rd_getra(rd, theta[i]), rd_getdec(rd, theta[i]));
220                 }
221             }
222 
223             if (plotfn) {
224                 plot_args_t pargs;
225                 plotimage_t* img;
226                 cairo_t* cairo;
227 
228                 plotstuff_init(&pargs);
229                 pargs.outformat = PLOTSTUFF_FORMAT_PNG;
230                 pargs.outfn = plotfn;
231                 img = plotstuff_get_config(&pargs, "image");
232                 img->format = PLOTSTUFF_FORMAT_JPG;
233                 plot_image_set_filename(img, "1.jpg");
234                 plot_image_setsize(&pargs, img);
235                 plotstuff_run_command(&pargs, "image");
236                 cairo = pargs.cairo;
237                 // red circles around every field star.
238                 cairo_set_color(cairo, "red");
239                 for (i=0; i<Nfield; i++) {
240                     cairoutils_draw_marker(cairo, CAIROUTIL_MARKER_CIRCLE,
241                                            fieldpix[2*i+0], fieldpix[2*i+1],
242                                            2.0 * sqrt(fieldsigma2s[i]));
243                     cairo_stroke(cairo);
244                 }
245                 // green crosshairs at every index star.
246                 cairo_set_color(cairo, "green");
247                 for (i=0; i<Nindex; i++) {
248                     cairoutils_draw_marker(cairo, CAIROUTIL_MARKER_XCROSSHAIR,
249                                            indexpix[2*i+0], indexpix[2*i+1],
250                                            3);
251                     cairo_stroke(cairo);
252                 }
253 
254                 // thick white circles for corresponding field stars.
255                 cairo_set_line_width(cairo, 2);
256                 for (i=0; i<Nfield; i++) {
257                     if (theta[i] < 0)
258                         continue;
259                     cairo_set_color(cairo, "white");
260                     cairoutils_draw_marker(cairo, CAIROUTIL_MARKER_CIRCLE,
261                                            fieldpix[2*i+0], fieldpix[2*i+1],
262                                            2.0 * sqrt(fieldsigma2s[i]));
263                     cairo_stroke(cairo);
264                     // thick cyan crosshairs for corresponding index stars.
265                     cairo_set_color(cairo, "cyan");
266                     cairoutils_draw_marker(cairo, CAIROUTIL_MARKER_XCROSSHAIR,
267                                            indexpix[2*theta[i]+0],
268                                            indexpix[2*theta[i]+1],
269                                            3);
270                     cairo_stroke(cairo);
271 
272                 }
273 
274                 plotstuff_output(&pargs);
275             }
276 
277             free(theta);
278             free(fieldsigma2s);
279         }
280 
281         free(fieldpix);
282         free(indexpix);
283     }
284 
285 
286 
287     if (xylist_close(xyls)) {
288         logmsg("Failed to close XYLS file.\n");
289     }
290     return 0;
291 }
292