/*------------------------------------------------------------------------------*
 *	File Name: 	ocmsp.h															*
 *	Purpose: shared header between OC and VC, all exported functions should be	*
 *  listed here
 *  Creation: CPY																*
 *  	Copyright (c) OriginLab Corp.	2007									*
 *	All Rights Reserved															*
 *					                                                        	*
 *	Modification log                                                        	*
 *	Cloud 11/12/2007 FIND_PEAKS_2ND_DERIVATIVE_MOVED_FROM_OCMATH				*
 *	Jack 11/18/2008 EXPOSE_FFT_SMOOTH_CUTOFF_FREQUENCY_FOR_PA					*
 *  Fisher 04/24/09 QA80-13487  ADV_DIGITAL_FILTERING                           *
 *	Fisher 7/16/09	REORGANIZE_PRO_ONLY_OCMATH_FUNCTION							*
 *	Sophy 8/14/2009 ADD_FLEXIBLE_PARAM_FOR_MORE_USER_OPTIONS					*
 *	Sophy 11/5/2009 QA80-14598-S4 OUTPUT_MORE_RESULT							*
 *------------------------------------------------------------------------------*/

#ifndef _OCMSP_H
#define _OCMSP_H

#ifdef _MSC_VER
	#ifdef ocmathsp_DLL
		#define OC_API __declspec(dllexport)
		#pragma message("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$we are in ocmathsp dll")
	#else
		#define OC_API __declspec(dllimport)
		#pragma message("$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$we are NOT in ocmathsp 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(ocmathsp)	// Associate all functions below to omath2.dll which must be in the Origin EXE folder
#endif	//_MSC_VER


enum{
	OCMSP_NOERROR = 0,
};

/// Cloud 11/12/2007 ADD_FFT_FILTER_SMOOTHING
// Comment last updated by Cloud on 06/05/2008
/** >Analysis>Signal Processing
	Remarks:
		Smoomth data by using FFT low-pass filter

	Example1:
		void ocmsp_fft_filter_smoothing_ex1()
		{
			vector vx = {0.86528, 0.39649, 0.44901, 0.77041, 0.43139, 0.11343, 0.12061, 0.00387, 0.21913, 0.66058};
			int nSize = vx.GetSize();
			vector vxs(nSize);
			ocmsp_fft_filter_smoothing(nSize, vx, vxs, 0.4);
			for (int ii=0; ii<10; ii++)
				printf ("%lf\n", vxs[ii]);
		}

	Parameters:
		nSize = [input] size of the data
		px = [input] pointer to the data to perform smoothing
		pxs = [output] pointer to the buffer of result data
		dPercent = [input] the cutoff frequency represented by percentile

	Return:
		Return OE_NOERROR if succeed, otherwise, non-zero error code is returned.
*/
OC_API int ocmsp_fft_filter_smoothing(uint nSize, const double* px, double* pxs, double dPercent);
/// End ADD_FFT_FILTER_SMOOTHING

