/*------------------------------------------------------------------------------*
 *	File Name: 	ocm.h															*
 *	Purpose: math functions for Origin C										*
 *  Creation: CPY																*
 *  	Copyright (c) OriginLab Corp.	2006									*
 *	All Rights Reserved															*
 *					                                                        	*
 *	Modification log                                                        	*
 *	Cheney 2006-7-20 LLVC_WEIGHTED_ADJAVE_SMOOTH								*
 *	ML 8/23/2006 CALLBACK_FROM_VC_INTO_OC										*
 *	ML 1/29/2007 QA70-9322 EXPORT_MACRO_MISSING									*
 *	Fisher 1/18/2008 REPLACE_OCMATH2_PARTIAL_DERIVATIVE_Y_BY_OCMATH2_PARTIAL_DERIVATIVE_COL_WISE
 *	Fisher 1/18/2008 REPLACE_OCMATH2_PARTIAL_DERIVATIVE_X_BY_OCMATH2_PARTIAL_DERIVATIVE_ROW_WISE
 *	Fisher 1/18/2008 ADD_OCMATH2_DERIVATIVE_POINT_WISE							*
 *	Fisher 1/18/2008 ADD_OCMATH2_DERIVATIVE										*
 *	Cloud 03/08/2008 USE_NAG_OPTIMIZER_FOR_MULTIPLE_REGRESSION					*
 *	Jack 03/17/2008 ADD_LOCAL_MAXIMUM_2D_FIND_PEAKS_ALGORITHM					*
 *  Jack 03/20/2008 UNIFY_API_INTERFACE_PARAMETER_WITH_LOCAL_MAXIMUM_METHOD     *
 *	Jack QA-12334 10/09/2008 ADD_GET_LARGEST_NEG_POS_PEAK_AND_INDEX_FOR_MATRIX  *
 *------------------------------------------------------------------------------*/

#ifndef _OCM_H
#define _OCM_H

