/* ***************************************
 * *                                     *
 * *  HiMath Library Related Structures  *
 * *                                     *
 * ***************************************
 * File: include/himath_lib.h
 *
 *  COPYRIGHT (c) 1989, 1990, 1992, 1995, 1996, 1997, 1998, 2001, 2002,
 *                          2003, 2008, 2011 BY 
 *            VAISALA INC., WESTFORD MASSACHUSETTS, U.S.A.  
 * 
 * THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND  COPIED
 * ONLY  IN  ACCORDANCE WITH  THE  TERMS  OF  SUCH  LICENSE  AND WITH THE
 * INCLUSION OF THE ABOVE COPYRIGHT NOTICE.  THIS SOFTWARE  OR  ANY OTHER
 * COPIES  THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY
 * OTHER PERSON.  NO TITLE TO AND OWNERSHIP OF  THE  SOFTWARE  IS  HEREBY
 * TRANSFERED. 
 */ 
#ifndef SIGMET_HIMATH_LIB_H
#define SIGMET_HIMATH_LIB_H 1

#define HIMATH_FFT_NOMEM      (HIMATH_FACILITY + 17)
#define HIMATH_FFT_SIZE       (HIMATH_FACILITY + 18)
#define HIMATH_LSQ_ORDER      (HIMATH_FACILITY + 25)
#define HIMATH_LSQ_POLY       (HIMATH_FACILITY + 26)
#define HIMATH_MPJ_BADARG     (HIMATH_FACILITY + 27)
#define HIMATH_MPJ_BADPROJ    (HIMATH_FACILITY + 28)
#define HIMATH_MPJ_BADREGION  (HIMATH_FACILITY + 29)
#define HIMATH_MPJ_DIVERGE    (HIMATH_FACILITY + 30)
#define HIMATH_MPJ_RESCALE    (HIMATH_FACILITY + 31)
#define HIMATH_MPJ_UNDERSPC   (HIMATH_FACILITY + 32)
#define HIMATH_MPJ_ZMAPSIZE   (HIMATH_FACILITY + 33)
#define HIMATH_MPJ_ZPIXSIZE   (HIMATH_FACILITY + 34)
#define HIMATH_POLY_ORDER     (HIMATH_FACILITY + 38)
#define HIMATH_POLY_ZDIV      (HIMATH_FACILITY + 39)

/* =============== Function prototypes for HiMath library ===================
 */