/// Cloud 11/12/2007 FIND_PEAKS_2ND_DERIVATIVE_MOVED_FROM_OCMATH
// Comment last updated by Cloud on 06/05/2008
/** >Analysis>Peak and Baseline
    Remarks:
		Find curve's peaks by 2nd derivative. Calculate curve's smoothed 2nd derivative on every point in px, py.
		Then the point is a peak, if the smoothed 2nd derivative on it is extremum. 
		POSITIVE_DIRECTION peak, if the smoothed 2nd derivative on it is local maximum.
		NEGATIVE_DIRECTION peak, if the smoothed 2nd derivative on it is local minimum.
		lsize returns the number of peaks, pxPeaks and pyPeaks contain X and Y coordinate's datas of peaks,and 
		pnIndices contains the indices of peaks.
	Keywords:
		2nd derivative
	Example1:
		void ocmsp_find_peaks_2nd_derivative_ex1( )
		{
			GraphLayer gl = Project.ActiveLayer();
			if (!gl)
			{
				return;
			}
			
			DataPlot dp = gl.DataPlots(0);		
			DataRange dr;
			vector vxData, vyData;
	        if(dp.GetDataRange(dr))
	        {
	        	DWORD dwPlotID;
	        	if(dr.GetData(DRR_GET_DEPENDENT | DRR_NO_FACTORS, 0, &dwPlotID, NULL, &vyData, &vxData) < 0)
	        	{
	        		printf("get_plot_data failed GetData");
	        		return;
	        	}
	        }

			uint nDataSize = vxData.GetSize();
			int iSize = vxData.GetSize();

			vector vxPeaks, vyPeaks;
			vector<int> vnIndices;
	
			vxPeaks.SetSize(nDataSize);
			vyPeaks.SetSize(nDataSize);
			vnIndices.SetSize(nDataSize);

			int nRet = ocmsp_find_peaks_2nd_derivative( &nDataSize, vxData, vyData, vxPeaks, vyPeaks, vnIndices, POSITIVE_DIRECTION | NEGATIVE_DIRECTION,11);
			if( nRet < OE_NOERROR )
			{
				printf("error code: %d\n", nRet);
				return;
			}
			vxPeaks.SetSize(nDataSize);
			vyPeaks.SetSize(nDataSize);
			vnIndices.SetSize(nDataSize);
			WorksheetPage wksPage;
			wksPage.Create();
			Worksheet wksResult = wksPage.Layers(0);
			int nIndCol, nXCol, nYCol;
			nIndCol = wksResult.AddCol("Indices");
			nXCol = wksResult.AddCol("X Coordinate");
			nYCol = wksResult.AddCol("Y Coordinate");
			wksResult.Columns(nIndCol).SetType(OKDATAOBJ_DESIGNATION_X);
			wksResult.Columns(nXCol).SetType(OKDATAOBJ_DESIGNATION_X);
			wksResult.Columns(nYCol).SetType(OKDATAOBJ_DESIGNATION_Y);
			DataRange drOut;
			drOut.Add("X", wksResult, 0, nIndCol, -1, nIndCol);
			drOut.Add("Y", wksResult, 0, nXCol, -1, nXCol);
			drOut.Add("Z", wksResult, 0, nYCol, -1, nYCol);
			drOut.SetData(&vyPeaks, &vxPeaks, &vnIndices);
			XYRange plotRange;
			plotRange.Add("X", wksResult, 0, nXCol, -1, nXCol);
			plotRange.Add("Y", wksResult, 0, nYCol, -1, nYCol);
			gl.AddPlot(plotRange, IDM_PLOT_SCATTER);
		}
		// At the end of example:
	Parameters:
		lSize = [modify] on input, size of px, py, pxPeaks, pyPeaks, pnIndices; on output, return number of peaks  
		px = [input] it contains curve's X coordinate's datas 
        py = [input] it contains curve's Y coordinate's datas 
		pxPeaks = [output] Its size is equal to the size of px. it contains peaks' X coordinate's datas, 
		                   if the number of peaks is less than its size, the excrescent elements of it are filled
						   with 0.
		pyPeaks = [output] Its size is equal to the size of py. it contains peaks' Y coordinate's datas, 
						   if the number of peaks is less than its size, the excrescent elements of it are filled
						   with 0.
		pnIndices = [output] Its size is equal to the size of px. it contains peaks' indices, if peaks's number is 
							 less than its size, the excrescent elements of it are filled with 0.
		dwCtrl = [input]  combine of POSITIVE_DIRECTION, NEGATIVE_DIRECTION,  KEEP_OPPOSITE_SIDE
		nPtsSmooth = [input] smooth points number
	Return:
		Return OE_NOERROR if succeed, otherwise, non-zero error code is returned.
*/
///Jack 11/18/2008 EXPOSE_FFT_SMOOTH_CUTOFF_FREQUENCY_FOR_PA 
// sandy need it for adjusment in PA GUI
//OC_API int ocmsp_find_peaks_2nd_derivative(UINT* lSize, const double* px, const double* py, double* pxPeaks, 
//												double* pyPeaks,  int* pnIndices, DWORD dwCtrl = POSITIVE_DIRECTION, int nPtsSmooth = 11);
///Jack 11/19/2008 OUTPUT_SECOND_DERIVATIVE
//OC_API int ocmsp_find_peaks_2nd_derivative(UINT* lSize, const double* px, const double* py, double* pxPeaks, 
//												double* pyPeaks,  int* pnIndices, DWORD dwCtrl = POSITIVE_DIRECTION, int nPtsSmooth = 11, double dCutoffFre = 0.2);
OC_API int ocmsp_find_peaks_2nd_derivative(UINT* lSize, const double* px, const double* py, double* pxPeaks, 
												double* pyPeaks,  int* pnIndices, DWORD dwCtrl = POSITIVE_DIRECTION, double dCutoffFre = 0.2, double * pSecondDeriv=NULL);
//End OUTPUT_SECOND_DERIVATIVE
///End EXPOSE_FFT_SMOOTH_CUTOFF_FREQUENCY_FOR_PA 
///End FIND_PEAKS_2ND_DERIVATIVE_MOVED_FROM_OCMATH

