/****************************************************************/
/* find_normal() - Function to find the set of normal equations	*/
/*		   that allow a quadratic trend surface to be	*/
/*		   fitted through N  points using least squares	*/
/* 		   V.1.0, Jo Wood, 27th November, 1994.  	*/
/****************************************************************/

#include "param.h"

void find_normal(double **normal,	/* Matrix of cross-products.	*/
		 double *w)		/* Weights matrix.		*/
{
    int edge=EDGE;		/* Store (wsize-1)/2 to save	*/
				/* on computation 		*/	 

    float  x,y,			/* Local coordinates of window.	*/
	   x1=0,y1=0,		/* coefficients of X-products.	*/
	   x2=0,y2=0,
	   x3=0,y3=0,
	   x4=0,y4=0,
	   xy2=0, x2y=0,
	   xy3=0, x3y=0,
 	   x2y2=0,xy=0,
  	   N=0;
	   
    int   row,col;		/* Pass through local window.	*/


    /* Initialise sums-of-squares and cross products matrix */

    for (row=0; row<6; row++)
        for (col=0; col<6;col++)
            normal[row][col] = 0.0;


    /* Calculate matrix of sums of squares and cross products */

    for (row=0; row<wsize; row++)
	for (col=0; col<wsize; col++)
	{
	   x = resoln*(col-edge); 
	   y = resoln*(row-edge);

	   x4   += x*x*x*x* *(w + row*wsize + col);
 	   x2y2 += x*x*y*y* *(w + row*wsize + col);
	   x3y  += x*x*x*y* *(w + row*wsize + col);
     	   x3   += x*x*x*   *(w + row*wsize + col);
	   x2y  += x*x*y*   *(w + row*wsize + col);
	   x2   += x*x*     *(w + row*wsize + col);

	   y4   += y*y*y*y* *(w + row*wsize + col);
   	   xy3  += x*y*y*y* *(w + row*wsize + col);
	   xy2  += x*y*y*   *(w + row*wsize + col);
	   y3   += y*y*y*   *(w + row*wsize + col);
	   y2   += y*y*     *(w + row*wsize + col);

	   xy   += x*y*     *(w + row*wsize + col);

	   x1   += x*       *(w + row*wsize + col);

	   y1   += y*       *(w + row*wsize + col);

	   N    +=          *(w + row*wsize + col);

	}

   /* --- Store cross-product matrix elements. ---*/

    normal[0][0] = x4;
    normal[0][1] = normal[1][0] = x2y2;
    normal[0][2] = normal[2][0] = x3y;
    normal[0][3] = normal[3][0] = x3;
    normal[0][4] = normal[4][0] = x2y;
    normal[0][5] = normal[5][0] = x2;

    normal[1][1] = y4;
    normal[1][2] = normal[2][1] = xy3;
    normal[1][3] = normal[3][1] = xy2;
    normal[1][4] = normal[4][1] = y3;
    normal[1][5] = normal[5][1] = y2;

    normal[2][2] = x2y2;
    normal[2][3] = normal[3][2] = x2y;
    normal[2][4] = normal[4][2] = xy2;
    normal[2][5] = normal[5][2] = xy;

    normal[3][3] = x2;
    normal[3][4] = normal[4][3] = xy;
    normal[3][5] = normal[5][3] = x1;
    
    normal[4][4] = y2;
    normal[4][5] = normal[5][4] = y1;

    normal[5][5] = N;
}


/****************************************************************/
/* find_obs() - Function to find the observed vector as part of	*/
/*		the set of normal equations for least squares.	*/
/* 		V.1.0, Jo Wood, 11th December, 1994.	 	*/
/****************************************************************/

void find_obs(DCELL  *z,		/* Local window of elevs.	*/
	 double *obs,		/* Observed column vector.	*/
	 double  *w)		/* Weighting matrix.		*/
{

    int	row,col,		/* Counts through local window.	*/
	edge=EDGE,		/* EDGE = (wsize-1)/2.		*/
	offset;			/* Array offset for weights & z	*/

    float x,y;			/* Local window coordinates.	*/

    for (row=0;row<6; row++)	/* Initialise column vector.	*/
	obs[row] = 0.0;


    for (row=0;row<wsize; row++)
	for (col=0; col<wsize; col++)
	{
	    x = resoln*(col-edge); 
	    y = resoln*(row-edge);
 	    offset = row*wsize + col;

	    obs[0] += *(w + offset) * *(z + offset) * x*x ;
	    obs[1] += *(w + offset) * *(z + offset) * y*y ;
	    obs[2] += *(w + offset) * *(z + offset) * x*y ;
	    obs[3] += *(w + offset) * *(z + offset) * x ;
	    obs[4] += *(w + offset) * *(z + offset) * y ;

	    if (!constrained)	/* If constrained, should remain 0.0 */
	 	obs[5] += *(w + offset) * *(z + offset) ;
	}
}


/****************************************************************/
/* find_weight() Function to find the weightings matrix for the */
/*               observed cell values.				*/
/*		 Uses an inverse distance function that can be  */
/*		 calibrated with an exponent (0= no decay,	*/
/*		 1=linear decay, 2=squared distance decay etc.)	*/
/*               V.1.1, Jo Wood, 11th May, 1995.		*/
/****************************************************************/

void find_weight(double *weight_ptr)
{
    int	edge=EDGE;		/* EDGE = (wsize-1)/2.		*/
    int row,col;		/* Counts through the rows and	*/
				/* columns of weights matrix.	*/

    double dist;		/* Distance to centre of kernel.*/


    /* --- Find inverse distance of all cells to centre. ---*/

    for (row=0; row<wsize; row++)
	for (col=0; col<wsize; col++)
	{
	    dist = 1.0 /
		pow(sqrt((edge-col)*(edge-col) + (edge-row)*(edge-row))+1.0,exponent);
	    *(weight_ptr + row*wsize + col) = dist;
	}
}

