Esempio n. 1
0
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;
}
Esempio n. 2
0
vio_err_t vio_partition_val(vio_ctx *ctx, vio_val *v, vio_val *q, vio_val **out_rets, vio_val **out_parts) {
    vio_err_t err = 0;
    struct partition *p = NULL;
    struct partition_item *it = NULL;
    vio_val *ret;
    sl_skiplist parts;

    sl_init(&parts, cmp_vals, ctx, NULL, NULL);

    for (uint32_t i = 0; i < v->vlen; ++i) {
        VIO__ERRIF(ctx->sp >= VIO_STACK_SIZE, VE_STACK_OVERFLOW);
        ctx->stack[ctx->sp++] = v->vv[i];
        vio_exec(ctx, q->bc);
        ret = ctx->stack[--ctx->sp];
        if (!sl_find(&parts, ret, &p)) {
            VIO__ERRIF((p = (struct partition *)malloc(sizeof(struct partition))) == NULL, VE_ALLOC_FAIL);
            p->last = NULL;
            p->size = 0;
            sl_insert(&parts, ret, p, NULL);
        }
        VIO__ERRIF((it = (struct partition_item *)malloc(sizeof(struct partition_item))) == NULL, VE_ALLOC_FAIL);
        it->next = p->last;
        it->v = v->vv[i];
        p->last = it;
        ++p->size;
    }

    VIO__CHECK(vio_vec(ctx, out_rets, sl_size(&parts), NULL));
    VIO__CHECK(vio_vec(ctx, out_parts, sl_size(&parts), NULL));
    struct part_data pd = { .i = 0, .rets = *out_rets, .parts = *out_parts, .ctx = ctx };
    sl_iter(&parts, fill_partitions_and_free, &pd);
    sl_free(&parts);
    return 0;

    error:
    sl_iter(&parts, gotta_free_em_all, NULL);
    sl_free(&parts);
    return err;
}

