void plotstuff_stack_text(plot_args_t* pargs, cairo_t* cairo, const char* txt, double px, double py) { cairocmd_t cmd; cairocmd_init(&cmd); set_cmd_args(pargs, &cmd); get_text_position(pargs, cairo, txt, &px, &py); cmd.type = TEXT; if (pargs->bg_rgba[3] > 0) { int dx, dy; logverb("Background text RGB [%g, %g, %g] alpha %g\n", pargs->bg_rgba[0], pargs->bg_rgba[1], pargs->bg_rgba[2], pargs->bg_rgba[3]); cmd.layer = pargs->text_bg_layer; memcpy(cmd.rgba, pargs->bg_rgba, sizeof(cmd.rgba)); for (dy=-1; dy<=1; dy++) { for (dx=-1; dx<=1; dx++) { cmd.text = strdup(txt); cmd.x = px + dx; cmd.y = py + dy; add_cmd(pargs, &cmd); } } } else logverb("No background behind text\n"); cmd.layer = pargs->text_fg_layer; memcpy(cmd.rgba, pargs->rgba, sizeof(cmd.rgba)); cmd.text = strdup(txt); cmd.x = px; cmd.y = py; add_cmd(pargs, &cmd); }
int multiindex_add_index(multiindex_t* mi, const char* fn, int flags) { anqfits_t* fits; quadfile_t* quads = NULL; codetree_t* codes = NULL; index_t* ind = NULL; logverb("Reading index file \"%s\"...\n", fn); fits = anqfits_open(fn); if (!fits) { ERROR("Failed to open FITS file \"%s\"", fn); goto bailout; } logverb("Reading quads from file \"%s\"...\n", fn); quads = quadfile_open_fits(fits); if (!quads) { ERROR("Failed to read quads from file \"%s\"", fn); anqfits_close(fits); goto bailout; } logverb("Reading codes from file \"%s\"...\n", fn); codes = codetree_open_fits(fits); if (!codes) { ERROR("Failed to read quads from file \"%s\"", fn); quadfile_close(quads); anqfits_close(fits); goto bailout; } ind = index_build_from(codes, quads, mi->starkd); ind->fits = fits; if (!ind->indexname) ind->indexname = strdup(fn); // shouldn't be needed, but set anyway ind->quadfn = strdup(fn); ind->codefn = strdup(fn); pl_append(mi->inds, ind); if (flags & INDEX_ONLY_LOAD_METADATA) { // don't let it unload the starkd! ind->starkd = NULL; index_unload(ind); ind->starkd = mi->starkd; } return 0; bailout: if (quads) { quadfile_close(quads); } if (codes) { codetree_close(codes); } if (fits) { anqfits_close(fits); } return -1; }
static int plot_annotations(augment_xylist_t* axy, const char* me, anbool verbose, const char* annfn, double plotscale, const char* bgfn) { sl* cmdline = sl_new(16); char* cmd; sl* lines; char* imgfn; imgfn = axy->pnmfn; if (bgfn) { append_executable(cmdline, "jpegtopnm", me); append_escape(cmdline, bgfn); sl_append(cmdline, "|"); imgfn = "-"; } else if (axy->imagefn && plotscale != 1.0) { append_executable(cmdline, "pnmscale", me); sl_appendf(cmdline, "%f", plotscale); append_escape(cmdline, axy->pnmfn); sl_append(cmdline, "|"); imgfn = "-"; } append_executable(cmdline, "plot-constellations", me); if (verbose) sl_append(cmdline, "-v"); sl_append(cmdline, "-w"); assert(axy->wcsfn); append_escape(cmdline, axy->wcsfn); sl_append(cmdline, "-i"); append_escape(cmdline, imgfn); if (plotscale != 1.0) { sl_append(cmdline, "-s"); sl_appendf(cmdline, "%f", plotscale); } sl_append(cmdline, "-N"); sl_append(cmdline, "-B"); sl_append(cmdline, "-C"); sl_append(cmdline, "-o"); assert(annfn); append_escape(cmdline, annfn); cmd = sl_implode(cmdline, " "); sl_free2(cmdline); logverb("Running:\n %s\n", cmd); if (run_command_get_outputs(cmd, &lines, NULL)) { ERROR("plot-constellations failed"); return -1; } free(cmd); if (lines && sl_size(lines)) { int i; if (strlen(sl_get(lines, 0))) { logmsg("Your field contains:\n"); for (i=0; i<sl_size(lines); i++) logmsg(" %s\n", sl_get(lines, i)); } } if (lines) sl_free2(lines); return 0; }
static int wcslib_pixelxy2radec(const anwcslib_t* anwcslib, double px, double py, double* ra, double* dec) { double pix[2]; double world[2]; double phi; double theta; double imgcrd[2]; int status = 0; int code; struct wcsprm* wcs = anwcslib->wcs; pix[0] = px; pix[1] = py; code = wcsp2s(wcs, 1, 0, pix, imgcrd, &phi, &theta, world, &status); /* int wcsp2s(struct wcsprm *wcs, int ncoord, int nelem, const double pixcrd[], double imgcrd[], double phi[], double theta[], double world[], int stat[]); */ if (code) { //ERROR("Wcslib's wcsp2s() failed: code=%i, status=%i (%s); (x,y)=(%g,%g)", code, status, wcs_errmsg[status], px, py); logverb("Wcslib's wcsp2s() failed: code=%i, status=%i (%s); (x,y)=(%g,%g)", code, status, wcs_errmsg[status], px, py); return -1; } if (ra) *ra = world[wcs->lng]; if (dec) *dec = world[wcs->lat]; return 0; }
int main(int argc, char** args) { pthread_t thread1; pthread_t thread2; pthread_attr_t attr; char* job1 = "job1.axy"; char* job2 = "job2.axy"; fits_use_error_system(); log_init(LOG_VERB); log_set_thread_specific(); logverb("Hello world!\n"); be = engine_new(); engine_parse_config_file(be, "astrometry.cfg"); pthread_mutex_init(&read_job_mutex, NULL); pthread_attr_init(&attr); pthread_create(&thread1, &attr, threadfunc, job1); pthread_create(&thread2, &attr, threadfunc, job2); pthread_join(thread1, NULL); pthread_join(thread2, NULL); pthread_mutex_destroy(&read_job_mutex); engine_free(be); return 0; }
int coadd_add_image(coadd_t* ca, const number* img, const number* weightimg, number weight, const anwcs_t* wcs) { int W, H; int i, j; int xlo,xhi,ylo,yhi; check_bounds_t cb; W = anwcs_imagew(wcs); H = anwcs_imageh(wcs); // if check_bounds: cb.xlo = W; cb.xhi = 0; cb.ylo = H; cb.yhi = 0; cb.wcs = ca->wcs; anwcs_walk_image_boundary(wcs, 50, check_bounds, &cb); xlo = MAX(0, floor(cb.xlo)); xhi = MIN(ca->W, ceil(cb.xhi)+1); ylo = MAX(0, floor(cb.ylo)); yhi = MIN(ca->H, ceil(cb.yhi)+1); logmsg("Image projects to output image region: [%i,%i), [%i,%i)\n", xlo, xhi, ylo, yhi); for (i=ylo; i<yhi; i++) { for (j=xlo; j<xhi; j++) { double ra, dec; double px, py; double wt; double val; // +1 for FITS if (anwcs_pixelxy2radec(ca->wcs, j+1, i+1, &ra, &dec)) { ERROR("Failed to project pixel (%i,%i) through output WCS\n", j, i); continue; } if (anwcs_radec2pixelxy(wcs, ra, dec, &px, &py)) { ERROR("Failed to project pixel (%i,%i) through input WCS\n", j, i); continue; } // -1 for FITS px -= 1; py -= 1; if (px < 0 || px >= W) continue; if (py < 0 || py >= H) continue; val = ca->resample_func(px, py, img, weightimg, W, H, &wt, ca->resample_token); ca->img[i*ca->W + j] += val * weight; ca->weight[i*ca->W + j] += wt * weight; } logverb("Row %i of %i\n", i+1, ca->H); } return 0; }
void* thread2(void* v) { FILE* flog = v; logmsg("I'm thread 2.\n"); log_set_level(LOG_VERB); log_to(flog); logmsg("%s\n", STRING2A); logverb("%s\n", STRING2B); return NULL; }
static void plot_hd(cairo_t* cairo, plot_args_t* pargs, plotann_t* ann) { int i, N; hd_catalog_t* hdcat = NULL; double ra,dec,rad; bl* hdlist = NULL; if (!ann->hd_catalog) return; hdcat = henry_draper_open(ann->hd_catalog); if (!hdcat) { ERROR("Failed to open Henry Draper catalog file \"%s\"", ann->hd_catalog); return; } if (plotstuff_get_radec_center_and_radius(pargs, &ra, &dec, &rad)) { ERROR("Failed to get RA,Dec,radius from plotstuff"); return; } hdlist = henry_draper_get(hdcat, ra, dec, deg2arcsec(rad)); logverb("Got %zu Henry Draper stars\n", bl_size(hdlist)); N = bl_size(hdlist); for (i=0; i<N; i++) { hd_entry_t* entry = bl_access(hdlist, i); double px, py; char label[16]; if (!plotstuff_radec2xy(pargs, entry->ra, entry->dec, &px, &py)) continue; px -= 1; py -= 1; if (px < 1 || py < 1 || px > pargs->W || py > pargs->H) continue; logverb("HD %i at RA,Dec (%g,%g) -> xy (%g, %g)\n", entry->hd, entry->ra, entry->dec, px, py); plotstuff_stack_marker(pargs, px, py); if (ann->HD_labels) { sprintf(label, "HD %i", entry->hd); plotstuff_stack_text(pargs, cairo, label, px, py); } } bl_free(hdlist); henry_draper_close(hdcat); }
void* thread1(void* v) { FILE* flog = v; logmsg("I'm thread 1.\n"); log_set_level(LOG_MSG); log_to(flog); logmsg("%s\n", STRING1A); sleep(1); logverb("%s\n", STRING1B); return NULL; }
static void add_quad(quadbuilder_t* qb, unsigned int* quad, void* token) { allquads_t* aq = token; if (log_get_level() > LOG_VERB) { int k; debug("quad: "); for (k=0; k<qb->dimquads; k++) debug("%-6i ", quad[k]); logverb("\n"); } quad_write_const(aq->codes, aq->quads, quad, aq->starkd, qb->dimquads, aq->dimcodes); }
static void delete_temp_files(sl* tempfiles, sl* tempdirs) { int i; if (tempfiles) { for (i=0; i<sl_size(tempfiles); i++) { char* fn = sl_get(tempfiles, i); logverb("Deleting temp file %s\n", fn); if (unlink(fn)) SYSERROR("Failed to delete temp file \"%s\"", fn); } sl_remove_all(tempfiles); } if (tempdirs) { for (i=0; i<sl_size(tempdirs); i++) { char* fn = sl_get(tempdirs, i); logverb("Deleting temp dir %s\n", fn); if (rmdir(fn)) SYSERROR("Failed to delete temp dir \"%s\"", fn); } sl_remove_all(tempdirs); } }
int plotstuff_read_and_run_command(plot_args_t* pargs, FILE* f) { char* cmd; int rtn; cmd = read_string_terminated(stdin, "\n\r\0", 3, FALSE); logverb("command: \"%s\"\n", cmd); if (!cmd || feof(f)) { free(cmd); return -1; } rtn = plotstuff_run_command(pargs, cmd); free(cmd); return rtn; }
static void run_engine(sl* engineargs) { char* cmd; cmd = sl_implode(engineargs, " "); logmsg("Solving...\n"); logverb("Running:\n %s\n", cmd); fflush(NULL); if (run_command_get_outputs(cmd, NULL, NULL)) { ERROR("engine failed. Command that failed was:\n %s", cmd); exit(-1); } free(cmd); fflush(NULL); }
void* threadfunc(void* arg) { char* jobfn = arg; logverb("Hello from thread-land!\n"); //pthread_mutex_lock(&read_job_mutex); job_t* job = engine_read_job_file(be, jobfn); //pthread_mutex_unlock(&read_job_mutex); engine_run_job(be, job); job_free(job); return NULL; }
int startree_write_tagalong_table(fitstable_t* intab, fitstable_t* outtab, const char* racol, const char* deccol) { int i, R, NB, N; char* buf; qfits_header* hdr; fitstable_clear_table(intab); fitstable_add_fits_columns_as_struct(intab); fitstable_copy_columns(intab, outtab); if (!racol) racol = "RA"; if (!deccol) deccol = "DEC"; fitstable_remove_column(outtab, racol); fitstable_remove_column(outtab, deccol); fitstable_read_extension(intab, 1); hdr = fitstable_get_header(outtab); qfits_header_add(hdr, "AN_FILE", AN_FILETYPE_TAGALONG, "Extra data for stars", NULL); if (fitstable_write_header(outtab)) { ERROR("Failed to write tag-along data header"); return -1; } R = fitstable_row_size(intab); NB = 1000; logverb("Input row size: %i, output row size: %i\n", R, fitstable_row_size(outtab)); buf = malloc(NB * R); N = fitstable_nrows(intab); for (i=0; i<N; i+=NB) { int nr = NB; if (i+NB > N) nr = N - i; if (fitstable_read_structs(intab, buf, R, i, nr)) { ERROR("Failed to read tag-along data from catalog"); return -1; } if (fitstable_write_structs(outtab, buf, R, nr)) { ERROR("Failed to write tag-along data"); return -1; } } free(buf); if (fitstable_fix_header(outtab)) { ERROR("Failed to fix tag-along data header"); return -1; } return 0; }
int plotstuff_init2(plot_args_t* pargs) { int i; logverb("Creating drawing surface (%ix%i)\n", pargs->W, pargs->H); // Allocate cairo surface switch (pargs->outformat) { case PLOTSTUFF_FORMAT_PDF: if (pargs->outfn) { pargs->fout = fopen(pargs->outfn, "wb"); if (!pargs->fout) { SYSERROR("Failed to open output file \"%s\"", pargs->outfn); return -1; } } pargs->target = cairo_pdf_surface_create_for_stream(cairoutils_file_write_func, pargs->fout, pargs->W, pargs->H); break; case PLOTSTUFF_FORMAT_JPG: case PLOTSTUFF_FORMAT_PPM: case PLOTSTUFF_FORMAT_PNG: case PLOTSTUFF_FORMAT_MEMIMG: pargs->target = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, pargs->W, pargs->H); break; default: ERROR("Unknown output format %i", pargs->outformat); return -1; break; } pargs->cairo = cairo_create(pargs->target); /* D'oh, this flips the coord sys, but not text! // Flip the cairo reference frame (make 0,0 the bottom-left) cairo_scale(pargs->cairo, 1.0, -1.0); // FIXME -- could deal with 0.5 issues here! cairo_translate(pargs->cairo, 0.0, -pargs->H); */ for (i=0; i<pargs->NP; i++) { if (pargs->plotters[i].init2 && pargs->plotters[i].init2(pargs, pargs->plotters[i].baton)) { ERROR("Plot initializer failed"); exit(-1); } } return 0; }
multiindex_t* multiindex_new(const char* skdtfn) { multiindex_t* mi = calloc(1, sizeof(multiindex_t)); logverb("Reading star KD tree from %s...\n", skdtfn); mi->fits = anqfits_open(skdtfn); if (!mi->fits) { ERROR("Failed to open multiindex file \"%s\"", skdtfn); goto bailout; } mi->inds = pl_new(16); if (multiindex_reload_starkd(mi)) { ERROR("Failed to open multiindex star kd-tree \"%s\"", skdtfn); goto bailout; } return mi; bailout: multiindex_free(mi); return NULL; }
static void plot_brightstars(cairo_t* cairo, plot_args_t* pargs, plotann_t* ann) { int i, N; // Get plot center, to use in trimming bright stars double rc,dc,radius; plotstuff_get_radec_center_and_radius(pargs, &rc, &dc, &radius); N = bright_stars_n(); for (i=0; i<N; i++) { double px, py; char* label; const brightstar_t* bs = bright_stars_get(i); // skip unnamed if (!strlen(bs->name) && !strlen(bs->common_name)) continue; // skip stars too far away if (deg_between_radecdeg(rc, dc, bs->ra, bs->dec) > radius * 1.2) continue; if (!plotstuff_radec2xy(pargs, bs->ra, bs->dec, &px, &py)) continue; logverb("Bright star %s/%s at RA,Dec (%g,%g) -> xy (%g, %g)\n", bs->name, bs->common_name, bs->ra, bs->dec, px, py); if (px < 1 || py < 1 || px > pargs->W || py > pargs->H) continue; px -= 1; py -= 1; if (ann->bright_pastel) { float r,g,b; color_for_radec(bs->ra, bs->dec, &r,&g,&b); plotstuff_set_rgba2(pargs, r,g,b, 0.8); plotstuff_builtin_apply(cairo, pargs); } plotstuff_stack_marker(pargs, px, py); if (ann->bright_labels) { label = (strlen(bs->common_name) ? bs->common_name : bs->name); plotstuff_stack_text(pargs, cairo, label, px, py); } } }
static int run_command(const char* cmd, anbool* ctrlc) { int rtn; logverb("Running: %s\n", cmd); fflush(NULL); rtn = system(cmd); fflush(NULL); if (rtn == -1) { SYSERROR("Failed to run command \"%s\"", cmd); return -1; } if (WIFSIGNALED(rtn)) { if (ctrlc && (WTERMSIG(rtn) == SIGTERM)) *ctrlc = TRUE; return -1; } rtn = WEXITSTATUS(rtn); if (rtn) { ERROR("Command exited with exit status %i", rtn); ERROR("Command was: \"%s\"\n", cmd); } return rtn; }
int plotstuff_line_constant_ra(plot_args_t* pargs, double ra, double dec1, double dec2, anbool startwithmove) { double decstep; double dec; double s; double pixscale; anbool lastok = FALSE; if (!startwithmove) lastok = TRUE; assert(pargs->wcs); pixscale = anwcs_pixel_scale(pargs->wcs); assert(pixscale > 0.0); decstep = arcsec2deg(pixscale * pargs->linestep); logverb("plotstuff_line_constant_ra: RA=%g, Dec=[%g,%g], pixscale %g, decstep %g\n", ra, dec1, dec2, anwcs_pixel_scale(pargs->wcs), decstep); //printf("plotstuff_line_constant_ra: RA=%g, Dec=[%g,%g], pixscale %g, decstep %g\n", //ra, dec1, dec2, anwcs_pixel_scale(pargs->wcs), decstep); s = 1.0; if (dec1 > dec2) s = -1; for (dec=dec1; (s*dec)<=(s*dec2); dec+=(decstep*s)) { double x, y; //logverb(" line_constant_ra: RA,Dec %g,%g\n", ra, dec); //printf(" line_constant_ra: RA,Dec %g,%g\n", ra, dec); if (anwcs_radec2pixelxy(pargs->wcs, ra, dec, &x, &y)) { printf(" bad xy\n"); lastok = FALSE; continue; } //printf(" x,y %.1f, %.1f\n", x, y); if (lastok) plotstuff_line_to(pargs, x, y); else plotstuff_move_to(pargs, x, y); lastok = TRUE; } return 0; }
int plot_index_plot(const char* command, cairo_t* cairo, plot_args_t* pargs, void* baton) { plotindex_t* args = (plotindex_t*)baton; int i; double ra, dec, radius; double xyz[3]; double r2; pad_qidxes(args); plotstuff_builtin_apply(cairo, pargs); if (plotstuff_get_radec_center_and_radius(pargs, &ra, &dec, &radius)) { ERROR("Failed to get RA,Dec center and radius"); return -1; } radecdeg2xyzarr(ra, dec, xyz); r2 = deg2distsq(radius); logmsg("Field RA,Dec,radius = (%g,%g), %g deg\n", ra, dec, radius); logmsg("distsq: %g\n", r2); for (i=0; i<pl_size(args->indexes); i++) { index_t* index = pl_get(args->indexes, i); int j, N; int DQ; double px,py; if (args->stars) { // plot stars double* radecs = NULL; startree_search_for(index->starkd, xyz, r2, NULL, &radecs, NULL, &N); if (N) { assert(radecs); } logmsg("Found %i stars in range in index %s\n", N, index->indexname); for (j=0; j<N; j++) { logverb(" RA,Dec (%g,%g) -> x,y (%g,%g)\n", radecs[2*j], radecs[2*j+1], px, py); if (!plotstuff_radec2xy(pargs, radecs[j*2], radecs[j*2+1], &px, &py)) { ERROR("Failed to convert RA,Dec %g,%g to pixels\n", radecs[j*2], radecs[j*2+1]); continue; } cairoutils_draw_marker(cairo, pargs->marker, px, py, pargs->markersize); cairo_stroke(cairo); } free(radecs); } if (args->quads) { DQ = index_get_quad_dim(index); qidxfile* qidx = pl_get(args->qidxes, i); if (qidx) { int* stars; int Nstars; il* quadlist = il_new(256); // find stars in range. startree_search_for(index->starkd, xyz, r2, NULL, NULL, &stars, &Nstars); logmsg("Found %i stars in range of index %s\n", N, index->indexname); logmsg("Using qidx file.\n"); // find quads that each star is a member of. for (j=0; j<Nstars; j++) { uint32_t* quads; int Nquads; int k; if (qidxfile_get_quads(qidx, stars[j], &quads, &Nquads)) { ERROR("Failed to get quads for star %i\n", stars[j]); return -1; } for (k=0; k<Nquads; k++) il_insert_unique_ascending(quadlist, quads[k]); } for (j=0; j<il_size(quadlist); j++) { plotquad(cairo, pargs, args, index, il_get(quadlist, j), DQ); } } else { // plot quads N = index_nquads(index); for (j=0; j<N; j++) { plotquad(cairo, pargs, args, index, j, DQ); } } } } return 0; }
void fits_guess_scale_hdr(const qfits_header* hdr, sl** p_methods, dl** p_scales) { sip_t sip; double val; anbool gotsip = FALSE; char* errstr; sl* methods = NULL; dl* scales = NULL; if (p_methods) { if (!*p_methods) *p_methods = sl_new(4); methods = *p_methods; } if (p_scales) { if (!*p_scales) *p_scales = dl_new(4); scales = *p_scales; } memset(&sip, 0, sizeof(sip_t)); errors_start_logging_to_string(); if (sip_read_header(hdr, &sip)) { val = sip_pixel_scale(&sip); if (val != 0.0) { addscale(methods, scales, "sip", val); gotsip = TRUE; } } errstr = errors_stop_logging_to_string("\n "); logverb("fits-guess-scale: failed to read SIP/TAN header:\n %s\n", errstr); free(errstr); if (!gotsip) { // it might have a correct CD matrix but be missing other parts (eg CRVAL) double cd11, cd12, cd21, cd22; double errval = -HUGE_VAL; cd11 = qfits_header_getdouble(hdr, "CD1_1", errval); cd12 = qfits_header_getdouble(hdr, "CD1_2", errval); cd21 = qfits_header_getdouble(hdr, "CD2_1", errval); cd22 = qfits_header_getdouble(hdr, "CD2_2", errval); if ((cd11 != errval) && (cd12 != errval) && (cd21 != errval) && (cd22 != errval)) { val = cd11 * cd22 - cd12 * cd21; if (val != 0.0) addscale(methods, scales, "cd", sqrt(fabs(val))); } } val = qfits_header_getdouble(hdr, "PIXSCALE", -1.0); if (val != -1.0) addscale(methods, scales, "pixscale", val); /* Why all this? val = qfits_header_getdouble(hdr, "PIXSCAL1", -1.0); if (val != -1.0) { if (val != 0.0) { printf("scale pixscal1 %g\n", val); } else { val = atof(qfits_pretty_string(qfits_header_getstr(hdr, "PIXSCAL1"))); if (val != 0.0) { printf("scale pixscal1 %g\n", val); } } } */ val = qfits_header_getdouble(hdr, "PIXSCAL1", 0.0); if (val != 0.0) addscale(methods, scales, "pixscal1", val); val = qfits_header_getdouble(hdr, "PIXSCAL2", 0.0); if (val != 0.0) addscale(methods, scales, "pixscal2", val); val = qfits_header_getdouble(hdr, "PLATESC", 0.0); if (val != 0.0) addscale(methods, scales, "platesc", val); val = qfits_header_getdouble(hdr, "CCDSCALE", 0.0); if (val != 0.0) addscale(methods, scales, "ccdscale", val); val = qfits_header_getdouble(hdr, "CDELT1", 0.0); if (val != 0.0) addscale(methods, scales, "cdelt1", 3600.0 * fabs(val)); }
int main(int argc, char *argv[]) { int argchar; char* progname = argv[0]; sl* infns = sl_new(16); char* outfnpat = NULL; char* racol = "RA"; char* deccol = "DEC"; char* tempdir = "/tmp"; anbool gzip = FALSE; sl* cols = sl_new(16); int loglvl = LOG_MSG; int nside = 1; double margin = 0.0; int NHP; double md; char* backref = NULL; fitstable_t* intable; fitstable_t** outtables; char** myargs; int nmyargs; int i; while ((argchar = getopt (argc, argv, OPTIONS)) != -1) switch (argchar) { case 'b': backref = optarg; break; case 't': tempdir = optarg; break; case 'c': sl_append(cols, optarg); break; case 'g': gzip = TRUE; break; case 'o': outfnpat = optarg; break; case 'r': racol = optarg; break; case 'd': deccol = optarg; break; case 'n': nside = atoi(optarg); break; case 'm': margin = atof(optarg); break; case 'v': loglvl++; break; case '?': fprintf(stderr, "Unknown option `-%c'.\n", optopt); case 'h': printHelp(progname); return 0; default: return -1; } if (sl_size(cols) == 0) { sl_free2(cols); cols = NULL; } nmyargs = argc - optind; myargs = argv + optind; for (i=0; i<nmyargs; i++) sl_append(infns, myargs[i]); if (!sl_size(infns)) { printHelp(progname); printf("Need input filenames!\n"); exit(-1); } log_init(loglvl); fits_use_error_system(); NHP = 12 * nside * nside; logmsg("%i output healpixes\n", NHP); outtables = calloc(NHP, sizeof(fitstable_t*)); assert(outtables); md = deg2dist(margin); /** About the mincaps/maxcaps: These have a center and radius-squared, describing the region inside a small circle on the sphere. The "mincaps" describe the regions that are definitely owned by a single healpix -- ie, more than MARGIN distance from any edge. That is, the mincap is the small circle centered at (0.5, 0.5) in the healpix and with radius = the distance to the closest healpix boundary, MINUS the margin distance. Below, we first check whether a new star is within the "mincap" of any healpix. If so, we stick it in that healpix and continue. Otherwise, we check all the "maxcaps" -- these are the healpixes it could *possibly* be in. We then refine with healpix_within_range_of_xyz. The maxcap distance is the distance to the furthest boundary point, PLUS the margin distance. */ cap_t* mincaps = malloc(NHP * sizeof(cap_t)); cap_t* maxcaps = malloc(NHP * sizeof(cap_t)); for (i=0; i<NHP; i++) { // center double r2; double xyz[3]; double* cxyz; double step = 1e-3; double v; double r2b, r2a; cxyz = mincaps[i].xyz; healpix_to_xyzarr(i, nside, 0.5, 0.5, mincaps[i].xyz); memcpy(maxcaps[i].xyz, cxyz, 3 * sizeof(double)); logverb("Center of HP %i: (%.3f, %.3f, %.3f)\n", i, cxyz[0], cxyz[1], cxyz[2]); // radius-squared: // max is the easy one: max of the four corners (I assume) r2 = 0.0; healpix_to_xyzarr(i, nside, 0.0, 0.0, xyz); logverb(" HP %i corner 1: (%.3f, %.3f, %.3f), distsq %.3f\n", i, xyz[0], xyz[1], xyz[2], distsq(xyz, cxyz, 3)); r2 = MAX(r2, distsq(xyz, cxyz, 3)); healpix_to_xyzarr(i, nside, 1.0, 0.0, xyz); logverb(" HP %i corner 1: (%.3f, %.3f, %.3f), distsq %.3f\n", i, xyz[0], xyz[1], xyz[2], distsq(xyz, cxyz, 3)); r2 = MAX(r2, distsq(xyz, cxyz, 3)); healpix_to_xyzarr(i, nside, 0.0, 1.0, xyz); logverb(" HP %i corner 1: (%.3f, %.3f, %.3f), distsq %.3f\n", i, xyz[0], xyz[1], xyz[2], distsq(xyz, cxyz, 3)); r2 = MAX(r2, distsq(xyz, cxyz, 3)); healpix_to_xyzarr(i, nside, 1.0, 1.0, xyz); logverb(" HP %i corner 1: (%.3f, %.3f, %.3f), distsq %.3f\n", i, xyz[0], xyz[1], xyz[2], distsq(xyz, cxyz, 3)); r2 = MAX(r2, distsq(xyz, cxyz, 3)); logverb(" max distsq: %.3f\n", r2); logverb(" margin dist: %.3f\n", md); maxcaps[i].r2 = square(sqrt(r2) + md); logverb(" max cap distsq: %.3f\n", maxcaps[i].r2); r2a = r2; r2 = 1.0; r2b = 0.0; for (v=0; v<=1.0; v+=step) { healpix_to_xyzarr(i, nside, 0.0, v, xyz); r2 = MIN(r2, distsq(xyz, cxyz, 3)); r2b = MAX(r2b, distsq(xyz, cxyz, 3)); healpix_to_xyzarr(i, nside, 1.0, v, xyz); r2 = MIN(r2, distsq(xyz, cxyz, 3)); r2b = MAX(r2b, distsq(xyz, cxyz, 3)); healpix_to_xyzarr(i, nside, v, 0.0, xyz); r2 = MIN(r2, distsq(xyz, cxyz, 3)); r2b = MAX(r2b, distsq(xyz, cxyz, 3)); healpix_to_xyzarr(i, nside, v, 1.0, xyz); r2 = MIN(r2, distsq(xyz, cxyz, 3)); r2b = MAX(r2b, distsq(xyz, cxyz, 3)); } mincaps[i].r2 = square(MAX(0, sqrt(r2) - md)); logverb("\nhealpix %i: min rad %g\n", i, sqrt(r2)); logverb("healpix %i: max rad %g\n", i, sqrt(r2a)); logverb("healpix %i: max rad(b) %g\n", i, sqrt(r2b)); assert(r2a >= r2b); } if (backref) { fitstable_t* tab = fitstable_open_for_writing(backref); int maxlen = 0; char* buf; for (i=0; i<sl_size(infns); i++) { char* infn = sl_get(infns, i); maxlen = MAX(maxlen, strlen(infn)); } fitstable_add_write_column_array(tab, fitscolumn_char_type(), maxlen, "filename", NULL); fitstable_add_write_column(tab, fitscolumn_i16_type(), "index", NULL); if (fitstable_write_primary_header(tab) || fitstable_write_header(tab)) { ERROR("Failed to write header of backref table \"%s\"", backref); exit(-1); } buf = malloc(maxlen+1); assert(buf); for (i=0; i<sl_size(infns); i++) { char* infn = sl_get(infns, i); int16_t ind; memset(buf, 0, maxlen); strcpy(buf, infn); ind = i; if (fitstable_write_row(tab, buf, &ind)) { ERROR("Failed to write row %i of backref table: %s = %i", i, buf, ind); exit(-1); } } if (fitstable_fix_header(tab) || fitstable_close(tab)) { ERROR("Failed to fix header & close backref table"); exit(-1); } logmsg("Wrote backref table %s\n", backref); free(buf); } for (i=0; i<sl_size(infns); i++) { char* infn = sl_get(infns, i); char* originfn = infn; int r, NR; tfits_type any, dubl; il* hps = NULL; bread_t* rowbuf; int R; char* tempfn = NULL; char* padrowdata = NULL; int ii; logmsg("Reading input \"%s\"...\n", infn); if (gzip) { char* cmd; int rtn; tempfn = create_temp_file("hpsplit", tempdir); asprintf_safe(&cmd, "gunzip -cd %s > %s", infn, tempfn); logmsg("Running: \"%s\"\n", cmd); rtn = run_command_get_outputs(cmd, NULL, NULL); if (rtn) { ERROR("Failed to run command: \"%s\"", cmd); exit(-1); } free(cmd); infn = tempfn; } intable = fitstable_open(infn); if (!intable) { ERROR("Couldn't read catalog %s", infn); exit(-1); } NR = fitstable_nrows(intable); logmsg("Got %i rows\n", NR); any = fitscolumn_any_type(); dubl = fitscolumn_double_type(); fitstable_add_read_column_struct(intable, dubl, 1, 0, any, racol, TRUE); fitstable_add_read_column_struct(intable, dubl, 1, sizeof(double), any, deccol, TRUE); fitstable_use_buffered_reading(intable, 2*sizeof(double), 1000); R = fitstable_row_size(intable); rowbuf = buffered_read_new(R, 1000, NR, refill_rowbuffer, intable); if (fitstable_read_extension(intable, 1)) { ERROR("Failed to find RA and DEC columns (called \"%s\" and \"%s\" in the FITS file)", racol, deccol); exit(-1); } for (r=0; r<NR; r++) { int hp = -1; double ra, dec; int j; double* rd; void* rowdata; void* rdata; if (r && ((r % 100000) == 0)) { logmsg("Reading row %i of %i\n", r, NR); } //printf("reading RA,Dec for row %i\n", r); rd = fitstable_next_struct(intable); ra = rd[0]; dec = rd[1]; logverb("row %i: ra,dec %g,%g\n", r, ra, dec); if (margin == 0) { hp = radecdegtohealpix(ra, dec, nside); logverb(" --> healpix %i\n", hp); } else { double xyz[3]; anbool gotit = FALSE; double d2; if (!hps) hps = il_new(4); radecdeg2xyzarr(ra, dec, xyz); for (j=0; j<NHP; j++) { d2 = distsq(xyz, mincaps[j].xyz, 3); if (d2 <= mincaps[j].r2) { logverb(" -> in mincap %i (dist %g vs %g)\n", j, sqrt(d2), sqrt(mincaps[j].r2)); il_append(hps, j); gotit = TRUE; break; } } if (!gotit) { for (j=0; j<NHP; j++) { d2 = distsq(xyz, maxcaps[j].xyz, 3); if (d2 <= maxcaps[j].r2) { logverb(" -> in maxcap %i (dist %g vs %g)\n", j, sqrt(d2), sqrt(maxcaps[j].r2)); if (healpix_within_range_of_xyz(j, nside, xyz, margin)) { logverb(" -> and within range.\n"); il_append(hps, j); } } } } //hps = healpix_rangesearch_radec(ra, dec, margin, nside, hps); logverb(" --> healpixes: ["); for (j=0; j<il_size(hps); j++) logverb(" %i", il_get(hps, j)); logverb(" ]\n"); } //printf("Reading rowdata for row %i\n", r); rowdata = buffered_read(rowbuf); assert(rowdata); j=0; while (1) { if (hps) { if (j >= il_size(hps)) break; hp = il_get(hps, j); j++; } assert(hp < NHP); assert(hp >= 0); if (!outtables[hp]) { char* outfn; fitstable_t* out; // MEMLEAK the output filename. You'll live. asprintf_safe(&outfn, outfnpat, hp); logmsg("Opening output file \"%s\"...\n", outfn); out = fitstable_open_for_writing(outfn); if (!out) { ERROR("Failed to open output table \"%s\"", outfn); exit(-1); } // Set the output table structure. if (cols) { fitstable_add_fits_columns_as_struct3(intable, out, cols, 0); } else fitstable_add_fits_columns_as_struct2(intable, out); if (backref) { tfits_type i16type; tfits_type i32type; // R = fitstable_row_size(intable); int off = R; i16type = fitscolumn_i16_type(); i32type = fitscolumn_i32_type(); fitstable_add_read_column_struct(out, i16type, 1, off, i16type, "backref_file", TRUE); off += sizeof(int16_t); fitstable_add_read_column_struct(out, i32type, 1, off, i32type, "backref_index", TRUE); } //printf("Output table:\n"); //fitstable_print_columns(out); if (fitstable_write_primary_header(out) || fitstable_write_header(out)) { ERROR("Failed to write output file headers for \"%s\"", outfn); exit(-1); } outtables[hp] = out; } if (backref) { int16_t brfile; int32_t brind; if (!padrowdata) { padrowdata = malloc(R + sizeof(int16_t) + sizeof(int32_t)); assert(padrowdata); } // convert to FITS endian brfile = htons(i); brind = htonl(r); // add backref data to rowdata memcpy(padrowdata, rowdata, R); memcpy(padrowdata + R, &brfile, sizeof(int16_t)); memcpy(padrowdata + R + sizeof(int16_t), &brind, sizeof(int32_t)); rdata = padrowdata; } else { rdata = rowdata; } if (cols) { if (fitstable_write_struct_noflip(outtables[hp], rdata)) { ERROR("Failed to copy a row of data from input table \"%s\" to output healpix %i", infn, hp); } } else { if (fitstable_write_row_data(outtables[hp], rdata)) { ERROR("Failed to copy a row of data from input table \"%s\" to output healpix %i", infn, hp); } } if (!hps) break; } if (hps) il_remove_all(hps); } buffered_read_free(rowbuf); // wack... buffered_read_free() just frees its internal buffer, // not the "rowbuf" struct itself. // who wrote this crazy code? Oh, me of 5 years ago. Jerk. free(rowbuf); fitstable_close(intable); il_free(hps); if (tempfn) { logverb("Removing temp file %s\n", tempfn); if (unlink(tempfn)) { SYSERROR("Failed to unlink() temp file \"%s\"", tempfn); } tempfn = NULL; } // fix headers so that the files are valid at this point. for (ii=0; ii<NHP; ii++) { if (!outtables[ii]) continue; off_t offset = ftello(outtables[ii]->fid); if (fitstable_fix_header(outtables[ii])) { ERROR("Failed to fix header for healpix %i after reading input file \"%s\"", ii, originfn); exit(-1); } fseeko(outtables[ii]->fid, offset, SEEK_SET); } if (padrowdata) { free(padrowdata); padrowdata = NULL; } } for (i=0; i<NHP; i++) { if (!outtables[i]) continue; if (fitstable_fix_header(outtables[i]) || fitstable_fix_primary_header(outtables[i]) || fitstable_close(outtables[i])) { ERROR("Failed to close output table for healpix %i", i); exit(-1); } } free(outtables); sl_free2(infns); sl_free2(cols); free(mincaps); free(maxcaps); return 0; }
int main(int argc, char *argv[]) { int argchar; char* outfn = NULL; char* infn; int overwrite = 0; int loglvl = LOG_MSG; anbool do_u8 = TRUE; int downsample = 0; int downsample_as_reqd = 0; int extension = 0; int plane = 0; simplexy_t sparams; simplexy_t* params = &sparams; memset(params, 0, sizeof(simplexy_t)); while ((argchar = getopt (argc, argv, OPTIONS)) != -1) switch (argchar) { case 'L': params->Lorder = atoi(optarg); break; case 'w': params->dpsf = atof(optarg); break; case 'a': params->saddle = atof(optarg); break; case 'm': params->maxsize = atoi(optarg); break; case 'g': params->sigma = atof(optarg); break; case 'b': params->nobgsub = TRUE; break; case 'G': params->nobgsub = TRUE; params->globalbg = atof(optarg); break; case 'P': plane = atoi(optarg); break; case 's': params->halfbox = atoi(optarg); break; case 'p': params->plim = atof(optarg); break; case 'B': params->bgimgfn = optarg; break; case 'S': params->bgsubimgfn = optarg; break; case 'M': params->maskimgfn = optarg; break; case 'U': params->smoothimgfn = optarg; break; case 'C': params->blobimgfn = optarg; break; case 'e': extension = atoi(optarg); break; case 'D': downsample_as_reqd = atoi(optarg); break; case 'H': downsample = 2; break; case 'd': downsample = atoi(optarg); break; case '8': do_u8 = FALSE; break; case 'v': loglvl++; break; case 'O': overwrite = 1; break; case 'o': outfn = strdup(optarg); break; case '?': case 'h': printHelp(); exit(0); } if (optind != argc - 1) { printHelp(); exit(-1); } infn = argv[optind]; log_init(loglvl); logverb("infile=%s\n", infn); if (!outfn) { // Create xylist filename (by trimming '.fits') asprintf_safe(&outfn, "%.*s.xy.fits", (int)(strlen(infn)-5), infn); logverb("outfile=%s\n", outfn); } if (overwrite && file_exists(outfn)) { logverb("Deleting existing output file \"%s\"...\n", outfn); if (unlink(outfn)) { SYSERROR("Failed to delete existing output file \"%s\"", outfn); exit(-1); } } if (downsample) logverb("Downsampling by %i\n", downsample); if (image2xy_files(infn, outfn, do_u8, downsample, downsample_as_reqd, extension, plane, params)) { ERROR("image2xy failed."); exit(-1); } free(outfn); return 0; }
int main(int argc, char** args) { char* default_configfn = "astrometry.cfg"; char* default_config_path = "../etc"; int c; char* configfn = NULL; int i; engine_t* engine; char* mydir = NULL; char* basedir = NULL; char* me; anbool help = FALSE; sl* strings = sl_new(4); char* cancelfn = NULL; char* solvedfn = NULL; int loglvl = LOG_MSG; anbool tostderr = FALSE; char* infn = NULL; FILE* fin = NULL; anbool fromstdin = FALSE; bl* opts = opts_from_array(myopts, sizeof(myopts)/sizeof(an_option_t), NULL); sl* inds = sl_new(4); char* datalog = NULL; engine = engine_new(); while (1) { c = opts_getopt(opts, argc, args); if (c == -1) break; switch (c) { case 'D': datalog = optarg; break; case 'p': engine->inparallel = TRUE; break; case 'i': sl_append(inds, optarg); break; case 'd': basedir = optarg; break; case 'f': infn = optarg; fromstdin = streq(infn, "-"); break; case 'E': tostderr = TRUE; break; case 'h': help = TRUE; break; case 'v': loglvl++; break; case 's': solvedfn = optarg; case 'C': cancelfn = optarg; break; case 'c': configfn = strdup(optarg); break; case '?': break; default: printf("Unknown flag %c\n", c); exit( -1); } } if (optind == argc && !infn) { // Need extra args: filename printf("You must specify at least one input file!\n\n"); help = TRUE; } if (help) { print_help(args[0], opts); exit(0); } bl_free(opts); gslutils_use_error_system(); log_init(loglvl); if (tostderr) log_to(stderr); if (datalog) { datalogfid = fopen(datalog, "wb"); if (!datalogfid) { SYSERROR("Failed to open data log file \"%s\" for writing", datalog); return -1; } atexit(close_datalogfid); data_log_init(100); data_log_enable_all(); data_log_to(datalogfid); data_log_start(); } if (infn) { logverb("Reading input filenames from %s\n", (fromstdin ? "stdin" : infn)); if (!fromstdin) { fin = fopen(infn, "rb"); if (!fin) { ERROR("Failed to open file %s for reading input filenames", infn); exit(-1); } } else fin = stdin; } // directory containing the 'engine' executable: me = find_executable(args[0], NULL); if (!me) me = strdup(args[0]); mydir = sl_append(strings, dirname(me)); free(me); // Read config file if (!configfn) { int i; sl* trycf = sl_new(4); sl_appendf(trycf, "%s/%s/%s", mydir, default_config_path, default_configfn); // if I'm in /usr/bin, look for config file in /etc if (streq(mydir, "/usr/bin")) { sl_appendf(trycf, "/etc/%s", default_configfn); } sl_appendf(trycf, "%s/%s", mydir, default_configfn); sl_appendf(trycf, "./%s", default_configfn); sl_appendf(trycf, "./%s/%s", default_config_path, default_configfn); for (i=0; i<sl_size(trycf); i++) { char* cf = sl_get(trycf, i); if (file_exists(cf)) { configfn = strdup(cf); logverb("Using config file \"%s\"\n", cf); break; } else { logverb("Config file \"%s\" doesn't exist.\n", cf); } } if (!configfn) { char* cflist = sl_join(trycf, "\n "); logerr("Couldn't find config file: tried:\n %s\n", cflist); free(cflist); } sl_free2(trycf); } if (!streq(configfn, "none")) { if (engine_parse_config_file(engine, configfn)) { logerr("Failed to parse (or encountered an error while interpreting) config file \"%s\"\n", configfn); exit( -1); } } if (sl_size(inds)) { // Expand globs. for (i=0; i<sl_size(inds); i++) { char* s = sl_get(inds, i); glob_t myglob; int flags = GLOB_TILDE | GLOB_BRACE; if (glob(s, flags, NULL, &myglob)) { SYSERROR("Failed to expand wildcards in index-file path \"%s\"", s); exit(-1); } for (c=0; c<myglob.gl_pathc; c++) { if (engine_add_index(engine, myglob.gl_pathv[c])) { ERROR("Failed to add index \"%s\"", myglob.gl_pathv[c]); exit(-1); } } globfree(&myglob); } } if (!pl_size(engine->indexes)) { logerr("\n\n" "---------------------------------------------------------------------\n" "You must list at least one index in the config file (%s)\n\n" "See http://astrometry.net/use.html about how to get some index files.\n" "---------------------------------------------------------------------\n" "\n", configfn); exit(-1); } if (engine->minwidth <= 0.0 || engine->maxwidth <= 0.0) { logerr("\"minwidth\" and \"maxwidth\" in the config file %s must be positive!\n", configfn); exit(-1); } free(configfn); if (!il_size(engine->default_depths)) { parse_depth_string(engine->default_depths, "10 20 30 40 50 60 70 80 90 100 " "110 120 130 140 150 160 170 180 190 200"); } engine->cancelfn = cancelfn; engine->solvedfn = solvedfn; i = optind; while (1) { char* jobfn; job_t* job; struct timeval tv1, tv2; if (infn) { // Read name of next input file to be read. logverb("\nWaiting for next input filename...\n"); jobfn = read_string_terminated(fin, "\n\r\0", 3, FALSE); if (strlen(jobfn) == 0) break; } else { if (i == argc) break; jobfn = args[i]; i++; } gettimeofday(&tv1, NULL); logmsg("Reading file \"%s\"...\n", jobfn); job = engine_read_job_file(engine, jobfn); if (!job) { ERROR("Failed to read job file \"%s\"", jobfn); exit(-1); } if (basedir) { logverb("Setting job's output base directory to %s\n", basedir); job_set_output_base_dir(job, basedir); } if (engine_run_job(engine, job)) logerr("Failed to run_job()\n"); job_free(job); gettimeofday(&tv2, NULL); logverb("Spent %g seconds on this field.\n", millis_between(&tv1, &tv2)/1000.0); } engine_free(engine); sl_free2(strings); sl_free2(inds); if (fin && !fromstdin) fclose(fin); return 0; }
int wcs_xy2rd(const char* wcsfn, int ext, const char* xylsfn, const char* rdlsfn, const char* xcol, const char* ycol, int forcetan, int forcewcslib, il* fields) { rdlist_t* rdls = NULL; xylist_t* xyls = NULL; anwcs_t* wcs = NULL; int i; int rtn = -1; anbool alloced_fields = FALSE; // read WCS. if (forcewcslib) { wcs = anwcs_open_wcslib(wcsfn, ext); } else if (forcetan) { wcs = anwcs_open_tan(wcsfn, ext); } else { wcs = anwcs_open(wcsfn, ext); } if (!wcs) { ERROR("Failed to read WCS file \"%s\", extension %i", wcsfn, ext); return -1; } // read XYLS. xyls = xylist_open(xylsfn); if (!xyls) { ERROR("Failed to read an xylist from file %s", xylsfn); goto bailout; } xylist_set_include_flux(xyls, FALSE); xylist_set_include_background(xyls, FALSE); if (xcol) xylist_set_xname(xyls, xcol); if (ycol) xylist_set_yname(xyls, ycol); // write RDLS. rdls = rdlist_open_for_writing(rdlsfn); if (!rdls) { ERROR("Failed to open file %s to write RDLS.\n", rdlsfn); goto bailout; } if (rdlist_write_primary_header(rdls)) { ERROR("Failed to write header to RDLS file %s.\n", rdlsfn); goto bailout; } if (!fields) { alloced_fields = TRUE; fields = il_new(16); } if (!il_size(fields)) { // add all fields. int NF = xylist_n_fields(xyls); for (i=1; i<=NF; i++) il_append(fields, i); } logverb("Processing %zu extensions...\n", il_size(fields)); for (i=0; i<il_size(fields); i++) { int fieldind = il_get(fields, i); starxy_t xy; rd_t rd; int j; if (!xylist_read_field_num(xyls, fieldind, &xy)) { ERROR("Failed to read xyls file %s, field %i", xylsfn, fieldind); goto bailout; } if (rdlist_write_header(rdls)) { ERROR("Failed to write rdls field header to %s", rdlsfn); goto bailout; } rd_alloc_data(&rd, starxy_n(&xy)); for (j=0; j<starxy_n(&xy); j++) { double x, y, ra, dec; x = starxy_getx(&xy, j); y = starxy_gety(&xy, j); anwcs_pixelxy2radec(wcs, x, y, &ra, &dec); rd_setra (&rd, j, ra); rd_setdec(&rd, j, dec); } if (rdlist_write_field(rdls, &rd)) { ERROR("Failed to write rdls field to %s", rdlsfn); goto bailout; } rd_free_data(&rd); starxy_free_data(&xy); if (rdlist_fix_header(rdls)) { ERROR("Failed to fix rdls field header for %s", rdlsfn); goto bailout; } rdlist_next_field(rdls); } if (rdlist_fix_primary_header(rdls) || rdlist_close(rdls)) { ERROR("Failed to fix header of RDLS file %s", rdlsfn); goto bailout; } rdls = NULL; if (xylist_close(xyls)) { ERROR("Failed to close XYLS file %s", xylsfn); goto bailout; } xyls = NULL; rtn = 0; bailout: if (alloced_fields) il_free(fields); if (rdls) rdlist_close(rdls); if (xyls) xylist_close(xyls); if (wcs) anwcs_free(wcs); return rtn; }
int fit_sip_wcs(const double* starxyz, const double* fieldxy, const double* weights, int M, const tan_t* tanin1, int sip_order, int inv_order, sip_t* sipout) { int sip_coeffs; double xyzcrval[3]; double cdinv[2][2]; double sx, sy, sU, sV, su, sv; int N; int i, j, p, q, order; double totalweight; int rtn; gsl_matrix *mA; gsl_vector *b1, *b2, *x1, *x2; gsl_vector *r1=NULL, *r2=NULL; tan_t tanin2; int ngood; const tan_t* tanin = &tanin2; // We need at least the linear terms to compute CD. if (sip_order < 1) sip_order = 1; // convenience: allow the user to call like: // fit_sip_wcs(... &(sipout.wcstan), ..., sipout); memcpy(&tanin2, tanin1, sizeof(tan_t)); memset(sipout, 0, sizeof(sip_t)); memcpy(&(sipout->wcstan), tanin, sizeof(tan_t)); sipout->a_order = sipout->b_order = sip_order; sipout->ap_order = sipout->bp_order = inv_order; // The SIP coefficients form an (order x order) upper triangular // matrix missing the 0,0 element. sip_coeffs = (sip_order + 1) * (sip_order + 2) / 2; N = sip_coeffs; if (M < N) { ERROR("Too few correspondences for the SIP order specified (%i < %i)\n", M, N); return -1; } mA = gsl_matrix_alloc(M, N); b1 = gsl_vector_alloc(M); b2 = gsl_vector_alloc(M); assert(mA); assert(b1); assert(b2); /* * We use a clever trick to estimate CD, A, and B terms in two * seperated least squares fits, then finding A and B by multiplying * the found parameters by CD inverse. * * Rearranging the SIP equations (see sip.h) we get the following * matrix operation to compute x and y in world intermediate * coordinates, which is convienently written in a way which allows * least squares estimation of CD and terms related to A and B. * * First use the x's to find the first set of parametetrs * * +--------------------- Intermediate world coordinates in DEGREES * | +--------- Pixel coordinates u and v in PIXELS * | | +--- Polynomial u,v terms in powers of PIXELS * v v v * ( x1 ) ( 1 u1 v1 p1 ) (sx ) * ( x2 ) = ( 1 u2 v2 p2 ) * (cd11 ) : * ( x3 ) ( 1 u3 v3 p3 ) (cd12 ) : * ( ...) ( ... ) (cd11*A + cd12*B ) : * cd11 is a scalar, degrees per pixel * cd12 is a scalar, degrees per pixel * cd11*A and cs12*B are mixture of SIP terms (A,B) and CD matrix * (cd11,cd12) * * Then find cd21 and cd22 with the y's * * ( y1 ) ( 1 u1 v1 p1 ) (sy ) * ( y2 ) = ( 1 u2 v2 p2 ) * (cd21 ) : * ( y3 ) ( 1 u3 v3 p3 ) (cd22 ) : * ( ...) ( ... ) (cd21*A + cd22*B ) : (Y4) * y2: scalar, degrees per pixel * y3: scalar, degrees per pixel * Y4: mixture of SIP terms (A,B) and CD matrix (cd21,cd22) * * These are both standard least squares problems which we solve with * QR decomposition, ie * min_{cd,A,B} || x - [1,u,v,p]*[s;cd;cdA+cdB]||^2 with * x reference, cd,A,B unrolled parameters. * * We get back (for x) a vector of optimal * [sx;cd11;cd12; cd11*A + cd12*B] * Now we can pull out sx, cd11 and cd12 from the beginning of this vector, * and call the rest of the vector [cd11*A] + [cd12*B]; * similarly for the y fit, we get back a vector of optimal * [sy;cd21;cd22; cd21*A + cd22*B] * once we have all those we can figure out A and B as follows * -1 * A' = [cd11 cd12] * [cd11*A' + cd12*B'] * B' [cd21 cd22] [cd21*A' + cd22*B'] * * which recovers the A and B's. * */ /* * Dustin's interpretation of the above: * We want to solve: * * min || b[M-by-1] - A[M-by-N] x[N-by-1] ||_2 * * M = the number of correspondences. * N = the number of SIP terms. * * And we want an overdetermined system, so M >= N. * * [ 1 u_1 v_1 u_1^2 u_1 v_1 v_1^2 ... ] * mA = [ 1 u_2 v_2 u_2^2 u_2 v_2 v_2^2 ... ] * [ ...... ] * * Where (u_i, v_i) are *undistorted* pixel positions minus CRPIX. * * The answers we want are: * * [ sx ] * x1 = [ cd11 ] * [ cd12 ] * [ (A) (B) ] * [ cd11*(A) + cd12*(B) ] * [ (A) (B) ] * * [ sy ] * x2 = [ cd21 ] * [ cd22 ] * [ (A) (B) ] * [ cd21*(A) + cd22*(B) ] * [ (A) (B) ] * * And the target vectors are the intermediate world coords of the * reference stars, in degrees. * * [ ix_1 ] * b1 = [ ix_2 ] * [ ... ] * * [ iy_1 ] * b2 = [ iy_2 ] * [ ... ] * * * (where A and B are tall vectors of SIP coefficients of order 2 * and above) * */ // Fill in matrix mA: radecdeg2xyzarr(tanin->crval[0], tanin->crval[1], xyzcrval); totalweight = 0.0; ngood = 0; for (i=0; i<M; i++) { double x=0, y=0; double weight = 1.0; double u; double v; Unused anbool ok; u = fieldxy[2*i + 0] - tanin->crpix[0]; v = fieldxy[2*i + 1] - tanin->crpix[1]; // B contains Intermediate World Coordinates (in degrees) // tangent-plane projection ok = star_coords(starxyz + 3*i, xyzcrval, TRUE, &x, &y); if (!ok) { logverb("Skipping star that cannot be projected to tangent plane\n"); continue; } gsl_vector_set(b1, ngood, weight * rad2deg(x)); gsl_vector_set(b2, ngood, weight * rad2deg(y)); if (weights) { weight = weights[i]; assert(weight >= 0.0); assert(weight <= 1.0); totalweight += weight; if (weight == 0.0) continue; } /* The coefficients are stored in this order: * p q * (0,0) = 1 <- order 0 * (1,0) = u <- order 1 * (0,1) = v * (2,0) = u^2 <- order 2 * (1,1) = uv * (0,2) = v^2 * ... */ j = 0; for (order=0; order<=sip_order; order++) { for (q=0; q<=order; q++) { p = order - q; assert(j >= 0); assert(j < N); assert(p >= 0); assert(q >= 0); assert(p + q <= sip_order); gsl_matrix_set(mA, ngood, j, weight * pow(u, (double)p) * pow(v, (double)q)); j++; } } assert(j == N); // The shift - aka (0,0) - SIP coefficient must be 1. assert(gsl_matrix_get(mA, i, 0) == 1.0 * weight); assert(fabs(gsl_matrix_get(mA, i, 1) - u * weight) < 1e-12); assert(fabs(gsl_matrix_get(mA, i, 2) - v * weight) < 1e-12); ngood++; } if (ngood == 0) { ERROR("No stars projected within the image\n"); return -1; } if (weights) logverb("Total weight: %g\n", totalweight); if (ngood < M) { _gsl_vector_view sub_b1 = gsl_vector_subvector(b1, 0, ngood); _gsl_vector_view sub_b2 = gsl_vector_subvector(b2, 0, ngood); _gsl_matrix_view sub_mA = gsl_matrix_submatrix(mA, 0, 0, ngood, N); rtn = gslutils_solve_leastsquares_v(&(sub_mA.matrix), 2, &(sub_b1.vector), &x1, NULL, &(sub_b2.vector), &x2, NULL); } else { // Solve the equation. rtn = gslutils_solve_leastsquares_v(mA, 2, b1, &x1, NULL, b2, &x2, NULL); } if (rtn) { ERROR("Failed to solve SIP matrix equation!"); return -1; } // Row 0 of X are the shift (p=0, q=0) terms. // Row 1 of X are the terms that multiply "u". // Row 2 of X are the terms that multiply "v". // Grab CD. sipout->wcstan.cd[0][0] = gsl_vector_get(x1, 1); sipout->wcstan.cd[0][1] = gsl_vector_get(x1, 2); sipout->wcstan.cd[1][0] = gsl_vector_get(x2, 1); sipout->wcstan.cd[1][1] = gsl_vector_get(x2, 2); // Compute inv(CD) i = invert_2by2_arr((const double*)(sipout->wcstan.cd), (double*)cdinv); assert(i == 0); // Grab the shift. sx = gsl_vector_get(x1, 0); sy = gsl_vector_get(x2, 0); // Extract the SIP coefficients. // (this includes the 0 and 1 order terms, which we later overwrite) j = 0; for (order=0; order<=sip_order; order++) { for (q=0; q<=order; q++) { p = order - q; assert(j >= 0); assert(j < N); assert(p >= 0); assert(q >= 0); assert(p + q <= sip_order); sipout->a[p][q] = cdinv[0][0] * gsl_vector_get(x1, j) + cdinv[0][1] * gsl_vector_get(x2, j); sipout->b[p][q] = cdinv[1][0] * gsl_vector_get(x1, j) + cdinv[1][1] * gsl_vector_get(x2, j); j++; } } assert(j == N); // We have already dealt with the shift and linear terms, so zero them out // in the SIP coefficient matrix. sipout->a[0][0] = 0.0; sipout->a[0][1] = 0.0; sipout->a[1][0] = 0.0; sipout->b[0][0] = 0.0; sipout->b[0][1] = 0.0; sipout->b[1][0] = 0.0; sip_compute_inverse_polynomials(sipout, 0, 0, 0, 0, 0, 0); sU = cdinv[0][0] * sx + cdinv[0][1] * sy; sV = cdinv[1][0] * sx + cdinv[1][1] * sy; logverb("Applying shift of sx,sy = %g,%g deg (%g,%g pix) to CRVAL and CD.\n", sx, sy, sU, sV); sip_calc_inv_distortion(sipout, sU, sV, &su, &sv); debug("sx = %g, sy = %g\n", sx, sy); debug("sU = %g, sV = %g\n", sU, sV); debug("su = %g, sv = %g\n", su, sv); wcs_shift(&(sipout->wcstan), -su, -sv); if (r1) gsl_vector_free(r1); if (r2) gsl_vector_free(r2); gsl_matrix_free(mA); gsl_vector_free(b1); gsl_vector_free(b2); gsl_vector_free(x1); gsl_vector_free(x2); return 0; }
int plot_healpix_plot(const char* command, cairo_t* cairo, plot_args_t* pargs, void* baton) { plothealpix_t* args = (plothealpix_t*)baton; double ra,dec,rad; il* hps; int i; double hpstep; int minx[12], maxx[12], miny[12], maxy[12]; plotstuff_builtin_apply(cairo, pargs); if (plotstuff_get_radec_center_and_radius(pargs, &ra, &dec, &rad)) { ERROR("Failed to get RA,Dec center and radius"); return -1; } hps = healpix_rangesearch_radec(ra, dec, rad, args->nside, NULL); logmsg("Found %zu healpixes in range.\n", il_size(hps)); hpstep = args->nside * args->stepsize * plotstuff_pixel_scale(pargs) / 60.0 / healpix_side_length_arcmin(args->nside); hpstep = MIN(1, hpstep); logmsg("Taking steps of %g in healpix space\n", hpstep); // For each of the 12 top-level healpixes, find the range of healpixes covered by this image. for (i=0; i<12; i++) { maxx[i] = maxy[i] = -1; minx[i] = miny[i] = args->nside+1; } for (i=0; i<il_size(hps); i++) { int hp = il_get(hps, i); int hpx, hpy; int bighp; healpix_decompose_xy(hp, &bighp, &hpx, &hpy, args->nside); logverb(" hp %i: bighp %i, x,y (%i,%i)\n", i, bighp, hpx, hpy); minx[bighp] = MIN(minx[bighp], hpx); maxx[bighp] = MAX(maxx[bighp], hpx); miny[bighp] = MIN(miny[bighp], hpy); maxy[bighp] = MAX(maxy[bighp], hpy); } il_free(hps); for (i=0; i<12; i++) { int hx,hy; int hp; double d, frac; double x,y; if (maxx[i] == -1) continue; logverb("Big healpix %i: x range [%i, %i], y range [%i, %i]\n", i, minx[i], maxx[i], miny[i], maxy[i]); for (hy = miny[i]; hy <= maxy[i]; hy++) { logverb(" y=%i\n", hy); for (d=minx[i]; d<=maxx[i]; d+=hpstep) { hx = floor(d); frac = d - hx; hp = healpix_compose_xy(i, hx, hy, args->nside); healpix_to_radecdeg(hp, args->nside, frac, 0.0, &ra, &dec); if (!plotstuff_radec2xy(pargs, ra, dec, &x, &y)) continue; if (d == minx[i]) cairo_move_to(pargs->cairo, x, y); else cairo_line_to(pargs->cairo, x, y); } cairo_stroke(pargs->cairo); } for (hx = minx[i]; hx <= maxx[i]; hx++) { for (d=miny[i]; d<=maxy[i]; d+=hpstep) { hy = floor(d); frac = d - hy; hp = healpix_compose_xy(i, hx, hy, args->nside); healpix_to_radecdeg(hp, args->nside, 0.0, frac, &ra, &dec); if (!plotstuff_radec2xy(pargs, ra, dec, &x, &y)) continue; if (d == miny[i]) cairo_move_to(pargs->cairo, x, y); else cairo_line_to(pargs->cairo, x, y); } cairo_stroke(pargs->cairo); } } return 0; }
int main(int argc, char** args) { int c; char* wcsfn = NULL; char* outfn = NULL; char* infn = NULL; sip_t sip; double scale = 1.0; anbool pngformat = TRUE; char* hdpath = NULL; anbool HD = FALSE; cairos_t thecairos; cairos_t* cairos = &thecairos; cairo_surface_t* target = NULL; cairo_t* cairot = NULL; cairo_surface_t* surfbg = NULL; cairo_t* cairobg = NULL; cairo_surface_t* surfshapes = NULL; cairo_t* cairoshapes = NULL; cairo_surface_t* surfshapesmask = NULL; cairo_t* cairoshapesmask = NULL; cairo_surface_t* surffg = NULL; cairo_t* cairo = NULL; double lw = 2.0; // circle linewidth. double cw = 2.0; double ngc_fraction = 0.02; // NGC linewidth double nw = 2.0; // leave a gap short of connecting the points. double endgap = 5.0; // circle radius. double crad = endgap; double fontsize = 14.0; double label_offset = 15.0; int W = 0, H = 0; unsigned char* img = NULL; anbool NGC = FALSE, constell = FALSE; anbool bright = FALSE; anbool common_only = FALSE; anbool print_common_only = FALSE; int Nbright = 0; double ra, dec, px, py; int i, N; anbool justlist = FALSE; anbool only_messier = FALSE; anbool grid = FALSE; double gridspacing = 0.0; double gridcolor[3] = { 0.2, 0.2, 0.2 }; int loglvl = LOG_MSG; char halign = 'L'; char valign = 'C'; sl* json = NULL; anbool whitetext = FALSE; while ((c = getopt(argc, args, OPTIONS)) != -1) { switch (c) { case 'V': valign = optarg[0]; break; case 'O': halign = optarg[0]; break; case 'F': ngc_fraction = atof(optarg); break; case 'h': print_help(args[0]); exit(0); case 'J': json = sl_new(4); break; case 'G': gridspacing = atof(optarg); break; case 'g': { char *tail = NULL; gridcolor[0] = strtod(optarg,&tail); if (*tail) { tail++; gridcolor[1] = strtod(tail,&tail); } if (*tail) { tail++; gridcolor[2] = strtod(tail,&tail); } } break; case 'D': HD = TRUE; break; case 'd': hdpath = optarg; break; case 'M': only_messier = TRUE; break; case 'n': nw = atof(optarg); break; case 'f': fontsize = atof(optarg); break; case 'L': justlist = TRUE; outfn = NULL; break; case 'x': whitetext = TRUE; break; case 'v': loglvl++; break; break; case 'j': print_common_only = TRUE; break; case 'c': common_only = TRUE; break; case 'b': Nbright = atoi(optarg); break; case 'B': bright = TRUE; break; case 'N': NGC = TRUE; break; case 'C': constell = TRUE; break; case 'p': pngformat = FALSE; break; case 's': scale = atof(optarg); break; case 'o': outfn = optarg; break; case 'i': infn = optarg; break; case 'w': wcsfn = optarg; break; case 'W': W = atoi(optarg); break; case 'H': H = atoi(optarg); break; } } log_init(loglvl); log_to(stderr); fits_use_error_system(); if (optind != argc) { print_help(args[0]); exit(-1); } if (!(outfn || justlist) || !wcsfn) { logerr("Need (-o or -L) and -w args.\n"); print_help(args[0]); exit(-1); } // read WCS. logverb("Trying to parse SIP/TAN header from %s...\n", wcsfn); if (!file_exists(wcsfn)) { ERROR("No such file: \"%s\"", wcsfn); exit(-1); } if (sip_read_header_file(wcsfn, &sip)) { logverb("Got SIP header.\n"); } else { ERROR("Failed to parse SIP/TAN header from %s", wcsfn); exit(-1); } if (!(NGC || constell || bright || HD || grid)) { logerr("Neither constellations, bright stars, HD nor NGC/IC overlays selected!\n"); print_help(args[0]); exit(-1); } if (gridspacing > 0.0) grid = TRUE; // adjust for scaling... lw /= scale; cw /= scale; nw /= scale; crad /= scale; endgap /= scale; fontsize /= scale; label_offset /= scale; if (!W || !H) { W = sip.wcstan.imagew; H = sip.wcstan.imageh; } if (!(infn || (W && H))) { logerr("Image width/height unspecified, and no input image given.\n"); exit(-1); } if (infn) { cairoutils_fake_ppm_init(); img = cairoutils_read_ppm(infn, &W, &H); if (!img) { ERROR("Failed to read input image %s", infn); exit(-1); } cairoutils_rgba_to_argb32(img, W, H); } else if (!justlist) { // Allocate a black image. img = calloc(4 * W * H, 1); if (!img) { SYSERROR("Failed to allocate a blank image on which to plot!"); exit(-1); } } if (HD && !hdpath) { logerr("If you specify -D (plot Henry Draper objs), you also have to give -d (path to Henry Draper catalog)\n"); exit(-1); } if (!justlist) { /* Cairo layers: -background: surfbg / cairobg --> gets drawn first, in black, masked by surfshapesmask -shapes: surfshapes / cairoshapes --> gets drawn second, masked by surfshapesmask -foreground/text: surffg / cairo --> gets drawn last. */ surffg = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, W, H); cairo = cairo_create(surffg); cairo_set_line_join(cairo, CAIRO_LINE_JOIN_BEVEL); cairo_set_antialias(cairo, CAIRO_ANTIALIAS_GRAY); cairo_set_source_rgba(cairo, 1.0, 1.0, 1.0, 1.0); cairo_scale(cairo, scale, scale); //cairo_select_font_face(cairo, "helvetica", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); cairo_select_font_face(cairo, "DejaVu Sans Mono Book", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); cairo_set_font_size(cairo, fontsize); surfshapes = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, W, H); cairoshapes = cairo_create(surfshapes); cairo_set_line_join(cairoshapes, CAIRO_LINE_JOIN_BEVEL); cairo_set_antialias(cairoshapes, CAIRO_ANTIALIAS_GRAY); cairo_set_source_rgba(cairoshapes, 1.0, 1.0, 1.0, 1.0); cairo_scale(cairoshapes, scale, scale); cairo_select_font_face(cairoshapes, "DejaVu Sans Mono Book", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); cairo_set_font_size(cairoshapes, fontsize); surfshapesmask = cairo_image_surface_create(CAIRO_FORMAT_A8, W, H); cairoshapesmask = cairo_create(surfshapesmask); cairo_set_line_join(cairoshapesmask, CAIRO_LINE_JOIN_BEVEL); cairo_set_antialias(cairoshapesmask, CAIRO_ANTIALIAS_GRAY); cairo_set_source_rgba(cairoshapesmask, 1.0, 1.0, 1.0, 1.0); cairo_scale(cairoshapesmask, scale, scale); cairo_select_font_face(cairoshapesmask, "DejaVu Sans Mono Book", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); cairo_set_font_size(cairoshapesmask, fontsize); cairo_paint(cairoshapesmask); cairo_stroke(cairoshapesmask); surfbg = cairo_image_surface_create(CAIRO_FORMAT_A8, W, H); cairobg = cairo_create(surfbg); cairo_set_line_join(cairobg, CAIRO_LINE_JOIN_BEVEL); cairo_set_antialias(cairobg, CAIRO_ANTIALIAS_GRAY); cairo_set_source_rgba(cairobg, 0, 0, 0, 1); cairo_scale(cairobg, scale, scale); cairo_select_font_face(cairobg, "DejaVu Sans Mono Book", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); cairo_set_font_size(cairobg, fontsize); cairos->bg = cairobg; cairos->fg = cairo; cairos->shapes = cairoshapes; cairos->shapesmask = cairoshapesmask; cairos->imgW = (float)W/scale; cairos->imgH = (float)H/scale; // } if (grid) { double ramin, ramax, decmin, decmax; double ra, dec; double rastep = gridspacing / 60.0; double decstep = gridspacing / 60.0; // how many line segments int N = 10; double px, py; int i; cairo_set_source_rgba(cairo, gridcolor[0], gridcolor[1], gridcolor[2], 1.0); sip_get_radec_bounds(&sip, 100, &ramin, &ramax, &decmin, &decmax); logverb("Plotting grid lines from RA=%g to %g in steps of %g; Dec=%g to %g in steps of %g\n", ramin, ramax, rastep, decmin, decmax, decstep); for (dec = decstep * floor(decmin / decstep); dec<=decmax; dec+=decstep) { logverb(" dec=%g\n", dec); for (i=0; i<=N; i++) { ra = ramin + ((double)i / (double)N) * (ramax - ramin); if (!sip_radec2pixelxy(&sip, ra, dec, &px, &py)) continue; // first time, move_to; else line_to ((ra == ramin) ? cairo_move_to : cairo_line_to)(cairo, px, py); } cairo_stroke(cairo); } for (ra = rastep * floor(ramin / rastep); ra <= ramax; ra += rastep) { //for (dec=decmin; dec<=decmax; dec += (decmax - decmin)/(double)N) { logverb(" ra=%g\n", ra); for (i=0; i<=N; i++) { dec = decmin + ((double)i / (double)N) * (decmax - decmin); if (!sip_radec2pixelxy(&sip, ra, dec, &px, &py)) continue; // first time, move_to; else line_to ((dec == decmin) ? cairo_move_to : cairo_line_to)(cairo, px, py); } cairo_stroke(cairo); } cairo_set_source_rgba(cairo, 1.0, 1.0, 1.0, 1.0); } } if (constell) { N = constellations_n(); logverb("Checking %i constellations.\n", N); for (c=0; c<N; c++) { const char* shortname = NULL; const char* longname; il* lines; il* uniqstars; il* inboundstars; float r,g,b; int Ninbounds; int Nunique; cairo_text_extents_t textents; double cmass[3]; uniqstars = constellations_get_unique_stars(c); inboundstars = il_new(16); Nunique = il_size(uniqstars); debug("%s: %zu unique stars.\n", shortname, il_size(uniqstars)); // Count the number of unique stars belonging to this contellation // that are within the image bounds Ninbounds = 0; for (i=0; i<il_size(uniqstars); i++) { int star; star = il_get(uniqstars, i); constellations_get_star_radec(star, &ra, &dec); debug("star %i: ra,dec (%g,%g)\n", il_get(uniqstars, i), ra, dec); if (!sip_radec2pixelxy(&sip, ra, dec, &px, &py)) continue; if (px < 0 || py < 0 || px*scale > W || py*scale > H) continue; Ninbounds++; il_append(inboundstars, star); } il_free(uniqstars); debug("%i are in-bounds.\n", Ninbounds); // Only draw this constellation if at least 2 of its stars // are within the image bounds. if (Ninbounds < 2) { il_free(inboundstars); continue; } // Set the color based on the location of the first in-bounds star. // This is a hack -- we have two different constellation // definitions with different numbering schemes! if (!justlist && (il_size(inboundstars) > 0)) { // This is helpful for videos: ensuring that the same // color is chosen for a constellation in each frame. int star = il_get(inboundstars, 0); constellations_get_star_radec(star, &ra, &dec); if (whitetext) { r = g = b = 1; } else { color_for_radec(ra, dec, &r, &g, &b); } cairo_set_source_rgba(cairoshapes, r,g,b,0.8); cairo_set_line_width(cairoshapes, cw); cairo_set_source_rgba(cairo, r,g,b,0.8); cairo_set_line_width(cairo, cw); } // Draw circles around each star. // Find center of mass (of the in-bounds stars) cmass[0] = cmass[1] = cmass[2] = 0.0; for (i=0; i<il_size(inboundstars); i++) { double xyz[3]; int star = il_get(inboundstars, i); constellations_get_star_radec(star, &ra, &dec); if (!sip_radec2pixelxy(&sip, ra, dec, &px, &py)) continue; if (px < 0 || py < 0 || px*scale > W || py*scale > H) continue; if (!justlist) { cairo_arc(cairobg, px, py, crad+1.0, 0.0, 2.0*M_PI); cairo_stroke(cairobg); cairo_arc(cairoshapes, px, py, crad, 0.0, 2.0*M_PI); cairo_stroke(cairoshapes); } radecdeg2xyzarr(ra, dec, xyz); cmass[0] += xyz[0]; cmass[1] += xyz[1]; cmass[2] += xyz[2]; } cmass[0] /= il_size(inboundstars); cmass[1] /= il_size(inboundstars); cmass[2] /= il_size(inboundstars); xyzarr2radecdeg(cmass, &ra, &dec); il_free(inboundstars); if (!sip_radec2pixelxy(&sip, ra, dec, &px, &py)) continue; shortname = constellations_get_shortname(c); longname = constellations_get_longname(c); assert(shortname && longname); logverb("%s at (%g, %g)\n", longname, px, py); if (Ninbounds == Nunique) { printf("The constellation %s (%s)\n", longname, shortname); } else { printf("Part of the constellation %s (%s)\n", longname, shortname); } if (justlist) continue; // If the label will be off-screen, move it back on. cairo_text_extents(cairo, shortname, &textents); if (px < 0) px = 0; if (py < textents.height) py = textents.height; if ((px + textents.width)*scale > W) px = W/scale - textents.width; if ((py+textents.height)*scale > H) py = H/scale - textents.height; logverb("%s at (%g, %g)\n", shortname, px, py); add_text(cairos, longname, px, py, halign, valign); // Draw the lines. cairo_set_line_width(cairo, lw); lines = constellations_get_lines(c); for (i=0; i<il_size(lines)/2; i++) { int star1, star2; double ra1, dec1, ra2, dec2; double px1, px2, py1, py2; double dx, dy; double dist; double gapfrac; star1 = il_get(lines, i*2+0); star2 = il_get(lines, i*2+1); constellations_get_star_radec(star1, &ra1, &dec1); constellations_get_star_radec(star2, &ra2, &dec2); if (!sip_radec2pixelxy(&sip, ra1, dec1, &px1, &py1) || !sip_radec2pixelxy(&sip, ra2, dec2, &px2, &py2)) continue; dx = px2 - px1; dy = py2 - py1; dist = hypot(dx, dy); gapfrac = endgap / dist; cairo_move_to(cairoshapes, px1 + dx*gapfrac, py1 + dy*gapfrac); cairo_line_to(cairoshapes, px1 + dx*(1.0-gapfrac), py1 + dy*(1.0-gapfrac)); cairo_stroke(cairoshapes); } il_free(lines); } logverb("done constellations.\n"); } if (bright) { double dy = 0; cairo_font_extents_t extents; pl* brightstars = pl_new(16); if (!justlist) { cairo_set_source_rgba(cairoshapes, 0.75, 0.75, 0.75, 0.8); cairo_font_extents(cairo, &extents); dy = extents.ascent * 0.5; cairo_set_line_width(cairoshapes, cw); } N = bright_stars_n(); logverb("Checking %i bright stars.\n", N); for (i=0; i<N; i++) { const brightstar_t* bs = bright_stars_get(i); if (!sip_radec2pixelxy(&sip, bs->ra, bs->dec, &px, &py)) continue; if (px < 0 || py < 0 || px*scale > W || py*scale > H) continue; if (!(bs->name && strlen(bs->name))) continue; if (common_only && !(bs->common_name && strlen(bs->common_name))) continue; if (strcmp(bs->common_name, "Maia") == 0) continue; pl_append(brightstars, bs); } // keep only the Nbright brightest? if (Nbright && (pl_size(brightstars) > Nbright)) { pl_sort(brightstars, sort_by_mag); pl_remove_index_range(brightstars, Nbright, pl_size(brightstars)-Nbright); } for (i=0; i<pl_size(brightstars); i++) { char* text; const brightstar_t* bs = pl_get(brightstars, i); if (!sip_radec2pixelxy(&sip, bs->ra, bs->dec, &px, &py)) continue; if (bs->common_name && strlen(bs->common_name)) if (print_common_only || common_only) text = strdup(bs->common_name); else asprintf_safe(&text, "%s (%s)", bs->common_name, bs->name); else text = strdup(bs->name); logverb("%s at (%g, %g)\n", text, px, py); if (json) { sl* names = sl_new(4); char* namearr; if (bs->common_name && strlen(bs->common_name)) sl_append(names, bs->common_name); if (bs->name) sl_append(names, bs->name); namearr = sl_join(names, "\", \""); sl_appendf(json, "{ \"type\" : \"star\", " " \"pixelx\": %g, " " \"pixely\": %g, " " \"name\" : \"%s\", " " \"names\" : [ \"%s\" ] } " , px, py, (bs->common_name && strlen(bs->common_name)) ? bs->common_name : bs->name, namearr); free(namearr); sl_free2(names); } if (bs->common_name && strlen(bs->common_name)) printf("The star %s (%s)\n", bs->common_name, bs->name); else printf("The star %s\n", bs->name); if (!justlist) { float r,g,b; // set color based on RA,Dec to match constellations above. if (whitetext) { r = g = b = 1; } else { color_for_radec(bs->ra, bs->dec, &r, &g, &b); } cairo_set_source_rgba(cairoshapes, r,g,b,0.8); cairo_set_source_rgba(cairo, r,g,b, 0.8); } if (!justlist) add_text(cairos, text, px + label_offset, py + dy, halign, valign); free(text); if (!justlist) { // plot a black circle behind the light circle... cairo_arc(cairobg, px, py, crad+1.0, 0.0, 2.0*M_PI); cairo_stroke(cairobg); cairo_arc(cairoshapes, px, py, crad, 0.0, 2.0*M_PI); cairo_stroke(cairoshapes); } } pl_free(brightstars); } if (NGC) { double imscale; double imsize; double dy = 0; cairo_font_extents_t extents; if (!justlist) { cairo_set_source_rgb(cairoshapes, 1.0, 1.0, 1.0); cairo_set_source_rgb(cairo, 1.0, 1.0, 1.0); cairo_set_line_width(cairo, nw); cairo_font_extents(cairo, &extents); dy = extents.ascent * 0.5; } // arcsec/pixel imscale = sip_pixel_scale(&sip); // arcmin imsize = imscale * (imin(W, H) / scale) / 60.0; N = ngc_num_entries(); logverb("Checking %i NGC/IC objects.\n", N); for (i=0; i<N; i++) { ngc_entry* ngc = ngc_get_entry(i); sl* str; sl* names; double pixsize; float ara, adec; char* text; if (!ngc) break; if (ngc->size < imsize * ngc_fraction) continue; if (ngcic_accurate_get_radec(ngc->is_ngc, ngc->id, &ara, &adec) == 0) { ngc->ra = ara; ngc->dec = adec; } if (!sip_radec2pixelxy(&sip, ngc->ra, ngc->dec, &px, &py)) continue; if (px < 0 || py < 0 || px*scale > W || py*scale > H) continue; str = sl_new(4); //sl_appendf(str, "%s %i", (ngc->is_ngc ? "NGC" : "IC"), ngc->id); names = ngc_get_names(ngc, NULL); if (names) { int n; for (n=0; n<sl_size(names); n++) { if (only_messier && strncmp(sl_get(names, n), "M ", 2)) continue; sl_append(str, sl_get(names, n)); } } sl_free2(names); text = sl_implode(str, " / "); printf("%s\n", text); pixsize = ngc->size * 60.0 / imscale; if (!justlist) { // black circle behind the white one... cairo_arc(cairobg, px, py, pixsize/2.0+1.0, 0.0, 2.0*M_PI); cairo_stroke(cairobg); cairo_move_to(cairoshapes, px + pixsize/2.0, py); cairo_arc(cairoshapes, px, py, pixsize/2.0, 0.0, 2.0*M_PI); debug("size: %f arcsec, pixsize: %f pixels\n", ngc->size, pixsize); cairo_stroke(cairoshapes); add_text(cairos, text, px + label_offset, py + dy, halign, valign); } if (json) { char* namelist = sl_implode(str, "\", \""); sl_appendf(json, "{ \"type\" : \"ngc\", " " \"names\" : [ \"%s\" ], " " \"pixelx\" : %g, " " \"pixely\" : %g, " " \"radius\" : %g }" , namelist, px, py, pixsize/2.0); free(namelist); } free(text); sl_free2(str); } } if (HD) { double rac, decc, ra2, dec2; double arcsec; hd_catalog_t* hdcat; bl* hdlist; int i; if (!justlist) cairo_set_source_rgb(cairo, 1.0, 1.0, 1.0); logverb("Reading HD catalog: %s\n", hdpath); hdcat = henry_draper_open(hdpath); if (!hdcat) { ERROR("Failed to open HD catalog"); exit(-1); } logverb("Got %i HD stars\n", henry_draper_n(hdcat)); sip_pixelxy2radec(&sip, W/(2.0*scale), H/(2.0*scale), &rac, &decc); sip_pixelxy2radec(&sip, 0.0, 0.0, &ra2, &dec2); arcsec = arcsec_between_radecdeg(rac, decc, ra2, dec2); // Fudge arcsec *= 1.1; hdlist = henry_draper_get(hdcat, rac, decc, arcsec); logverb("Found %zu HD stars within range (%g arcsec of RA,Dec %g,%g)\n", bl_size(hdlist), arcsec, rac, decc); for (i=0; i<bl_size(hdlist); i++) { double px, py; char* txt; hd_entry_t* hd = bl_access(hdlist, i); if (!sip_radec2pixelxy(&sip, hd->ra, hd->dec, &px, &py)) { continue; } if (px < 0 || py < 0 || px*scale > W || py*scale > H) { logverb(" HD %i at RA,Dec (%g, %g) -> pixel (%.1f, %.1f) is out of bounds\n", hd->hd, hd->ra, hd->dec, px, py); continue; } asprintf_safe(&txt, "HD %i", hd->hd); if (!justlist) { cairo_text_extents_t textents; cairo_text_extents(cairo, txt, &textents); cairo_arc(cairobg, px, py, crad+1.0, 0.0, 2.0*M_PI); cairo_stroke(cairobg); cairo_arc(cairoshapes, px, py, crad, 0.0, 2.0*M_PI); cairo_stroke(cairoshapes); px -= (textents.width * 0.5); py -= (crad + 4.0); add_text(cairos, txt, px, py, halign, valign); } if (json) sl_appendf(json, "{ \"type\" : \"hd\"," " \"pixelx\": %g, " " \"pixely\": %g, " " \"name\" : \"HD %i\" }" , px, py, hd->hd); printf("%s\n", txt); free(txt); } bl_free(hdlist); henry_draper_close(hdcat); } if (json) { FILE* fout = stderr; char* annstr = sl_implode(json, ",\n"); fprintf(fout, "{ \n"); fprintf(fout, " \"status\": \"solved\",\n"); fprintf(fout, " \"git-revision\": %s,\n", AN_GIT_REVISION); fprintf(fout, " \"git-date\": \"%s\",\n", AN_GIT_DATE); fprintf(fout, " \"annotations\": [\n%s\n]\n", annstr); fprintf(fout, "}\n"); free(annstr); } sl_free2(json); json = NULL; if (justlist) return 0; target = cairo_image_surface_create_for_data(img, CAIRO_FORMAT_ARGB32, W, H, W*4); cairot = cairo_create(target); cairo_set_source_rgba(cairot, 0, 0, 0, 1); // Here's where you set the background surface's properties... cairo_set_source_surface(cairot, surfbg, 0, 0); cairo_mask_surface(cairot, surfshapesmask, 0, 0); cairo_stroke(cairot); // Add on the shapes. cairo_set_source_surface(cairot, surfshapes, 0, 0); //cairo_mask_surface(cairot, surfshapes, 0, 0); cairo_mask_surface(cairot, surfshapesmask, 0, 0); cairo_stroke(cairot); // Add on the foreground. cairo_set_source_surface(cairot, surffg, 0, 0); cairo_mask_surface(cairot, surffg, 0, 0); cairo_stroke(cairot); // Convert image for output... cairoutils_argb32_to_rgba(img, W, H); if (pngformat) { if (cairoutils_write_png(outfn, img, W, H)) { ERROR("Failed to write PNG"); exit(-1); } } else { if (cairoutils_write_ppm(outfn, img, W, H)) { ERROR("Failed to write PPM"); exit(-1); } } cairo_surface_destroy(target); cairo_surface_destroy(surfshapesmask); cairo_surface_destroy(surffg); cairo_surface_destroy(surfbg); cairo_surface_destroy(surfshapes); cairo_destroy(cairo); cairo_destroy(cairot); cairo_destroy(cairobg); cairo_destroy(cairoshapes); cairo_destroy(cairoshapesmask); free(img); return 0; }
int main(int argc, char** argv) { int argchar; allquads_t* aq; int loglvl = LOG_MSG; int i, N; char* catfn = NULL; startree_t* starkd; fitstable_t* cat; char* racol = NULL; char* deccol = NULL; int datatype = KDT_DATA_DOUBLE; int treetype = KDT_TREE_DOUBLE; int buildopts = 0; int Nleaf = 0; char* indexfn = NULL; //index_params_t* p; aq = allquads_init(); aq->skdtfn = "allquads.skdt"; aq->codefn = "allquads.code"; aq->quadfn = "allquads.quad"; while ((argchar = getopt (argc, argv, OPTIONS)) != -1) switch (argchar) { case 'v': loglvl++; break; case 'd': aq->dimquads = atoi(optarg); break; case 'I': aq->id = atoi(optarg); break; case 'h': print_help(argv[0]); exit(0); case 'i': catfn = optarg; break; case 'o': indexfn = optarg; break; case 'u': aq->quad_d2_upper = arcmin2distsq(atof(optarg)); aq->use_d2_upper = TRUE; break; case 'l': aq->quad_d2_lower = arcmin2distsq(atof(optarg)); aq->use_d2_lower = TRUE; break; default: return -1; } log_init(loglvl); if (!catfn || !indexfn) { printf("Specify in & out filenames, bonehead!\n"); print_help(argv[0]); exit( -1); } if (optind != argc) { print_help(argv[0]); printf("\nExtra command-line args were given: "); for (i=optind; i<argc; i++) { printf("%s ", argv[i]); } printf("\n"); exit(-1); } if (!aq->id) logmsg("Warning: you should set the unique-id for this index (with -I).\n"); if (aq->dimquads > DQMAX) { ERROR("Quad dimension %i exceeds compiled-in max %i.\n", aq->dimquads, DQMAX); exit(-1); } aq->dimcodes = dimquad2dimcode(aq->dimquads); // Read reference catalog, write star kd-tree logmsg("Building star kdtree: reading %s, writing to %s\n", catfn, aq->skdtfn); logverb("Reading star catalogue..."); cat = fitstable_open(catfn); if (!cat) { ERROR("Couldn't read catalog"); exit(-1); } logmsg("Got %i stars\n", fitstable_nrows(cat)); starkd = startree_build(cat, racol, deccol, datatype, treetype, buildopts, Nleaf, argv, argc); if (!starkd) { ERROR("Failed to create star kdtree"); exit(-1); } logmsg("Star kd-tree contains %i data points in dimension %i\n", startree_N(starkd), startree_D(starkd)); N = startree_N(starkd); for (i=0; i<N; i++) { double ra,dec; int ok; ok = startree_get_radec(starkd, i, &ra, &dec); logmsg(" data %i: ok %i, RA,Dec %g, %g\n", i, ok, ra, dec); } if (startree_write_to_file(starkd, aq->skdtfn)) { ERROR("Failed to write star kdtree"); exit(-1); } startree_close(starkd); fitstable_close(cat); logmsg("Wrote star kdtree to %s\n", aq->skdtfn); logmsg("Running allquads...\n"); if (allquads_open_outputs(aq)) { exit(-1); } if (allquads_create_quads(aq)) { exit(-1); } if (allquads_close(aq)) { exit(-1); } logmsg("allquads: wrote %s, %s\n", aq->quadfn, aq->codefn); // build-index: //build_index_defaults(&p); // codetree /* if (step_codetree(p, codes, &codekd, codefn, &ckdtfn, tempfiles)) return -1; */ char* ckdtfn=NULL; char* tempdir = NULL; ckdtfn = create_temp_file("ckdt", tempdir); logmsg("Creating code kdtree, reading %s, writing to %s\n", aq->codefn, ckdtfn); if (codetree_files(aq->codefn, ckdtfn, 0, 0, 0, 0, argv, argc)) { ERROR("codetree failed"); return -1; } char* skdt2fn=NULL; char* quad2fn=NULL; // unpermute-stars logmsg("Unpermute-stars...\n"); skdt2fn = create_temp_file("skdt2", tempdir); quad2fn = create_temp_file("quad2", tempdir); logmsg("Unpermuting stars from %s and %s to %s and %s\n", aq->skdtfn, aq->quadfn, skdt2fn, quad2fn); if (unpermute_stars_files(aq->skdtfn, aq->quadfn, skdt2fn, quad2fn, TRUE, FALSE, argv, argc)) { ERROR("Failed to unpermute-stars"); return -1; } allquads_free(aq); // unpermute-quads /* if (step_unpermute_quads(p, quads2, codekd, &quads3, &codekd2, quad2fn, ckdtfn, &quad3fn, &ckdt2fn, tempfiles)) return -1; */ char* quad3fn=NULL; char* ckdt2fn=NULL; ckdt2fn = create_temp_file("ckdt2", tempdir); quad3fn = create_temp_file("quad3", tempdir); logmsg("Unpermuting quads from %s and %s to %s and %s\n", quad2fn, ckdtfn, quad3fn, ckdt2fn); if (unpermute_quads_files(quad2fn, ckdtfn, quad3fn, ckdt2fn, argv, argc)) { ERROR("Failed to unpermute-quads"); return -1; } // index /* if (step_merge_index(p, codekd2, quads3, starkd2, p_index, ckdt2fn, quad3fn, skdt2fn, indexfn)) return -1; */ quadfile_t* quad; codetree_t* code; startree_t* star; logmsg("Merging %s and %s and %s to %s\n", quad3fn, ckdt2fn, skdt2fn, indexfn); if (merge_index_open_files(quad3fn, ckdt2fn, skdt2fn, &quad, &code, &star)) { ERROR("Failed to open index files for merging"); return -1; } if (merge_index(quad, code, star, indexfn)) { ERROR("Failed to write merged index"); return -1; } codetree_close(code); startree_close(star); quadfile_close(quad); printf("Done.\n"); free(ckdtfn); free(skdt2fn); free(quad2fn); free(ckdt2fn); free(quad3fn); return 0; }