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
10 #include "qfits_header.h"
11 #include "fitsioutils.h"
12 #include "starutil.h"
13 #include "ioutils.h"
14 #include "qidxfile.h"
15 #include "errors.h"
16
17 #define CHUNK_QIDX 0
18
callback_read_header(fitsbin_t * fb,fitsbin_chunk_t * chunk)19 static int callback_read_header(fitsbin_t* fb, fitsbin_chunk_t* chunk) {
20 qfits_header* primheader = fitsbin_get_primary_header(fb);
21 qidxfile* qf = chunk->userdata;
22
23 if (fits_check_endian(primheader)) {
24 ERROR("qidx file was written with wrong endianness");
25 return -1;
26 }
27 qf->numstars = qfits_header_getint(primheader, "NSTARS", -1);
28 qf->numquads = qfits_header_getint(primheader, "NQUADS", -1);
29 qf->dimquads = qfits_header_getint(primheader, "DIMQUADS", 4);
30 if ((qf->numstars == -1) || (qf->numquads == -1)) {
31 ERROR("Couldn't find NSTARS or NQUADS entries in FITS header");
32 return -1;
33 }
34
35 chunk->nrows = qf->numstars * 2 + qf->numquads * qf->dimquads;
36 return 0;
37 }
38
new_qidxfile(const char * fn,anbool writing)39 static qidxfile* new_qidxfile(const char* fn, anbool writing) {
40 qidxfile* qf;
41 fitsbin_chunk_t chunk;
42
43 qf = calloc(1, sizeof(qidxfile));
44 if (!qf) {
45 SYSERROR("Couldn't malloc a qidxfile struct");
46 return NULL;
47 }
48
49 // default
50 qf->dimquads = 4;
51
52 if (writing)
53 qf->fb = fitsbin_open_for_writing(fn);
54 else
55 qf->fb = fitsbin_open(fn);
56 if (!qf->fb) {
57 ERROR("Failed to create fitsbin");
58 free(qf); //# Modified by Robert Lancaster for the StellarSolver Internal Library, to prevent leak
59 return NULL;
60 }
61
62 fitsbin_chunk_init(&chunk);
63 chunk.tablename = "qidx";
64 chunk.required = 1;
65 chunk.callback_read_header = callback_read_header;
66 chunk.userdata = qf;
67 chunk.itemsize = sizeof(uint32_t);
68 fitsbin_add_chunk(qf->fb, &chunk);
69 fitsbin_chunk_clean(&chunk);
70
71 return qf;
72 }
73
qidxfile_open(const char * fn)74 qidxfile* qidxfile_open(const char* fn) {
75 qidxfile* qf = NULL;
76
77 qf = new_qidxfile(fn, FALSE);
78 if (!qf)
79 goto bailout;
80
81 if (fitsbin_read(qf->fb)) {
82 ERROR("Failed to find qidx table.\n");
83 goto bailout;
84 }
85
86 qf->index = fitsbin_get_chunk(qf->fb, CHUNK_QIDX)->data;
87 qf->heap = qf->index + 2 * qf->numstars;
88 return qf;
89
90 bailout:
91 if (qf)
92 qidxfile_close(qf);
93 return NULL;
94 }
95
qidxfile_close(qidxfile * qf)96 int qidxfile_close(qidxfile* qf) {
97 int rtn;
98 if (!qf) return 0;
99 if (fitsbin_get_fid(qf->fb))
100 fits_pad_file(fitsbin_get_fid(qf->fb));
101 rtn = fitsbin_close(qf->fb);
102 free(qf);
103 return rtn;
104 }
105
106
107
qidxfile_open_for_writing(const char * fn,int nstars,int nquads)108 qidxfile* qidxfile_open_for_writing(const char* fn, int nstars, int nquads) {
109 qidxfile* qf;
110 qfits_header* hdr;
111 qf = new_qidxfile(fn, TRUE);
112 if (!qf)
113 goto bailout;
114 qf->numstars = nstars;
115 qf->numquads = nquads;
116
117 hdr = fitsbin_get_primary_header(qf->fb);
118 fits_add_endian(hdr);
119 fits_header_add_int(hdr, "NSTARS", qf->numstars, "Number of stars used.");
120 fits_header_add_int(hdr, "NQUADS", qf->numquads, "Number of quads used.");
121 qfits_header_add(hdr, "AN_FILE", "QIDX", "This is a quad index file.", NULL);
122 qfits_header_add(hdr, "COMMENT", "The data table of this file has two parts:", NULL, NULL);
123 qfits_header_add(hdr, "COMMENT", " -the index", NULL, NULL);
124 qfits_header_add(hdr, "COMMENT", " -the heap", NULL, NULL);
125 fits_add_long_comment(hdr, "The index contains two uint32 values for each star: the offset and "
126 "length, in the heap, of the list of quads to which it belongs. "
127 "The offset and length are in units of uint32s, not bytes. "
128 "Offset 0 is the first uint32 in the heap. "
129 "The heap is ordered and tightly packed. "
130 "The heap is a flat list of quad indices (uint32s).");
131 return qf;
132
133 bailout:
134 if (qf)
135 qidxfile_close(qf);
136 return NULL;
137 }
138
qidxfile_write_header(qidxfile * qf)139 int qidxfile_write_header(qidxfile* qf) {
140 fitsbin_t* fb = qf->fb;
141 fitsbin_chunk_t* chunk;
142 chunk = fitsbin_get_chunk(fb, CHUNK_QIDX);
143 chunk->nrows = 2 * qf->numstars + qf->dimquads * qf->numquads;
144 if (fitsbin_write_primary_header(fb) ||
145 fitsbin_write_chunk_header(fb, chunk)) {
146 ERROR("Failed to write qidxfile header");
147 return -1;
148 }
149 qf->cursor_index = 0;
150 qf->cursor_heap = 0;
151 return 0;
152 }
153
qidxfile_write_star(qidxfile * qf,int * quads,int nquads)154 int qidxfile_write_star(qidxfile* qf, int* quads, int nquads) {
155 fitsbin_t* fb = qf->fb;
156 FILE* fid;
157 uint32_t nq;
158 int i;
159 fitsbin_chunk_t* chunk;
160
161 fid = fitsbin_get_fid(fb);
162 chunk = fitsbin_get_chunk(fb, CHUNK_QIDX);
163
164 // Write the offset & size:
165 if (fseeko(fid, fitsbin_get_data_start(fb, chunk) + qf->cursor_index * 2 * sizeof(uint32_t), SEEK_SET)) {
166 ERROR("qidxfile_write_star: failed to fseek");
167 return -1;
168 }
169 nq = nquads;
170 if (fitsbin_write_item(fb, chunk, &qf->cursor_heap) ||
171 fitsbin_write_item(fb, chunk, &nq)) {
172 ERROR("qidxfile_write_star: failed to write a qidx offset/size");
173 return -1;
174 }
175 // Write the quads.
176 if (fseeko(fid, fitsbin_get_data_start(fb, chunk) + qf->numstars * 2 * sizeof(uint32_t) +
177 qf->cursor_heap * sizeof(uint32_t), SEEK_SET)) {
178 SYSERROR("qidxfile_write_star: failed to fseek");
179 return -1;
180 }
181
182 for (i=0; i<nquads; i++) {
183 // (in case uint != uint32_t)
184 uint32_t q = quads[i];
185 if (fitsbin_write_item(fb, chunk, &q)) {
186 ERROR("qidxfile_write_star: failed to write quads");
187 return -1;
188 }
189 }
190
191 qf->cursor_index++;
192 qf->cursor_heap += nquads;
193 return 0;
194 }
195
qidxfile_get_quads(const qidxfile * qf,int starid,uint32_t ** quads,int * nquads)196 int qidxfile_get_quads(const qidxfile* qf, int starid, uint32_t** quads, int* nquads) {
197 int heapindex = qf->index[2*starid];
198 *nquads = qf->index[2*starid + 1];
199 *quads = qf->heap + heapindex;
200 return 0;
201 }
202
qidxfile_get_header(const qidxfile * qf)203 qfits_header* qidxfile_get_header(const qidxfile* qf) {
204 return fitsbin_get_primary_header(qf->fb);
205 }
206