vio_err_t vio_partition(vio_ctx *ctx) {
    vio_err_t err = 0;
    vio_val *q, *vec, *rets, *parts;
    VIO__RAISEIF(ctx->sp < 2, VE_STACK_EMPTY,
                 "Partition context requires a quotation and vector, but the "
                 "stack doesnt't have enough values.");

    VIO__CHECK(vio_coerce(ctx, ctx->stack[--ctx->sp], &q, vv_quot));
    VIO__CHECK(vio_coerce(ctx, ctx->stack[--ctx->sp], &vec, vv_vec));
    VIO__CHECK(vio_partition_val(ctx, vec, q, &rets, &parts));
    ctx->stack[ctx->sp++] = rets;
    ctx->stack[ctx->sp++] = parts;
    return 0;

    error:
    return err;
}
Esempio n. 3
0
void sl_remove_duplicates(sl* lst) {
	int i, j;
	for (i=0; i<sl_size(lst); i++) {
		const char* s1 = sl_get(lst, i);
		for (j=i+1; j<sl_size(lst); j++) {
			const char* s2 = sl_get(lst, j);
			if (strcmp(s1, s2) == 0) {
				sl_remove(lst, j);
				j--;
			}
		}
	}
}
Esempio n. 4
0
void sl_free2(sl* list) {
	int i;
	if (!list) return;
	for (i=0; i<sl_size(list); i++)
		free(sl_get(list, i));
	bl_free(list);
}
Esempio n. 5
0
void  sl_remove_all(sl* list) {
	int i;
	if (!list) return;
	for (i=0; i<sl_size(list); i++)
		free(pl_get(list, i));
	bl_remove_all(list);
}
Esempio n. 6
0
int plot_annotations_command(const char* cmd, const char* cmdargs,
							 plot_args_t* pargs, void* baton) {
	plotann_t* ann = (plotann_t*)baton;
	if (streq(cmd, "annotations_no_ngc")) {
		ann->NGC = FALSE;
	} else if (streq(cmd, "annotations_no_bright")) {
		ann->bright = FALSE;
	} else if (streq(cmd, "annotations_ngc_size")) {
		ann->ngc_fraction = atof(cmdargs);
	} else if (streq(cmd, "annotations_target")) {
		sl* args = sl_split(NULL, cmdargs, " ");
		double ra, dec;
		char* name;
		if (sl_size(args) != 3) {
			ERROR("Need RA,Dec,name");
			return -1;
		}
		ra = atof(sl_get(args, 0));
		dec = atof(sl_get(args, 1));
		name = sl_get(args, 2);
		plot_annotations_add_target(ann, ra, dec, name);
	} else if (streq(cmd, "annotations_targetname")) {
		const char* name = cmdargs;
		return plot_annotations_add_named_target(ann, name);
	} else {
		ERROR("Unknown command \"%s\"", cmd);
		return -1;
	}
	return 0;
}
Esempio n. 7
0
void opts_print_help(bl* opts, FILE* fid,
                     void (*special_case)(an_option_t* opt, bl* allopts, int index,
                             FILE* fid, void* extra), void* extra) {
    int i;
    for (i=0; i<bl_size(opts); i++) {
        an_option_t* opt = bl_access(opts, i);
        int nw = 0;
        sl* words;
        int j;
        if (opt->help) {
            if ((opt->shortopt >= 'a' && opt->shortopt <= 'z') ||
                    (opt->shortopt >= 'A' && opt->shortopt <= 'Z') ||
                    (opt->shortopt >= '0' && opt->shortopt <= '9'))
                nw += fprintf(fid, "  -%c / --%s", opt->shortopt, opt->name);
            else
                nw += fprintf(fid, "  --%s", opt->name);
            if (opt->has_arg == optional_argument)
                nw += fprintf(fid, " [<%s>]", opt->argname);
            else if (opt->has_arg == required_argument)
                nw += fprintf(fid, " <%s>", opt->argname);
            nw += fprintf(fid, ": ");
            if (!opt->help)
                continue;
            words = split_long_string(opt->help, 80-nw, 70, NULL);
            for (j=0; j<sl_size(words); j++)
                fprintf(fid, "%s%s\n", (j==0 ? "" : "          "), sl_get(words, j));
        } else if (special_case)
            special_case(opt, opts, i, fid, extra);
    }
}
Esempio n. 8
0
int fitstable_add_fits_columns_as_struct3(const fitstable_t* intab,
					  fitstable_t* outtab,
					  const sl* colnames,
					  int c_offset) {
	int i, NC;
	int noc = ncols(outtab);
	NC = sl_size(colnames);
	for (i=0; i<NC; i++) {
		const qfits_col* qcol;
		fitscol_t* col;
		const char* name = sl_get_const(colnames, i);
		int j = fits_find_column(intab->table, name);
		int off;
		if (j == -1) {
			ERROR("Failed to find FITS column \"%s\"", name);
			return -1;
		}
		qcol = qfits_table_get_col(intab->table, j);
		// We give the offset of the column in the *input* table, so that
		// the resulting "outtab" can handle raw data from the "intab".
		off = fits_offset_of_column(intab->table, j);
		fitstable_add_read_column_struct(outtab, qcol->atom_type, qcol->atom_nb,
						 c_offset + off, qcol->atom_type, qcol->tlabel, TRUE);
		// set the FITS column number.
		col = getcol(outtab, ncols(outtab)-1);
		col->col = noc + i;
	}
	return 0;
}
Esempio n. 9
0
static char* sljoin(sl* list, const char* join, int forward) {
    int start, end, inc;

	int len = 0;
	int i, N;
	char* rtn;
	int offset;
	int JL;

    if (sl_size(list) == 0)
        return strdup("");

    // step through the list forward or backward?
    if (forward) {
        start = 0;
        end = sl_size(list);
        inc = 1;
    } else {
        start = sl_size(list) - 1;
        end = -1;
        inc = -1;
    }

	JL = strlen(join);
	N = sl_size(list);
	for (i=0; i<N; i++)
		len += strlen(sl_get(list, i));
	len += ((N-1) * JL);
	rtn = malloc(len + 1);
	if (!rtn)
		return rtn;
	offset = 0;
	for (i=start; i!=end; i+= inc) {
		char* str = sl_get(list, i);
		int L = strlen(str);
		if (i != start) {
			memcpy(rtn + offset, join, JL);
			offset += JL;
		}
		memcpy(rtn + offset, str, L);
		offset += L;
	}
	assert(offset == len);
	rtn[offset] = '\0';
	return rtn;
}
Esempio n. 10
0
int plotstuff_append_doubles(const char* str, dl* lst) {
	int i;
	sl* strs = sl_split(NULL, str, " ");
	for (i=0; i<sl_size(strs); i++)
		dl_append(lst, atof(sl_get(strs, i)));
	sl_free2(strs);
	return 0;
}
Esempio n. 11
0
void test_log_ts(CuTest* tc) {
    pthread_t t1, t2;
    FILE *f1, *f2;
    char *fn1, *fn2;
    sl* lst;

    log_init(LOG_VERB);
    logmsg("Logging initialized.\n");

    log_set_thread_specific();
    logmsg("Logging set thread specific.\n");

    fn1 = create_temp_file("log", "/tmp");
    fn2 = create_temp_file("log", "/tmp");

    logmsg("File 1 is %s\n", fn1);
    logmsg("File 2 is %s\n", fn2);

    f1 = fopen(fn1, "w");
    f2 = fopen(fn2, "w");

    CuAssertIntEquals(tc, 0, pthread_create(&t1, NULL, thread1, f1));
    CuAssertIntEquals(tc, 0, pthread_create(&t2, NULL, thread2, f2));

    CuAssertIntEquals(tc, 0, pthread_join(t1, NULL));
    CuAssertIntEquals(tc, 0, pthread_join(t2, NULL));

    fclose(f1);
    fclose(f2);

    lst = file_get_lines(fn1, FALSE);
    CuAssertIntEquals(tc, 0, strcmp(sl_get(lst, 0), STRING1A));
    CuAssertIntEquals(tc, 1, sl_size(lst));
    sl_free2(lst);

    lst = file_get_lines(fn2, FALSE);
    CuAssertIntEquals(tc, 0, strcmp(sl_get(lst, 0), STRING2A));
    CuAssertIntEquals(tc, 0, strcmp(sl_get(lst, 1), STRING2B));
    CuAssertIntEquals(tc, 2, sl_size(lst));
    sl_free2(lst);

    unlink(fn1);
    unlink(fn2);
    free(fn1);
    free(fn2);
}
Esempio n. 12
0
ptrdiff_t sl_last_index_of(sl* lst, const char* str) {
    ptrdiff_t i;
    for (i=sl_size(lst)-1; i>=0; i--) {
        char* s = sl_get(lst, i);
        if (strcmp(s, str) == 0)
            return i;
    }
    return BL_NOT_FOUND;
}
Esempio n. 13
0
ptrdiff_t sl_index_of(sl* lst, const char* str) {
    size_t i;
    for (i=0; i<sl_size(lst); i++) {
        char* s = sl_get(lst, i);
        if (strcmp(s, str) == 0)
            return i;
    }
    return BL_NOT_FOUND;
}
Esempio n. 14
0
void sl_append_contents(sl* dest, sl* src) {
	int i;
	if (!src)
		return;
	for (i=0; i<sl_size(src); i++) {
		char* str = sl_get(src, i);
		sl_append(dest, str);
	}
}
Esempio n. 15
0
int sl_index_of(sl* lst, const char* str) {
    int i;
    for (i=0; i<sl_size(lst); i++) {
        char* s = sl_get(lst, i);
        if (strcmp(s, str) == 0)
            return i;
    }
    return -1;
}
Esempio n. 16
0
int sl_last_index_of(sl* lst, const char* str) {
    int i;
    for (i=sl_size(lst)-1; i>=0; i--) {
        char* s = sl_get(lst, i);
        if (strcmp(s, str) == 0)
            return i;
    }
    return -1;
}
Esempio n. 17
0
void test_sl_split_2(CuTest* tc) {
    int i;
    sl* s = sl_split(NULL, "hello  world  this  is  a  test     ", "  ");
    CuAssertPtrNotNull(tc, s);
    printf("got: ");
    for (i=0; i<sl_size(s); i++)
        printf("/%s/ ", sl_get(s, i));
    printf("\n");
    CuAssertIntEquals(tc, 8, sl_size(s));
    CuAssertIntEquals(tc, 0, strcmp(sl_get(s, 0), "hello"));
    CuAssertIntEquals(tc, 0, strcmp(sl_get(s, 1), "world"));
    CuAssertIntEquals(tc, 0, strcmp(sl_get(s, 2), "this"));
    CuAssertIntEquals(tc, 0, strcmp(sl_get(s, 3), "is"));
    CuAssertIntEquals(tc, 0, strcmp(sl_get(s, 4), "a"));
    CuAssertIntEquals(tc, 0, strcmp(sl_get(s, 5), "test"));
    CuAssertIntEquals(tc, 0, strcmp(sl_get(s, 6), ""));
    CuAssertIntEquals(tc, 0, strcmp(sl_get(s, 7), " "));
    sl_free2(s);
}
Esempio n. 18
0
void test_sl_split_1(CuTest* tc) {
    sl* s = sl_split(NULL, "hello world this is a test", " ");
    CuAssertPtrNotNull(tc, s);
    CuAssertIntEquals(tc, 6, sl_size(s));
    CuAssertIntEquals(tc, 0, strcmp(sl_get(s, 0), "hello"));
    CuAssertIntEquals(tc, 0, strcmp(sl_get(s, 1), "world"));
    CuAssertIntEquals(tc, 0, strcmp(sl_get(s, 2), "this"));
    CuAssertIntEquals(tc, 0, strcmp(sl_get(s, 3), "is"));
    CuAssertIntEquals(tc, 0, strcmp(sl_get(s, 4), "a"));
    CuAssertIntEquals(tc, 0, strcmp(sl_get(s, 5), "test"));
    sl_free2(s);
}
Esempio n. 19
0
ptrdiff_t sl_remove_string_byval(sl* list, const char* string) {
    size_t N = sl_size(list);
    size_t i;
    for (i=0; i<N; i++) {
        char* str = sl_get(list, i);
        if (strcmp(str, string) == 0) {
            sl_remove(list, i);
            return i;
        }
    }
    return BL_NOT_FOUND;
}
Esempio n. 20
0
int sl_remove_string_byval(sl* list, const char* string) {
	int N = sl_size(list);
	int i;
	for (i=0; i<N; i++) {
        char* str = sl_get(list, i);
		if (strcmp(str, string) == 0) {
			sl_remove(list, i);
			return i;
		}
	}
	return -1;
}
Esempio n. 21
0
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);
    }
}
Esempio n. 22
0
char* sl_remove_string_bycaseval(sl* list, const char* string) {
	int N = sl_size(list);
	int i;
	for (i=0; i<N; i++) {
        char* str = sl_get(list, i);
		if (strcasecmp(str, string) == 0) {
            char* s = sl_get(list, i);
			sl_remove(list, i);
            return s;
		}
	}
	return NULL;
}
Esempio n. 23
0
/* device_mover_setup()
 *==========================================================================
 * RETURNS TRUE - SUCCESS
 *	   FALSE- ERROR! ( probably memory allocation )
 */
