/** @file  pmAstrometryObjects.h
*
*  @brief This file defines the basic types for matching objects
*  based on their astrometry.
*
*  @ingroup AstroImage
*
*  @author EAM, IfA
*
*  @version $Revision: 1.2 $ $Name: not supported by cvs2svn $
*  @date $Date: 2006-01-26 21:10:50 $
*
*  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
*/

#if !defined(PM_ASTROMETRYOBJECTS_H)
#define PM_PM_ASTROMETRYOBJECTS_H_H

# include <stdio.h>
# include <strings.h>  // for strcasecmp
# include <unistd.h>   // for unlink
# include <pslib.h>
# include <pmAstrometry.h>

/*
 * 
 * This structure specifies the coordinate of the detection in each of the
 * four necessary coordinate frames: pix defines the position in the psReadout
 * frame, FP defines the position in the Focal Plane frame, TP defines the
 * position in the Tangent Plane frame, sky defines the position on the Celestial
 * Sphere. In addition, a measurement of the brightness is given by the element
 * Mag. Such a data structure should be used for both the raw and the reference
 * stars. In astrometric processing, the raw detections will be projected using
 * the best available information to each of these coordinate frames from the pix
 * coordinates, while the reference detections will be projected to the other
 * frames from the sky coordinates.
 * 
 * XXX: There are more members here than in the SDRS.
 * 
 */
typedef struct
{
    psPlane pix;                        ///< the position in the pmReadout frame
    psPlane cell;                       ///< the position in the pmCell frame
    psPlane chip;                       ///< the position in the pmChip frame
    psPlane FP;                         ///< the position in the pmFPA frame
    psPlane TP;                         ///< the position in the tangent plane
    psSphere sky;                       ///< the position on the Celestial Sphere.
    double Mag;                         ///< A measurement of the brightness.
    double dMag;                        ///< What is this?
}
pmAstromObj;



/*
 * 
 * The pmAstromMatch structure defines the cross-correlation between two
 * arrays. A single such data item specifies that item number pmAstromMatch.idx1
 * in the first list corresponds to pmAstromMatch.idx2 in the second list.
 * 
 */
typedef struct
{
    int i1;                             ///< What is this?
    int i2;                             ///< What is this?
}
pmAstromMatch;


/*
 * 
 * XXX: Not in SDRS.
 * 
 */
typedef struct
{
    psPlane center;                     ///<
    psPlane offset;                     ///<
    double  angle;                      ///<
    double  minMetric;                  ///<
    double  minVar;                     ///<
    int     nMatch;                     ///<
}
pmAstromStats;



/*
 * 
 * If the two sets of coordinates are expected to agree very well (ie, the
 * current best-guess astrometric solution is quite close to the radius. The
 * following function accepts two sets of pmAstromObj sources and determines the
 * matched objects between the two lists. The input sources must have been
 * projected to the Focal Plane coordinates (pmAstromObj.FP), and the supplied
 * options entry must contain the desired match radius (keyword:
 * ASTROM.MATCH.RADIUS). The output consists an array of pmAstromMatch values,
 * defined below.
 * 
 */
psArray *pmAstromRadiusMatch(
    psArray *st1,
    psArray *st2,
    psMetadata *config
);



/*
 * 
 * This function accepts an array of pmAstromObj objects and rotates them by
 * the given angle about the given center coordinate pCenter,qCenter in the Focal
 * Plane Array coordinates.
 * 
 * XXX: This differs from the SDRS
 * 
 */
/* SDRS
psArray *pmAstromRotateObj(
    psArray *old,
    double angle,
    double pCenter,
    double qCenter
);
*/
psArray *pmAstromRotateObj(
    psArray *old,
    psPlane center,
    double angle
);


/*
 * 
 * If the two sets of coordinates are not known to agree well, but the
 * relative scale and approximate relative rotation is known, then a much faster
 * match can be found using pair-pair displacements. In such a case, the two
 * lists can be considered as having the same coordinate system, with an unknown
 * relative displacement. In this algorithm, all possible pair-wise differences
 * between the source positions in the two lists are constructed and accumulated
 * in a grid of possible offset values. The resulting grid is searched for a
 * cluster representing the offset between the two input lists. This algorithm
 * can only tolerate a small error in the relative scale or the relative rotation
 * of the two coordinate lists. However, this process is naturally O(N2), and is
 * thus advantageous over triangle matching in some circumstances. This process
 * can be extended to allow a larger uncertainty in the relative rotation by
 * allowing the procedure to scan over a range of rotations. We define the
 * following function to apply this matching algorithm:
 * 
 * XXX: In the SDRS, this function is a pointer.
 * 
 */
pmAstromStats pmAstromGridMatch(
    psArray *st1,
    psArray *st2,
    psMetadata *config
);


/*
 * 
 * The result of a pmAstromGridMatch may be used to modify the astrometry
 * transformation information for a pmFPA image hierarchy structure. The result
 * of pmAstromGridMatch defines the adjustments which should be made to the
 * reference coordinate of the projection (pmFPA.projection.R,D) and the
 * effective rotation of the Focal Plane.  The rotation implies modification of
 * the linear terms of the pmFPA.toTangentPlane transformation. These two
 * adjustments are made using the function:
 * 
 * XXX: This function name is different in the SDRS.
 * 
 */