#ifdef _MSC_VER
	#ifdef OCMATH2_DLL
		#define OC_API __declspec(dllexport)
		#pragma message("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$we are in ocmath2 dll")
	#else
		#define OC_API __declspec(dllimport)
		#pragma message("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$we are NOT in ocmath2 dll, but some other DLL")
	#endif
	
	#define uint UINT

	#ifdef __cplusplus
		extern "C" {
			#pragma message("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ extern C in ocm.h")
	#endif
#else
	#define OC_API
	#pragma dll(ocmath2)	// Associate all functions below to omath2.dll which must be in the Origin EXE folder
#endif	//_MSC_VER

#ifndef _VC_EDGEPAD_DEF
	#define _VC_EDGEPAD_DEF
	enum {
		EDGEPAD_ZERO, 
		EDGEPAD_REFLECT, 
		EDGEPAD_REPEAT, 
		EDGEPAD_EXTRAPOLATE, 
		EDGEPAD_PERIODIC
	};
#endif	//_VC_EDGEPAD_DEF

enum{
	OCM_NOERROR = 0,
	OCM_UNKOWN_ERROR = -1,
	OCM_SIZE_LT = -2,
	OCM_RANGE_ZERO = -3,
	OCM_INVALID_WINSIZE = -4,
	OCM_INVALID_SIZE = -5,
	OCM_INVALID_RANGE = -6,
	OCM_LACKPOINTS = -7,
	OCM_INVALID_POINT = -8,
	OCM_SMOOTHPTS_LT_ZERO = -9,
	OCM_UNKNOWN_METHOD = -10,
	OCM_NULL_POINTER = -11,
	OCM_INVALID_DIMENSION = -12,
	OCM_INVALID_DATASIZE = -13,

	OCM_REAL_ARG_LT = -14,
	OCM_INT_ARG_LT = -15,
	OCM_NOT_INCREASING = -16,
	OCM_NOT_STRICTLY_INCREASING = -17,
	OCM_BAD_PARAM = -18,
	OCM_ALLOC_FAIL = -19,
	OCM_ABSCI_OUTSIDE_KNOT_INTVL = - 20,
	OCM_WEIGHTS_NOT_POSITIVE = - 21,
	OCM_DATA_ILL_CONDITIONED = - 22,
	OCM_COEFF_CONV = - 23,
	OCM_END_KNOTS_CONS = -24,
	OCM_POINT_OUTSIDE_RECT = -25,
	OCM_NUM_KNOTS_1D_GT = -26,
	OCM_ENUMTYPE_WARM = -27,
	OCM_SF_D_K_CONS = -28,
	OCM_RANGE_INVALID = -29,

	OCM_INCOMPATIBLE_X_COL = -30,
	OCM_DEVIDED_BY_ZERO	= -31,
	OCM_NOT_SPACED_EQUALLY = -32,
    OCM_CANNOT_SORT = -33,
	OCM_DUPLICATE_POINT = -34,
	OCM_TPS_INVALID_SMOOTH = -35,
	OCM_TPS_INVALID_FIT = -36,
	OCM_INVALID_PARAMETERS = -37,
	OCM_KRIG_SOLVE_LINEAR_SYSTEM_FAIL = -38,
	OCM_AVMC_NO_OVERLAPPED_PTS = -39,
	OCM_AVMC_BUFFER_TOO_SMALL = -40,
	OCM_UNDERFLOW = -41,
	OCM_OVERFLOW = -42,
	OCM_TOLERANCE_TOO_SMALL = -43,
	OCM_TOLERANCE_TOO_LARGE = -44,
	OCM_REDUCE_DATA_FAILED = -45,
};

OC_API int ocm_fit_slope(UINT nSize, const double* px, const double* py, double* pSlope);


/* 	Remarks:
 * 		Function to calculate the derivative point-wise. The number of nearest points used for forward
 * 		and backward difference are given by the parameter nLeftPts and nRightPts.
 * 
 * 	Parameters:
 * 		pXData=Input			vector that contains the X data, with size nSize
 * 		pYData=[Input]			vector that contains the Y data, with size nSize
 * 		nSize=[Input]			the size of input vector
 * 		iX=[Input]				the index of point that needed to calculate the derivative by X
 * 		dDev=[Output]			the pointer for the output derivative value
 *		dwCntrl=[input] 		options, DERV_PEAK_AS_ZERO, will fill zero if data change direction, otherwise the average is used
 * 		nLeftPts=[Input]		the number of nearest points used for backward difference, default is 1
 * 		nRightPts=[Input]		the number of nearest points used for forward difference, default is -1, which means equal to the nLeftPts
 * 
 * 	Return:
 * 		Return OE_NOERROR if succeed, otherwise, non-zero error code is returned.
 */
OC_API int ocm_derivative_point_wise(const double* pXData, double* pYData, UINT nSize, UINT iX, double *dDev, DWORD dwCntrl=0, int nLeftPts=1, int nRightPts=-1);


/* 	Remarks:
 * 		Function to calculate the derivative of a curve. The number of nearest points used for forward
 * 		and backward difference are given by the parameter nLeftPts and nRightPts.
 * 
 * 	Parameters:
 * 		pXData=Input			vector that contains the X data, with size nSize
 * 		pYData=[Input/Output]	vector that contains the Y data, with size nSize, output with the derivative by X
 * 		nSize=[Input]			the size of input vector
 *		dwCntrl=[input] 		options, DERV_PEAK_AS_ZERO, will fill zero if data change direction, otherwise the average is used
 * 		nLeftPts=[Input]		the number of nearest points used for backward difference, default is 1
 * 		nRightPts=[Input]		the number of nearest points used for forward difference, default is -1, which means equal to the nLeftPts
 * 
 * 	Return:
 * 		Return OE_NOERROR if succeed, otherwise, non-zero error code is returned.
 */
OC_API int ocm_derivative(const double* pXData, double* pYData, UINT nSize, DWORD dwCntrl = 0, int nLeftPts=1, int nRightPts=-1);


/**
	Remarks:
		Function to calculate the partial derivative row-wise. The number of nearest points used for forward
		and backward difference are given by the parameter nLeftPts and nRightPts.

	Example 1:
		void partial_derivative_ex1(void)
		{
			matrix mat = {{0, 0, 0}, {0, 1, 0}, {0, 0, 0}, {0, 0, 0}};
			vector vz;
			int ii, jj;
			MatrixPage mp;

			mat.GetAsVector(vz);
			
			ocm_partial_derivative_row_wise(3, 4, vz);
			mp.Create("origin");
			Matrix dmat;
			dmat.Attach(mp.GetName());
			dmat.SetSize(4, 3);
			dmat.SetByVector(vz);
			
			//	result is	0	0	0
			//				1	0	-1
			//				0	0	0
			//				0	0	0
			//
			  
			mat.GetAsVector(vz);
			ocm_partial_derivative_col_wise(3, 4, vz);
			mp.Create("origin");
			dmat.Attach(mp.GetName());
			dmat.SetSize(4, 3);
			dmat.SetByVector(vz);
				
			//
			//	result is	0		1	0
			//				0		0	0
			//				0    -0.5	0
			//				0		0	0
			//
		}

	Example 2:
		#include <origin.h>
		#include <ocm.h>

		#define NROWS	1000
		#define NCOLS	1000

		void partial_derivative_ex2(string str1 ="MBook6", string str2 = "MBook2")
		{
			int i,j;
			Matrix m1(str1);
			Matrix m2(str2);
	
			if(!m1)
			{
				MatrixPage mp1; 
				mp1.Create("origin");
				m1.Attach(mp1.GetName());
	
				m1.SetSize(NROWS, NCOLS);
				for(i=0;i<NROWS;++i)
				for(j=0;j<NCOLS;j++)
				m1[i][j] = sin(i+j);
			}
		
			if(!m2)
			{
				MatrixPage mp2; 
				mp2.Create("origin");
				m2.Attach(mp2.GetName());
				m2.SetSize(NROWS, NCOLS);
			}
		
			vector vz(NCOLS*NROWS);

			m1.GetAsVector(vz);
			
			int t=GetTickCount();
			ocm_partial_derivative_row_wise(NCOLS, NROWS, vz);
			printf("time = %d\n", GetTickCount()-t);
			
			m2.SetByVector(vz);
			
		}


	Parameters:
		nCol=[Input]		the number of columns
		nRow=[Input]		the number of rows
		pz=[Input/Output]	vector that contains the matrix data, with size nRow*nCol, output with the partial derivative
		nLeftPts=[Input]	the number of nearest points used for backward difference, default is 1
		nRightPts=[Input]	the number of nearest points used for forward difference, default is -1, which means equal to the nLeftPts
		pRow=[Input]		the column independent vector, with size nCol


	Return:
		Return OE_NOERROR if succeed, otherwise, non-zero error code is returned.
*/
OC_API int ocm_partial_derivative_row_wise(UINT nCol, UINT nRow, double* pz, int nLeftPts=1, int nRightPts=-1, const double* pCol=NULL);


/**
	Remarks:
		Function to calculate the partial derivative row-wise. The number of nearest points used for forward
		and backward difference are given by the parameter nLeftPts and nRightPts.

	Example 1:
		void partial_derivative_ex1(void)
		{
			matrix mat = {{0, 0, 0}, {0, 1, 0}, {0, 0, 0}, {0, 0, 0}};
			vector vz;
			int ii, jj;
			MatrixPage mp;

			mat.GetAsVector(vz);
			ocm_partial_derivative_col_wise(3, 4, vz);
			mp.Create("origin");
			dmat.Attach(mp.GetName());
			dmat.SetSize(4, 3);
			dmat.SetByVector(vz);
				
			//
			//	result is	0		1	0
			//				0		0	0
			//				0    -0.5	0
			//				0		0	0
			//
		}

	Parameters:
		nCol=[Input]		the number of columns
		nRow=[Input]		the number of rows
		pz=[Input/Output]	vector that contains the matrix data, with size nRow*nCol, output with the partial derivative
		nLeftPts=[Input]	the number of nearest points used for backward difference, default is 1
		nRightPts=[Input]	the number of nearest points used for forward difference, default is -1, which means equal to the nLeftPts
		pCol=[Input]		the row independent vector, with size nRow

		
	Return:
		Return OE_NOERROR if succeed, otherwise, non-zero error code is returned.

*/
OC_API int ocm_partial_derivative_col_wise(UINT nCol, UINT nRow, double* pz, int nLeftPts=1, int nRightPts=-1, const double* pRow=NULL);


/// Fisher 1/18/2008 REPLACE_OCMATH2_PARTIAL_DERIVATIVE_X_BY_OCMATH2_PARTIAL_DERIVATIVE_ROW_WISE
// OC_API int ocmath2_partial_derivative_x(UINT nlx, UINT nly, double* pz, const double* px, int nLeftPts=1);

/// Fisher 1/18/2008 REPLACE_OCMATH2_PARTIAL_DERIVATIVE_Y_BY_OCMATH2_PARTIAL_DERIVATIVE_COL_WISE
// OC_API int ocmath2_partial_derivative_y(UINT nlx, UINT nly, double* pz, const double* py, int nLeftPts=1);



/// Jack 03/20/2008 UNIFY_API_INTERFACE_PARAMETER_WITH_LOCAL_MAXIMUM_METHOD
/**
	Remarks: Last updated by Jack 21/3/2008
		Function to find peak on a matrix. This function uses partial derivatives to determine the position of the peaks.

	Parameters:

		pZ = [input]		matrix data pointer
		nRows = [input]		row number of the matrix data
		nCols = [input]		column number of the matrix data
		pzPeak = [output]	peak's z value (or peak height)
		pPeakRowIndex = [output] peak's row index  (start from zero)
		pPeakColIndex = [output] peak's column index (start from zero)
		nMaxNumPeak = [Input]	the maximum number of peaks to be found, also is the array size of pzPeak, pPeakColIndex, pPeakRowIndex (array or vector pointer)
		nLeftPts = [Input]	number of points on each side used to fit the partial derivative, default is 1
		nRightPts = [Input]	number of points on each side used to fit the partial derivative, default is -1
		dwCtrl = [input]  combine of POSITIVE_DIRECTION, NEGATIVE_DIRECTION,  KEEP_OPPOSITE_SIDE

	Return:
		Return number of peaks (>0), return 0 if no peak found, return <0 if error

*/
// OC_API int ocm_2d_find_peak_by_partial_derivative(UINT nlx, UINT nly, const double* pz, const double* px, const double* py, int* pNumPeak, int* pxPeakInd, int* pyPeakInd, int nLeftPts=1, int nRightPts=-1, int nDir=3);
OC_API int ocm_2d_find_peak_by_partial_derivative(const double* pz, UINT nRows, UINT nCols, double* pzPeak, int* pPeakRowIndex, int* pPeakColIndex, int nMaxNumPeak, int nLeftPts=1, int nRightPts=-1, DWORD dwCtrl=POSITIVE_DIRECTION);
/// End UNIFY_API_INTERFACE_PARAMETER_WITH_LOCAL_MAXIMUM_METHOD



/**
	Remarks:
		Function to get the height and width on x and y direction of the peaks, according to x and y indices of the peaks and max width

	Parameters:
		nlx=[Input]			the number of columns
		nly=[Input]			the number of rows
		pz=[Input]			vector that contains the matrix data, with size nly*nlx
		px=[Input]			vector that contains the x data, with size nlx
		py=[Input]			vector that contains the y data, with size nly
		nPeakNum=[Input]	the number of the peaks
		pxPeakInd=[Input]	integer vector that contains the x indices of the peaks, with size nPeakNum
		pyPeakInd=[Input]	integer vector that contains the y indices of the peaks, with size nPeakNum
		pxPeak=[Output]		vector that contains the x coordinate, should have size nPeakNum initially
		pyPeak=[Output]		vector that contains the y coordinate, should have size nPeakNum initially
		pxWidth=[Output]	vector that contains the width of the peaks on x direction, should have size nPeakNum initially
		pyWidth=[Output]	vector that contains the width of the peaks on y direction, should have size nPeakNum initially

	Return:
		Return OE_NOERROR if succeed, otherwise, non-zero error code is returned.
*/
///Arvin 03/14/08 REPLICA_AUTO_INIT_PARAMS_FOR_SURFACE_FIT
//OC_API int ocm_2d_find_peak_parameter(UINT nlx, UINT nly, const double* pz, const double* px, const double* py, int nPeakNum, const int* pxPeakInd, const int* pyPeakInd, double maxHWx, double maxHWy, double* pxPeak, double* pyPeak, double* pzPeak, double* pxWidth, double* pyWidth);
OC_API int ocm_2d_find_peak_parameter(UINT nlx, UINT nly, const double* pz, const double* px, const double* py, int nPeakNum, const int* pxPeakInd, const int* pyPeakInd, double* pxPeak, double* pyPeak, double* pzPeak, double* pxWidth, double* pyWidth);
OC_API int ocm_1d_find_peak_parameter(UINT nSize, const double* px, const double* py, int nPeakNum, const int* pPeakInd, double* pxPeak, double* pyPeak, double* pxWidth);
///end 	 REPLICA_AUTO_INIT_PARAMS_FOR_SURFACE_FIT
OC_API int ocm_get_matrix_noise_level(double* pxNoise, double* pyNoise, UINT nlx, UINT nly, const double* pz, const double* px=NULL, const double* py=NULL);
OC_API int ocm_get_row_noise_level(double* pxNoise, UINT nlx, UINT nly, const double* pz, const double* px=NULL, const double* py=NULL);
OC_API int ocm_get_square_range_for_2d_data(UINT nSize, double* pz, double* px, double* py, double dLeft, double dRight, double dBottom, double dTop);
OC_API int ocm_create_xy_gridding(UINT nSize, const double* px, const double* py, int* pnCols, int* pnRows, double* pxGrid, double* pyGrid, bool* pbXChangeFirst=NULL);

/// Jack 03/17/2007 ADD_LOCAL_MAXIMUM_2D_FIND_PEAKS_ALGORITHM
/** 
	Remarks:
		Scan the matrix data in pZ by a 2D search window, find local maximum/minimum point in the search window.
		Store the local maximum as a peak when its index equal to the middle point of the search window (Peak Criterion)
		The size of the search window is determined from nxLocalPts and nyLocalPts
		Return number of peaks found
		
	Keywords:
		local maximum 2D
	Exmaple1:
		void ocmath_find_peaks_by_local_maximum_2D_ex3()
	{
		MatrixLayer ml = Project.ActiveLayer();
		UINT nRows;
		UINT nCols;
		Matrix mzData(ml);// Get the active Matrix from a MatrixLayer

	
		printf("The active matrix is %d x %d\n",mzData.GetNumRows(), mzData.GetNumCols());
		nRows=mzData.GetNumRows();
		nCols=mzData.GetNumCols();
	

		//Col and Row index of peak's position to be obtained from local_maximum_2D API	(the indices start from zero)
		vector<UINT> vnPeakColIndex;
		vector<UINT> vnPeakRowIndex;
		vnPeakColIndex.SetSize(nRows);
		vnPeakRowIndex.SetSize(nRows); 
		//Note: the size of vnPeakRowIndex should be larger than the peaks number found in practice here set as nRows size for convenience
	
		//peak's x, y position to be converted from peak's Col and Row index
		vector<double> vyPeak;
		vyPeak.SetSize(nRows);
		vector<double> vxPeak;
		vxPeak.SetSize(nRows);
	
		vector<double> vzPeak;
		vzPeak.SetSize(nRows);
	
	
		DWORD dwCtrl=POSITIVE_DIRECTION;
		int nxLocalPts=1;
		int nyLocalPts=1;
		int nPeakNum;
		nPeakNum=ocm_2d_find_peak_by_local_maximum(mzData, nRows, nCols,
													  vnPeakColIndex, vnPeakRowIndex, vzPeak,
													  nxLocalPts, nyLocalPts, dwCtrl);
	
		double dXMin,dXMax;
		double dYMin,dYMax;
		dYMax=mzData.GetYMax();
		dYMin=mzData.GetYMin();
		dXMax=mzData.GetXMax();
		dXMin=mzData.GetXMin();
		double XDividence=(dXMax-dXMin)/(nCols-1);
		double YDividence=(dYMax-dYMin)/(nRows-1);
		vxPeak=dXMin+vnPeakColIndex*XDividence;
		vyPeak=dYMin+vnPeakRowIndex*YDividence;
	
	
		
		// Peak's position and z values
		printf("PeakNumber=%d\n",nPeakNum);
		printf("peakX peakY peakZ\n");
		
		for(int ll=0; ll<nPeakNum; ll++)
		{
			double dTempPeakz=vzPeak[ll];
			printf("%f\t%f\t%f\n",vxPeak[ll], vyPeak[ll], vzPeak[ll]);
		}

		printf("peakColIndex peakRowIndex peakZ\n");
		for(int jj=0; jj<nPeakNum; jj++)
		{
			printf("%d %d %f\n",vnPeakColIndex[jj], vnPeakRowIndex[jj], vzPeak[jj]);
		}
	
}
		// At the end of example:
	Parameters:
		pZ = [input] matrix data pointer
		nRows = [input] row number of the matrix data
		nCols = [input] column number of the matrix data
		pzPeak = [output] peak's z value (or peak height)
		pPeakRowIndex = [output] peak's row index  (start from zero)
		pPeakColIndex = [output] peak's column index (start from zero)
		nMaxNumPeak = [Input] the maximum number of peaks to be found, also is the array size of pzPeak, pPeakColIndex, pPeakRowIndex (array pointer)
		nxLocalPts = [input] number of local points in x-dimension to be used to determine size of search window
		nyLocalPts = [input] number of local points in y-dimension to be used to determine size of search window
		dwCtrl = [input]  combine of POSITIVE_DIRECTION, NEGATIVE_DIRECTION,  KEEP_OPPOSITE_SIDE
	Return:
		Return number of peaks (>0), return 0 if no peak found, return <0 if error
	SeeAlso:	
*/
OC_API int ocm_2d_find_peak_by_local_maximum(const double* pZ, UINT nRows, UINT nCols, 
												  double* pzPeak, int* pPeakRowIndex, int* pPeakColIndex, int nMaxNumPeak,
												  int nxLocalPts, int nyLocalPts, DWORD dwCtrl);
// End ADD_LOCAL_MAXIMUM_2D_FIND_PEAKS_ALGORITHM

/// Jack QA-12334 10/09/2008 ADD_GET_LARGEST_NEG_POS_PEAK_AND_INDEX_FOR_MATRIX
// this is for usage in one peak matrix data initilize code 
// see for example in oc ADD_ONE_PEAK_MATRIX_DATA_INITILIZE_CODE
OC_API int ocm_2d_find_largest_neg_pos_peak_in_matrix(const double* pZ, UINT nRows, UINT nCols, double* pPosPeakZ, int* pPosPeakRowIndex, int* pPosPeakColIndex, double* pNegPeakZ, int* pNegPeakRowIndex, int* pNegPeakColIndex,const double *pNAN = NULL);
/// end ADD_GET_LARGEST_NEG_POS_PEAK_AND_INDEX_FOR_MATRIX

/**	  testing only, should remove this later
		multiply given vector by a factor
	Example:
		#include <ocm.h>
		void dd(int nSize = 3, double factor = 1.5)
		{
			vector vv;
			vv.Data(1, nSize);
			double dSum = ocm_test(vv, vv.GetSize(), factor);
			out_double("sum = ", dSum);
			for(int ii = 0; ii < vv.GetSize(); ii++)
				printf("%d: %f\n", ii+1, vv[ii]);
		}
	Paramaters:
		pData = [input/output] buffer to hold double data
		nSize = [input] buffer size
		factor = [input] multiple by this value
	Return:
		sum of the data
*/

OC_API double ocm_test(double* pData, uint nSize, double factor);

///Cheney 2006-7-20 LLVC_WEIGHTED_ADJAVE_SMOOTH
/** >Analysis.Spectral Analysis
	Remarks:
		This function performs weighted adjacent averaging smoothing on the curve.
	Keywords:
		smooth
	Example1:
		#include <ocm.h>
		void adjave_smooth_Ex1(int nLeftRightPts = 15)
		{
			//assume a worksheet active and have two columns
			//1st column has X data, 2nd column has Y data
			Worksheet wks = Project.ActiveLayer();
			int nCol = 0;
			Dataset dsX(wks, nCol++);
			Dataset dsY(wks, nCol++);
			
			int nSize = dsY.GetSize();
			vector vY(nSize);
			vY = dsY;
			vector vYWSmooth(nSize);
			int nRet = ocm_weighted_adjave_smooth(vY, vYWSmooth,  nSize, nLeftRightPts); // weighted average 
			if(nRet != 0)
			{
				printf("failed to weight smooth");
				return;
			}
			wks.AddCol(); //add column for weight average result
			Dataset dsYWSmooth(wks, nCol++);
			wks.Columns(nCol-1).SetFormat(OKCOLTYPE_NUMERIC);
			dsYWSmooth = vYWSmooth;
		}
	Example2:
		#include <ocm.h>
		void adjave_smooth_Ex2(int dWinLenPerc = 1, int nLeftRightPts = 100)
		{
			//assume a worksheet active and have two columns
			//1st column has X data, 2nd column has Y data
			Worksheet wks = Project.ActiveLayer();
			int nCol = 0;
			Dataset dsX(wks, nCol++);
			Dataset dsY(wks, nCol++);
			
			int nSize = dsY.GetSize();
			vector vX(nSize);
			vX = dsX;
			vector vY(nSize);
			vY = dsY;
			vector vYWSmooth(nSize);
			int nRet = ocm_weighted_adjave_smooth(vY, vYWSmooth, nSize, nLeftRightPts, vX, dWinLenPerc); // weighted average 
			if(nRet != 0)
			{
				printf("failed to weight smooth");
				return;
			}
			wks.AddCol(); //add column for weight average result
			Dataset dsYWSmooth(wks, nCol++);
			wks.Columns(nCol-1).SetFormat(OKCOLTYPE_NUMERIC);
			dsYWSmooth = vYWSmooth;
		}
	Parameters:
		pYData		  = [input]  Pointer to data of type double to smooth
		pYSmoothData  = [output] Pointer to data of type double to receive results
		nSize		  = [input]  Size of dataset
		nLeftRightPts = [input]  Symmetric function considers n points to right and left of given point.
								 Zero leaves the data unchanged. 
		pXData		  = [input]	 Pointer to X-axis data of type double to smooth.
								 if dWinLenPerc>0, it should not be NULL.
		dWinLenPerc	  =	[input]	 percent of size should be used for smoothing.
								 when pYData[ii] being averageing,
								 if	dWinLenPerc = 0, nLeftRightPts*2+1 points will be used to smooth.
								 else count points in a dWinLenPerc%*winlen*2 length interval, 
								 which center point is (pXData[ii], pYData[ii]), where winlen means max(pXData) - min(pXData).
								 if number of Points in the interval less than nLeftRightPts*2+1, use nPts points to smooth,
								 otherwise nLeftRightPts*2+1 points will be used to smooth.
								 so 0<=dWinLenPerc<=100.
	Return:
		return OCM_NOERROR for success, otherwise return OCM_SMOOTHPTS_LT_ZERO
	SeeAlso:
		ocmath_adjave_smooth, ocmath_savitsky_golay
*/
OC_API int ocm_weighted_adjave_smooth(const double* pYData, double* pYSmoothData, uint nSize, int nLeftRightPts, const double* pXData = NULL, double dWinLenPerc = 0.0) ;
///end LLVC_WEIGHTED_ADJAVE_SMOOTH

/// ML 8/23/2006 CALLBACK_FROM_VC_INTO_OC
typedef	double	(*PFNTESTCALLBACK)(int nArg, double rArg, double *prArg);

/**
	Example:
		#include <ocm.h>

		static	double	oc_callback(int nArg, double rArg, double *prArg)
		{
			double		rr = rArg * nArg;
			*prArg = rArg / nArg;
			return rr;
		}


		void	test_oc_callback_via_vc(int nArg = 10, double rArg = 99.)
		{
			double		rResDirectly;
			double		rCallDirectly = oc_callback(nArg, rArg, &rResDirectly);
			double		rResViaCallback;
			double		rCallViaCallBack = ocm_test_callbalck(nArg, rArg, &rResViaCallback, oc_callback);
			
			ASSERT(rCallDirectly == rCallViaCallBack);
			ASSERT(rResDirectly == rResViaCallback);
		}
*/
OC_API double	ocm_test_callbalck(int nArg, double rArg, double *prArg, PFNTESTCALLBACK pfnCallBack);
/// end CALLBACK_FROM_VC_INTO_OC

///Arvin 9/15/06 QA70-8960 ADD_REDUCE_DATA
enum{
	RD_LARGEST_TRIANGLE,
	RD_Y_THRESHOLD,
	RD_POINT_DISTANCE,
	RD_DOUGLAS_PEUCKER_HULL,
	RD_LOCAL_EXTREME,
};
/**	 simplify polylines by reducing data point and do best to keep polyline's visage. User should give an acceptable range [nMin, nMax];
	If the function finds n points according to the current tolerance dTolTmp,
	then if n < nMin, set dTolMax = dTolTmp(dTolTmp = dTol, dTolMin = 0 and dTolMax = 1, initially) and dTolTmp = (dTolMin+dTolMax)/2.0,
	loop again, if n > nMax, set dToMin = dTolTmp and dTolTmp = (dTolMin+dTolMax)/2.0, loop again, until abs(dTolMin - dTolMax) < 1e-5.
	if n is in [nMin, nMax], return indices and actual number of reserved points.
	Example:
		#include <ocm.h>
		void ocm_reduce_data_ex1(uint nMin, uint nMax, uint nMethod = RD_LARGEST_TRIANGLE)
		{
			GraphLayer gl = Project.ActiveLayer();
			if (!gl)
			{
				return;
			}
			
			DataPlot dp = gl.DataPlots(0);		
			DataRange dr;
			vector vx, vy;
			if(dp.GetDataRange(dr))
	        {
	        	DWORD dwPlotID;
	        	if(dr.GetData(DRR_GET_DEPENDENT | DRR_NO_FACTORS, 0, &dwPlotID, NULL, &vy, &vx) < 0)
	        	{
	        		printf("get_plot_data failed GetData");
	        		return;
	        	}
	        }
	        vector<uint>  vInd;
	        vInd.SetSize(vy.GetSize());
			uint nSize = vInd.GetSize();
	        int nRet = ocm_reduce_data(vy.GetSize(), vx, vy, vInd, &nSize, nMin, nMax, nMethod);
	        if(nRet!=OCM_NOERROR)
	        	return;
	        vector vy2, vx2;
			vy2.SetSize(nSize);
			vx2.SetSize(nSize);
			for(int ii = 0; ii< nSize; ii++)
			{
				vx2[ii] = vx[vInd[ii]];
				vy2[ii] = vy[vInd[ii]];
			}
			WorksheetPage wksPage;
			wksPage.Create();
			Worksheet wksResult = wksPage.Layers(0);
			int nXCol, nYCol;
			nXCol = wksResult.AddCol("X Coordinate");
			nYCol = wksResult.AddCol("Y Coordinate");
			wksResult.Columns(nXCol).SetType(OKDATAOBJ_DESIGNATION_X);
			wksResult.Columns(nYCol).SetType(OKDATAOBJ_DESIGNATION_Y);
			DataRange drOut;
			drOut.Add("X", wksResult, 0, nXCol, -1, nXCol);
			drOut.Add("Y", wksResult, 0, nYCol, -1, nYCol);
			drOut.SetData(&vy2, &vx2);
			XYRange plotRange;
			plotRange.Add("X", wksResult, 0, nXCol, -1, nXCol);
			plotRange.Add("Y", wksResult, 0, nYCol, -1, nYCol);
			gl.AddPlot(plotRange);
		}
	Paramaters:
		nSize = [input] size of original data
		px = [input] buffer to hold X coordinates
		py = [input] buffer to hold Y coordinates
		pIndices = [output] buffer to hold indices of preserved points after reducing
		nIndSize = [input/output] on input, size of pIndices; on output, actual number of points
		nMin = [input] Minimum points number which user want to reduce current data to, nMin <= nIndSize
		nMax = [input] Maximum points number which user want to reduce current data to
		nMethod = [input] reducing data method, RD_LARGEST_TRIANGLE, RD_Y_THRESHOLD or RD_POINT_DISTANCE
		dTol = [input] tolerance to dertermine which points will be preserved, default value is 0. 0 <= dTol <= 1.0 
	Return:
		OCM_NOERROR on success, error code on fail
	Reference 
		 "Algorithm for the reduction of number of points required to represent a line or its caricature", D.H. Douglas, T.K. Peucker
		 "Speeding up the Douglas-Peucker Line-Simplification Algorithm", John Hershberger, Jack Snoeyink
*/

///Jack	30/10/2008 QA80-12405 REDUCE_DATA_XF 
// change uint to int 
//OC_API int ocm_reduce_data(uint nSize, const double* px, const double* py, UINT* pIndices, UINT* nIndSize, UINT nMin, UINT nMax, UINT nMethod = RD_LARGEST_TRIANGLE, double dTol = 0);
OC_API int ocm_reduce_data(int nSize, const double* px, const double* py, UINT* pIndices, UINT* nIndSize, int nMin, int nMax, int nMethod = RD_LARGEST_TRIANGLE, double dTol = 0, BOOL bByTol = FALSE);
///End REDUCE_DATA_XF 

///end ADD_REDUCE_DATA

/// Jack 30/10/2008 QA80-12405 REDUCE_DATA_XF 
// get reduce data vector
OC_API int ocm_get_reduce_data(int nSize, const double* px, const double* py, UINT* pIndices, UINT nIndSize, double * pOutX, double * pOutY);
/// End REDUCE_DATA_XF 

/// Hong 12/05/06 ADD_CHECK_INFINITE_VALUE
/**
	Parameters:
		lpData = [input] point to data to check
		nLength = [input] length of the data
		bConvert = [input] true to convert the infinite value to Origin missing value, other not
	Returns: 
		return the number of infinite value
*/
OC_API int ocm_check_infinite_value(double* lpData, int nLength, bool bConvert = true); 
/// end	ADD_CHECK_INFINITE_VALUE

/// ML 1/29/2007 QA70-9322 EXPORT_MACRO_MISSING
///// Hong 01/27/07 FOR_TEMP_TEST
//// this code is temp create to test if origin compilier support macro "__cdecl"
//int __cdecl ocm_test_cdecl_marco(LPCSTR strMessage, ...);
///// end FOR_TEMP_TEST
OC_API	int __cdecl ocm_test_cdecl_marco(LPCSTR strMessage, ...);
/// end EXPORT_MACRO_MISSING

/// Cloud 03/08/2008 USE_NAG_OPTIMIZER_FOR_MULTIPLE_REGRESSION
OC_API int ocm_multiple_regression(int nData, int nIndep, const double* pDep, const double* pIndep, const double* pLower, const double* pUpper, double* pParams);
/// End USE_NAG_OPTIMIZER_FOR_MULTIPLE_REGRESSION

#ifdef _MSC_VER
	#ifdef __cplusplus
	}
	#endif
#endif	//_MSC_VER

#endif //_OCM_H