void
device_mover_setup( DEV_PTR list_ptr, int font_count,
	            int base, int slider, int up, int down,
	            int first_obj, int last_obj, int base_obj,
	            int start_index, int num_slits )
{
    int i;

    dhdptr = list_ptr;
    Total = font_count;

    Mbase 	= base;
    Mslider	= slider;
    Mup		= up;
    Mdown	= down;
    First_Obj	= first_obj;
    Base_Obj	= base_obj;
    Obj_Beg	= first_obj;
    Obj_End	= last_obj;           
    MAX_SLITS   = num_slits;
        
    for( i = 0; i < MAX_SLITS;i++ )
    {
        Deselect( First_Obj + ( i * 6 ) + 5 );
        
        Device_Slit[i] = NULL;
	TedText( First_Obj + ( i * 6 ) + 2 ) = fblank3;
        HideObj( First_Obj + ( i * 6 ) + 3 );	
        HideObj( First_Obj + ( i * 6 ) + 4 );	
    }
        
    if( Total > MAX_SLITS )
    {
       if( start_index > Total - MAX_SLITS )
           start_index = Total - MAX_SLITS;
    }
    else
       start_index = 0;
       
    device_offset_adjust( dhdptr, start_index, Device_Slit );

    if( start_index )
        start_index = Get_Device_Index( dhdptr, Device_Slit[0] );
    
    Old_Slit = Cur_Slit = start_index;
    sl_size( tree, Mbase, Mslider, Total, MAX_SLITS, VERTICAL, 0 );
    sl_y( tree, Mbase, Mslider, Cur_Slit,
          max( Total - MAX_SLITS, 0 ), 0, NULLFUNC );

}
Esempio n. 24
0
void test_sl_split_3(CuTest* tc) {
    sl* s, *s2;
    s = sl_new(1);
    sl_append(s, "guard");
    s2 = sl_split(s, "XYhelloXYworldXYXY", "XY");
    CuAssertPtrNotNull(tc, s2);
    CuAssertPtrEquals(tc, s, s2);
    CuAssertIntEquals(tc, 5, sl_size(s));
    CuAssertIntEquals(tc, 0, strcmp(sl_get(s, 0), "guard"));
    CuAssertIntEquals(tc, 0, strcmp(sl_get(s, 1), ""));
    CuAssertIntEquals(tc, 0, strcmp(sl_get(s, 2), "hello"));
    CuAssertIntEquals(tc, 0, strcmp(sl_get(s, 3), "world"));
    CuAssertIntEquals(tc, 0, strcmp(sl_get(s, 4), ""));
    sl_free2(s);
}
Esempio n. 25
0
/* mover_setup()
 *==========================================================================
 * RETURNS TRUE - SUCCESS
 *	   FALSE- ERROR! ( probably memory allocation )
 */