/// end EXPORT_MACRO_MISSING

/// Fisher 11/10/2008 QA80-12507 	OSCILLOSCOPE_SIGNAL_PROCESSING_FEATURES
struct RiseTimeResult
{
   double dRiseTime;
   int it1, it2;
   double t1, t2;
   double y1, y2;
   int i1y1, i1y2, i2y1, i2y2; 
   double b1, b2;
   ///Sophy 11/5/2009 QA80-14598-S4 OUTPUT_MORE_RESULT
   double velocity;
   double max_velocity;
   ///end OUTPUT_MORE_RESULT
};
///Sophy 8/27/2009 SUPPORT_CUSTOMER_SPECIFIED_LOW_HIGHT_STATE_LEVEL
enum {
	CTRL_FIX_LOWLEVEL = 0x0001,
	CTRL_FIX_HIGHLEVEL = 0x0002,
};
///end SUPPORT_CUSTOMER_SPECIFIED_LOW_HIGHT_STATE_LEVEL

/// Fisher 11/24/09 QA80-14719 PROPER_LOW_HIGN_LEVEL_FINDING
enum{
	MINMAX_AVERAGE = 0,
	MINMAX_MAXIMAL_MEAN,
};
/// End PROPER_LOW_HIGN_LEVEL_FINDING

///Sophy 8/14/2009 ADD_FLEXIBLE_PARAM_FOR_MORE_USER_OPTIONS
//later if we need more parameters to pass into this function, just add them in this struct
typedef	struct tagRiseTimeParams {
	double	dLowLevelVolt;			//user specified, if dwCtrl contains CTRL_FIX_LOWLEVEL
	double	dHighLevelVolt;			//user specified, if dwCtrl contains CTRL_FIX_HIGHLEVEL
	double	dLowLevelRefer;			//from of step height by percentage
	double	dHighLevelRefer;		//to of step height by percentage
	int		nMethod;				//method to find rise/fall area, should be one of linear/histogram/largest triangle
	double	dTolerance;				//tolerance value to find  rise/fall area
	int		nMinMaxFindingMethod;	/// Fisher 11/24/09 QA80-14719 PROPER_LOW_HIGN_LEVEL_FINDING
	int		nSmoothPoints;
	int		nSmoothPointsEx;
	int		nBins;
	BOOL	bAveVal; //use average value of the bin that has the maximum number of hits
	DWORD	dwCtrl;			
}RiseTimeParams;
///end ADD_FLEXIBLE_PARAM_FOR_MORE_USER_OPTIONS
enum{
	RTIME_LINEAR_SEARCH = 0 ,
	RTIME_HISTOGRAM,
	RTIME_LOCAL_EXTREME,
};

/*
	The following return values are needed:

	1. OE_NOERROR = Success
	2. OE_LACKPOINTS = nSize too few points
	3. OE_NO_BASE_FOUND = No base found
	4. OE_ONLY_ONE_BASE_FOUND = Only one base found 

	bForward == TRUE		Find Risetime
	bForward == FALSE		Find Falltime
 */

///Sophy 8/14/2009 ADD_FLEXIBLE_PARAM_FOR_MORE_USER_OPTIONS
//OC_API int ocmsp_find_fall_or_fall_time( UINT nSize, const double* px, const double* py, RiseTimeResult *pstResult, double dReferenceLevelLow=0.1, double dReferenceLevelHigh=0.9, int nMethod = RTIME_LINEAR_SEARCH, double dTol=0.03, int nSmoothPoints = 100, int nSmoothPointsEx = 10, int nBins = 256, BOOL bForward = TRUE);		
OC_API int ocmsp_find_fall_or_fall_time( UINT nSize, const double* px, const double* py, RiseTimeResult *pstResult, RiseTimeParams *pParams, BOOL bForward = TRUE);		
///end ADD_FLEXIBLE_PARAM_FOR_MORE_USER_OPTIONS
/// End 	OSCILLOSCOPE_SIGNAL_PROCESSING_FEATURES



/// Fisher 04/24/09 QA80-13487  ADV_DIGITAL_FILTERING
//#ifdef __ADV_DIGITAL_FILTERING__
enum DECIMATE
{
	DEC_FILTER_NONE,
	DEC_FILTER_MOVING_AVE,
	DEC_FILTER_FIR,
	DEC_FILTER_IIR,
};