psPlaneTransform *pmAstromGridApply(
    psPlaneTransform *map,
    pmAstromStats stat
);


/*
 * 
 * This function is identical to pmAstromGridMatch, but is valid for only a
 * single relative rotation. The input config information need not contain any of
 * the GRID.*.ANGLE entries (they will be ignored).
 * 
 */
/* in pmAstromGrid.c */
pmAstromStats pmAstromGridAngle(
    psArray *st1,
    psArray *st2,
    psMetadata *config);



/*
 * 
 * This function accepts the raw and reference source lists and the list of
 * matched entries. It uses the matched list to determine a polynomial
 * transformation between the two coordinate systems. The fitting uses clipping
 * to exclude outliers, likely representing poor matches. The config element must
 * contain the information ASTROM.NSIGMA (specifying the number of sigma used in
 * the clipping) and ASTROM.NCLIP (specifying the number of clipping iterations
 * must be performed). The config element must also specify the order of the
 * polynomial fit (keyword: ASTROM.ORDER). The result of this fit is a set of
 * modifications of the components of the pmFPA.toTangentPlane transformation,
 * and the modifications of the reference coordinate of the projection
 * (pmFPA.projection.R,D) and the projection scale (pmFPA.projection.Xs,Ys). The
 * modifications to pmFPA.toTangentPlane incorporate the rotation component of
 * the linear terms and the higher-order terms of the polynomial fits.
 * 
 * XXX: No prototype code.
 * 
 */
bool pmAstromFitFPA(
    pmFPA *fpa,
    psArray *st1,
    psArray *st2,
    psArray *match,
    psMetadata *config
);



/*
 *
 * This function accepts the raw and reference source lists for a single chip
 * and the list of matched entries. It uses the matched list to determine a
 * polynomial transformation between the two coordinate systems. The fitting
 * uses clipping to exclude outliers, likely representing poor matches. The
 * config element must contain the information ASTROM.NSIGMA
 *(specifying the number of sigma used in the clipping) and ASTROM.NCLIP
 *(specifying the number of clipping iterations must be performed). The config
 *element must also specify the order of the polynomial fit (keyword:
 *ASTROM.ORDER).  The result of this fit is a set of modifications of the
 *components of the pmChip.toFPA transformation.
 * 
 * XXX: No prototype code.
 * 
 */
bool pmAstromFitChip(
    pmFPA *fpa,
    psArray *st1,
    psArray *st2,
    psArray *match,
    psMetadata *config
);


/*
 * 
 * The following function determines the position residual, in the tangent
 * plane, as a function of position in the focal plane, for a collection of raw
 * measurements and matched reference stars. The configuration data must include
 * the bin size over which the gradient is measured (keyword: ASTROM.GRAD.BOX).
 * The function returns an array of pmAstromGradient structures, defined below.
 * 
 * XXX: No prototype code.
 * 
 */
psArray pmAstromMeasureGradients(
    psArray *starlist1,
    psArray *starlist2,
    psArray *match,
    psMetadata *config
);



/*
 * 
 * The following data structure carries the information about the residual
 * gradient of source positions in the tangent plane (pmAstromObj.TP) as a
 * function of position in the focal plane (pmAstromObj.FP).
 * 
 */
typedef struct
{
    psPlane FP;
    psPlane dTPdL;
    psPlane dTPdM;
}
pmAstromGradient;


/*
 * 
 * The gradient set measured above can be fitted with a pair of 2D
 * polynomials. The resulting fits can then be related back to the implied
 * polynomials which represent the distortion. The following function performs
 * the fit and applies the result to the distortion transformation of the
 * supplied pmFPA structure. The configuration variable supplies the polynomial
 * order (keyword: ASTROM.DISTORT.ORDER).
 * 
 * XXX: No prototype code.
 * 
 */
psArray pmAstromFitDistortion(
    pmFPA *fpa,
    psArray *gradients,
    psMetadata *config);





/*******************************************************************************
 The following functions and structs were in the prototype code, but not the
 SDRS.
 ******************************************************************************/
/*
 * 
 * 
 * 
 * 
 */


/*
 * 
 * Allocates a pmAstromObj struct.
 * 
 */
pmAstromObj *pmAstromObjAlloc (void);



/*
 * 
 * Copies a pmAstromObj struct.
 * 
 */
pmAstromObj *pmAstromObjCopy(
    pmAstromObj *old
);



/*
 * 
 * 
 * 
 */
pmAstromMatch *pmAstromMatchAlloc(
    int i1,
    int i2
);




/*
 * 
 * 
 * 
 */
psPlaneTransform *pmAstromMatchFit(
    psPlaneTransform *map,
    psArray *st1,
    psArray *st2,
    psArray *match,
    psMetadata *config
);



/*
 * 
 * 
 * 
 */
int pmAstromObjSortByFPX(
    const void **a,
    const void **b
);



/*
 * 
 * 
 * 
 */
int pmAstromObjSortByMag(
    const void **a,
    const void **b
);

#endif