void
mover_setup( HDEVICE_PTR list_ptr, int font_count,
	     int base, int slider, int up, int down,
	     int first_obj, int last_obj, int base_obj,
	     int start_index, int num_slits )
{
    int i;

    hdptr = list_ptr;
    Total = font_count;

    Mbase 	= base;
    Mslider	= slider;
    Mup		= up;
    Mdown	= down;
    First_Obj	= first_obj;
    Base_Obj	= base_obj;
    Obj_Beg	= first_obj;
    Obj_End	= last_obj;           
    MAX_SLITS   = num_slits;
        
    for( i = 0; i < MAX_SLITS;i++ )
    {
        Active_Slit[i] = NULL;
        TedText( First_Obj + i ) = fblank;
    }
        
    if( Total > MAX_SLITS )
    {
       if( start_index > Total - MAX_SLITS )
           start_index = Total - MAX_SLITS;
    }
    else
       start_index = 0;
       
    slit_offset_adjust( hdptr, start_index, Active_Slit );

    if( start_index )
        start_index = Get_Findex( hdptr, Active_Slit[0] );
    
    Old_Slit = Cur_Slit = start_index;
    sl_size( tree, Mbase, Mslider, Total, MAX_SLITS, VERTICAL, 0 );
    sl_y( tree, Mbase, Mslider, Cur_Slit,
          max( Total - MAX_SLITS, 0 ), 0, NULLFUNC );

}
int main(int argc, char *argv[]) {
	char* progname = argv[0];
    int argchar;
	char* infn;

    sl* methods = NULL;
    dl* scales = NULL;
    int i;
    int loglvl = LOG_MSG;

    while ((argchar = getopt (argc, argv, OPTIONS)) != -1)
        switch (argchar) {
        case '?':
        case 'h':
			printHelp(progname);
            return 0;
        case 'v':
            loglvl++;
            break;
        default:
            return -1;
        }

	if (optind != (argc - 1)) {
		printHelp(progname);
		exit(-1);
	}
	infn = argv[optind];

    log_init(loglvl);

    fits_use_error_system();

    if (fits_guess_scale(infn, &methods, &scales))
        exit(-1);

    for (i=0; i<sl_size(methods); i++) {
        printf("scale %s %g\n", sl_get(methods, i), dl_get(scales, i));
    }

    sl_free2(methods);
    dl_free(scales);

    return 0;
}
Esempio n. 27
0
multiindex_t* multiindex_open(const char* skdtfn, const sl* indfns,
                              int flags) {
	multiindex_t* mi = multiindex_new(skdtfn);
	if (!mi)
		return NULL;
	int i;
	for (i=0; i<sl_size(indfns); i++) {
		const char* fn = sl_get_const(indfns, i);
		if (multiindex_add_index(mi, fn, flags)) {
			goto bailout;
		}
	}
    if (flags & INDEX_ONLY_LOAD_METADATA) {
        multiindex_unload_starkd(mi);
    }
	return mi;
 bailout:
	multiindex_free(mi);
	return NULL;
}
Esempio n. 28
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;
}
Esempio n. 29
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;
}
Esempio n. 30
0
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;
}