/*
	filter function

	y = filter(b,a,X) filters the data in vector X with the filter described 
	by numerator coefficient vector b and denominator coefficient vector a. 

	The filter function is implemented as a direct form II transposed structure
	
*/
OC_API int	ocmsp_1d_digital_filter(const double *pIn, double *pOut, UINT nSize, double *pa, UINT na, double *pb, UINT nb);

/*
	Zero-phase digital filtering
*/
OC_API int	ocmsp_1d_digital_filtfilt(const double *pIn, double *pOut, UINT nSize, double *pa, UINT na, double *pb, UINT nb);

// This function returns the new size after decimation, fail if return < 0 
OC_API int	ocmsp_decimate(const double *px, const double *py, UINT nSize, UINT d, double *pxd, double *pyd, int nFilterType=DEC_FILTER_NONE, UINT nOrder=0, UINT nBegin=0);

//#endif // __ADV_DIGITAL_FILTERING__
/// End ADV_DIGITAL_FILTERING

/// Fisher 7/16/09	REORGANIZE_PRO_ONLY_OCMATH_FUNCTION
OC_API int ocmsp_reduce_data(int nSize, const double* px, const double* py, UINT* pIndices, UINT* nIndSize, int nMin, int nMax, int nMethod, double dTol=0.0, BOOL bByTol=FALSE);
/// End	REORGANIZE_PRO_ONLY_OCMATH_FUNCTION



/// Fisher	07/29/09 http://wiki.originlab.com/~originla/internal/index.php?title=Sales:Surface_Statistics

struct	 RoughnessParametersCtrls
{
	BOOL		bProfileByRow;
	double		dSamplingLength;
};

struct	ProfileParameters
{
	double		*pR_a;		// arithmetic average of absolute values 
	double		*pR_q;		// root mean squared 
	double		*pR_v;		// maximum valley depth
	double		*pR_p;		// maximum peak height 
	double		*pR_t;		// Maximum Height of the Profile 
	double		*pR_sk;		// skewness 
	double		*pR_ku;		// kurtosis
	double		*pR_din;	// average distance between the highest peak and lowest valley in each sampling length, ASME Y14.36M - 1996 Surface Texture Symbols 
	double		*pR_jis;	// Japanese Industrial Standard for Rz, based on the five highest peaks and lowest valleys over the entire sampling length.
	double		*pR_dq;		// the RMS slope of the profile within the sampling length 
};

struct	ArealParameters
{
	// Amplitude Parameters
	double		*pS_a;		// Average Roughness
	double		*pS_q;		// RMS Roughness	
	double		*pS_sk;		// Skewness		
	double		*pS_ku;		// Kurtosis
	double		*pS_p;		// Peak Height
	double		*pS_v;		// Valley Depth
	double		*pS_t;		// Peak to Valley Height
	double		*pS_z;		// Ten-Point Height
	double		*pS_PaX;	// Mean Profile Pa along the X axis
	double		*pS_PaY;	// Mean Profile Pa along the Y axis
	double		*pS_PtX;	// Mean Profile Pt along the X axis
	double		*pS_PtY;	// Mean Profile Pt along the Y axis

	// Functional Parameters
	//double		*pS_k;		// Core Roughness Depth
	//double		*pS_pk;		// Reduced Peak Height
	//double		*pS_vk;		// Reduced Valley Depth
	//double		*pS_r1;		// Upper Bearing Surface
	//double		*pS_r2;		// Lower Bearing Surface
	//double		*pS_bi;		// Surface Bearing Index
	//double		*pS_ci;		// Core Fluid Retention Index
	//double		*pS_vi;		// Valley Fluid Retention Index

	// Hybrid Parameters
	//double		*pS_sc;		// Arithmetic Mean Summit Curvature
	//double		*pS_dq;		// RMS Slope
	//double		*pS_dr;		// Developed Interfacial Area Ratio
	//double		*pS_HSC;	// High Spot Count
};

OC_API	int	ocmath_profile_roughness_parameters(const double *pX, const double *pData, const UINT nSize, const UINT nOffset, RoughnessParametersCtrls *pstCtrl, ProfileParameters *pstProfiles);
OC_API	int	ocmath_areal_parameters(const double *pxGrid, const double *pyGrid, const double *pzMat, const UINT nRows, const UINT nCols, RoughnessParametersCtrls *pstCtrl, ArealParameters *pstAreal);

OC_API	int	ocmath_3d_grid_statistics_roughness_parameters(	const double *pxGrid, const double *pyGrid, const double *pzMat, const UINT nRows, const UINT nCols, RoughnessParametersCtrls *pstCtrl, ArealParameters *pstAreal, ProfileParameters *pstProfiles);

///---------


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

#endif //_OCMSP_H