#ifdef __cplusplus
extern "C" {
#endif

/* Fast Fourier transform and correlation routines for all hardware
 * platforms (better to use IntelIPP for dedicated Linux/PC).
 */
#define FFT_INVERSE (0x01)	/* Control flag values for FFT */
#define FFT_SCALE   (0x02)	/*  routines. */

#define FFT_MAXSIZELOG 16	/* Largest FFT we're willing to do */

MESSAGE fft_complex
( const float *freal_in_a,	/* Real input data */
  const float *fimag_in_a,	/* Imaginary input data */
  int32_t inc_in_a,		/* Increment between input values */
  float *freal_out_a,		/* Real output data */
  float *fimag_out_a,		/* Imaginary output data */
  int32_t inc_out_a,		/* Increment between output values */
  int32_t iszlog_a,		/* LOG base 2 of xform size */
  uint32_t iflags_a ) ;		/* Control Flags */

MESSAGE dft_or_fft_complex
( const float *freal_in_a,	/* Real input data */
  const float *fimag_in_a,	/* Imaginary input data */
  int32_t inc_in_a,		/* Increment between input values */
  float *freal_out_a,		/* Real and imaginary output data */
  float *fimag_out_a,		/*   (okay to overlap input data) */
  int32_t inc_out_a,		/* Increment between output values */
  int32_t iSize_a,		/* Transform size */
  uint32_t iflags_a ) ;		/* Control Flags (from FFT_xxx) */

MESSAGE fft_initmem
( int32_t maxszlog_a ) ;

MESSAGE fft_real_input
( const float *freal_in_a,	/* Real input data */
  int32_t inc_in_a,		/* Increment between input values */
  float *freal_out_a,		/* Real output data */
  float *fimag_out_a,		/* Imaginary output data */
  int32_t inc_out_a,		/* Increment between output values */
  int32_t iszlog_a,		/* LOG base 2 of xform (input array) size */
  uint32_t iflags_a ) ;		/* Control Flags */

MESSAGE fft_real_output
( const float *freal_in_a,	/* Real input data */
  const float *fimag_in_a,	/* Imaginary input data */
  int32_t inc_in_a,		/* Increment between input values */
  float *freal_out_a,		/* Real output data */
  int32_t inc_out_a,		/* Increment between output values */
  int32_t iszlog_a,		/* LOG base 2 of xform (output array) size */
  uint32_t iflags_a ) ;		/* Control Flags */

MESSAGE fft_real_2d_xcor
( const float *freal1_a,		/* First real input array */
  const float *freal2_a,		/* Second real input array */
  int32_t inxsize_a,		/* Dimensions of input arrays */
  int32_t inysize_a,
  float *fcorel_a,		/* Real output crosscorrelation array */
  int32_t ioutxsz_a,		/* Dimensions of output array */
  int32_t ioutysz_a,
  int32_t ixzpos_a,		/* Location of zero position in output array */
  int32_t iyzpos_a ) ;

int32_t ibitrev
( int32_t iarg_a,
  int32_t isize_a ) ;

/* Fundamental matrix and vector operations
 */
double double_dot_product
( const double *va_a,
  const double *vb_a,
  SINT4 iSize_a );

int idouble_matrix_invert
( double *in_a,
  double *out_a,
  SINT4 iSize_a );

int isingle_matrix_invert
( float *in_a,
  float *out_a,
  SINT4 iSize_a );

void himath_lib_nls_init(void); /* File: himath_lib_message_init.c */
#define HIMATH_LIB_INIT himath_lib_nls_init()

/* Fundamental operations on polynomials
 */
void poly_add
( const struct polynomial *arg1_a,
  const struct polynomial *arg2_a,
  struct polynomial *sum_a ) ;

void poly_sub
( const struct polynomial *arg1_a,
  const struct polynomial *arg2_a,
  struct polynomial *diff_a ) ;	/* Set to arg1 - arg2 */

void poly_mpy
( const struct polynomial *arg1_a,
  const struct polynomial *arg2_a,
  struct polynomial *prod_a ) ;

void poly_div
( const struct polynomial *num_a,     /* Numerator */
  const struct polynomial *den_a,     /* Denominator */
  struct polynomial *quo_a,	      /* Quotient */
  struct polynomial *rem_a ) ;	      /* Remainder */

void poly_deriv
( const struct polynomial *poly_a,
  struct polynomial *deriv_a ) ;

FLT4 fpoly_eval
( const struct polynomial *poly_a,
  FLT4 fxval_a ) ;

FLT8 fpoly_eval8
( const struct polynomial *poly_a,
  FLT8 dxval_a);
  
void poly_at_poly
( const struct polynomial *poly_a,
  const struct polynomial *arg_a,
  struct polynomial *prod_a ) ;	      /* poly_a( arg_a ) */

FLT8 fpoly_length8
( const struct polynomial *poly_a,
  const FLT8 fXLimits_a[2] );

void poly_zeros8
( const struct polynomial *poly_a,
  SINT4 *icount_a,
  double fzeros_a[]) ;

/* Line fitting, curve fitting, and least squares routines
 */
MESSAGE lsq_init
( struct lsquare8 *lsq_a,
  SINT4 order_a ) ;

SINT4 ilsq_accum
( struct lsquare8 *lsq_a,
  double xval_a,
  double yval_a,
  double fWeight_a ) ;

SINT4 ilsq_merge
( struct lsquare8 *sum_a,
  struct lsquare8 *new_a ) ;

SINT4 ilsq_stats8
( struct lsquare8 *lsq_a,
  double *fxmean_a,		/* Mean X value */
  double *fymean_a ) ;		/* Mean Y value */

MESSAGE polyfit_stats
( struct lsquare8 *lsq_a,
  struct polynomial *poly_a,  /* Polynomial coefficient structure a0, a1, ...  */
  FLT4 *error_a,              /* Mean square deviation of the polynomial */
  SINT4 order_a ) ;	      /* Order of the polynomial to be fit */

MESSAGE polyfit_stats8
( struct lsquare8 *lsq_a,
  struct polynomial *poly_a,  /* Polynomial coefficient structure a0, a1, ...  */
  double *fError_a,           /* Mean square deviation of the polynomial */
  SINT4 order_a ) ;	      /* Order of the polynomial to be fit */

void normfit_stats
( struct lsquare8 *lsq_a,
  double *angle_a,
  double *offset_a, 
  double *error_a,
  double *ferror_perp_a ) ;

/* Given a map projection definition, and a pinned region structure,
 * convert a Lat/Lon Earth location to a pixel coordinate.  The units for
 * the pixel coordinates are such that (0,0) corresponds to the lower left
 * corner of the region, and (fxpix, fypix) corresponds to the upper right.
 * Note that the center of the lower left corner pixel would by (0.5,0.5).
 */
#ifdef SIGMET_PROJECTION_H 
MESSAGE mpj_earth_to_pixel
( const struct mpj_projection8 *projection_a, /* Type of map projection */
  const struct mpj_region8 *region_a, 	      /* Region structure (already pinned) */
  volatile const struct latlon8 *pEarth_a,    /* Earth coordinates (radians) */
  struct XYPoint8 *pPixel_a,                  /* Pixel coordinates */
  uint8_t *plValid_a );                       /* Pixel value is valid */

  /* Extract information about the Earths's Geode model from the projection definition. */
void mpj_get_geode_info
( double *pfa_a,    /* a is the equitorial radius of the earth in meters */
  double *pfb_a,    /* b is the polar radius of the earth in meters */
  double *pfe_a,    /* e is the eccentricity of the earth */
  double *pff_a,    /* f is 1/the flattening of the earth, 0 for circular */
  const struct mpj_projection8 *projection_a );

/* Return the reverse flattening from the a and b earth radii. */
double mpj_rf_from_a_b
( double fa_a,     /* a is the equitorial radius of the earth in meters */
  double fb_a );   /* b is the polar radius of the earth in meters */

MESSAGE mpj_pixel_to_earth
( const struct mpj_projection8 *projection_a, /* Type of map projection */
  const struct mpj_region8 *region_a, 	      /* Region structure (already pinned) */
  const struct XYPoint8  *pPixel_a,	      /* Pixel coordinates */
  volatile struct latlon8 *pEarth_a );        /* Earth coordinates (radians) */

/* Pin region, override latitudes to hit specified Y size. */
MESSAGE mpj_pin_region_xy
(const struct mpj_projection8 *pProjection_a, /* Type of map projection */
 struct mpj_region8 *pRegion_a,	              /* Entry and Exit region structure */
 uint32_t iMask_a);                           /* Mask of valid region parameters */

/* Pin region, Y size is filled in */
MESSAGE mpj_pin_region_x
( const struct mpj_projection8 *projection_a, /* Type of map projection */
  struct mpj_region8 *region_a, 	      /* Entry and Exit region structure */
  uint32_t imask_a );		              /* Mask of valid region parameters */

MESSAGE mpj_rescale_region
( const struct mpj_projection8 *projection_a, /* Type of map projection */
  struct mpj_region8 *region_a, 	      /* Entry and Exit region structure */
  uint32_t imask_a,                           /* Mask of fixed region parameters */
  double fratio_a ) ;		              /* Desired height/width ratio */

  MESSAGE mpj_earth_to_map  /* Internal routine, do not call */
(const struct mpj_projection8 *projection_a, /* Type of map projection */
 volatile const struct latlon8 *pEarth_a,    /* Earth coordinates (radians) */
 struct XYPoint8 *pMap_a,                    /* Map coordinates (unit earth) */
 uint8_t *plValid_a );                       /* Map output is valid */

  MESSAGE mpj_map_to_earth  /* Internal routine, do not call */
(const struct mpj_projection8 *projection_a, /* Type of map projection */
 const struct XYPoint8 *pMap_a,              /* Map coordinates (unit earth) */
 volatile struct latlon8 *pEarth_a );        /* Earth coordinates (radians) */

  MESSAGE mpj_validate_projection  /* Checks for possible invalid projection */
  (const struct mpj_projection8 *projection_a) ;/* Type of map projection */

  /* Access functions to get the various values from the region. */
  double mpj_get_earth_de( const struct mpj_region8 *pRegion_a );
  void mpj_set_earth_de( struct mpj_region8 *pRegion_a, double fkm_a );
  double mpj_get_earth_scale_e( const struct mpj_region8 *pRegion_a );

  double mpj_get_earth_dn( const struct mpj_region8 *pRegion_a );
  void mpj_set_earth_dn( struct mpj_region8 *pRegion_a, double fkm_a );
  double mpj_get_earth_scale_n( const struct mpj_region8 *pRegion_a );

  double mpj_get_map_de( const struct mpj_region8 *pRegion_a );

  void mpj_set_map_de( struct mpj_region8 *pRegion_a, double fkm_a );

  double mpj_get_map_dn( const struct mpj_region8 *pRegion_a );

  void mpj_set_map_dn( struct mpj_region8 *pRegion_a, double fkm_a );
  double mpj_get_map_scale( const struct mpj_region8 *pRegion_a );

#endif  /* #ifdef SIGMET_PROJECTION_H */

/* Two-Dimensional polynomial evaluation and curve fitting.
 */
void  xypolyAreaFit
( struct xypoly_area8 *area_a, FLT4 (*Zfunc_a)( FLT4 fx_a, FLT4 fy_a ),
  FLT4 fMinX_a, FLT4 fMaxX_a, FLT4 fMinY_a, FLT4 fMaxY_a,
  SINT4 iOrder_a, UINT4 iIgnoreMask_a, UINT4 iFlags_a ) ;

FLT4 fxypolyAreaEval( const struct xypoly_area8 *area_a, FLT4 fx_a, FLT4 fy_a ) ;

void  xypolyLSQInit( struct xypoly_lsq8 *lsq_a, SINT4 iOrder_a ) ;
void xypolyLSQAccum( struct xypoly_lsq8 *lsq_a, FLT8 fx_a, FLT8 fy_a, FLT8 fz_a ) ;

FLT8 fxypolyLSQFitter
( const struct xypoly_lsq8 *lsq_a, struct xypoly8 *xypoly_a, SINT4 iOrder_a,
  UINT4 iIgnoreMask_a ) ;

void xypolyMakeXYTerms( struct xypoly8 *xypoly_a, FLT8 fx_a, FLT8 fy_a ) ;
FLT8       fxypolyEval( const struct xypoly8 *xypoly_a, FLT8 fx_a, FLT8 fy_a ) ;
void    xypolyInitZero( struct xypoly8 *xypoly_a, SINT4 iOrder_a ) ;
SINT4  ixypolyNumTerms( SINT4 iOrder_a ) ;
SINT4  ixypolyNumUDiag( SINT4 iOrder_a ) ;

/* Trigonometry and Geometry
 */
UINT1 triangle_sas
( FLT8  fside1_a,
  FLT8  fside2_a,
  FLT8 *fside3_a,
  FLT8 *fangle1_a,
  FLT8 *fangle2_a,
  FLT8  fangle3_a );

UINT1 triangle_ssa
( FLT8  fside1_a,
  FLT8  fside2_a,
  FLT8 *fside3_a,
  FLT8  fangle1_a,
  FLT8 *fangle2_a,
  FLT8 *fangle3_a );

#ifdef __cplusplus
}
#endif
#endif /* #ifndef SIGMET_HIMATH_LIB_H */
