/*
* match: a package to match lists of stars (or other items)
* Copyright (C) 2000 Michael William Richmond
*
* Contact: Michael William Richmond
* Physics Department
* Rochester Institute of Technology
* 85 Lomb Memorial Drive
* Rochester, NY 14623-5603
* E-mail: mwrsps@rit.edu
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
/*
*
* FILE: match.c
*
*
* This file contains the 'main' routine, which takes instructions
* from the user, reads information from files, calls the matching
* routines, and writes information back onto disk.
*
*
*
*
* 7/18/96 - Added transonly option. MWR
*
* 6/1/2000 - Added 'recalc' option; this goes through the usual steps:
*
* 1. read in complete lists of stars from two sources
* 2. using only N brightest, find a set of matching pairs
* 3. calc TRANS
* 4. apply TRANS to all of list A
* 5. match all of list A (with TRANS'ed coords) against
* all of list B to find _many_ pairs
*
* but now it also adds the following
*
* 6. using these _many_ pairs, calc TRANS again
*
* The point is to avoid running the similar-triangles code
* on the _many_ pairs, since that's the slow part;
* we can very quickly calc a new, more accurate TRANS from
* the _many_ pairs.
*
* MWR
*
* 6/14/2000 - Added "--version" and "--help" options, plus GPL.
* MWR
*
* 7/30/2000 - Added "id1" and "id2" options. MWR
*
* 1/21/2001 - Added "max_iter" and "halt_sigma" options, plus some sanity
* checks on values of user-supplied arguments.
* MWR
*
* 12/14/2001- Added additional output values in TRANS which describe
* the quality of the fit. Added optional arguments which
* cause calculation of additional statistics.
* Thanks to John Blakeslee.
* MWR
*
* 12/31/2001- Added options:
* allow user to specify an input TRANS
* allow user to specify a pure offset between coords
* Thanks to John Blakeslee.
* MWR
*
* 11/23/2002- Fixed bug in "reset_A_coords()" which caused an assert
* failure if given empty lists. Now the routine
* simply prints a warning message and returns
* with normal code.
* MWR
*
*
*
*/
#include
#include
#include
#include
#include "misc.h"
#include "match.h"
#include "atpmatch.h"
#undef DEBUG /* get some of diagnostic output */
static void reset_copy_ids(int numA, struct s_star *star_list_A,
struct s_star *star_list_A_copy);
static int reset_A_coords(int numA, struct s_star *post_list_A,
struct s_star *pre_list_A);
static int prepare_to_recalc(char *outfile,
int *num_matched_A, struct s_star **matched_list_A,
int *num_matched_B, struct s_star **matched_list_B,
struct s_star *star_list_A_copy, TRANS *trans);
#define USAGE "Usage:\nmatch "\
" \n"\
" [id1=] [id2=] [max_iter=] [halt_sigma=] \n"\
" [outfile=] [trirad=] [nobj=] [matchrad=] \n"\
" [scale=] [min_scale=] [max_scale=] [transonly] \n"\
" [recalc] [linear|quadratic|cubic]\n"\
" [medtf] [medsigclip=] "\
" [intrans=] [identity [xsh=] [ysh=]]\n"\
" [--version] [--help] [help]\n"
char progname[CMDBUFLEN + 1];
int
main
(
int argc,
char *argv[]
)
{
int i, ret;
int numA, numB;
int num_matched_A, num_matched_B;
int numA_copy;
int x1col, y1col, mag1col;
int x2col, y2col, mag2col;
int id1col = -1, id2col = -1;
int max_iter = AT_MATCH_MAXITER;
int trans_order = AT_TRANS_LINEAR;
char *fileA, *fileB;
double triangle_radius = AT_TRIANGLE_RADIUS; /* in triangle-space coords */
double match_radius = AT_MATCH_RADIUS; /* in units of list B */
double scale = -1.0;
double min_scale = -1.0;
double max_scale = -1.0;
double halt_sigma = AT_MATCH_HALTSIGMA;
double medsigclip = 0.0; /* used in MEDTF calcs */
double xshift = 0.0; /* guessed shift in X dir */
double yshift = 0.0; /* guessed shift in y dir */
int nobj = AT_MATCH_NBRIGHT;
int transonly = 0; /* if 1, only find TRANS */
int recalc = 0; /* if 1, calc TRANS again */
int num_matches = 0; /* number of matching pairs */
int medtf_flag = 0; /* calculate MEDTF stats? */
int intrans = 0; /* use given input TRANS? */
int identity = 0; /* use identity as TRANS? */
char outfile[CMDBUFLEN + 1];
char intransfile[CMDBUFLEN + 1];
char matched_file_A[CMDBUFLEN + 5];
char matched_file_B[CMDBUFLEN + 5];
struct s_star *star_list_A, *star_list_B;
struct s_star *star_list_A_copy;
struct s_star *matched_list_A, *matched_list_B;
TRANS *trans;
MEDTF *medtf;
/* buffer overflow paranoia */
outfile[CMDBUFLEN] = '\0';
progname[CMDBUFLEN] = '\0';
intransfile[CMDBUFLEN] = '\0';
matched_file_A[CMDBUFLEN + 4] = '\0';
matched_file_B[CMDBUFLEN + 4] = '\0';
strncpy(outfile, AT_MATCH_OUTFILE, CMDBUFLEN);
strncpy(progname, argv[0], CMDBUFLEN);
/* make special search for --version, --help, and help */
if ((argc < 2) ||
(strncmp(argv[1], "--help", 6) == 0) ||
(strncmp(argv[1], "help", 4) == 0)) {
printf("%s\n", USAGE);
exit(0);
}
if (strncmp(argv[1], "--version", 9) == 0) {
printf("%s: version %s\n", progname, VERSION);
exit(0);
}
/*
* If we get here, the user seems to want to run the program normally.
* Make sure there are at least the required arguments
*/
if (argc < 8) {
fprintf(stderr, "%s\n", USAGE);
exit(1);
}
/* these are all required args for normal usage */
fileA = argv[1];
if (sscanf(argv[2], "%d", &x1col) != 1) {
shFatal("invalid argument for column for X values in first file");
}
if (sscanf(argv[3], "%d", &y1col) != 1) {
shFatal("invalid argument for column for Y values in first file");
}
if (sscanf(argv[4], "%d", &mag1col) != 1) {
shFatal("invalid argument for column for mag values in first file");
}
fileB = argv[5];
if (sscanf(argv[6], "%d", &x2col) != 1) {
shFatal("invalid argument for column for X values in second file");
}
if (sscanf(argv[7], "%d", &y2col) != 1) {
shFatal("invalid argument for column for Y values in second file");
}
if (sscanf(argv[8], "%d", &mag2col) != 1) {
shFatal("invalid argument for column for mag values in second file");
}
/*
* check for optional arguments
*/
for (i = 9; i < argc; i++) {
if (strncmp(argv[i], "nobj=", 5) == 0) {
if (sscanf(argv[i] + 5, "%d", &nobj) != 1) {
shFatal("invalid argument for nobj argument");
}
if (nobj <= 0) {
shFatal("invalid value %d for nobj: must be > 0", nobj);
}
}
else if (strncmp(argv[i], "trirad=", 7) == 0) {
if (sscanf(argv[i] + 7, "%lf", &triangle_radius) != 1) {
shFatal("invalid argument for trirad argument");
}
if (triangle_radius <= 0) {
shFatal("invalid value %lf for triangle_radius: must be > 0",
triangle_radius);
}
}
else if (strncmp(argv[i], "matchrad=", 9) == 0) {
if (sscanf(argv[i] + 9, "%lf", &match_radius) != 1) {
shFatal("invalid argument for matchrad argument");
}
if (match_radius <= 0) {
shFatal("invalid value %lf for match_radius: must be > 0",
match_radius);
}
}
else if (strncmp(argv[i], "scale=", 6) == 0) {
if (sscanf(argv[i] + 6, "%lf", &scale) != 1) {
shFatal("invalid argument for scale argument");
}
if (scale <= 0) {
shFatal("invalid value %lf for scale: must be > 0", scale);
}
}
else if (strncmp(argv[i], "min_scale=", 10) == 0) {
if (sscanf(argv[i] + 10, "%lf", &min_scale) != 1) {
shFatal("invalid argument for min_scale argument");
}
if (min_scale <= 0) {
shFatal("invalid value %lf for min_scale: must be > 0", min_scale);
}
}
else if (strncmp(argv[i], "max_scale=", 10) == 0) {
if (sscanf(argv[i] + 10, "%lf", &max_scale) != 1) {
shFatal("invalid argument for max_scale argument");
}
if (max_scale <= 0) {
shFatal("invalid value %lf for max_scale: must be > 0", max_scale);
}
}
else if (strncmp(argv[i], "outfile=", 8) == 0) {
strncpy(outfile, argv[i] + 8, CMDBUFLEN);
}
else if (strncmp(argv[i], "transonly", 9) == 0) {
transonly = 1;
}
else if (strncmp(argv[i], "recalc", 6) == 0) {
recalc = 1;
}
else if (strncmp(argv[i], "linear", 6) == 0) {
trans_order = AT_TRANS_LINEAR;
}
else if (strncmp(argv[i], "quadratic", 9) == 0) {
trans_order = AT_TRANS_QUADRATIC;
}
else if (strncmp(argv[i], "cubic", 5) == 0) {
trans_order = AT_TRANS_CUBIC;
}
else if (strncmp(argv[i], "id1", 3) == 0) {
if (sscanf(argv[i] + 4, "%d", &id1col) != 1) {
shFatal("invalid argument for id1col argument");
}
if (id1col < 0) {
shFatal("invalid value %d for id1: must be >= 0", id1col);
}
}
else if (strncmp(argv[i], "id2", 3) == 0) {
if (sscanf(argv[i] + 4, "%d", &id2col) != 1) {
shFatal("invalid argument for id2col argument");
}
if (id2col < 0) {
shFatal("invalid value %d for id2col: must be >= 0", id2col);
}
}
else if (strncmp(argv[i], "max_iter", 8) == 0) {
if (sscanf(argv[i] + 9, "%d", &max_iter) != 1) {
shFatal("invalid argument for max_iter argument");
}
if (max_iter < 0) {
shFatal("invalid value %d for max_iter: must be >= 0", max_iter);
}
}
else if (strncmp(argv[i], "halt_sigma", 10) == 0) {
if (sscanf(argv[i] + 11, "%lf", &halt_sigma) != 1) {
shFatal("invalid argument for halt_sigma argument");
}
if (halt_sigma <= 0) {
shFatal("invalid value %lf for halt_sigma: must be > 0", halt_sigma);
}
}
else if (strncmp(argv[i], "medtf", 5) == 0) {
medtf_flag = 1;
}
else if (strncmp(argv[i], "medsigclip", 10) == 0) {
if (sscanf(argv[i] + 11, "%lf", &medsigclip) != 1) {
shFatal("invalid argument for medsigclip");
}
if (medsigclip <= 0) {
shFatal("invalid value %lf for medsigclip: must be >= 0",
medsigclip);
}
}
else if (strncmp(argv[i], "intrans", 7) == 0) {
if (sscanf(argv[i] + 8, "%s", intransfile) != 1) {
shFatal("invalid argument for intransfile");
}
intrans = 1;
}
else if (strncmp(argv[i], "identity", 8) == 0) {
/*
* note that we force scale factor to be 1.0 when user
* ask for the identity transformation
*/
identity = 1;
scale = 1.0;
}
else if (strncmp(argv[i], "xsh", 3) == 0) {
if (sscanf(argv[i] + 4, "%lf", &xshift) != 1) {
shFatal("invalid value for xsh argument");
}
}
else if (strncmp(argv[i], "ysh", 3) == 0) {
if (sscanf(argv[i] + 4, "%lf", &yshift) != 1) {
shFatal("invalid value for ysh argument");
}
}
else {
/* this isn't any known argument. Complain and quit */
shFatal("Invalid argument: %s", argv[i]);
}
}
/*
* All done with command-line parsing. Phew.
*
* Next, we check the validity of the arguments.
*/
/*
* We can only calculate _clipped_ MEDTF statistics if we calculate
* the regular ones. So it makes no sense to specify 'medsigclip',
* but not 'medtf'.
*/
if ((medtf_flag == 0) && (medsigclip != 0.0)) {
shError("WARNING: medsigclip requires the 'medtf' option");
shError("WARNING: Setting medtf ");
medtf_flag = 1;
}
/*
* Impossible to calculation the MEDTF statistics unless we match
* up stars after finding the TRANS. So, if the user does want
* the MEDTF stats, we force the necessary step.
*/
if ((medtf_flag == 1) && (recalc == 0)) {
shError("WARNING: 'medtf' requires the 'recalc' option");
shError("WARNING: Setting recalc ");
recalc = 1;
}
/*
* Check to make sure that the user did exactly one of the following:
* a. did not specify "scale" or "min_scale" or "max_scale"
* b. did specify "scale" only
* c. did specify "min_scale" and "max_scale", but not "scale"
*
* If choice b., then translate the single "scale" value into
* a pair of "min_scale" and "max_scale" limits. We'll always
* pass these limits to the matching procedures.
*/
if ((scale == -1) && (min_scale == -1) && (max_scale == -1)) {
/* okay */
;
}
else if ((scale != -1) && (min_scale == -1) && (max_scale == -1)) {
/* okay */
min_scale = scale - (0.01*AT_MATCH_PERCENT*scale);
max_scale = scale + (0.01*AT_MATCH_PERCENT*scale);
}
else if ((scale == -1) && (min_scale != -1) && (max_scale != -1)) {
/* okay */
if (min_scale > max_scale) {
shFatal("min_scale must be smaller than max_scale");
}
}
else {
/* not okay */
shFatal("invalid combination of 'scale', 'min_scale', 'max_scale'");
}
#ifdef DEBUG
if ((scale == -1) && (min_scale == -1) && (max_scale == -1)) {
printf("No limits set on relative scales for matching. \n");
}
else {
printf("using min_scale %f max_scale %f \n", min_scale, max_scale);
}
#endif
/* Can only specify one of 'identity' and 'intrans' */
if ((intrans != 0) && (identity != 0)) {
shFatal("Cannot specify both 'identity' and an input TRANS file");
}
/* Makes no sense to specify 'identity' and 'quadratic' or 'cubic' */
if ((identity != 0) && (trans_order != AT_TRANS_LINEAR)) {
shFatal("Cannot specify both 'identity' and any order beyond linear");
}
/*
* Likewise, makes no sense to specify 'intrans=' and
* 'quadratic' or 'cubic' (or 'linear', actually, but we have
* no easy way to check for that mistake :-(
*/
if ((intrans != 0) && (trans_order != AT_TRANS_LINEAR)) {
shFatal("Cannot specify both 'intrans' and any order ");
}
/*
* There are three possibilities for the initial TRANS values:
*
* 1. The user specified "identity", so we start with a linear TRANS
* which has no scale change or rotation; it has no translation,
* unless the user gave 'xsh' and 'ysh'.
*
* 2. The user specified "intrans=file", in which case we read
* the initial TRANS values from the given file.
*
* 3. The user didn't give us either, so we start with an empty
* TRANS and will have to find one ourselves via atFindTrans().
*
* In either case 1 or 2, we will end up with a non-zero initial
* TRANS structure -- which means that we want to use IT to find
* matches, instead of atFindTrans(). We'll therefore set the 'intrans'
* flag to 1, to indicate "don't try to find a TRANS, just use
* the one the user provided".
*/
if (identity == 1) {
trans = getIdentityTrans();
trans_order = trans->order;
if (xshift != 0.0) {
trans->a = xshift;
}
if (yshift != 0.0) {
trans->d = yshift;
}
intrans = 1;
} else if (intrans == 1) {
if ((trans = getGuessTrans(intransfile)) == NULL) {
shFatal("GetGuessTrans fails -- must give up");
}
trans_order = trans->order;
}
else {
/* this will be an "empty" TRANS; atFindTrans will try to fill it */
atTransOrderSet(trans_order);
trans = atTransNew();
trans->order = trans_order;
}
#ifdef DEBUG
printf("using trans_order %d\n", trans_order);
#endif
/* read information from the first file */
if (read_star_file(fileA, x1col, y1col, mag1col, id1col, -1,
&numA, &star_list_A) != SH_SUCCESS) {
shError("can't read data from file %s", fileA);
exit(1);
}
/*
* We always (whether given initial TRANS or not) will
* make a second calculation of the TRANS, using only objects in
* the set of matched pairs.
* As input to this second calculation, we will need items
* from list A with their original coordinates.
* Therefore, we now create a copy of the stars in set A,
* so that we can restore the output matched coords
* (which have been converted to those in set B) with the original coords.
*/
if (read_star_file(fileA, x1col, y1col, mag1col, id1col, -1,
&numA_copy, &star_list_A_copy) != SH_SUCCESS) {
shFatal("can't read data from file %s", fileA);
}
/* sanity check */
shAssert(numA_copy == numA);
/*
* reset the 'id' field values in the star_list_A_copy so that they
* match the 'id' field values in their counterparts in star_list_A
*/
reset_copy_ids(numA, star_list_A, star_list_A_copy);
/* read information from the second file */
if (read_star_file(fileB, x2col, y2col, mag2col, id2col, -1,
&numB, &star_list_B) != SH_SUCCESS) {
shError("can't read data from file %s", fileB);
exit(1);
}
/*
* Now, if the has has not given us an initial TRANS structure, we need
* to find one ourselves.
*/
if (intrans == 0) {
ret = atFindTrans(numA, star_list_A, numB, star_list_B,
triangle_radius, nobj, min_scale, max_scale,
max_iter, halt_sigma, trans);
if (ret != SH_SUCCESS) {
shFatal("initial call to atFindTrans fails");
}
}
#ifdef DEBUG
printf("using trans_order %d.\n",trans_order);
printf("Initial trans structure:\n");
print_trans(trans);
#endif
/*
* if the "transonly" flag is set, stop at this point
*/
if (transonly == 1) {
print_trans(trans);
return(0);
}
/*
* having found (or been given) the TRANS that takes A -> B, let us apply
* it to all the elements in A; thus, we'll have two sets of
* of stars, each in the same coordinate system
*/
atApplyTrans(numA, star_list_A, trans);
/*
* now match up the two sets of items, and find four subsets:
*
* those from list A that do have matches in list B
* those from list B that do have matches in list A
* those from list A that do NOT have matches in list B
* those from list B that do NOT have matches in list A
*
* We may use the two sets of matched objects for further processing,
* so we put the names of the files containing those matched objects
* into 'matched_file_A' and 'matched_file_B' for easy reference.
*/
atMatchLists(numA, star_list_A, numB, star_list_B,
match_radius, outfile, &num_matches);
trans->nm = num_matches;
/*
* Okay, there are two possibilities at this point:
*
* 1. The user gave us information about the initial TRANS,
* either via 'intrans=' or 'identity'. We have applied
* his initial TRANS to the input list A, and looked for
* matched pairs.
*
* 2. The user didn't give us any information about an initial
* TRANS, so we called 'atFindTrans()' to find one.
* We have applied this TRANS to input list A, and
* looked for matched pairs.
*
* Now, we want to improve the initial TRANS, whether it was supplied
* by user or determined by 'atFindTrans()'. We do so by applying
* the initial TRANS to only the matched objects in list A, and then
* calling 'atRecalcTrans()' on the matched objects only. This should
* give an improved TRANS, since it very likely won't be contaminated
* by any spurious matches.
*/
/* need to send trans to prepare_to_recalc because it adds sdx,sdy to it */
if (prepare_to_recalc(outfile, &num_matched_A, &matched_list_A,
&num_matched_B, &matched_list_B,
star_list_A_copy, trans) != 0) {
shFatal("prepare_to_recalc fails");
}
/* okay, now we're ready to call atRecalcTrans, on matched items only */
if (atRecalcTrans(num_matched_A, matched_list_A,
num_matched_B, matched_list_B,
max_iter, halt_sigma, trans) != SH_SUCCESS) {
shFatal("atRecalcTrans fails on matched pairs only");
}
#ifdef DEBUG
printf("TRANS based on matches only :\n");
print_trans(trans);
#endif
/*
* At this point, we have a TRANS which is based solely on those items
* which matched. If the user wishes, we can improve the TRANS
* even more by applying the current transformation to ALL items
* in list A, making a second round of matching pairs, and then
* using these pairs to calculate a new and better TRANS.
*
* The point is that we'll probably end up with more matched pairs
* if we start with the current TRANS, instead of the initial TRANS.
*/
if (recalc == 1) {
/* re-set coords of all items in star A */
if (reset_A_coords(numA, star_list_A, star_list_A_copy) != 0) {
shFatal("reset_A_coords returns with error before recalc");
}
/*
* apply the current TRANS (which is probably much better than
* the initial TRANS) to all items in list A
*/
atApplyTrans(numA, star_list_A, trans);
/*
* Match items in list A to those in list B
*/
atMatchLists(numA, star_list_A, numB, star_list_B, match_radius,
outfile, &num_matches);
trans->nm = num_matches;
#ifdef DEBUG
printf("After tuning with recalc, num matches is %d\n", num_matches);
print_trans(trans);
#endif
/* prepare to call atRecalcTrans one last time */
/* need to send trans to prepare_to_recalc because it adds sdx,sdy */
if (prepare_to_recalc(outfile, &num_matched_A, &matched_list_A,
&num_matched_B, &matched_list_B,
star_list_A_copy, trans) != 0) {
shFatal("prepare_to_recalc fails");
}
/* final call atRecalcTrans, on matched items only */
if (atRecalcTrans(num_matched_A, matched_list_A,
num_matched_B, matched_list_B,
max_iter, halt_sigma, trans) != SH_SUCCESS) {
shFatal("atRecalcTrans fails on matched pairs only");
}
#ifdef DEBUG
printf("TRANS based on recalculated matches is \n");
print_trans(trans);
#endif
}
/*
* If the user wants summary statistics on the straight translation
* differences between the lists (without any scale or rotation),
* we calculate them now. We take all the pairs of stars which
* match -- based on their TRANSFORMED coordinates -- and go back
* to look at the differences between their ORIGINAL coordinates.
*
* This only makes sense if a pure translation connects the lists.
*/
if (medtf_flag) {
if (reset_A_coords(num_matched_A, matched_list_A,
star_list_A_copy) != 0) {
shFatal("second call to reset_A_coords returns with error");
}
medtf = atMedtfNew();
if (atFindMedtf(num_matched_A, matched_list_A,
num_matched_B, matched_list_B,
medsigclip, medtf) != SH_SUCCESS) {
shError("atFindMedtf fails");
} else {
print_medtf(medtf);
}
atMedtfDel(medtf);
}
print_trans(trans);
return(0);
}
/***********************************************************************
* FUNCTION: reset_copy_ids
*
* Modify the 'id' field values in the given list (a copy of list A)
* so that they will match the 'id' values in the corresponding
* stars of list A.
*
* We have to do this because the routine which creates new s_star
* structs keeps incrementing the 'id' values, and so the copies
* have a different value.
*
* RETURNS
* nothing
*/
static void
reset_copy_ids
(
int numA, /* I: number of stars in list A */
struct s_star *star_list_A, /* I: original star A list */
struct s_star *star_list_A_copy /* I/O: copy of star A list */
)
{
int i;
struct s_star *star, *star_copy;
star = star_list_A;
star_copy = star_list_A_copy;
for (i = 0; i < numA; i++) {
shAssert(star != NULL);
shAssert(star_copy != NULL);
star_copy->id = star->id;
star = star->next;
star_copy = star_copy->next;
}
}
/***********************************************************************
* FUNCTION: reset_A_coords
*
* Given the number of elements in list 'post_list_A',
* and two versions of the
* stars in list A (after conversion to coord system of list B,
* and before conversion), restore the original coords of stars
* in the the matched list.
*
* RETURNS
* 0 if all goes well
* 1 otherwise
*/
static int
reset_A_coords
(
int numA, /* I: number of stars in the list */
struct s_star *post_list_A, /* I/O: stars in A, after they have */
/* been matched to stars in */
/* list B; coords have been */
/* converted. We'll reset */
/* coords in this list */
struct s_star *pre_list_A /* I: stars in A, with original coords */
)
{
int post_index;
int found_it;
struct s_star *pre_star, *post_star;
/* if handed empty list, do nothing. */
if (numA == 0) {
shError("reset_A_coords: handed empty list, will do nothing");
return(0);
}
/* sanity checks */
shAssert(post_list_A != NULL);
shAssert(pre_list_A != NULL);
for (post_index = 0, post_star = post_list_A;
post_index < numA;
post_index++, post_star = post_star->next) {
shAssert(post_star != NULL);
found_it = 0;
pre_star = pre_list_A;
while (pre_star != NULL) {
if (pre_star->id == post_star->id) {
post_star->x = pre_star->x;
post_star->y = pre_star->y;
found_it = 1;
break;
}
pre_star = pre_star->next;
}
if (found_it == 0) {
printf("reset_A_coords: no match for post_star %d?\n", post_index);
shAssert(0);
}
}
return(0);
}
/**********************************************************************
* PROCEDURE: prepare_to_recalc
*
* DESCRIPTION: This function sets us up to call "atRecalcTrans".
* We have already found (or been given) a TRANS, and
* used it to match up items from list A and list B.
* Those matched items are in a pair of files
* with names based on 'outfile', but with
* extensions "mtA" and "mtB".
* Ex: if 'outfile' is "matched",
* then the two sets of matched items are in
*
* matched.mtA matched.mtB
*
* The format of each file is one star per line,
* with 4 fields:
*
* internal_ID xval yval mag
*
* where the coords (xval, yval) are in system of list B.
*
* We are about to use these good, matched items to
* find an improved TRANS -- which should take objects
* from coord system A to coord system B.
*
* In order to do that, we need to
*
* a. Read in the good, matched items. The coordinates
* of objects in list A will have been transformed
* to their corresponding values in coord system
* of list B, so ...
*
* b. We must then re-set the coords of the items in
* list A to their original values, so that we can
* re-calculate a TRANS which takes the coords
* from system A to system B.
*
* We also take this opportunity to compare the transformed
* positions of items in list A against the positions of
* the matching objects in list B. We calculate the
* RMS of the differences in both "x" and "y" directions,
* and place them into the "sx" and "sy" members of
* the current TRANS.
*
*
* RETURNS:
* 0 if all goes well
* 1 if there's an error
*/
static int
prepare_to_recalc
(
char *outfile, /* I: stem of files with matched items */
int *num_matched_A, /* O: number of stars in matched set */
/* from list A */
struct s_star **matched_list_A, /* O: fill this with matched items from */
/* list A, in coord system B */
int *num_matched_B, /* O: number of stars in matched set */
/* from list B */
struct s_star **matched_list_B, /* O: fill this with matched items from */
/* list B, in coord system B */
struct s_star *star_list_A_copy, /* O: fill this with matched items from */
/* list A, with their orig coords */
TRANS *trans /* O: we calc herein the sx, sy fields */
/* so put them into this TRANS */
)
{
char matched_file_A[CMDBUFLEN + 4];
char matched_file_B[CMDBUFLEN + 4];
double Xrms,Yrms;
shAssert(outfile != NULL);
sprintf(matched_file_A, "%s.mtA", outfile);
if (read_matched_file(matched_file_A, num_matched_A, matched_list_A)
!= SH_SUCCESS) {
shError("read_matched_file can't read data from file %s",
matched_file_A);
return(1);
}
sprintf(matched_file_B, "%s.mtB", outfile);
if (read_matched_file(matched_file_B, num_matched_B, matched_list_B)
!= SH_SUCCESS) {
shError("read_matched_file can't read data from file %s",
matched_file_B);
return(1);
}
/* here we find the rms of those stars we read in -- JPB 17/Jan/02 */
if (atCalcRMS(*num_matched_A, *matched_list_A,
*num_matched_B, *matched_list_B,
&Xrms, &Yrms) != SH_SUCCESS) {
shFatal("atCalcRMS fails on matched pairs");
}
trans->sx = Xrms;
trans->sy = Yrms;
/************************************************/
if (reset_A_coords(*num_matched_A, *matched_list_A, star_list_A_copy) != 0) {
shError("prepare_to_recalc: reset_A_coords returns with error");
return(1);
}
return(0);
}