1 /*
2 # This file is part of the Astrometry.net suite.
3 # Licensed under a 3-clause BSD style license - see LICENSE
4 */
5
6 #include <stdio.h>
7 #include <math.h>
8 #include <string.h>
9 #include <assert.h>
10
11 #include "quadfile.h"
12 #include "qfits_header.h"
13 #include "fitsioutils.h"
14 #include "starutil.h"
15 #include "ioutils.h"
16 #include "errors.h"
17 #include "an-endian.h"
18
19 #define CHUNK_QUADS 0
20
quads_chunk(quadfile_t * qf)21 static fitsbin_chunk_t* quads_chunk(quadfile_t* qf) {
22 return fitsbin_get_chunk(qf->fb, CHUNK_QUADS);
23 }
24
callback_read_header(fitsbin_t * fb,fitsbin_chunk_t * chunk)25 static int callback_read_header(fitsbin_t* fb, fitsbin_chunk_t* chunk) {
26 qfits_header* primheader = fitsbin_get_primary_header(fb);
27 quadfile_t* qf = chunk->userdata;
28
29 qf->dimquads = qfits_header_getint(primheader, "DIMQUADS", 4);
30 qf->numquads = qfits_header_getint(primheader, "NQUADS", -1);
31 qf->numstars = qfits_header_getint(primheader, "NSTARS", -1);
32 qf->index_scale_upper = qfits_header_getdouble(primheader, "SCALE_U", -1.0);
33 qf->index_scale_lower = qfits_header_getdouble(primheader, "SCALE_L", -1.0);
34 qf->indexid = qfits_header_getint(primheader, "INDEXID", 0);
35 qf->healpix = qfits_header_getint(primheader, "HEALPIX", -1);
36 qf->hpnside = qfits_header_getint(primheader, "HPNSIDE", 1);
37
38 if ((qf->numquads == -1) || (qf->numstars == -1) ||
39 (qf->index_scale_upper == -1.0) || (qf->index_scale_lower == -1.0)) {
40 ERROR("Couldn't find NQUADS or NSTARS or SCALE_U or SCALE_L entries in FITS header");
41 return -1;
42 }
43 if (fits_check_endian(primheader)) {
44 ERROR("Quad file was written with the wrong endianness");
45 return -1;
46 }
47
48 chunk->itemsize = qf->dimquads * sizeof(uint32_t);
49 chunk->nrows = qf->numquads;
50 return 0;
51 }
52
new_quadfile(const char * fn,anqfits_t * fits,anbool writing)53 static quadfile_t* new_quadfile(const char* fn, anqfits_t* fits, anbool writing) {
54 quadfile_t* qf;
55 fitsbin_chunk_t chunk;
56 qf = calloc(1, sizeof(quadfile_t));
57 if (!qf) {
58 SYSERROR("Couldn't malloc a quadfile struct");
59 return NULL;
60 }
61 qf->healpix = -1;
62 qf->hpnside = 1;
63
64 if (writing)
65 if (fn) {
66 qf->fb = fitsbin_open_for_writing(fn);
67 } else {
68 qf->fb = fitsbin_open_in_memory();
69 }
70 else {
71 if (fits)
72 qf->fb = fitsbin_open_fits(fits);
73 else
74 qf->fb = fitsbin_open(fn);
75 }
76 if (!qf->fb) {
77 ERROR("Failed to create fitsbin");
78 free(qf); //# Modified by Robert Lancaster for the StellarSolver Internal Library, to prevent leak
79 return NULL;
80 }
81
82 fitsbin_chunk_init(&chunk);
83 chunk.tablename = "quads";
84 chunk.required = 1;
85 chunk.callback_read_header = callback_read_header;
86 chunk.userdata = qf;
87 fitsbin_add_chunk(qf->fb, &chunk);
88 fitsbin_chunk_clean(&chunk);
89
90 return qf;
91 }
92
quadfile_check(const quadfile_t * qf)93 int quadfile_check(const quadfile_t* qf) {
94 int q, i;
95 if (qf->dimquads < 3 || qf->dimquads > DQMAX) {
96 ERROR("Dimquads has illegal value %i", qf->dimquads);
97 return -1;
98 }
99 for (q=0; q<qf->numquads; q++) {
100 unsigned int stars[DQMAX];
101 if (quadfile_get_stars(qf, q, stars)) {
102 ERROR("Failed to get quad %i of %i", q, qf->numquads);
103 return -1;
104 }
105 for (i=0; i<qf->dimquads; i++) {
106 if (stars[i] >= qf->numstars) {
107 ERROR("Star ID %i is out of bounds: num stars %i", stars[i], qf->numstars);
108 return -1;
109 }
110 }
111 }
112 return 0;
113 }
114
quadfile_dimquads(const quadfile_t * qf)115 int quadfile_dimquads(const quadfile_t* qf) {
116 return qf->dimquads;
117 }
118
quadfile_nquads(const quadfile_t * qf)119 int quadfile_nquads(const quadfile_t* qf) {
120 return qf->numquads;
121 }
122
quadfile_get_header(const quadfile_t * qf)123 qfits_header* quadfile_get_header(const quadfile_t* qf) {
124 return fitsbin_get_primary_header(qf->fb);
125 }
126
my_open(const char * fn,anqfits_t * fits)127 static quadfile_t* my_open(const char* fn, anqfits_t* fits) {
128 quadfile_t* qf = NULL;
129 fitsbin_chunk_t* chunk;
130
131 qf = new_quadfile(fn, fits, FALSE);
132 if (!qf)
133 goto bailout;
134 if (fitsbin_read(qf->fb)) {
135 ERROR("Failed to open quads file");
136 goto bailout;
137 }
138 chunk = quads_chunk(qf);
139 qf->quadarray = chunk->data;
140
141 // close fd.
142 if (qf->fb->fid) {
143 if (fclose(qf->fb->fid)) {
144 ERROR("Failed to close quadfile FID");
145 goto bailout;
146 }
147 qf->fb->fid = NULL;
148 }
149
150 return qf;
151
152 bailout:
153 if (qf)
154 quadfile_close(qf);
155 return NULL;
156 }
157
quadfile_get_filename(const quadfile_t * qf)158 char* quadfile_get_filename(const quadfile_t* qf) {
159 return fitsbin_get_filename(qf->fb);
160 }
161
quadfile_open_fits(anqfits_t * fits)162 quadfile_t* quadfile_open_fits(anqfits_t* fits) {
163 return my_open(NULL, fits);
164 }
165
quadfile_open(const char * fn)166 quadfile_t* quadfile_open(const char* fn) {
167 return my_open(fn, NULL);
168 }
169
quadfile_close(quadfile_t * qf)170 int quadfile_close(quadfile_t* qf) {
171 int rtn;
172 if (!qf) return 0;
173 rtn = fitsbin_close(qf->fb);
174 free(qf);
175 return rtn;
176 }
177
open_for_writing(const char * fn)178 static quadfile_t* open_for_writing(const char* fn) {
179 quadfile_t* qf;
180 qfits_header* hdr;
181 qf = new_quadfile(fn, NULL, TRUE);
182 if (!qf)
183 goto bailout;
184 qf->dimquads = 4;
185 // add default values to header
186 hdr = fitsbin_get_primary_header(qf->fb);
187 fits_add_endian(hdr);
188 qfits_header_add(hdr, "AN_FILE", "QUAD", "This file lists, for each quad, its stars.", NULL);
189 qfits_header_add(hdr, "DIMQUADS", "0", "", NULL);
190 qfits_header_add(hdr, "NQUADS", "0", "", NULL);
191 qfits_header_add(hdr, "NSTARS", "0", "", NULL);
192 qfits_header_add(hdr, "SCALE_U", "0.0", "", NULL);
193 qfits_header_add(hdr, "SCALE_L", "0.0", "", NULL);
194 qfits_header_add(hdr, "INDEXID", "0", "", NULL);
195 qfits_header_add(hdr, "HEALPIX", "-1", "", NULL);
196 qfits_header_add(hdr, "HPNSIDE", "1", "", NULL);
197 fits_add_long_comment(hdr, "The first extension contains the quads "
198 "stored as %i 32-bit native-endian unsigned ints.", qf->dimquads);
199 return qf;
200
201 bailout:
202 if (qf)
203 quadfile_close(qf);
204 return NULL;
205 }
206
quadfile_open_for_writing(const char * fn)207 quadfile_t* quadfile_open_for_writing(const char* fn) {
208 if (!fn) {
209 ERROR("Non-NULL filename required");
210 return NULL;
211 }
212 return open_for_writing(fn);
213 }
214
quadfile_open_in_memory()215 quadfile_t* quadfile_open_in_memory() {
216 return open_for_writing(NULL);
217 }
218
quadfile_switch_to_reading(quadfile_t * qf)219 int quadfile_switch_to_reading(quadfile_t* qf) {
220 if (quadfile_fix_header(qf)) {
221 ERROR("Failed to fix quads header");
222 return -1;
223 }
224 if (fitsbin_switch_to_reading(qf->fb)) {
225 ERROR("Failed to switch to read mode");
226 return -1;
227 }
228 if (fitsbin_read(qf->fb)) {
229 ERROR("Failed to open quads file");
230 return -1;
231 }
232 qf->quadarray = quads_chunk(qf)->data;
233 return 0;
234 }
235
add_to_header(qfits_header * hdr,quadfile_t * qf)236 static void add_to_header(qfits_header* hdr, quadfile_t* qf) {
237 fits_header_mod_int(hdr, "DIMQUADS", qf->dimquads, "Number of stars in a quad.");
238 fits_header_mod_int(hdr, "NQUADS", qf->numquads, "Number of quads.");
239 fits_header_mod_int(hdr, "NSTARS", qf->numstars, "Number of stars.");
240 fits_header_mod_double(hdr, "SCALE_U", qf->index_scale_upper, "Upper-bound index scale (radians).");
241 fits_header_mod_double(hdr, "SCALE_L", qf->index_scale_lower, "Lower-bound index scale (radians).");
242 fits_header_mod_int(hdr, "INDEXID", qf->indexid, "Index unique ID.");
243 fits_header_mod_int(hdr, "HEALPIX", qf->healpix, "Healpix of this index.");
244 fits_header_mod_int(hdr, "HPNSIDE", qf->hpnside, "Nside of the healpixelization");
245 }
246
quadfile_write_header(quadfile_t * qf)247 int quadfile_write_header(quadfile_t* qf) {
248 fitsbin_t* fb = qf->fb;
249 fitsbin_chunk_t* chunk = quads_chunk(qf);
250 qfits_header* hdr;
251 chunk->itemsize = qf->dimquads * sizeof(uint32_t);
252 chunk->nrows = qf->numquads;
253
254 hdr = fitsbin_get_primary_header(fb);
255 add_to_header(hdr, qf);
256
257 if (fitsbin_write_primary_header(fb) ||
258 fitsbin_write_chunk_header(fb, chunk)) {
259 ERROR("Failed to write quadfile header");
260 return -1;
261 }
262 return 0;
263 }
264
quadfile_write_header_to(quadfile_t * qf,FILE * fid)265 int quadfile_write_header_to(quadfile_t* qf, FILE* fid) {
266 fitsbin_t* fb = qf->fb;
267 fitsbin_chunk_t* chunk = quads_chunk(qf);
268 qfits_header* hdr;
269 chunk->itemsize = qf->dimquads * sizeof(uint32_t);
270 chunk->nrows = qf->numquads;
271 hdr = fitsbin_get_primary_header(fb);
272 add_to_header(hdr, qf);
273
274 if (fitsbin_write_primary_header_to(fb, fid) ||
275 fitsbin_write_chunk_header_to(fb, chunk, fid)) {
276 ERROR("Failed to write quadfile header");
277 return -1;
278 }
279 return 0;
280 }
281
quadfile_write_quad(quadfile_t * qf,unsigned int * stars)282 int quadfile_write_quad(quadfile_t* qf, unsigned int* stars) {
283 uint32_t* data;
284
285 #ifndef _MSC_VER //# Modified by Robert Lancaster for the StellarSolver Internal Library
286 uint32_t ustars[qf->dimquads];
287 #else
288 uint32_t* ustars = (uint32_t*)malloc(sizeof(uint32_t)*qf->dimquads);
289 #endif
290
291 int i;
292 fitsbin_chunk_t* chunk = quads_chunk(qf);
293
294 if (sizeof(uint32_t) == sizeof(uint)) {
295 data = stars;
296 } else {
297 data = ustars;
298 for (i=0; i<qf->dimquads; i++)
299 ustars[i] = stars[i];
300 }
301 #ifdef _MSC_VER //# Modified by Robert Lancaster for the StellarSolver Internal Library
302 free(ustars);
303 #endif
304 if (fitsbin_write_item(qf->fb, chunk, data)) {
305 ERROR("Failed to write a quad");
306 return -1;
307 }
308 qf->numquads++;
309 return 0;
310 }
311
quadfile_write_all_quads_to(quadfile_t * qf,FILE * fid)312 int quadfile_write_all_quads_to(quadfile_t* qf, FILE* fid) {
313 fitsbin_chunk_t* chunk = quads_chunk(qf);
314 if (fitsbin_write_items_to(chunk, qf->quadarray, quadfile_nquads(qf), fid)) {
315 ERROR("Failed to write %i quads", quadfile_nquads(qf));
316 return -1;
317 }
318 return 0;
319 }
320
quadfile_fix_header(quadfile_t * qf)321 int quadfile_fix_header(quadfile_t* qf) {
322 qfits_header* hdr;
323 fitsbin_t* fb = qf->fb;
324 fitsbin_chunk_t* chunk = quads_chunk(qf);
325
326 chunk->itemsize = qf->dimquads * sizeof(uint32_t);
327 chunk->nrows = qf->numquads;
328
329 hdr = fitsbin_get_primary_header(fb);
330 add_to_header(hdr, qf);
331
332 if (fitsbin_fix_primary_header(fb) ||
333 fitsbin_fix_chunk_header(fb, chunk)) {
334 ERROR("Failed to fix quad header");
335 return -1;
336 }
337 return 0;
338 }
339
quadfile_get_index_scale_upper_arcsec(const quadfile_t * qf)340 double quadfile_get_index_scale_upper_arcsec(const quadfile_t* qf) {
341 return rad2arcsec(qf->index_scale_upper);
342 }
343
quadfile_get_index_scale_lower_arcsec(const quadfile_t * qf)344 double quadfile_get_index_scale_lower_arcsec(const quadfile_t* qf) {
345 return rad2arcsec(qf->index_scale_lower);
346 }
347
quadfile_get_stars(const quadfile_t * qf,unsigned int quadid,unsigned int * stars)348 int quadfile_get_stars(const quadfile_t* qf, unsigned int quadid, unsigned int* stars) {
349 int i;
350 if (quadid >= qf->numquads) {
351 ERROR("Requested quadid %i, but number of quads is %i", quadid, qf->numquads);
352 assert(quadid < qf->numquads);
353 return -1;
354 }
355
356 for (i=0; i<qf->dimquads; i++) {
357 stars[i] = qf->quadarray[quadid * qf->dimquads + i];
358 }
359 return 0;
360 }
361
362
363
364