/*------------------------------------------------------------------------------*
 * File Name:	curve_utils.c													*
 * Creation:  Sandy 12/14/05													*
 * Purpose: OriginC Source C file												*
 * Copyright (c) OriginLab Corp. 2004, 2005, 2006, 2007, 2008, 2009, 2010		*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 * Raine 2006-04-30 GET_GAUSSIAN_FILTER											*
 * Cloud 04/04/2007 ADD_FIND_PEAKS_BY_NUMBER									*
 * Cloud 04/05/2007 IMPROVE_FIND_PEAKS_FEET										*
 * Cloud 04/10/2007 PROCESS_THE_NEGATIVE_PEAK									*
 * Cloud 04/14/2007 REORGANIZE_FUNCTIONS										*
 * Cloud 06/30/2007 USE_FIND_MARKER_BY_WIDTH_TO_REPLACE_BY_FULLWIDTH			*
 * Cloud 7/5/07 LIMIT_SMOOTH_POINTS												*
 *	Hong 11/23/07 v8.0753 CLEAN_CENTRALIZE_CODE_AVOID_DATAPLOT_DEPENDENCE		*
 *	Hong 11/26/07 v8.0754 CLEAN_CENTRALIZE_CODE_AVOID_DATAPLOT_DEPENDENCE		*
 *	Folger 11/30/07 CLEAN_CODE_BY_FIND_FUNCTION									*
 *	CPY 12/8/2007 QA80-10788 FIND_FLAT_REGIONS_IN_CURVE							*
 *	CPY 12/8/2007 QA80-10788 CURVE_UTILS_SHOULD_NOT_NEED_PRO_DLLS				*
 *	Folger 12/10/07 FIND_PEAKS_SHOULD_RETURN_OCMATH_ERROR_CODE					*
 *	Hong 12/20/07 v8.0773d IMPROVE_FILTER_PEAK_ALLOW_SPECIFY_FILTER_VALUE		*
 * Cloud 01/11/08 FIX_FOR_NON_MONOTONIC_DATA									*
 *	Arvin 03/13/08 REPLICA_AUTO_INIT_PARAMS_FOR_SURFACE_FIT						*
 *	Arvin 03/26/08 RESET_REPLICA_NUMBER_WHEN_CAN_NOT_FIND_ENOUGH_PEAK			*
 *	Folger 04/18/08 QA80-11441 CENTRALIZE_CODE_OF_LOCAL_MAXIMUN_METHOD			*
 *	Sim 06-06-2008 SEPARATE_AUTO_FIND_BASELINE_POINTS							*
 *  Jack QA80-12334 10/09/2008 ADD_ONE_PEAK_MATRIX_DATA_INITILIZE_CODE			*
 *	Jack QA80-12525 11/25/2008	DEGAULT_TO_USE_FFT_SMOOTH_SECOND_DERIV_METHOD	*
 *	Folger 12/26/08 QA80-12856 v8.0991 IMRPOVE_ocmath_xy_remove_duplicates		*
 *  Iris 2/02/2010 QA81-14165 ALSO_SHOW_PRO_IN_PRO_VERSION						*
 *	Kyle 03/11/2010 PICK_PEAK_ROI_TOOL_SHARES_UTILS_FUNCTION_WITH_PA			*
 *	Folger 03/18/10 QA81-15209 IMPROVE_PA_FIND_PEAKS_FOR_NONE_BASELINE			*
 *	Kyle 09/10/2010 ORG-998-P8 IN_BOTH_DIR_FAIL_TO_FIND_PEAKS_WHICH_CAN_BE_FOUND_IN_NEGATIVE_DIR
 *	Folger 09/27/2010 CODE_CLEANUP_ABOUT_FINDING_PEAKS							*
 *	Folger 09/27/2010 ORG-1159 MOVE_match_peaks_centers_by_index_TO_VC_AS_OCMATH_FUNCTION
 *------------------------------------------------------------------------------*/
 
#include <Origin.h>

#pragma labtalk(0) //CPY 12/6/06 QA70-12736 LT_NEED_MORE_CNTRL_ON_ALLOWING_OC_FUNCS

#include "curve_utils.h"
//---- CPY 12/8/2007 QA80-10788 CURVE_UTILS_SHOULD_NOT_NEED_PRO_DLLS
//#include <fft_utils.h>
//#include <ocmsp.h> /// Hong 11/26/07 v8.0754 CLEAN_CENTRALIZE_CODE_AVOID_DATAPLOT_DEPENDENCE
/////Arvin 01/10/06 ADD_CREATING_CURVES_FUNCTIONS_FOR_PALETTE_EDIT_TOOL
//#include "nlsf_utils.h" 
//#include "NLFitSession.h"
//----
///Arvin 03/13/08 REPLICA_AUTO_INIT_PARAMS_FOR_SURFACE_FIT
#include <ocm.h>
#include <ocTriCtr.h>
///end REPLICA_AUTO_INIT_PARAMS_FOR_SURFACE_FIT
///-----
//#define 	SMOOTH_WINDOW_WIDTH  	1.0/15
//#define 	SMOOTH_RIGHT_LEFT_PTS  	4
//#define 	BASELINE_NOISE_LEVEL  	0.1
//#define 	MAX_PIVOT_POINT_NUM 	5
//#define		MAX_BASELINE_ITER		500

//#define     MAX_RANGE_OF_PEAK		0.1
//#define     MIN_RANGE_OF_PEAK		0.03  
//#define     MIN_HEIGHT              0.2



/*  ///test code///
void find_peaks_from_baseline_ex1()
{
	Worksheet wks = Project.ActiveLayer();
	if(!wks)
		return;

	Dataset dsX(wks, 0);
	Dataset dsY(wks, 1);
	
	vector vx = dsX;
	vector vy = dsY;
	
	int nSize;
	nSize=vx.GetSize();
	if(nSize!=vy.GetSize())
		return;
	
	double maxWidth, minWidth, minHeight;	
	maxWidth = (vx[nSize-1] - vx[0])/2;
	minWidth = (vx[nSize-1] - vx[0])/20;
	double dMin, dMax;
	vy.GetMinMax(dMin, dMax);
	minHeight = (dMax - dMin)/4;
	
	vector<int> vnIndices, vFeetInd;
    vector vbx, vby;
	find_peaks_from_baseline(vx, vy, vbx, vby, vnIndices, vFeetInd, 
	                          minHeight, maxWidth, minWidth);
	                          
	int nPeakNum = vnIndices.GetSize();	 
	int nMarkerNum = vFeetInd.GetSize();	 
	                          
	vector vxPeaks(nPeakNum);
	for(int ii=0; ii<nPeakNum; ii++)
	{
		vxPeaks[ii] = vx[vnIndices[ii]];
	}
	
	vector vxMarkers(nMarkerNum); 
	for(ii=0; ii<nMarkerNum; ii++)
	{
		vxMarkers[ii] = vx[vFeetInd[ii]];
	}

	
	GraphPage gp;
	gp.Create("Line");
	GraphLayer gl = gp.Layers(0);
	gl.AddPlot(wks, IDM_PLOT_LINE);
	gl.Rescale();
	
	Axis ay = gl.YAxis;
	
	Tree tryScale;
	tryScale = ay.Scale;

	for (int k = 0; k < vxPeaks.GetSize(); k++)
	{
		int n1st = wks.AddCol();
		int n2nd = wks.AddCol();
		Dataset ds1(wks, n1st), ds2(wks, n2nd);
		ds1.SetSize(2);
		ds2.SetSize(2);
		
		ds1[0] = vxPeaks[k];
		ds1[1] = vxPeaks[k];
		ds2[0] = tryScale.From.dVal;
		ds2[1] = tryScale.To.dVal;
	
		Curve crv(wks, n1st, n2nd);
		int nPlot = gl.AddPlot(crv, IDM_PLOT_LINE);
		gl.DataPlots(nPlot).SetColor(2);
	}
	
	for ( k = 0; k < nMarkerNum; k++)
	{
		int n1st = wks.AddCol();
		int n2nd = wks.AddCol();
		Dataset ds3(wks, n1st), ds4(wks, n2nd);
		ds3.SetSize(2);
		ds4.SetSize(2);
		
		ds3[0] = vxMarkers[k];
		ds3[1] = vxMarkers[k];
		ds4[0] = tryScale.From.dVal;
		ds4[1] = tryScale.To.dVal;
	
		Curve crv(wks, n1st, n2nd);
		int nPlot = gl.AddPlot(crv, IDM_PLOT_LINE);
		gl.DataPlots(nPlot).SetColor(4);
	}
}*/

///Sandy 12/15/05 MOVE_COMMENT_FROM_MODLL
/// GCJ 10/19/00 Notes on the baseline procedure

//end 12/15/05 MOVE_COMMENT_FROM_MODLL
/*
bool create_baseline_mask(const vector& vbxi, const vector& vbyi, vector& vbxo, vector& vbyo)
{
	long lSize = vbyi.GetSize();
	vbyo.SetSize(0);
	vector  vTemp(lSize);
	vector  vBaseTemp(lSize);
	vector<uint>  vBaseMaskIndex(lSize);
	
	int ii, jj=0, kk=0;
	long lNewSize = lSize;

	double  dSmoothWin = SMOOTH_WINDOW_WIDTH;
	
	int nSmoothPts, nSmoothRightPts, nSmoothLeftPts;

	nSmoothPts = max(lNewSize*dSmoothWin, 1.0);
	nSmoothRightPts = SMOOTH_RIGHT_LEFT_PTS;
	nSmoothLeftPts = SMOOTH_RIGHT_LEFT_PTS;

	// First perform adjacent average smoothing 
	ocmath_adjave_smooth(vbyi, vTemp, lSize, SMOOTH_RIGHT_LEFT_PTS, EDGEPAD_ZERO);

	// Get noise value, i.e. the average variation between two consecutive
	// values in the data set.
	double dNoise = 0;
	//Sandy 12/26/05 encapsulate to GetNoiseLevel(vector& vy)
	//vector vDelta;
	//
	//if(!vbyi.Difference(vDelta))
		//return false;
//
	//vDelta = abs(vDelta);
	//vDelta.Sum(dNoise);
	//end encapsulate to GetNoiseLevel(vector& vy)
	dNoise = get_noise_level(vbyi);
	double BaseResolution = BASELINE_NOISE_LEVEL * dNoise;    // resolution set to half the noise value

	/// GCJ 3/13/00 t7689 v6.0265 STRICTER_EXIT_FOR_BASELINE_FIND
	int nCount = 0;
	/// STRICTER_EXIT_FOR_BASELINE_FIND
	while (kk < MAX_PIVOT_POINT_NUM )
	{
		jj = 0;
		kk = 0;
		/// GCJ 3/13/00 t7689 v6.0265 STRICTER_EXIT_FOR_BASELINE_FIND
		nCount++;
		if(nCount > MAX_BASELINE_ITER)
			return false;
		/// STRICTER_EXIT_FOR_BASELINE_FIND
		for(ii = nSmoothPts, jj=0; ii < lSize; ii++)
		{
			double dData = vbyi[ii];
			double dSmooth = vTemp[ii];

			if( abs(dData - dSmooth) < BaseResolution )						  // change this based on Y range
			{
				vBaseTemp[jj] = ii;
				jj++;
			}
		}

		/// stricter exit for baseline find
		if(jj <  MAX_PIVOT_POINT_NUM)
		{
			BaseResolution *= 1.1; // increment by 10%
			continue;
		}	

		// Now we need to filter this data so that only points which have two
		// immediate neighbours in this set are read in.
		for(ii = 0; ii < jj-2; ii++)
		{
			long nCurrent =  vBaseTemp[ii];
			long nNext =  vBaseTemp[ii + 1];
			long nNext2 = vBaseTemp[ii + 2];
			if( (nCurrent + 1 == nNext) && (nCurrent + 2 == nNext2))
			{
				vBaseMaskIndex[kk] = vBaseTemp[ii];
				kk++;
			}
		}

		BaseResolution *= 1.1; // increment by 10%
	}
	
	//Get baseline point
	vbxo = vbxi;
	vbyo = vbyi;
	vbxo.Reorder(vBaseMaskIndex);
	vbyo.Reorder(vBaseMaskIndex);
	vbxo.SetSize(kk);
	vbyo.SetSize(kk);
	 
	return true;
}*/

/**
Algorithm description:
This X-Function is working on spectrum with sharp peaks, that is, the peak width is quite narrow
compared with the whole spectrum range. It will first find all ordinary peaks by 1st-derivative method.
Then the data corresponding to all peaks are erased from input data. The left data would be good approximation
of the baseline after interpolation. The two feet of a peak are determined by find_peaks_partition(). 
*/

//2006-4-5 add by Sandy REPLACE_CREATE_BASELINE_MASK
bool create_baseline_by_masking_peaks(const vector& vxData,const vector& vyData, vector& vx, vector& vy)
{
	int iSize = vxData.GetSize();
	
	double dMax, dMin;
	vyData.GetMinMax(dMax, dMin);
	double dRange = abs(dMax - dMin);
	if(dRange == 0)
		dRange = 1;
	
	int nPtsSmooth = iSize*get_noise_level(vyData)*SMOOTH_LEVEL/dRange;
	/// Cloud 7/5/07 LIMIT_SMOOTH_POINTS
	if (nPtsSmooth > vyData.GetSize()*0.2)
		nPtsSmooth = vyData.GetSize() * 0.2;
	/// End LIMIT_SMOOTH_POINTS
	
	vector vxPeaks, vyPeaks;
	vector<int> vnIndices;
	
	smooth(vyData, 0, nPtsSmooth, nPtsSmooth);
	if (!find_peaks_1st_derivative(vxData, vyData, vxPeaks, vyPeaks, vnIndices, POSITIVE_DIRECTION | NEGATIVE_DIRECTION))
	{
		return false;
	}
	
	
	vector vx1, vy1;
	vx1 = vxData;
	vy1 = vyData;
	for (int ii = 0; ii < vxPeaks.GetSize(); ii++)
	{
	
		vector vxSub, vySub;
	
		int nStart, nEnd;
	
		if (!find_peaks_partition(vxData, vyData, vxPeaks[ii], nStart, nEnd, nPtsSmooth))
		{
			continue;
		}
		
		int iMid = (nStart + nEnd)/2;
		nStart = iMid - (iMid - nStart)*2;
		nEnd = iMid + (nEnd - iMid)*2;
		
		if (nStart < 0)
		{
			nStart = 0;
		}
		if (nEnd >= iSize)
		{
			nEnd = iSize - 1;		
		}
	
		
		vxSub.SetSize(nEnd - nStart -1);
		vySub.SetSize(nEnd - nStart -1);
		vxSub = NANUM;
		vySub = NANUM;
		vx1.SetSubVector(vxSub, nStart+1);
		vy1.SetSubVector(vySub, nStart+1);
	}
	
	vx1.Trim();
	vy1.Trim();
	
	vx = vx1;
	vy = vy1;
	return true;
}
//
//bool create_baseline_by_positive_peak_mask(const vector& vxi, const vector& vyi, vector& vbxo, vector& vbyo)
//{
	//int ii;
	////prepare data setting for minwidth and maxwidth
	//long	lSize = vyi.GetSize();
	//
	//long	lMinWidth =(long) (MIN_RANGE_OF_PEAK * lSize) / 2.;
	//long	lMaxWidth =(long) (MAX_RANGE_OF_PEAK * lSize) / 2.;
	//long    lMinHeight;
//
	//if(lMinWidth == 1) 
		//lMinWidth++;			// make sure small datasets are okay
//
	//if (lMinWidth < 2)
		//return false;
	//
	//if (lMaxWidth < 3 || lMaxWidth <= lMinWidth)
		//return false;
	//
	//// Find total amplitude:
	//double dMinValue, dMaxValue;
	//vyi.GetMinMax(dMinValue, dMaxValue);
	//
	//lMinHeight = MIN_HEIGHT * (dMaxValue - dMinValue);  // percentage of total amplitude
//
	////finding peak 
	//vector	vFirstDeriv(lSize);
	//vector	vSecondDeriv(lSize);
	//vector	vnIndices(lSize);
	//vector  vFeetInd(lSize);
	//
	//vFirstDeriv = vyi;
//
	//// Get first and second derivatives
	//if(OE_NOERROR != ocmath_derivative(vxi, vFirstDeriv, lSize))
		//return false;
	//
	//vSecondDeriv = vFirstDeriv;
	//if(OE_NOERROR != ocmath_derivative(vxi, vSecondDeriv, lSize))
		//return false;
//
	//long		lNumPeaks = 0;
	//long		lNumMarkers = 0;
	//
	//ii = lMinWidth;     // to leave enough space for the leftmost peak
	//long	nRightMarkerInd = 0;           // last marker index 
	//long	nLeftMarkerInd = 0;            // last left marker
	//
	//while (ii < lSize - lMinWidth)          // to leave enough space for the 
	                                           //// rightmost peak
	//{ 
	    //// should not be too close	   
		//if (lNumMarkers && nRightMarkerInd > ii - lMinWidth)                                                      // to the previous peak.
		//{
			//ii++;
			//continue;
		//}
			//
	   //// Does the first der change sign from + to - ?
		//if(!(vFirstDeriv[ii-2] > 0. && vFirstDeriv[ii-1] > 0. && vFirstDeriv[ii+1] < 0. && vFirstDeriv[ii+2] < 0.))
		//{
			//ii++;
			//continue;
		//}
		//
		//if ( !is_sign_fix_in_width(ii, lMinWidth, vFirstDeriv, 1) )  // Is it wide enough?
		//{
			//ii++;
			//continue;
		//}
		//
		//// Is it too wide? If not, find the left and the right marker indices:
		//if ( !is_peak_width_enough(ii, lMaxWidth, vFirstDeriv, vSecondDeriv, nLeftMarkerInd, nRightMarkerInd) ) 
		//{
			//ii++;
			//continue;
		//}
		//
		//// Is the height OK?
		//if ( !is_peak_height_ok(ii, lMinHeight, vxi, vyi, nLeftMarkerInd, nRightMarkerInd) )
		//{
			//ii = nRightMarkerInd + lMinWidth;  // if  too small, increment for
			                                  //// the minimum halfwidth
			                                  //// but keep nRightMarkerInd.
			//continue;
		//}
		//
		//// Peak found         
		//vnIndices[lNumPeaks++] = (double)ii;
		//vFeetInd[lNumMarkers++] = (double)nLeftMarkerInd;
		//vFeetInd[lNumMarkers++] = (double)nRightMarkerInd;
		//
		//ii = nRightMarkerInd + lMinWidth;
		//
	//}
	//vnIndices.SetSize(lNumPeaks);
	//vFeetInd.SetSize(lNumMarkers);
//
	//// create baseline indices
	//int kk=0;
	//vbxo.SetSize(0);
	//vbyo.SetSize(0);
	//
	//vFeetInd.InsertAt(0, 0);
	//for(ii = 0; ii<lNumPeaks; ii++)
	//{
		//vector vtemp;
		//vxi.GetSubVector(vtemp, vFeetInd[ii*2], vFeetInd[ii*2+1]);
		//vbxo.Append(vtemp);
		//
		//vyi.GetSubVector(vtemp, vFeetInd[ii*2], vFeetInd[ii*2+1]);
		//vbyo.Append(vtemp);
		//
		//kk+=vtemp.GetSize();
	//}
	 //
	//return true;
//}

bool is_sign_fix_in_width(long iCurrent, long lHalfWidth, vector &vData, int nSign)
{
	long    ii;
	long	nBadSign = 0;
	for (ii = iCurrent - lHalfWidth; ii < iCurrent; ii++)
	{
		if ( vData[ii] * nSign < 0. )
			nBadSign++;
	}                  
	if (nBadSign > 1)
		return false;    // not OK

	nBadSign = 0;
	for (ii = iCurrent + 1; ii <= iCurrent + lHalfWidth; ii++)
	{
		if ( vData[ii] * nSign > 0. )		
			nBadSign++;
	}                  
	if (nBadSign > 1)
		return false;    // not OK
	
	return true;        // potentially good point
}

// ------------------------------------------------------------------------------------------- //
// Tests the peak at 'iCurrent' for the maximum width 'maxwidth' points to the left and
// to the right. If the width is fine, it sets the marker indices
// nLeftMarkerInd and nRightMarkerInd.
// Returns:
//		1 for pass, 0 for failure.
//                                
// ------------------------------------------------------------------------------------------- //
bool is_peak_width_enough(long iCurrent, long maxwidth, vector& vFirstDeriv, vector& vSecondDeriv,
							  long& nLeftMarkerInd,  long& nRightMarkerInd)
{
	long		nRightInd;
	long		nLeftInd;

	BOOL	bMaxWidthRightOK = 0;
	// First test the right side:
	{
		long	ii = iCurrent;
		double	dSecDer1 = vSecondDeriv[ii];
		double	dSecDerMax = dSecDer1;
		double	FirstDerMax = vFirstDeriv[ii++];
		double	dTempPrev = FirstDerMax; 
		// Now find the "foot" of the peak
		while ((ii <= iCurrent + maxwidth) && (ii < vSecondDeriv.GetSize()))
		{
			double	dTemp;                
			// First "foot" criterium: Two consecutive first derivatives
			// must satisfy the same condition: change of sign
			if ( (dTemp = vFirstDeriv[ii]) > 0. && dTempPrev > 0. ) 
			{
				if ( (nRightInd = ii - 2) > iCurrent )  // make sure we are far enough from the peak 
				                                        // and set the right marker value
				{
					bMaxWidthRightOK = 1;
					break;
				}
			}   
			if ( dTemp < FirstDerMax )              // update (Abs value) max first der.
				FirstDerMax = dTemp;    

			// Second "foot" criterium:
			// These conditions say: put the marker here if the second derivative is 
			// substantially smaller than the max value 
			// and if the first derivatives have decreased and are small enough.
			if ( (dSecDer1 = vSecondDeriv[ii]) < dSecDerMax / 10. && 
				abs(dTemp) < abs(dTempPrev) && abs(dTempPrev) < abs(FirstDerMax) / 10. )
				if ( (nRightInd = ii) > iCurrent )
				{
					bMaxWidthRightOK = 1;
					break;
				}
			if ( dSecDer1 > dSecDerMax )
				dSecDerMax = dSecDer1;                  // update max. second derivative
			
			dTempPrev = dTemp;                 
			ii++;
		}
	}             

	BOOL	bMaxWidthLeftOK = 0;
    // Now test the left side:
	{ 
		long	ii = iCurrent;
		double	dSecDer1 = vSecondDeriv[ii];
		double	dSecDerMax = dSecDer1;
		double	FirstDerMax = vFirstDeriv[ii--];
		double	dTempPrev = FirstDerMax;
		// Now find the "foot" of the peak
		while (ii >= 0 && ii >= iCurrent - maxwidth && ii >= nRightMarkerInd - 2) 
		// The summation goes 2 points beyond the last marker because of the first
		// foot criterium, which actually goes two points "into" the previous peak
		// (that is also why "nLeftInd = ii + 2").
		{
			double	dTemp;
			// The first "foot" criterium: Two consecutive first derivatives
			// must satisfy the same condition: change of sign
			if ( (dTemp = vFirstDeriv[ii]) < 0. && dTempPrev < 0. ) 
			{
				if ( (nLeftInd = ii + 2) < iCurrent ) // make sure we are far enough from the peak
                                                      // and set the left marker value
				{
					bMaxWidthLeftOK = 1;
					break;                            // exit the loop
				}
			}
			if ( dTemp > FirstDerMax )                // update max first der.
				FirstDerMax = dTemp;    

			// Second "foot" criterium:
			// The condition "ii >= nRightMarkerInd" is here because of -2 in the "while" condition
			// These conditions say: put the marker here if the second derivative is 
			// substantially smaller than the max value 
			// and if the first derivatives have decreased and are small enough.
			if ( ii >= nRightMarkerInd && (dSecDer1 = vSecondDeriv[ii]) < dSecDerMax / 10. && 
				abs(dTemp) < abs(dTempPrev) &&  abs(dTempPrev) < abs(FirstDerMax) / 10.)
				if ( (nLeftInd = ii) < iCurrent )    // set left marker value
				{
					bMaxWidthLeftOK = 1;
					break;
				}
			if ( dSecDer1 > dSecDerMax )
				dSecDerMax = dSecDer1;
			    
			
			dTempPrev = dTemp;                     // update max. second derivative
			ii--;
		}
	}             
	//	break;
	//}

	if ( !bMaxWidthLeftOK && !bMaxWidthRightOK )
		return 0;                     // failure

	if ( bMaxWidthLeftOK && !bMaxWidthRightOK )
		if ( (nRightInd = iCurrent + (iCurrent - nLeftInd) + 1) >= vSecondDeriv.GetSize() )
			return 0;                 // failure

	if ( !bMaxWidthLeftOK && bMaxWidthRightOK )
		if ( (nLeftInd = iCurrent - (nRightInd - iCurrent) - 1) < 0 && nLeftInd < nRightMarkerInd )
			return 0;                 // failure

	nLeftMarkerInd = nLeftInd;
	nRightMarkerInd = nRightInd;
	return 1;                         // success
}

// ---------------------------------------------------------------------------------------- //
// Tests the peak for the height. First it finds the absolute maximum of the original data
// between the markers and adjusts the peak position 'iPeak' accordingly.
// The height is determined by linearly interpolating
// between the markers and finding the difference with the data value at the peak point.
// Returns:
//		1 for pass, 0 for failure.
//
// ---------------------------------------------------------------------------------------- //
bool is_peak_height_ok(long& lPeak, double dMinHeight, vector& vx, vector& vy,
                       long nLeftMarkerInd, long nRightMarkerInd)
{
		double 	dLeftX, dLeftY, dRightX, dRightY, dPeakX, dPeakY;
		
		// Should not be no value!
		if(nRightMarkerInd < nLeftMarkerInd || vx.GetSize() < nRightMarkerInd)
			return false;
		
		dLeftX = vx[nLeftMarkerInd];
		dLeftY = vy[nLeftMarkerInd];
		dRightX = vx[nRightMarkerInd];
		dRightY = vy[nRightMarkerInd];

		/// First find maximum data value between the markers.
		long		iPeakInd = -1;
		double		atpeak = -1.e+123;
		for (long ii = nLeftMarkerInd + 1; ii < nRightMarkerInd; ii++)
			if ( (vy[ii] != NANUM) && (vy[ii] > atpeak) )
			{
				iPeakInd = ii;
				atpeak = vy[ii];
			}
		

		dPeakX = vx[iPeakInd];
		dPeakY = vy[iPeakInd];
		
		// Is the peak in between the markers (it has to be)?
		if ( (dRightX <= dLeftX ) || (dPeakX <= dLeftX) || (dPeakX >= dRightX) )
			return false;
		
		// Linear interpolation:
		double dPeakHeight; 
		dPeakHeight = dPeakY - dLeftY - (dPeakX - dLeftX) * (dRightY - dLeftY) / (dRightX - dLeftX); 
		if (dPeakHeight < dMinHeight)
			return false;         // too small
		
		lPeak = iPeakInd;   // adjust the index
		return true;    // OK
} 



//bool find_peaks_from_baseline_1st_derivative(vector& vx, vector& vy, const vector& vbx, const vector& vby, 
                                       //int nDir, vector<int>& vnIndices, vector& vxPeaks, vector& vyPeaks)
//{
//
	//long ii, jj = 0;
	//long lSize = vy.GetSize();
	//int  nSign;
	//
	//if(vx.GetSize()!=lSize)
		//return false;
//
	//// construct the new baseline based on the basex and basey datasets
	//// these will have to be present at all times
	//vector vyTemp(lSize);
	//if(vbx.GetSize() != 0)
	//{
		//double dxMin, dxMax;
		//vbx.GetMinMax(dxMin, dxMax);
		//long lBSize = vbx.GetSize();
		//
		//vector vxBase(lSize);
		//vxBase.Data(dxMin, dxMax, (dxMax-dxMin)/(lSize-1));
		//vector vyBase(lSize);
		//
		//int nRet;                               // construct baseline set
		//vector<uint> vN;
		//vbx.Sort(SORT_ASCENDING, false, vN);
		//vby.Reorder(vN);
		//if(OE_NOERROR != ocmath_interpolate(vxBase, vyBase, lSize, vbx, vby, lBSize, INTERP_TYPE_LINEAR))
		//{
			//return false;
		//}
		//
		////subtract the base
		//vyTemp = vy - vyBase;
//
	//}
	//else
	//{
		//vyTemp = vy;
	//}
//
	//bool nRet = find_peaks_1st_derivative(vx, vyTemp, vxPeaks, vyPeaks, vnIndices, nDir, NUM_SMOOTH_POINT_FOR_PEAK);
	//
	//return nRet;
//}
/*
bool find_peaks_from_baseline_1st_derivative(vector& vx, vector& vy, const vector& vbx, const vector& vby, int nDir, 
				vector<int>& vnIndices, vector& vxPeaks, vector& vyPeaks, int* nSize, bool bSmoothMode)
{
	///Sandy 2006-9-13 for centralize code
	//long lSize = vy.GetSize();
	//int nRet;	
	//if(vx.GetSize()!=lSize)
		//return false;
//
	//vector vyTemp(lSize);
	//if(vbx.GetSize() != 0)
	//{
		//double dxMin, dxMax;
		//vbx.GetMinMax(dxMin, dxMax);
		//long lBSize = vbx.GetSize();
		//
		//vector vxBase(lSize);
		//vxBase.Data(dxMin, dxMax, (dxMax-dxMin)/(lSize-1));
		//vector vyBase(lSize);
//
		//if(nRet = ocmath_interpolate(vxBase, vyBase, lSize, vbx, vby, lBSize, INTERP_TYPE_LINEAR))
		//{
			//return nRet;
		//}
		//vyTemp = vy - vyBase;
	//}
	//else
	//{
		//vyTemp = vy;
	//}
	int nRet;	
	vector vyTemp;
	vyTemp = vy;
	subtract_baseline(vx,vyTemp, vbx, vby);

	//bool nRet = find_peaks_1st_derivative(vx, vyTemp, vxPeaks, vyPeaks, vnIndices, nDir, NUM_SMOOTH_POINT_FOR_PEAK);
	if(bSmoothMode)
		nRet = ocmath_find_peaks_1st_derivative(nSize, vx, vyTemp, vxPeaks, vyPeaks, vnIndices, nDir, NUM_SMOOTH_POINT_FOR_NOISE); 
    else
		nRet = ocmath_find_peaks_1st_derivative(nSize, vx, vyTemp, vxPeaks, vyPeaks, vnIndices, nDir, NUM_SMOOTH_POINT_FOR_PEAKS);  
	
	return nRet;
}
*/


bool find_feet_of_peaks_by_height_and_width(const vector& vx, const vector& vy, vector<int> vnIndices, 
                      double dFootHeight, double dMaxWidth, double dMinWidth, vector<int>& vFeetInd)
{
	//test the max and min width
	if(dMaxWidth < dMinWidth)
		return false;
	
	double dMin, dMax;
	vx.GetMinMax(dMin, dMax);
	if(dMaxWidth > dMax)
		dMaxWidth = dMax;
	
	if(dMinWidth < 0)
		dMinWidth = 0;
	
	int ii, nPeakNum;
	vector vTemp;
	vTemp = vy;
	vTemp.Replace(dFootHeight, NANUM, MATREPL_TEST_LESSTHAN|MATREPL_USE_ABSOLUTE_VALUE_IN_TEST);
	nPeakNum = vnIndices.GetSize();
	vFeetInd.SetSize(2*nPeakNum);
	
	int nCurrInd = 0;
	int nLastInd;
	for(ii = 0; ii < nPeakNum; ii++)
	{
		int nLeftMarker, nRightMarker, nPeakInd;
		nLeftMarker = nRightMarker = nPeakInd = vnIndices[ii];
		bool isWidthOK=false;
		
		//left marker;
		do
		{
		    if(vTemp[nLeftMarker] == NANUM || nLeftMarker <= 0)
		    {
		    	break;
		    }
		    nLeftMarker --;
			isWidthOK = is_inside_range((vx[nPeakInd]-vx[nLeftMarker]), dMinWidth, dMaxWidth);
		}
		while(!isWidthOK);
		
		nLastInd = nCurrInd;
        if( ii == 0 && nLeftMarker >= 0)
        {
			//nLastInd = nCurrInd;
			vFeetInd[nCurrInd++] = nLeftMarker;        	
        }
        else if(nLeftMarker < vnIndices[ii])
		{
			//nLastInd = nCurrInd;
			vFeetInd[nCurrInd++] = nLeftMarker;
		}
		else
		{
			//nLastInd = nCurrInd;
			vFeetInd[nCurrInd++] = NANUM;			
		}
			
		//right marker;
		do
		{
		    if(vTemp[nRightMarker] == NANUM || nRightMarker >= (vTemp.GetSize() - 1))
		    {
		    	break;
		    }
		    nRightMarker ++;
			isWidthOK = is_inside_range((vx[nRightMarker]-vx[nPeakInd]), dMinWidth, dMaxWidth);
		}
		while( !isWidthOK );
//		vFeetInd[ii*2+1] = nRightMarker; 

		nLastInd = nCurrInd;
		if( ii == (nPeakNum-1) && nRightMarker < vTemp.GetSize())
		{
			//nLastInd = nCurrInd;
			vFeetInd[nCurrInd++] = nRightMarker;			
		}
		else if(nRightMarker > vnIndices[ii])
		{
			//nLastInd = nCurrInd;
			vFeetInd[nCurrInd++] = nRightMarker;
		}
		else
		{
			vFeetInd[nCurrInd++] = NANUM;
		}
		
		nLeftMarker = nRightMarker;
	}
	
	vFeetInd.SetSize(nCurrInd);
	
	return true;
}

bool is_inside_range(double Data, double Value1, double Value2, bool isInculding = false)
{
	double minValue, maxValue;
	minValue = min(Value1, Value2);
	maxValue = max(Value1, Value2);
	
	if(Data < maxValue && Data > minValue)
		return true;

	if(isInculding && (Data == Value1 || Data == Value2 ))
		return true;
		
	return false;
	
}




/// this function computes the mean variation between points in the
// data set. We call this the Noise Level.
double get_noise_level(vector& vy)
{
	long lSize = vy.GetSize();
	if(lSize<2)
		return 0;
	
	double dNoise = 0;
	vector vDelta;
	
	if(!vy.Difference(vDelta))
		return 0;

	///Sandy 2009-1-8 SPEED_UP_VECTOR_ABS
	//vDelta = abs(vDelta);
	vDelta.Abs();
	//end SPEED_UP_VECTOR_ABS
	
	vDelta.Sum(dNoise);
	
	dNoise = dNoise/lSize;

	return dNoise;

}



// -------------------------------------------------------------------------------- //
// Tests for a zero of the vector vData at the point iCurrent
// Returns:
//     1 for the "zero" found, direction is Positive to Negative,
//     -1 for the "zero" found , direction is Negative to Positive
//     0 otherwise.
//
// -------------------------------------------------------------------------------- //
int isPosToNeg(long iCurrent, vector& vData)
{
	if(iCurrent < 2 || iCurrent > vData.GetSize()-3 )
		return 0;
	double		dLeft2 = vData[iCurrent - 2];
	double		dLeft1 = vData[iCurrent - 1];
	double		dRight1 = vData[iCurrent + 1];
	double		dRight2 = vData[iCurrent + 2];

	if (dLeft2 > 0. && dLeft1 > 0. && dRight1 < 0. && dRight2 < 0.)
		return 1;    
		
	if (dLeft2 < 0. && dLeft1 < 0. && dRight1 > 0. && dRight2 > 0.)
		return -1;  
		
	return 0;          // bad point
}

//Sandy 2005-12-26 MOVE_FROM_PFM_UTTILS

//this function is no use at present
// LLOC for finding baseline points using 2nd derivative method
//int curve_find_baseline(curvebase& crvData, vector& vBsln, double dPercentile)
//{
	//// NOTE: IT IS ASSUMED THAT THE DATA IN CRVDATA IS SORTED IN X.
	//// IF NOT, HLOC SHOULD SORT BEFORE CALLING THIS LLOC.
	//
	/////Kevin 08/09/2005 ADD_A_CONDITION
	//if( dPercentile < 0 || dPercentile > 100 )
		//return 0;
	//
	//bool bRet;
	//int iRet;
	//double 	dThresh;
	//
	//// First create a copy of the data curve for further processing
	//Curve crvDataCopy(crvData);
	//
	//// Smooth the data curve using 3-pt adjacent averaging
	//if( !(bRet = curve_smooth_adjave(crvDataCopy,1)) ) return -1;
	//
	//if( 1 != (iRet = curve_derivative(crvDataCopy)) ) return -2;
	//if( 1 != (iRet = curve_derivative(crvDataCopy)) ) return -2;
//
	//// Take the absolute value of the data
	//crvDataCopy = abs(crvDataCopy);
//
//
	//// Get the percentile value
	//Data_percentiles( &crvDataCopy, &dPercentile, &dThresh, 1 );
//
	//// Replace points outside threshold with NANUM
	//crvDataCopy.Replace(dThresh, NANUM, MATREPL_TEST_GREATER | MATREPL_USE_ABSOLUTE_VALUE_IN_TEST);
	//
	//// Remove all points that do not have a neighbor on either side. This is to ensure
	//// that spurious baseline points that correspond to peaks in the data are removed.
	//// Also get the index values of these points
	//int iSize = crvDataCopy.GetSize();
	//vBsln.SetSize(iSize);
	//vBsln.Data(1,iSize,1);		//index values for baseline points
	//
	//vector vTemp;
	//vTemp=crvDataCopy;
	//vTemp.SetSize(iSize);
	//vTemp.Replace(NANUM,1,MATREPL_TEST_GREATER | MATREPL_TEST_LESSTHAN); //Replace values that are not equal to NANUM with 1
	//vBsln*=vTemp;
	//vTemp=crvDataCopy;
	//vTemp.InsertAt(0,NANUM); 		//Insert row to check previous point
	//vTemp.SetSize(iSize);
	//vTemp.Replace(NANUM,1,MATREPL_TEST_GREATER | MATREPL_TEST_LESSTHAN); //Replace values that are not equal to NANUM with 1
	//vBsln*=vTemp;					//Remove indexes
	//vTemp=crvDataCopy;
	//vTemp.RemoveAt(0,1);			//Remove row to check next point
	//vTemp.InsertAt(iSize-1,NANUM);
	//vTemp.Replace(NANUM,1,MATREPL_TEST_GREATER | MATREPL_TEST_LESSTHAN);
	//vBsln*=vTemp;
	//vBsln.Trim();					//Remove NANUM from baseline vector
//
	//return vBsln.GetSize();
//}

////------------
//// LLOC for finding peaks using 1st derivative method
//// iDirection = 1: only positive peaks; = -1: only negative peaks; =0: both pos and neg peaks
//int curve_find_peaks(const curvebase& crvData, vector& vPks, double dThresh, int iDirection)// = 2)
//{
	//// NOTE: IT IS ASSUMED THAT THE DATA IN CRVDATA IS SORTED IN X.
	//// IF NOT, HLOC SHOULD SORT BEFORE CALLING THIS LLOC.
	//
	//bool bRet;
	//int iRet;
	//
	//// First create a copy of the data curve for further processing
	//Curve crvDataCopy(crvData);
	//
	//// Smooth the data curve using 3-pt adjacent averaging
	//if( !(bRet = curve_smooth_adjave(crvDataCopy, 1)) ) return -1;
	//
	//// Compute 1st derivative of the smoothed curve
	//if( 1 != (iRet = curve_derivative(crvDataCopy)) ) return -2;
	//
	//// Compute threshold on original data, as percentage of ratio of max to min
	//double dSpread = curve_spread(crvData);
	//dThresh = dThresh* abs(dSpread);
//
	//int iSize = crvDataCopy.GetSize();
//
	//// Look for all points of the 1st deriv and look for zero crossings.  If for a zero
	//// crossing in the deriv, the absolute value of the original data is above theshold,
	//// then that corresponds to a peak. Save the index value of the peak.
//
	//vector vTemp,vTempPk,vPksIndex;
	//vPksIndex.SetSize(iSize);
	//vPksIndex.Data(1,iSize,1);		//Vector for peak indexes
	//vTemp=abs(crvData);
	//vTemp.SetSize(iSize);
	//vTemp.Replace(dThresh,1,MATREPL_TEST_GREATER | MATREPL_SET_TO_MISSING_VALUE_WHEN_TEST_RESULT_IS_FALSE);
	//vPksIndex*=vTemp;				
	//vTemp=abs(crvData);
	//vTemp.RemoveAt(0,1);
	//vTemp.SetSize(iSize);
	//vTemp.Replace(dThresh,1,MATREPL_TEST_GREATER | MATREPL_SET_TO_MISSING_VALUE_WHEN_TEST_RESULT_IS_FALSE);
	//vPksIndex*=vTemp;
	//vTempPk=vPksIndex;
	//if(iDirection >= 0)		//Search for positive peaks
	//{
		//vTemp=crvDataCopy;
		//vTemp.InsertAt(0,NANUM);	//Find points where first deriv crosses zero from positive to negative
		//vTemp.SetSize(iSize);
		//vTemp.Replace(0,1,MATREPL_TEST_GREATER | MATREPL_SET_TO_MISSING_VALUE_WHEN_TEST_RESULT_IS_FALSE);
		//vPksIndex*=vTemp;
		//vTemp=crvDataCopy;
		//vTemp.SetSize(iSize);
		//vTemp.Replace(0,1,MATREPL_TEST_LESSTHAN | MATREPL_SET_TO_MISSING_VALUE_WHEN_TEST_RESULT_IS_FALSE);
		//vPksIndex*=vTemp;
		//vPksIndex.Trim();
		//vPks.Append(vPksIndex); 
	//}
//
	//if(iDirection <= 0)		//Search for negative peaks
	//{
		//vPksIndex=vTempPk;	//Reset to get negative peaks
		//vTemp=crvDataCopy;
		//vTemp.SetSize(iSize);
		//vTemp.Replace(0,1,MATREPL_TEST_LESSTHAN | MATREPL_SET_TO_MISSING_VALUE_WHEN_TEST_RESULT_IS_FALSE);
		//vPksIndex*=vTemp;
		//vTemp=crvDataCopy;
		//vTemp.RemoveAt(0,1);//Find points where first deriv crosses zero from negative to positive
		//vTemp.SetSize(iSize);
		//vTemp.Replace(0,1,MATREPL_TEST_GREATER | MATREPL_SET_TO_MISSING_VALUE_WHEN_TEST_RESULT_IS_FALSE);
		//vPksIndex*=vTemp;
		//vPksIndex.Trim();
		//vPks.Append(vPksIndex); 
	//}
//
	//return vPks.GetSize();
//}	

/////Forest 7/30/04 QA70-6077 PEAK_FIRST_DERIVATIVE_METHOD
//// LLOC for finding peaks using 1st derivative method
//// iDirection = 1: only positive peaks; = -1: only negative peaks; =0: both pos and neg peaks
//int find_peaks_1st_derivative(vector& vxData, vector& vyData, vector& vxPeaks, vector& vyPeaks, double dThresh, int iDirection, int nSmoothPts)
//{
	//// NOTE: IT IS ASSUMED THAT THE DATA IN VXDATA IS SORTED.
	//// IF NOT, HLOC SHOULD SORT BEFORE CALLING THIS LLOC.
	//
	//bool bRet;
	//int iRet;
	//
	//Curve crvData(vxData, vyData);
	//
	//// Compute threshold on original data, as percentage of ratio of max to min
	//double dSpread = curve_spread(crvData);
	//dThresh = dThresh* abs(dSpread);
	//
	//// Smooth the data curve using nSmoothPts-pt adjacent averaging
	//// nSmoothPts = 0 for no smoothing
	//if(nSmoothPts != 0)
		//if( !(bRet = curve_smooth_adjave(crvData,(nSmoothPts-1)/2)) )
			//return -1;
	//
	//// Compute 1st derivative of the smoothed curve
	//if( 1 != (iRet = curve_derivative(crvData)) ) return -2;
		//
	//int iSize = crvData.GetSize();
//
	//// Look for all points of the 1st deriv and look for zero crossings.  If for a zero
	//// crossing in the deriv, the absolute value of the original data is above theshold,
	//// then that corresponds to a peak. Also save the peak points.
//
	//vector vTemp, vxPks, vyPks, vxPksCopy, vyPksCopy;
	//
	//vxPks = vxData;
	//vyPks = vyData;
	//vxPks.SetSize(iSize);
	//vyPks.SetSize(iSize);
		//
	//vTemp = abs(vyData);
	//vTemp.SetSize(iSize);
	//vTemp.Replace(dThresh,1,MATREPL_TEST_GREATER | MATREPL_SET_TO_MISSING_VALUE_WHEN_TEST_RESULT_IS_FALSE);
	//vxPks*=vTemp;
	//vyPks*=vTemp;
	//
	//vTemp = abs(vyData);
	//vTemp.RemoveAt(0,1);
	//vTemp.SetSize(iSize);
	//vTemp.Replace(dThresh,1,MATREPL_TEST_GREATER | MATREPL_SET_TO_MISSING_VALUE_WHEN_TEST_RESULT_IS_FALSE);
	//vxPks*=vTemp;
	//vyPks*=vTemp;
	//
	//vxPksCopy=vxPks;		//create a copy for further processing
	//vyPksCopy=vyPks;
	//
	//vxPeaks.SetSize(0);		//set vxPeaks and vyPeaks to null
	//vyPeaks.SetSize(0);
	//
	//if(iDirection >= 0)		//Search for positive peaks
	//{
		//vTemp=crvData;
		//vTemp.InsertAt(0,NANUM);	//Find points where first deriv crosses zero from positive to negative
		//vTemp.SetSize(iSize);
		//vTemp.Replace(0,1,MATREPL_TEST_GREATER | MATREPL_SET_TO_MISSING_VALUE_WHEN_TEST_RESULT_IS_FALSE);
		//vxPks*=vTemp;
		//vyPks*=vTemp;
		//
		//vTemp=crvData;
		//vTemp.SetSize(iSize);
		//vTemp.Replace(0,1,MATREPL_TEST_LESSTHAN | MATREPL_SET_TO_MISSING_VALUE_WHEN_TEST_RESULT_IS_FALSE);
		//vxPks*=vTemp;
		//vyPks*=vTemp;
		//
		//vxPks.Trim();
		//vyPks.Trim();
		//vxPeaks.Append(vxPks);	//Append positive peaks
		//vyPeaks.Append(vyPks);
	//}
//
	//if(iDirection <= 0)		//Search for negative peaks
	//{
		//vxPks=vxPksCopy;	//Reset to get negative peaks
		//vyPks=vyPksCopy;
		//
		//vTemp=crvData;
		//vTemp.SetSize(iSize);
		//vTemp.Replace(0,1,MATREPL_TEST_LESSTHAN | MATREPL_SET_TO_MISSING_VALUE_WHEN_TEST_RESULT_IS_FALSE);
		//vxPks*=vTemp;
		//vyPks*=vTemp;
		//
		//vTemp=crvData;
		//vTemp.RemoveAt(0,1);//Find points where first deriv crosses zero from negative to positive
		//vTemp.SetSize(iSize);
		//vTemp.Replace(0,1,MATREPL_TEST_GREATER | MATREPL_SET_TO_MISSING_VALUE_WHEN_TEST_RESULT_IS_FALSE);
		//vxPks*=vTemp;
		//vyPks*=vTemp;
		//
		//vxPks.Trim();
		//vyPks.Trim();
		//vxPeaks.Append(vxPks);	//Append negative peaks
		//vyPeaks.Append(vyPks);
	//}
//
	//return vxPeaks.GetSize();
//}
//
// LLOC for finding base markers - uses data points and peak points found using prev LLOC
//int find_basemarkers_1st_derivative(vector& vxData, vector& vyData, vector& vxPeaks, vector& vyPeaks, vector& vxBaseMarkers, vector& vyBaseMarkers)
//{
	//// NOTE: IT IS ASSUMED THAT VXDATA IS SORTED. IF NOT, HLOC SHOULD SORT BEFORE CALLING THIS LLOC.
	//
	//int  iRet;
	//
	//Curve	crvData(vxData, vyData);
	//int iSize = crvData.GetSize();
		//
	//// First create a copy of the data curve for further processing
		//
	//// Compute 1st derivative of the smoothed curve
	//if( 0 != (iRet = Curve_derivative(&crvData, &crvData, 1)) ) return -1;
	//
	//// There will be two base markers for each peak
	//int iNumPks = vxPeaks.GetSize();
	//vxBaseMarkers.SetSize(iNumPks * 2);
	//vyBaseMarkers.SetSize(iNumPks * 2);
	//
	//// Find index of all peaks
	//vector vPkIndex(iNumPks), vTemp;
	//for(int ii = 0; ii < iNumPks; ii++)
		//vPkIndex[ii] = Data_list(vxPeaks[ii], &vxData);
	//
	////vIndexPtoN store index of points where first deriv crosses zero from positive to negative
	////vIndexNtoP store index of points where first deriv crosses zero from negative to positive
	//vector	vIndexPtoN, vIndexNtoP;
	//vIndexPtoN.SetSize(iSize);
	//vIndexPtoN.Data(0,iSize - 1,1);
	//vIndexNtoP.SetSize(iSize);
	//vIndexNtoP.Data(0,iSize - 1,1);	
	//
	//vTemp = crvData;
	//vTemp.InsertAt(0,NANUM);	//Insert row to check previous point
	//vTemp.SetSize(iSize);
	//vTemp.Replace(0,1,MATREPL_TEST_GREATER | MATREPL_SET_TO_MISSING_VALUE_WHEN_TEST_RESULT_IS_FALSE);
	//vIndexPtoN *= vTemp;
	//vTemp = crvData;
	//vTemp.SetSize(iSize);
	//vTemp.Replace(0,1,MATREPL_TEST_LESSTHAN | MATREPL_SET_TO_MISSING_VALUE_WHEN_TEST_RESULT_IS_FALSE);
	//vIndexPtoN *= vTemp;
	//vIndexPtoN.Trim();			//Remove NANUM from vector
	//
	//vTemp = crvData;
	//vTemp.InsertAt(0,NANUM);	//Insert row to check previous point
	//vTemp.SetSize(iSize);
	//vTemp.Replace(0,1,MATREPL_TEST_LESSTHAN | MATREPL_SET_TO_MISSING_VALUE_WHEN_TEST_RESULT_IS_FALSE);
	//vIndexNtoP *= vTemp;
	//vTemp = crvData;
	//vTemp.SetSize(iSize);
	//vTemp.Replace(0,1,MATREPL_TEST_GREATER | MATREPL_SET_TO_MISSING_VALUE_WHEN_TEST_RESULT_IS_FALSE);
	//vIndexNtoP *= vTemp;
	//vIndexNtoP.Trim();			//Remove NANUM from vector
//
	//// Loop thru all peaks and find base markers
	//for(ii = 0; ii < iNumPks; ii++)
	//{
		//int	iDirection;
		//if(vyPeaks[ii] > 0) 
			//iDirection = 1;
		//else 
			//iDirection = -1;
		//int	iLtMrkrIndex, iRtMrkrIndex, nIndexSize;
		//// Now start finding left of vPkIndex[ii] for last change in sign of 1st derivative
		//int iLower = 0;
		//int iUpper = vPkIndex[ii];	
//
		//vector<uint> vIndex;
		//vIndex.SetSize(0);
		//if(1 == iDirection)
		//{			
			//vIndexNtoP.Find(vIndex, iLower, iUpper);
			//nIndexSize = vIndex.GetSize();
			//if(nIndexSize < 1)
				//iLtMrkrIndex = 0;
			//else
				//iLtMrkrIndex = vIndexNtoP[nIndexSize - 1];
		//}
		//else
		//{
			//vIndexPtoN.Find(vIndex, iLower, iUpper);
			//nIndexSize = vIndex.GetSize();
			//if(nIndexSize < 1)
				//iLtMrkrIndex = 0;
			//else
				//iLtMrkrIndex = vIndexPtoN[nIndexSize - 1];
		//}	
		//// Now start finding right of vPkIndex[ii] for first change in sign of 1st derivative 
		//iLower = vPkIndex[ii];
		//iUpper= iSize - 1;
		//vIndex.SetSize(0);
		//if(1 == iDirection)
		//{			
			//vIndexNtoP.Find(vIndex, iLower, iUpper);
			//nIndexSize = vIndex.GetSize();
			//if(nIndexSize < 1)
				//iRtMrkrIndex = iSize - 1;
			//else
				//iRtMrkrIndex = vIndexNtoP[vIndex[0]] - 1;
		//}
		//else
		//{
			//vIndexPtoN.Find(vIndex, iLower, iUpper);
			//nIndexSize = vIndex.GetSize();
			//if(nIndexSize < 1)
				//iRtMrkrIndex = iSize - 1;
			//else
				//iRtMrkrIndex = vIndexPtoN[vIndex[0]] - 1;
		//}
		//// Copy base markers to vectors
		//vyBaseMarkers[ii * 2] = vyData[iLtMrkrIndex];
		//vxBaseMarkers[ii * 2] = vxData[iLtMrkrIndex];
		//vyBaseMarkers[ii * 2 + 1] = vyData[iRtMrkrIndex];
		//vxBaseMarkers[ii * 2 + 1] = vxData[iRtMrkrIndex];
	//}
	//
	//return 0;
//}
///End PEAK_FIRST_DERIVATIVE_METHOD

///End MOVED_PEAK_AND_BASLINE_FUNCS_TO_PFM_UTILS

//Sandy 2005-12-26 CHANGE_FUNCTION_NAME_AFTER_MERGE_RELATIVE_FUNCTIONS
//bool find_peaks_1st_derivative2(vector& vxData, vector& vyData, vector& vxPeaks, vector& vyPeaks, int nDir, int nPtsSmooth)
bool find_peaks_1st_derivative(const vector& vxData, const vector& vyData, 
							   vector& vxPeaks, vector& vyPeaks,
							   vector<int>& vnIndices, int nDir, int nPtsSmooth)
{
	Curve cvData(vxData, vyData);
	if (nPtsSmooth > 3 && !curve_smooth_sg(cvData,(nPtsSmooth-1)/2))
	{
		return false;
	}
	curve_derivative(cvData);
	if (nPtsSmooth > 3 && !curve_smooth_sg(cvData,(nPtsSmooth-1)/2))
	{
		return false
	}
	
	int iSize = cvData.GetSize();
	vector vTemp1, vTemp2;
	

	vxPeaks.SetSize(0);
	vyPeaks.SetSize(0);
	vnIndices.SetSize(0);		//Vector for peak indexes
	
	vector vTempPkInd;
	vTempPkInd.SetSize(iSize);
	vTempPkInd.Data(1,iSize,1);		
	
	vector vxp, vyp;

	if (nDir &  POSITIVE_DIRECTION)
	{
		cvData.CopyData(vTemp1, vTemp2);
		vTemp1 = vTemp2;
		vTemp2.InsertAt(0, vTemp2[0]);
		vTemp2.SetSize(iSize);
	
		vTemp1.Replace(0, 1, MATREPL_TEST_LESSTHAN | MATREPL_SET_TO_MISSING_VALUE_WHEN_TEST_RESULT_IS_FALSE);
		vTemp2.Replace(0, 1, MATREPL_TEST_GREATER | MATREPL_SET_TO_MISSING_VALUE_WHEN_TEST_RESULT_IS_FALSE);
		
		vTemp1 *= vTemp2;
		
		vxp = vxData * vTemp1;
		vyp = vyData * vTemp1;
		
		vTempPkInd = vTempPkInd * vTemp1;
		
		vxp.Trim();
		vyp.Trim();
		vTempPkInd.Trim();
		
		vxPeaks.Append(vxp);	//Append positive peaks
		vyPeaks.Append(vyp);
		vnIndices.Append(vTempPkInd);
	}
	
	vTempPkInd.SetSize(iSize);  //reset peak indexes
	vTempPkInd.Data(1,iSize,1);	

	
	if (nDir & NEGATIVE_DIRECTION)
	{
		cvData.CopyData(vTemp1, vTemp2);
		vTemp1 = vTemp2;
		vTemp1.RemoveAt(0);
		vTemp1.SetSize(iSize);
		
		vTemp1.Replace(0, 1, MATREPL_TEST_GREATER | MATREPL_SET_TO_MISSING_VALUE_WHEN_TEST_RESULT_IS_FALSE);
		vTemp2.Replace(0, 1, MATREPL_TEST_LESSTHAN | MATREPL_SET_TO_MISSING_VALUE_WHEN_TEST_RESULT_IS_FALSE);
		
		vTemp1 *= vTemp2;
		
		vxp = vxData * vTemp1;
		vyp = vyData * vTemp1;
		
		vTempPkInd = vTempPkInd * vTemp1;
		
		vxp.Trim();
		vyp.Trim();
		vTempPkInd.Trim();
		
		vxPeaks.Append(vxp);	//Append negative peaks
		vyPeaks.Append(vyp);
		
		vnIndices.Append(vTempPkInd);
	}

	return true;
}

///Leo 2005-12-05	FIND_PEAKS_HEIGHT	
///Sandy 2005-12-26 CHANGE_FUNCTION_NAME_AND_RECREATE_ANOTHER_FUNCTION_TO_TEST_PEAKS_BY_HEIGHT
//bool find_peaks_by_height(vector& vxPeaks, vector& vyPeaks, int numPeaks, int nDir)
bool test_peaks_by_number(vector& vxPeaks, vector& vyPeaks, vector<int>& vnIndices, int numPeaks)
{
	if (vxPeaks.GetSize() != vyPeaks.GetSize())
	{
		return false;
	}
	if (numPeaks >= vxPeaks.GetSize())
	{
		return true;
	}
	vector vTemp;
	
	///Sandy 2009-1-8 SPEED_UP_VECTOR_ABS
	//vTemp = abs(vyPeaks);
	vTemp = vyPeaks;
	vTemp.Abs();
	//end SPEED_UP_VECTOR_ABS
	
	vector<uint> vN;
	vTemp.Sort(SORT_DESCENDING, false, vN);
	vTemp.Replace(vTemp[numPeaks], 1, MATREPL_TEST_GREATER | MATREPL_SET_TO_MISSING_VALUE_WHEN_TEST_RESULT_IS_FALSE);
	vTemp.Reorder(vN);
	vxPeaks *= vTemp;
	vyPeaks *= vTemp;
	vnIndices *= vTemp;
	
	vxPeaks.Trim();
	vyPeaks.Trim();
	vnIndices.Sort(SORT_DESCENDING);
	vnIndices.SetSize(vxPeaks.GetSize());
	vnIndices.Sort(SORT_ASCENDING);
	
	return true;
}
///END FIND_PEAKS_HEIGHT


bool test_peaks_by_height(vector& vxPeaks, vector& vyPeaks, vector<int>& vnIndices, double dMinHeight)
{
	long lSize = vxPeaks.GetSize();
	if (lSize != vyPeaks.GetSize() || lSize != vnIndices.GetSize())
	{
		return false;
	}

	int ii;

	for(ii = 0; ii <= lSize-1; ii++)
	{
		if( abs(vyPeaks[ii]) < dMinHeight )
		{
			vxPeaks[ii] = NANUM;
			vyPeaks[ii] = NANUM;
			vnIndices[ii] = 0;
		}	
	}
	
	vxPeaks.Trim();
	vyPeaks.Trim();
	//trim index too
	vector<uint> vN(0);
	vnIndices.Sort(SORT_DESCENDING);
	int nFound = vnIndices.Find(vN, 0);
	if(nFound>0)
		vnIndices.SetSize(vN[0]);
	
	vnIndices.Sort(SORT_ASCENDING);
	
	return true;
}

	
//bool test_peaks_by_width(vector& vxPeaks, vector& vyPeaks, double dHalfWidth)
//{
	//long lSize = vxPeaks.GetSize();
	//if (lSize != vyPeaks.GetSize())
	//{
		//return false;
	//}
//
	//int ii, kk=0;
	//vector vRecoder(0);
	//for(ii = 1; ii <= lSize-1; ii++)
	//{
		//if( (vxPeaks[ii]-vxPeaks[ii-1])<dHalfWidth || (vxPeaks[ii]-vxPeaks[ii+1])<dHalfWidth )
		//{
			//if( (vyPeaks[ii]<vyPeaks[ii-1]) || (vxPeaks[ii]<vxPeaks[ii+1]) )
			//{
				//vRecoder[kk] = ii;
				//kk++;
			//}
		//}
			//
	//}
	//
	//for(ii=0; ii< kk; ii++)
	//{			
		//vxPeaks[vRecoder[ii]] = NANUM;
		//vyPeaks[vRecoder[ii]] = NANUM;
	//}
	//
	//vxPeaks.Trim();
	//vyPeaks.Trim();
	//
	//return true;
//}	

//end MOVE_FROM_PFM_UTTILS

bool init_baseline_by_connect_ends(const vector& vx, const vector& vy, vector& vbx, vector& vby, int npts)
{
	int nLast = vx.GetSize()-1;
	double x1 = vx[0];
	double x2 = vx[nLast];
	
	vbx.Data(x1, x2, (x2-x1)/(npts-1));

	vby.SetSize(vbx.GetSize());
	
	double y1 = vy[0];
	double y2 = vy[nLast];
	for(int ii = 0; ii < vbx.GetSize(); ii++)
	{
		vby[ii] = y1 + (y2-y1) * (vbx[ii] - x1)/(x2-x1);
	}
	
	return true;
}




int check_linear(const vector& vx, const vector& vy, double dMaxRatio, double dR, uint nOffset, bool bDir )
{
	uint	i1 = nOffset+1 ,i2 ,it, count;
	uint 	iMax = dMaxRatio * vx.GetSize();
	short   inc;
	
	double	slope0,err,intercept0;

	short direction;
	(bDir)?(direction = 1):(direction = -1);
	
	inc = direction * max((uint)1, iMax/10);
	
	i2 = i1 + 3 * inc;
	if( (i2 - i1) * direction > iMax)
		i2 = i1 + direction * iMax;

	if( i1 > i2) 
		{it = i2,i2 = i1,i1 = it;}

	FitParameter sFitParameter[2];
	
	int nErr = ocmath_linear_fit(vx, vy, vx.GetSize(), sFitParameter);


	slope0 = sFitParameter[0].Value;		
	intercept0 = sFitParameter[1].Value;		
	err = sFitParameter[0].Error *dR;			
	
	for ( i1 += inc,i2 +=inc; abs((double)((direction< 0)? i1:i2) - (nOffset+1)) < iMax; i1 += inc,i2 += inc )
	{

		nErr = ocmath_linear_fit(vx, vy, vx.GetSize(), sFitParameter);
		
		if ( abs(sFitParameter[0].Value - slope0) > err )
			break;
		
		it = (direction< 0)? i1:i2;
		it -= inc;
		
		nErr = ocmath_linear_fit(vx, vy, vx.GetSize(), sFitParameter);
		slope0 = sFitParameter[0].Value;
		intercept0 = sFitParameter[1].Value;
		err = sFitParameter[0].Error * dR;

	}
	i2 -= inc,i1 -= inc;


	i2 = (direction< 0)? i1:i2-1;
	nOffset = (direction< 0)? nOffset:(nOffset+1);

	return(i2);

}


//2006-4-4 Sandy MOVE_FROM_PFM_UTILS
bool find_peaks_partition(vector& vxData, vector& vyData, double dxPeak, int& nStart, int& nEnd, int nPtsSmooth)
{
	Curve cvData(vxData, vyData);
	if (nPtsSmooth > 3 && !curve_smooth_sg(cvData,(nPtsSmooth-1)/2))
	{
		return false;
	}
	curve_derivative(cvData);
	if (nPtsSmooth > 3 && !curve_smooth_sg(cvData,(nPtsSmooth-1)/2))
	{
		return false;
	}
	curve_derivative(cvData);
	if (nPtsSmooth > 3 && !curve_smooth_sg(cvData,(nPtsSmooth-1)/2))
	{
		return false;
	}

	int iSize = cvData.GetSize();
	
	vector vxKnod, vyTemp, vyTemp2;
	cvData.CopyData(vxKnod, vyTemp);
	vyTemp2 = vyTemp;
	vyTemp2.InsertAt(0, vyTemp[0]);
	vyTemp2.SetSize(iSize);
	vyTemp *= vyTemp2;
	vyTemp.Replace(0,1,MATREPL_TEST_LESSTHAN | MATREPL_SET_TO_MISSING_VALUE_WHEN_TEST_RESULT_IS_FALSE);	
	vxKnod *= vyTemp;
	vxKnod.Trim();
	
	vxKnod.InsertAt(0, dxPeak);
	vxKnod.Sort();

	int iPeak, iLeft, iRight;
	vector<uint> vIndex;
	vxKnod.Find(vIndex, dxPeak);
	
	iPeak = vIndex[0];
	
	if (iPeak == 0)
	{
		iLeft = 0;
	}
	else
	{
		vxData.Find(vIndex, vxKnod[iPeak-1]);
		iLeft = vIndex[0];
	}
	if (iPeak == vxKnod.GetSize()-1)
	{
		iRight = iSize-1;
	}
	else
	{
		vxData.Find(vIndex, vxKnod[iPeak+1]);
		iRight = vIndex[0];
	}

	nStart = iLeft;
	nEnd = iRight;
	
	////direction
	//vxData.Find(vIndex, dxPeak);
	//iPeak = vIndex[0];
	//double dMean = (vyData[nStart]+vyData[nEnd])/2;
	//if(vyData[iPeak]>dMean)
		//nDir = POSITIVE_DIRECTION;
	//else 
		//nDir = NEGATIVE_DIRECTION;
		

	return true;
}



static void _make_one_annotation(TreeNode& tr, int nIndex, const string& strLabel, int nColor = 0, int nAngle = 0, int nYoffset = -80, int nXoffset = 0)
{
	tr.Tether.Color.nVal = nColor;
	tr.Tether.Width.dVal = 0.5;
	tr.Label.Angle.nVal = nAngle;
	tr.Label.Color.nVal = nColor;
	TreeNode trText1 = tree_check_get_node(tr.Label, "Text");
	trText1.strVal = strLabel;
	tr.Reference.nVal = nIndex;
	tr.XOffset.dVal = nXoffset;
	tr.YOffset.dVal = nYoffset;
}

bool curve_labels(DataPlot& dp, const vector<int>& vn, const vector<string>& vsLabels, int nYoffset)
{
	if(!dp)
		return false;
	
	Tree tr;
	tr.Root.Annotations.DataID = 1000; // DataID not really needed, but this is a quick way to create the tree, please do not use ID as that didnt work  for me
	for(int ii = 0; ii < vn.GetSize(); ii++)
	{
		string strLabel;
		TreeNode tr = tree_check_get_node(tr.Root.Annotations, "Annotation" + (ii+1));
		if(ii < vsLabels.GetSize())
			strLabel = vsLabels[ii];
		_make_one_annotation(tr, vn[ii], strLabel, nYoffset);
	}
	
	int nErr = dp.UpdateThemeIDs(tr.Root, "Error", "Unknown tag");
	return dp.ApplyFormat(tr, TRUE, TRUE);
}


void add_labels(BOOL bRemoveAll = false)
{
	GraphLayer gl = Project.ActiveLayer();
	DataPlot dp = gl.DataPlots(0);
	
	vector<int> vn = {0, 10, 30, -1};
	vector<string> vs = {"1st", "2nd", "3rd", "last"};
	if(bRemoveAll)
	{
		vn.SetSize(0);
	}
	curve_labels(dp, vn, vs);
}

bool subtract_baseline(vector& vx, vector& vy, vector& vbx, vector& vby, bool bResize_vb)
{
	int nSize = vy.GetSize();
	int nRet;	
	if(vx.GetSize()!=nSize)
		return false;
	
	vector vxBase(nSize), vyBase(nSize);
	
	if(vbx.GetSize() == 0)
	{
		return false;
	}
	
	double dxMin, dxMax;
	vbx.GetMinMax(dxMin, dxMax);
	int nBSize = vbx.GetSize();
	
	vxBase.Data(dxMin, dxMax, (dxMax-dxMin)/(nSize-1));
	
	if(vxBase.GetSize()!=nSize)
		return false;

	//if(nRet = ocmath_interpolate(vxBase, vyBase, nSize, vbx, vby, nBSize, INTERP_TYPE_LINEAR))
	if(nRet = ocmath_interpolate(vx, vyBase, nSize, vbx, vby, nBSize, INTERP_TYPE_LINEAR))
	{
		return nRet;
	}

	vy -= vyBase;
	
	if(bResize_vb)
	{
		vbx = vxBase;
		vby = vyBase;
	}
	return true;
}

//define for auto baseline
enum {
	AUTO_BASELINE_END_WEIGHTED_LINEAR = 0,
	AUTO_BASELINE_SMOOTH_ENTIRE_DATASET,
	AUTO_BASELINE_ENTIRE_DATASET_SANS_SMOOTHING,
	AUTO_BASELINE_POSITIVE_PEAKS_BASES,
};
#define END_SIZE_RATIO 	 	0.125
bool auto_create_baseline(const vector& vx, const vector& vy, vector& vbx, vector& vby, int type, int nSmoothLeftPts)
{
	
	long lSize = vx.GetSize();
	if(lSize != vy.GetSize() || lSize < 3)
	{
		return false;
	}
	
	long lEndSize = lSize * END_SIZE_RATIO;
	
	vbx.SetSize(0);
	vby.SetSize(0);
	
	//remove the header and the end point
	vector vx1;
	vector vy1;

	int nNSize = lSize - 2 * lEndSize;

	vy.GetSubVector(vy1, 1, lSize - 2);
	vx.GetSubVector(vx1, 1, lSize - 2);
	
	vector vx2(0), vy2(0);
	
	int i,j,k;
	int nRet;
	
	vector vSmooth(lSize);
	if(nSmoothLeftPts != 0 )
	{
		if(OE_NOERROR != ocmath_savitsky_golay(vy, vSmooth, lSize, nSmoothLeftPts))
		{
			///Sandy 2007-4-20 if fail to smooth, should continue
			//return false;
			vSmooth = vy;
		}
	}	
	else
		vSmooth = vy;
	
	switch(type)
	{
	case AUTO_BASELINE_END_WEIGHTED_LINEAR:
		{
		
			int lbegin, lend;
			nRet = ocmath_check_linear(vx.GetSize(), vx, vSmooth, &lbegin, END_SIZE_RATIO, 1.0, 0, true);
			nRet = ocmath_check_linear(vx.GetSize(), vx, vSmooth, &lend, END_SIZE_RATIO, 1.0, lSize - 1, false);
			vx1 = vx;
			vy1 = vy;
			vx1.SetSize(lbegin);
			vy1.SetSize(lbegin);
			vbx.Append(vx1);
			vby.Append(vy1);
			
			//recorder the ending
			vx.GetSubVector(vx1,lend);
			vy.GetSubVector(vy1,lend);
			
			vbx.Append(vx1);
			vby.Append(vy1);
		
		}
		break;
		
	case AUTO_BASELINE_SMOOTH_ENTIRE_DATASET:  
		{
			// do smoothing here with default values as set below. Store any previously
			// existing values and reassign after the fit
			vSmooth.GetSubVector(vy1, 1, lSize - 2);
		}

		
	case AUTO_BASELINE_ENTIRE_DATASET_SANS_SMOOTHING:
	{		
		vector<uint> vn;
		vx1.Sort(SORT_ASCENDING, true, vn);
		vy1.Reorder(vn);
		
		vx2.SetSize(vx1.GetSize());
		vy2.SetSize(vx1.GetSize());
		if ( OE_NOERROR != ocmath_create_baseline_by_masking_peaks(vx1.GetSize(), vx1, vy1,
											vx2.GetSize(), vx2, vy2, BOTH_DIRECTION) )
		{
			return false;
		}
		
		break;
	}
	case AUTO_BASELINE_POSITIVE_PEAKS_BASES:
	{
		vSmooth.GetSubVector(vy1, 1, lSize - 2);
		vector<uint> vn;
		vx1.Sort(SORT_ASCENDING, true, vn);
		vy1.Reorder(vn);
		
		vx2.SetSize(vx1.GetSize());
		vy2.SetSize(vx1.GetSize());
		if ( OE_NOERROR != ocmath_create_baseline_by_masking_peaks(vx1.GetSize(), vx1, vy1,
											vx2.GetSize(), vx2, vy2, POSITIVE_DIRECTION) )
		{
			return false;
		}
		break;
	}
	default:
		return false;
	}
	
	
	//add the header and end back
	if(vbx.GetSize() == 0)
	{
		vbx = vx2;
		vby = vy2;
		vbx.InsertAt(0, vx[0]);
		vby.InsertAt(0, vy[0]);
		vbx.InsertAt(vbx.GetSize(), vx[lSize-1]);
		vby.InsertAt(vby.GetSize(), vy[lSize-1]);
	}

	return true;
}

///Arvin 03/19/07 IMPROVE_CALCULATION_CENTROID_METHOD
//bool integrate_curve(const vector& vx, const vector& vy,const vector& vbx, const vector& vby, int nDir, vector& vIntegrated, ocmath_IntegResult& result)
bool integrate_curve(const vector& vx, const vector& vy,const vector& vbx, const vector& vby, int nDir, vector& vIntegrated, IntegrationResult& result)
///end IMPROVE_CALCULATION_CENTROID_METHOD
{
    // construct baseline set
	vector vxo, vyo;
	vxo = vx;
	vyo.SetSize(vy.GetSize());    
	if(OE_NOERROR != ocmath_interpolate(vxo, vyo, vx.GetSize(), vbx, vby, vbx.GetSize(), INTERP_TYPE_LINEAR))
	{
		return false;
	}
	
	vyo = vy - vyo;
	if(nDir == 0)// positive
	   vyo.Replace(0, 0, MATREPL_TEST_LESSTHAN);
	else if(nDir == 1)// negative
	   vyo.Replace(0, 0, MATREPL_TEST_GREATER);
	
	//integrate
	int nFrom = 0, nTo = vyo.GetUpperIndex();	//	integration index
	//IntegrationResult result;
	string strLabel;
	
	
	vIntegrated.SetSize(nTo+1);	// size = last_index + 1
	if (OE_NOERROR != ocmath_integrate(vxo, vyo, nFrom, nTo, &result, vIntegrated))
	{
		return false;
	}
	
	return true;
}

/////Arvin 01/10/06 ADD_CREATING_CURVES_FUNCTIONS_FOR_PALETTE_EDIT_TOOL
//static bool _line_segement_curve(const vector& vx, const vector& vy, vector& vCurveX, vector& vCurveY)
//{
	//int nRet = ocmath_interpolate(vCurveX, vCurveY, vCurveX.GetSize(), vx, vy, vx.GetSize(), INTERP_TYPE_LINEAR);
	//if(nRet != OE_NOERROR)
		//return false;
	//
	//return true;
//}
//
//static bool _spline_curve(const vector& vx, const vector& vy, vector& vCurveX, vector& vCurveY)
//{
	//int nRet = ocmath_interpolate(vCurveX, vCurveY, vCurveX.GetSize(), vx, vy, vx.GetSize(), INTERP_TYPE_SPLINE);
	//if(nRet != OE_NOERROR)
		//return false;
	//
	//return true;
//}

//bool nlsf_func_curve(const vector& vx, const vector& vy, const string strFuncName, vector& vCurveX, vector& vCurveY)
//{	
	//string strCategory = "Origin Basic Functions";
	////TreeNode trFDF;
	////if(!nlsf_get_FDF_tree_from_func_name(trFDF, strFuncName, strCategory))
	////	return false;
	//
	//NLFitSessionBase fit(false);
	//if (!fit.SetFunction(strFuncName, strCategory ))
	//{
		//return false;
	//}
	//if (!fit.SetData(vy, vx))
	//{
		//return false;
	//}
	//if (!fit.ParamsInitValues())
	//{
		//return false;
	//}
	//vector vParams, vErrors;
	//if (!fit.GetFitResultsParams(vParams, vErrors))
	//{
		//return false;
	//}
	//
	//int nFitOutcome;
	//if (!fit.Fit(&nFitOutcome))
	//{
		//if (!fit.GetFitResultsParams(vParams, vErrors))
		//{
			//return false;
		//}
	//}
	//
	//if(nlsf_evaluate(strFuncName, strCategory, vCurveX, vCurveY, vParams))
	//{
		//return true;
	//}
	//
	//return false;
//}

//bool nlsf_logistic_curve(const vector& vx, const vector& vy, 
						//const int nPower, const int nCenter,
						//vector& vCurveX, vector& vCurveY)
//{	
	//string strCategory = "Origin Basic Functions";
	//string strFuncName = "Logistic";
//
	//NLFitSessionBase fit(false);
	//if (!fit.SetFunction(strFuncName, strCategory ))
	//{
		//return false;
	//}
	//if (!fit.SetData(vy, vx))
	//{
		//return false;
	//}
	//if (!fit.ParamsInitValues())
	//{
		//return false;
	//}
	//vector vParams, vErrors;
	//if (!fit.GetFitResultsParams(vParams, vErrors))
	//{
		//return false;
	//}
	//
	//vParams[2] = nCenter;
	//vParams[3] = nPower;
	//
	//int nFitOutcome;
	//if (!fit.Fit(&nFitOutcome))
	//{
		//if (!fit.GetFitResultsParams(vParams, vErrors))
		//{
			//return false;
		//}
	//}
	//
	//if(nlsf_evaluate(strFuncName, strCategory, vCurveX, vCurveY, vParams))
	//{
		//return true;
	//}
	//
	//return false;
//}
//Sandy 2007-2-9 move to XF
//bool create_curve_for_palette_edit(const vector& vx, const vector& vy, vector& vCurveX, vector& vCurveY, int nPts, int nCurveType)
//{
	//vector<uint> vN;
	//vx.Sort(SORT_ASCENDING, true, vN);
	//vy.Reorder(vN);
	//
	//int nSize = vx.GetSize();
	//double dMin, dMax;
	//dMin = vx[0];
	//dMax = vx[nSize-1];
	//vCurveX.Data(dMin, dMax, (dMax-dMin)/(nPts-1.0));
	//vCurveY.SetSize(nPts);
	//
	//switch(nCurveType)
	//{
	//case LINE_SEGMENT_CURVE:
		//return _line_segement_curve(vx, vy, vCurveX, vCurveY);
		//
	//case SPLINE_CURVE:
		//return _spline_curve(vx, vy, vCurveX, vCurveY);
		//
	//case GUASSAMP_CURVE:
		//string strFuncName = "GaussAmp";
		//return _nlsf_func_curve(vx, vy, strFuncName, vCurveX, vCurveY);
		//
	//case LOGISTIC_CURVE:
		//string strFuncName = "Logistic";
		//return _nlsf_func_curve(vx, vy, strFuncName, vCurveX, vCurveY);		
	//}
	//
	//return false;
//}
//


//bool _fill_range(vector& vx, vector& vy, double dLeft, double dRight, double dFillValue)
//{
	//for(int ii = 0; ii<vx.GetSize(); ii++)
	//{
		//vy[ii] = (vx[ii]>=dLeft&&vx[ii]<=dRight ? dFillValue : vy[ii]);
	//}
	//return true;
//}

///sandy 2007-3-22 add for a new baseline XF and integPeaks.oxf
bool fill_subrange_by_interp(vector& vx, vector& vy, double dLeft, double dRight, int nFunction)
{

	vector<uint> vecIndex;
	int nFound = vx.Find(vecIndex, dLeft, dRight);
    if( -1 == nFound ||  0 == nFound)
    {
    	return false;
    }
    
	vector vxSub, vySub,  vxIntp, vyIntp;
	if(vecIndex.GetSize() <= 0)
		return false;
	
    int nOrgSize = vx.GetSize();
    int nIndSize = vecIndex.GetSize();
	
	//int nBegin = vecIndex[0]+1;
	//int nEnd = vecIndex[vecIndex.GetSize()-1]-1;
	int nBegin = (vecIndex[0] > 0? vecIndex[0] : 1);
	int nEnd = (vecIndex[nIndSize-1] < (nOrgSize-1)? vecIndex[nIndSize-1]: (nOrgSize-1));
	
	vx.GetSubVector(vxSub, nBegin, nEnd);
	vy.GetSubVector(vySub, nBegin, nEnd);
	
	int nSize = vySub.GetSize();
	
	int nInterpType;
	switch(nFunction)
	{
	case CUR_SUBRANGE_INTERP_TYPE_LINEAR://INTERP_TYPE_LINEAR
		vxIntp.SetSize(2);
		vyIntp.SetSize(2);
		vxIntp[0] = vxSub[0];
		vxIntp[1] = vxSub[nSize-1];
		vyIntp[0] = vySub[0];
		vyIntp[1] = vySub[nSize-1];  
		nInterpType = INTERP_TYPE_LINEAR;
		break;
	case CUR_SUBRANGE_INTERP_TYPE_BSPLINE://INTERP_TYPE_BSPLINE
		vxIntp = vx;
		vyIntp = vy;
		vector vxTemp, vyTemp;
		vxIntp.GetSubVector(vxTemp, nEnd, -1);
		vyIntp.GetSubVector(vyTemp, nEnd, -1);
	
		vxIntp.SetSize(nBegin);
		vyIntp.SetSize(nBegin);
		
		vxIntp.Append(vxTemp);
		vyIntp.Append(vyTemp);
		nInterpType = INTERP_TYPE_BSPLINE;
		break;
	}
	
	if(0 != ocmath_interpolate(vxSub, vySub, vxSub.GetSize(), vxIntp, vyIntp, vxIntp.GetSize(), nInterpType))
	{
		return false;
	}
	vy.SetSubVector(vySub, nBegin);
	return true;		

}

///sandy 2007-3-22 add for a new baseline XF and integPeaks.oxf
bool delete_subrange_of_data(vector& vx, vector& vy, double dLeft, double dRight)
{
	vector<uint> vecIndex;
	int nFound = vx.Find(vecIndex, dLeft, dRight);
    if( -1 == nFound || 0 == nFound)
    {
    	return false;
    }
    
    int nOrgSize = vx.GetSize();
    int nSize = vecIndex.GetSize();
    
    
	vector vxSub, vySub;
	//int nBegin = vecIndex[0];
	//int nEnd = vecIndex[nSize-1];
	int nBegin = (vecIndex[0] > 0? vecIndex[0] : 1);
	int nEnd = (vecIndex[nSize-1] < (nOrgSize-1)? vecIndex[nSize-1]: (nOrgSize-1));
	
	vx.GetSubVector(vxSub, nEnd, -1);
	vy.GetSubVector(vySub, nEnd, -1);

	vx.SetSize(nBegin);
	vy.SetSize(nBegin);
	
	vx.Append(vxSub);
	vy.Append(vySub);
	return true;
}

///sandy 2007-3-22 add for a new baseline XF and integPeaks.oxf
bool fit_poly_baseline(vector& vbx, vector& vby, vector& vxPloy, vector& vyPloy)
{
	int nOrder = 3;
	vector vCoeff(nOrder+1);
	if(!fitpoly(vxPloy, vyPloy, 3, vCoeff, NULL, NULL))
		return false;
		
	if(!ocmath_polynomial(vbx, vby, vbx.GetSize(), vCoeff, nOrder))
		return false;
	
	return true;
}

///sandy 2007-3-22 add for a new baseline XF and integPeaks.oxf
/// Cloud 04/14/2007 REORGANIZE_FUNCTIONS
//int find_max_height_peaks(vector& vx, vector& vy, int nNum, vector& vXofPeaks, vector& vYOfPeaks)
int find_max_height_peaks(vector& vx, vector& vy, int nNum, vector& vXofPeaks, vector& vYOfPeaks, vector<int>& vIndexOfPeaks, int iDir)
/// End REORGANIZE_FUNCTIONS
{
	int nPeakNum = vx.GetSize();
	vector<int> vPeaksInd(nPeakNum);		
	vector vxPeaks(nPeakNum), vyPeaks(nPeakNum);
	
	/// Cloud 04/14/2007 REORGANIZE_FUNCTIONS
	double dRange;
	double dMin, dMax;
	vy.GetMinMax(dMin, dMax);
	dRange = dMax - dMin;
	
	//double dNoise = sqrt(ocmath_get_noise_level(nPeakNum, vy));
	double dNoise = ocmath_get_noise_level(nPeakNum, vy);
	
	int iPtsSmooth = dNoise / (dRange*0.005) * SMOOTH_LEVEL;
	/// Cloud 7/5/07 LIMIT_SMOOTH_POINTS
	if (iPtsSmooth > vy.GetSize()*0.2)
		iPtsSmooth = vy.GetSize() * 0.2;
	/// End LIMIT_SMOOTH_POINTS
	
	//int nRet = ocmath_find_peaks_1st_derivative(&nPeakNum, vx, vy, vxPeaks, vyPeaks, vPeaksInd, PKF_BOTH_DIRECTION);
	//Sandy 2008-11-18 APPLY_NEW_OCMATH_FUNCTION_PROTOTYPE_WITH_SG_DERIV
	//int nRet = ocmath_find_peaks_1st_derivative(&nPeakNum, vx, vy, vxPeaks, vyPeaks, vPeaksInd, iDir, iPtsSmooth);
	int nRet = ocmath_find_peaks_1st_derivative(&nPeakNum, vx, vy, vxPeaks, vyPeaks, vPeaksInd, iDir, false, iPtsSmooth);
	/// End REORGANIZE_FUNCTIONS
	if(nRet != OE_NOERROR)
	{
		return 0;
	}
	
	vxPeaks.SetSize(nPeakNum);
	vyPeaks.SetSize(nPeakNum);
	vPeaksInd.SetSize(nPeakNum);
	
	//Sandy 2007-7-25 do not test if the number of peaks is less than the request.
	if(nPeakNum>nNum)
	{
		//check the height of peak
		nRet = ocmath_test_peaks_by_number(nPeakNum, vxPeaks, vyPeaks, vPeaksInd, nNum);
		if(nRet != OE_NOERROR)
		{
			return 0;
		}
		vxPeaks.SetSize(nNum);
		vyPeaks.SetSize(nNum);
		vPeaksInd.SetSize(nNum);		
	}	

	
	vXofPeaks = vxPeaks;
	vYOfPeaks = vyPeaks;
	
 	vector<uint> vn;
    vXofPeaks.Sort(SORT_ASCENDING, true, vn);// sorting the peaks by position
    vYOfPeaks.Reorder(vn);
    
	/// Cloud 04/14/2007 REORGANIZE_FUNCTIONS
	if (vIndexOfPeaks!=NULL)
	{
		vIndexOfPeaks = vPeaksInd;
		vIndexOfPeaks.Reorder(vn);
	}
	/// End REORGANIZE_FUNCTIONS
	
	return vXofPeaks.GetSize();
}

/// Cloud 04/04/2007 ADD_FIND_PEAKS_BY_NUMBER
/// Cloud 04/10/2007 PROCESS_THE_NEGATIVE_PEAK
//bool find_peaks_by_number(vector& vx, vector& vy, int iPeakNum, vector& vxPeaks, vector& vStart, vector& vEnd, vector<int>& vStartIndice, vector<int>& vEndIndice)
bool find_peaks_by_number_full_auto(vector& vx, vector& vy, int iPeakNum, vector& vxPeaks, vector& vStart, vector& vEnd, vector<int>& vStartIndice, vector<int>& vEndIndice, int iDir)
/// End PROCESS_THE_NEGATIVE_PEAK
{
	/// Cloud 04/14/2007 REORGANIZE_FUNCTIONS
	//int iSize = vx.GetSize();

	//double dRange;
	//double dMin, dMax;
	//vy.GetMinMax(dMin, dMax);
	//dRange = dMax - dMin;
	//double dNoise = sqrt(ocmath_get_noise_level(iSize, vy));
	//int iPtsSmooth = dNoise / (dRange*0.1) * SMOOTH_LEVEL;
	//vector vYs(iSize);
	//if (iPtsSmooth>=3)
		//ocmath_savitsky_golay(vy, vYs, iSize, (iPtsSmooth-1)/2, (iPtsSmooth-1)/2, 2, 0, EDGEPAD_NONE);
	//else
		//vYs = vy;
	/// Cloud 04/10/2007 PROCESS_THE_NEGATIVE_PEAK
	//int ii;
	//vector vBaseline(iSize);
	//vBaseline.Data(vYs[0], vYs[iSize-1], (vYs[iSize-1]-vYs[0])/(iSize-1));
	//vYs -= vBaseline;
	//if (NEGATIVE_DIRECTION==iDir)
		//vYs = -vYs;
	//else if (BOTH_DIRECTION==iDir)
		//vYs = abs(vYs);
	/// End PROCESS_THE_NEGATIVE_PEAK
	
	//vector tmpx(iSize);
	vector tmpy;
	vector<int> tmpi;
	//ocmath_find_peaks_1st_derivative(&iSize, vx, vYs, tmpx, tmpy, tmpi, iDir, 1);
	//ocmath_test_peaks_by_number(iSize, tmpx, tmpy, tmpi, iPeakNum);

	//vxPeaks.SetSize(iPeakNum);
	//tmpx.GetSubVector(vxPeaks, 0, iPeakNum-1);
	find_max_height_peaks(vx, vy, iPeakNum, vxPeaks, tmpy, tmpi, iDir);

	if (NULL==vStart && NULL==vEnd && NULL==vStartIndice && NULL==vEndIndice)
		return TRUE;

	return find_peaks_marker_by_height_and_width(vx, vy, tmpi, vStart, vEnd, vStartIndice, vEndIndice, iDir);
	/// End REORGANIZE_FUNCTIONS
}

/// Cloud 04/14/2007 REORGANIZE_FUNCTIONS
bool find_peaks_marker_by_height_and_width(vector& vx, vector& vy, vector<int>& vPeakInd, vector& vStart, vector& vEnd, vector<int>& vStartIndice, vector<int>& vEndIndice, int iDir)
{
	/// Cloud 04/05/2007 IMPROVE_FIND_PEAKS_FEET
	//vector<int> tmpstartindex;
	//vector<int> tmpendindex;
	//vector tmpstart;
	//vector tmpend;
	//int iStart;
	//int iEnd;
	/// End IMPROVE_FIND_PEAKS_FEET
	int iSize = vx.GetSize();
	int iPeakNum = vPeakInd.GetSize();

	/// Cloud 04/05/2007 IMPROVE_FIND_PEAKS_FEET
	//for (int ii=0; ii<iPeakNum; ii++)
	//{
		//ocmath_find_peaks_partition(iSize, vx, vy, vxPeaks[ii], &iStart, &iEnd, iPtsSmooth);
		//tmpstartindex.Add(iStart);
		//tmpendindex.Add(iEnd);
		//tmpstart.Add(vx[iStart]);
		//tmpend.Add(vx[iEnd]);
	//}
	double dRange;
	double dMin, dMax;
	vy.GetMinMax(dMin, dMax);
	dRange = dMax - dMin;
	
	//double dNoise = sqrt(ocmath_get_noise_level(iSize, vy));
	double dNoise = ocmath_get_noise_level(iSize, vy);
	
	int iPtsSmooth = dNoise / (dRange*0.005) * SMOOTH_LEVEL;
	/// Cloud 7/5/07 LIMIT_SMOOTH_POINTS
	if (iPtsSmooth > iSize*0.2)
		iPtsSmooth = iSize * 0.2;
	/// End LIMIT_SMOOTH_POINTS
	vector vYs(iSize);
	if (iPtsSmooth>=3)
		ocmath_savitsky_golay(vy, vYs, iSize, (iPtsSmooth-1)/2, (iPtsSmooth-1)/2, 2, 0, EDGEPAD_NONE);
	else
		vYs = vy;
	vector vBaseline(iSize);
	vBaseline.Data(vYs[0], vYs[iSize-1], (vYs[iSize-1]-vYs[0])/(iSize-1));
	vYs -= vBaseline;
	if (NEGATIVE_DIRECTION==iDir)
		vYs = -vYs;
	else if (BOTH_DIRECTION==iDir)	
		//vYs = abs(vYs);
		vYs.Abs();///Sandy 2009-1-8 SPEED_UP_VECTOR_ABS


	vector<int> tmpmarker(2*iPeakNum);
	
	//double dMinHeight = sqrt(ocmath_get_noise_level(iSize, vYs));
	double dMinHeight = ocmath_get_noise_level(iSize, vYs);
	/// Cloud 06/30/2007 USE_FIND_MARKER_BY_WIDTH_TO_REPLACE_BY_FULLWIDTH
	//vector vMinWidth(iPeakNum);
	//vector vMaxWidth(iPeakNum);
	double dMinWidth;
	double dMaxWidth;
	//vMaxWidth = vx[iSize-1] - vx[0];
	
	///Sandy 2007-7-11 fix bug for decreasing X vector
	//dMaxWidth = vx[iSize-1] - vx[0];
	dMaxWidth = abs(vx[iSize-1] - vx[0]);
	
	int ii;
	//for (ii=0; ii<iPeakNum; ii++)
	//{
		//int iStart, iEnd;
		//find_peaks_partition(vx, vy, vx[vPeakInd[ii]], iStart, iEnd, 0);
		//vMinWidth[ii] = vx[iEnd]-vx[iStart];
	//}
	dMinWidth = 0;
	//int iRet = ocmath_find_markers_of_peaks_by_height_and_full_width(iSize, vx, vYs, iPeakNum, vPeakInd, 2*iPeakNum, tmpmarker, dMinHeight, vMaxWidth, vMinWidth);
	int iRet = ocmath_find_markers_of_peaks_by_height_and_width(iSize, vx, vYs, iPeakNum, vPeakInd, 2*iPeakNum, tmpmarker, dMinHeight, dMaxWidth, dMinWidth);
	/// End USE_FIND_MARKER_BY_WIDTH_TO_REPLACE_BY_FULLWIDTH
	if (iRet != OE_NOERROR)
		return FALSE;
	
	if (vStart!=NULL)
		//vStart = tmpstart;
		for (ii=0; ii<iPeakNum; ii++)
			vStart.Add(vx[tmpmarker[2*ii]]);
	
	if (vEnd!=NULL)
		for (ii=0; ii<iPeakNum; ii++)
			vEnd.Add(vx[tmpmarker[2*ii+1]]);
		//vEnd = tmpend;

	if (vStartIndice!=NULL)
		//vStartIndice = tmpstartindex;
		for (ii=0; ii<iPeakNum; ii++)
			vStartIndice.Add(tmpmarker[2*ii]);

	if (vEndIndice!=NULL)
		//vEndIndice = tmpendindex;
		for (ii=0; ii<iPeakNum; ii++)
			vEndIndice.Add(tmpmarker[2*ii+1]);

	return TRUE;
}
/// End ADD_FIND_PEAKS_BY_NUMBER				
/// End REORGANIZE_FUNCTIONS

/// Cloud 05/21/2007 CALC_FEET_HEIGHT_OF_PEAK
double get_feet_height_by_percent_of_total_height(const vector& vy, double percent)
{
	double dMin, dMax;
	vy.GetMinMax(dMin, dMax);
	
	///Sandy 2008-6-11 protect the thres always in the range of vy as Jack's suggestion
	//double totalHeight = dMax-dMin;
	double dThres = percent*dMax +(1-percent)*dMin;
	vector vyAbs;
	//vyAbs = abs(vy);//Sandy 2009-1-8 speed up
	vyAbs = vy;
	vyAbs.Abs();
	//ocmath_replace_data_in_vector(vyAbs.GetSize(), vyAbs, totalHeight*percent, NANUM, MATREPL_TEST_GREATER);
	ocmath_replace_data_in_vector(vyAbs.GetSize(), vyAbs, dThres, NANUM, MATREPL_TEST_GREATER);
	vyAbs.Trim();
	double dBaseHeight;
	
	///Sandy 2008-6-11 remove dangerous code if empty vector
	//vyAbs.Sum(dBaseHeight);
	//return dBaseHeight / vyAbs.GetSize();
	double dRet;
	if(vyAbs.GetSize()>0)
	{
		vyAbs.Sum(dBaseHeight);
		dRet = dBaseHeight / vyAbs.GetSize();
	}
	else
	{
		dRet = 0;
	}
	return dRet;
	
}
/// End CALC_FEET_HEIGHT_OF_PEAK

///Sandy 2007-5-23 MOVE_FROM_XF
///------Sandy 2008-9-9 ADD_LOCAL_BASELINE_VECTOR
//bool integrate_individual_peak(const vector& vx, const vector& vy, 	double dFromX, double dToX, 
										///Arvin 03/19/07 IMPROVE_CALCULATION_CENTROID_METHOD
										//ocmath_IntegResult& IntResult, int& nFrom, int& nTo, vector& vIntegrated)
										//IntegrationResult& IntResult, int& nFrom, int& nTo, vector& vIntegrated )
										///end IMPROVE_CALCULATION_CENTROID_METHOD								
bool integrate_individual_peak(const vector& vx, const vector& vy, double dFromX, double dToX, 
										IntegrationResult& IntResult, int& nFrom, int& nTo, vector& vIntegrated,  const vector& vby )
{

	if(vby != NULL && vby.GetSize()!=vy.GetSize())
		return false;
	
	//find markers' index
	double d1, d2;
	int nTemp, nSize = vx.GetSize();	//	integration index
	vector vFind(nSize);
	vFind = dFromX;
	
	///---Sandy 2008-12-22 MARKO_SUGGEST_VECTOR_ABS_IMPROVE_SPEED_OF_HUGE_DATA
	//vFind = abs(vx - vFind);
	vFind = vx - vFind;
    vFind.Abs();
    //---end MARKO_SUGGEST_VECTOR_ABS_IMPROVE_SPEED_OF_HUGE_DATA
    
	vFind.GetMinMax(d1, d2, &nFrom);

	vFind = dToX;
	
	///---Sandy 2008-12-22 MARKO_SUGGEST_VECTOR_ABS_IMPROVE_SPEED_OF_HUGE_DATA
	//vFind = abs(vx - vFind);
	vFind = vx - vFind;
    vFind.Abs();
    //---end MARKO_SUGGEST_VECTOR_ABS_IMPROVE_SPEED_OF_HUGE_DATA
    
	vFind.GetMinMax(d1, d2, &nTo);
	
	if(nFrom < 0 || nFrom > nSize || nTo<0 || nTo > nSize)
		return false;
	
	//integrate
	
	vector vData(nTo+1);
	
	///------Sandy 2008-9-9 ADD_LOCAL_BASELINE_VECTOR
	int nRet;
	if(vby == NULL)
		//nRet= ocmath_integrate(vx, vy, nFrom, nTo, &IntResult, vData);//Sandy 2009-1-25 QA80-12999&13019 OCMATH_INTEGRATE_COMPUTED_WRONG_VALUE_FOR_FWHM_WITH_MULTIPLE_PEAKS_DATA
		nRet= ocmath_integrate(vx, vy, nFrom, nTo, &IntResult, vData, MATHEMATICAL_AREA, NULL, false, SEARCH_FROM_PEAK);
	else
		//nRet = ocmath_integrate(vx, vy, nFrom, nTo, &IntResult, vData, MATHEMATICAL_AREA, vby);//Sandy 2009-1-25 QA80-12999&13019 OCMATH_INTEGRATE_COMPUTED_WRONG_VALUE_FOR_FWHM_WITH_MULTIPLE_PEAKS_DATA
		nRet = ocmath_integrate(vx, vy, nFrom, nTo, &IntResult, vData, MATHEMATICAL_AREA, vby, false, SEARCH_FROM_PEAK);
	if (OE_NOERROR != nRet)
	{
		return false;
	}
	
	//vIntegrated.SetSize(nTo+1);
	if(vIntegrated != NULL)
		vData.GetSubVector(vIntegrated, nFrom, -1);
	return true;
}
//end MOVE_FROM_XF

///Sandy MOVE_FROM_BLPWIZ
bool update_smooth_point(TreeNode &tr, vector &vyi, string *pstrErrMsg)
{
	TreeNode trSmooth = tr.smooth;
	//------ Folger 04/18/08 QA80-11441 CENTRALIZE_CODE_OF_LOCAL_MAXIMUN_METHOD
	//if (!trSmooth)
	TreeNode trMethod = tr.method;		//another assumption here, need to cleau up later
	if ( !trSmooth || !trMethod )
	//------
	{
		if (pstrErrMsg!=NULL)
			*pstrErrMsg = CER_INVALID_TREENODE;
		return false;
	}

	if (1==octree_get_auto_support(&trSmooth))
	{
		//------ Folger 04/18/08 QA80-11441 CENTRALIZE_CODE_OF_LOCAL_MAXIMUN_METHOD
		/*
		vector vy;
		vy = vyi;
		double dRange;
		double dMin, dMax;
		vy.GetMinMax(dMin, dMax);
		dRange = dMax - dMin;
		ocmath_replace_data_in_vector(vy.GetSize(), vy, 0, NANUM);
		vy.Trim();
		//double dNoise = sqrt(ocmath_get_noise_level(vy.GetSize(), vy));
		double dNoise = ocmath_get_noise_level(vy.GetSize(), vy);
		//trSmooth.nVal = dNoise / (dRange*0.05) * SMOOTH_LEVEL;
		trSmooth.nVal = dNoise / (dRange*0.005) * SMOOTH_LEVEL;
		if (trSmooth.nVal<=1)
			trSmooth.nVal = 0;
		/// Cloud 7/5/07 LIMIT_SMOOTH_POINTS
		if (trSmooth.nVal > vyi.GetSize()*0.2)
			trSmooth.nVal = vyi.GetSize() * 0.2;
		/// End LIMIT_SMOOTH_POINTS
		*/
		trSmooth.nVal = smooth_points_calculation_for_finding_peak(vyi, trMethod.nVal);
		//------ End CENTRALIZE_CODE_OF_LOCAL_MAXIMUN_METHOD
	}
	else
	{
		if (trSmooth.nVal<0)
		{
			if (pstrErrMsg!=NULL)
				*pstrErrMsg = XFERR_BAD_PARAM_FOR_FIND_PEAKS;
			return false;
		}
	}
	
	return true;
}

int interpolate_baseline_base_on_data(vector& vbx, vector& vby, vector& vx, vector& vy, int npts, int nInterpType)
{
	//sort the vbx and vby base on vbx increasing
	//vector<uint> vn;
	//vbx.Sort(SORT_ASCENDING, true, vn);
	//vby.Reorder(vn);
	///----Sandy 2008-12-2 remove duplicated points and sort for keep strict increasing in X
	int nSize = vby.GetSize();
	///------ Folger 12/26/08 QA80-12856 v8.0991 IMRPOVE_ocmath_xy_remove_duplicates
	//if(OE_NOERROR != ocmath_xy_remove_duplicates(&nSize,vbx,vby, Replace_With_Median, 1.0e-8, true))
	if((nSize = ocmath_xy_remove_duplicates(vbx,vby, nSize, Replace_With_Median, 1.0e-8, true)) < OE_NOERROR )
	///------ End IMRPOVE_ocmath_xy_remove_duplicates
		error_report("ocmath_xy_remove_duplicates return error in interpolate_baseline_base_on_data()");
	vbx.SetSize(nSize);
	vby.SetSize(nSize);
	//end
	

	
	//interpolate to npts
	double dxMin, dxMax;
	vx.GetMinMax(dxMin, dxMax);
	vector vxTemp(npts);
	if(npts == vx.GetSize())
		vxTemp = vx;
	else
		vxTemp.Data(dxMin, dxMax, (dxMax-dxMin)/(npts-1));
	
	vector vyTemp(npts);



	int nRet;
	if(nInterpType ==INTERP_TYPE_BSPLINE)
	{
		///Sandy 2008-6-3 add smooth factor 
		double dfactor = ocmath_get_noise_level(vx.GetSize(), vy, vx);
		dfactor *= dfactor;
		//end
		nRet = ocmath_interpolate(vxTemp, vyTemp, npts, vbx, vby, vbx.GetSize(), nInterpType, dfactor);
	}
	else
		nRet = ocmath_interpolate(vxTemp, vyTemp, npts, vbx, vby, vbx.GetSize(), nInterpType);
	
	///Sandy 2008-9-4 when there are all missing in x vector or y vector, return false;
	//if(0 != nRet)
	if(0 != nRet || vyTemp.GetSize()  == ocmath_count(NANUM,vyTemp.GetSize(), vyTemp) || ocmath_count(NANUM,vxTemp.GetSize(), vxTemp) == vxTemp.GetSize())
	{
		return nRet;
	}
	vbx = vxTemp;
	vby = vyTemp;
	
	return OE_NOERROR;
}

///Jasmine 08/28/09 CENTRALIZE_FIND_PEAK_METHOD_COMBO
bool is_find_peak_method_available(int nMethod)
{	
	int	nLastOption 	= is_pro_version()? FIND_PEAK_RESIDUE : FIND_PEAK_1ST_DERIVATIVE;
	return nMethod <= nLastOption;		
}

string get_find_peak_methods()
{	
	string 	strProOption	= PRO_ONLY_FIND_PEAK_METHOD;	
	//if ( !is_pro_version() ) /// Iris 2/02/2010 QA81-14165 ALSO_SHOW_PRO_IN_PRO_VERSION
	{
		vector<string> vsCombo;
		int nCount = strProOption.GetTokens(vsCombo, '|');
		for(int ii = 0; ii < nCount; ii++)
			vsCombo[ii] = vsCombo[ii] + " " + STR_PRO_POSTFIX;
		strProOption.SetTokens(vsCombo, '|');
	}
	
	return REGULAR_FIND_PEAK_METHOD + "|" + strProOption;
}
///End CENTRALIZE_FIND_PEAK_METHOD_COMBO


/// Hong 11/23/07 v8.0753 CLEAN_CENTRALIZE_CODE_AVOID_DATAPLOT_DEPENDENCE
int test_peaks(vector& vxPeaks, vector& vyPeaks, vector<int>& vnIndices, int nMothed, double dTestValue)
{
	int nRet = OE_NOERROR;
	int nSize = vyPeaks.GetSize();
	switch (nMothed)
	{
	case TEST_PEAK_HEIGHT:
		nRet = ocmath_test_peaks_by_height(&nSize, vxPeaks, vyPeaks, vnIndices, dTestValue);
		break;
	case TEST_PEAK_NUMBER:
		nRet = ocmath_test_peaks_by_number(nSize, vxPeaks, vyPeaks, vnIndices, (int)dTestValue);
		
		if(nRet != OE_POINT_OUTSIDE_RECT)  ///Sandy 2008-4-25
			nSize = dTestValue;
		break;
	default:
		break;
	}
	//------ Folger 12/10/07 FIND_PEAKS_SHOULD_RETURN_OCMATH_ERROR_CODE
	//if (nRet != OE_NOERROR)
		//return XFERR_BAD_PARAM_FOR_FIND_PEAKS;
	//------
	
	vxPeaks.SetSize(nSize);
	vyPeaks.SetSize(nSize);
	vnIndices.SetSize(nSize);
	
	///Sandy 2008-6-3 add error message if all peak be trimed
	if(nSize <= 0)
		nRet = OE_NO_PEAK_FOUND;
	//end
	
	return nRet;
}

static int get_test_height_width(const vector& vx, const vector& vy, double& dHeight, double& dWidth, bool bPercent = false)
{
	if ( dHeight < 0 || dWidth < 0 )
		return INTOPTN_OUT_OF_RANGE;
	
	if( bPercent )
	{
		if( dHeight>100 || dWidth>100 )
			return INTOPTN_OUT_OF_RANGE;
		
		double dMin, dMax, dTotalHeight, dTotalWidth;	
		vy.GetMinMax(dMin, dMax);
		dTotalHeight = max(abs(dMax), abs(dMin));
		/// Cloud 01/11/08 FIX_FOR_NON_MONOTONIC_DATA
		//dTotalWidth = abs(vx[vx.GetSize()-1] - vx[0]);
		vx.GetMinMax(dMin, dMax);
		dTotalWidth = dMax - dMin;
		/// End FIX_FOR_NON_MONOTONIC_DATA
				
		dHeight *= dTotalHeight/100;
		dWidth *= dTotalWidth/100;
	}
	
	return OE_NOERROR;
}

///Sandy 2008-6-10 CHANGE_RETURN_INT_FOR_MORE_ERR_MSG
//------ Folger 11/30/07 CLEAN_CODE_BY_FIND_FUNCTION
//typedef bool (*FUNC_CVEC_CVEV_VEC_VEC_VN_INT_INT)(const vector& vx,const vector& vy, vector& vxPeaks, vector& vyPeaks, vector<int>& vnIndices, int nDir, int nPtsSmooth);
//---Sandy 2008-11-18 APPLY_NEW_OCMATH_FUNCTION_PROTOTYPE_WITH_SG_DERIV
//typedef int (*FUNC_CVEC_CVEV_VEC_VEC_VN_INT_INT)(const vector& vx,const vector& vy, vector& vxPeaks, vector& vyPeaks, vector<int>& vnIndices, int nDir, int nPtsSmooth);
typedef int (*FUNC_CVEC_CVEV_VEC_VEC_VN_INT_BOOL_INT_INT)(const vector& vX,const vector& vY, vector& vxPeaks, vector& vyPeaks, vector<int>& vnIndices, int nDir, bool bUseSG , int nPtsSmooth, int nPloyDeg);
//------

//---Sandy 2008-11-18 APPLY_NEW_OCMATH_FUNCTION_PROTOTYPE_WITH_SG_DERIV
////----- CPY 12/8/2007 QA80-10788 CURVE_UTILS_SHOULD_NOT_NEED_PRO_DLLS
////int find_peaks_2nd_derivative_ex(UINT* lSize, const vector& vx,const vector& vy, vector& vxPeaks, vector& vyPeaks, vector<int>& vnIndices, DWORD dwCtrl, int nPtsSmooth);
//typedef int (*FUNC_PUI4_CVEC_CVEV_VEC_VEC_VN_UI4_I4)(UINT* lSize, const vector& vx, const vector& vy, vector& vxPeaks, vector& vyPeaks, vector<int>& vnIndices, DWORD dwCtrl, int nPtsSmooth);
typedef int (*FUNC_PUI4_CVEC_CVEV_VEC_VEC_VN_UI4_INT_VEC_INT_DOUBLE_INT)(UINT* lSize, const vector& vx, const vector& vy, vector& vxPeaks, vector& vyPeaks, vector<int>& vnIndices,DWORD dwCtrl,int nSmoothDerivativeMethod, vector& v2ndDeriv,  int nSGPtsSmooth, double dCutoffFreq, int nPolyOrder);
////-----

/// Hong 12/20/07 v8.0773d IMPROVE_FILTER_PEAK_ALLOW_SPECIFY_FILTER_VALUE
//int find_peaks(vector& vxData, vector& vyData, vector& vxPeaks, vector& vyPeaks, vector<int>& vnIndices, int nFindMathod,
//		double& dWidth, double& dHeight, int nPtsSmooth, int nDir, int npts, bool bPercent, int nTestMathod) // = BOTH_DIRECTION, 0, false, -1

//--Sandy 2008-11-20 APPLY_NEW_OCMATH_FUNCTION_PROTOTYPE_WITH_SG_DERIV
//int find_peaks(vector& vxData, vector& vyData, vector& vxPeaks, vector& vyPeaks, vector<int>& vnIndices, int nFindMathod,
		//double& dWidth, double& dHeight, int nPtsSmooth, int nDir, int npts, bool bPercent, int nTestMathod, const double* pdFilterValue)
int find_peaks(vector& vxData, vector& vyData, vector& vxPeaks, vector& vyPeaks, vector<int>& vnIndices,int nFindMathod,
		double& dWidth, double& dHeight, int nPtsSmooth, int nDir, int npts, bool bPercent, int nTestMathod, const double* pdFilterValue,
		 int nSmoothDerivativeMethod, vector& v2ndDeriv, int nSGPtsSmooth, double dFFTCutOff, int nPolyOrder) // = BOTH_DIRECTION, 0, false, -1, NULL, 0,  11,0.2, 2
//--end APPLY_NEW_OCMATH_FUNCTION_PROTOTYPE_WITH_SG_DERIV
/// end IMPROVE_FILTER_PEAK_ALLOW_SPECIFY_FILTER_VALUE
{
	int nRet = OE_NOERROR;	
	get_test_height_width(vxData, vyData, dHeight, dWidth, bPercent);
	/// Cloud 5/14/2007 add control for users to decide how much smooth
	/// Cloud 01/11/08 FIX_FOR_NON_MONOTONIC_DATA
	int nSize = vxData.GetSize();
	//if (nPtsSmooth > 1)
	
	//if (nPtsSmooth>1 && ocmath_is_monotonic(vxData, nSize)!=MONO_NOT)///Sandy 2008-11-6 should use unStrict
	///------ Folger 09/27/2010 CODE_CLEANUP_ABOUT_FINDING_PEAKS
	/*
	if(ocmath_is_monotonic(vxData, nSize, false)==MONO_NOT)
	{
		vector<uint> vn;
		vxData.Sort(SORT_ASCENDING, true, vn);
		vyData.Reorder(vn);
	}
	*/
	check_sort_data_for_find_peaks(vyData, vxData);
	///------ End CODE_CLEANUP_ABOUT_FINDING_PEAKS
	
	vector vyBackUp;
	///------ Folger 09/27/2010 CODE_CLEANUP_ABOUT_FINDING_PEAKS
	//vyBackUp = vyData;//Sandy 2008-11-21 for back up data before smoothed and use in later match_peaks_centers_by_index()
	///------ End CODE_CLEANUP_ABOUT_FINDING_PEAKS
	
	if (nPtsSmooth>1)
	/// End FIX_FOR_NON_MONOTONIC_DATA
	{
		///------ Folger 09/27/2010 CODE_CLEANUP_ABOUT_FINDING_PEAKS
		vyBackUp = vyData;
		///------ End CODE_CLEANUP_ABOUT_FINDING_PEAKS
		vector vytemp;
		vytemp = vyData;
		nRet = ocmath_savitsky_golay(vytemp, vyData, nSize, nPtsSmooth/2);
		if (nRet!=OE_NOERROR)
			//------ Folger 12/10/07 FIND_PEAKS_SHOULD_RETURN_OCMATH_ERROR_CODE
			//return XFERR_BAD_PARAM_FOR_FIND_PEAKS;
			return nRet;
			//------
		
		//vy = vytemp; // this code should be error code
	}
	int nPeakNum = nSize;
	bool bResetSize = true; /// Hong 11/26/07 v8.0754 CLEAN_CENTRALIZE_CODE_AVOID_DATAPLOT_DEPENDENCE
	//----- CPY 12/8/2007 QA80-10788 CURVE_UTILS_SHOULD_NOT_NEED_PRO_DLL
	if(vxPeaks.GetSize() < nPeakNum)
		vxPeaks.SetSize(nPeakNum);
	if(vyPeaks.GetSize() < nPeakNum)
		vyPeaks.SetSize(nPeakNum);
	if(vnIndices.GetSize() < nPeakNum)
		vnIndices.SetSize(nPeakNum);
	//-----	
	switch ( nFindMathod )
	{
	case FIND_PEAK_LOCAL_MAX:
		nRet = ocmath_find_peaks_by_local_maximum(&nPeakNum, vxData, vyData, vxPeaks, vyPeaks, vnIndices, nDir, npts); 
		break;
	case FIND_PEAK_WINDOW_SEARCH:
		nRet = ocmath_find_peaks_by_search_window(&nPeakNum, vxData, vyData, vxPeaks, vyPeaks, vnIndices, nDir, dWidth, dHeight);
		break;
	/// Hong 11/26/07 v8.0754 CLEAN_CENTRALIZE_CODE_AVOID_DATAPLOT_DEPENDENCE
	case FIND_PEAK_1ST_DERIVATIVE:
		//Sandy 2008-11-18 APPLY_NEW_OCMATH_FUNCTION_PROTOTYPE_WITH_SG_DERIV
		//nRet = ocmath_find_peaks_1st_derivative(&nPeakNum, vxData, vyData, vxPeaks, vyPeaks, vnIndices, nDir, 0);
		bool bUseSGderivativeForFindPeak = (nSmoothDerivativeMethod == DERIV_SMOOTH_SG? true:false);
		nRet = ocmath_find_peaks_1st_derivative(&nPeakNum, vxData, vyData, vxPeaks, vyPeaks, vnIndices, nDir, bUseSGderivativeForFindPeak, nSGPtsSmooth,  nPolyOrder);
		break;
	case FIND_PEAK_2ND_DERIVATIVE:
		
		//----------Sandy 2008-11-18 APPLY_NEW_OCMATH_FUNCTION_PROTOTYPE_WITH_SG_DERIV
		/*//----- CPY 12/8/2007 QA80-10788 CURVE_UTILS_SHOULD_NOT_NEED_PRO_DLLS
		//nRet = ocmsp_find_peaks_2nd_derivative(&nPeakNum, vxData, vyData, vxPeaks, vyPeaks, vnIndices, nDir, 0);
		FUNC_PUI4_CVEC_CVEV_VEC_VEC_VN_UI4_I4 pfnsp = Project.FindFunction("find_peaks_2nd_derivative_ex", "OriginLab\\PFM_Utils.c", true);
		if(pfnsp)
			nRet = pfnsp(&nPeakNum, vxData, vyData, vxPeaks, vyPeaks, vnIndices, nDir, 0);
		else
			error_report("pfm_utils find_peaks_2nd_derivative_ex failed to be loaded");
		//----- end CURVE_UTILS_SHOULD_NOT_NEED_PRO_DLLS
		*/
		
		FUNC_PUI4_CVEC_CVEV_VEC_VEC_VN_UI4_INT_VEC_INT_DOUBLE_INT pfnsp = Project.FindFunction("find_peaks_2nd_derivative_ex", "OriginLab\\PFM_Utils.c", true);
		if(pfnsp)
			nRet = pfnsp(&nPeakNum, vxData, vyData, vxPeaks, vyPeaks, vnIndices,  nDir, nSmoothDerivativeMethod, v2ndDeriv, nSGPtsSmooth, dFFTCutOff, nPolyOrder);
		else
			error_report("pfm_utils find_peaks_2nd_derivative_ex failed to be loaded");
		//----------end APPLY_NEW_OCMATH_FUNCTION_PROTOTYPE_WITH_SG_DERIV

		break;
	case FIND_PEAK_RESIDUE:
		//nRet = find_peaks_by_residuals(vxData, vyData, vxPeaks, vyPeaks, vnIndices, nDir, 0);	 // need to remove it to this c file from PFM_utils.c
		
		//----------Sandy 2008-11-18 APPLY_NEW_OCMATH_FUNCTION_PROTOTYPE_WITH_SG_DERIV
		//--- Folger 11/30/07 CLEAN_CODE_BY_FIND_FUNCTION
		/*FUNC_CVEC_CVEV_VEC_VEC_VN_INT_INT pfn = Project.FindFunction("find_peaks_by_residuals", "OriginLab\\PFM_Utils.c", true);
		//if (pfn)
			////nRet = pfn(vxData, vyData, vxPeaks, vyPeaks, vnIndices, nDir, 0) ? OE_NOERROR : OE_UNKOWN_ERROR;
			//nRet = pfn(vxData, vyData, vxPeaks, vyPeaks, vnIndices, nDir, 0);
		////---
		*/
		bool bUseSGderivativeForFindPeak = (nSmoothDerivativeMethod == DERIV_SMOOTH_SG? true:false);
		FUNC_CVEC_CVEV_VEC_VEC_VN_INT_BOOL_INT_INT pfn = Project.FindFunction("find_peaks_by_residuals", "OriginLab\\PFM_Utils.c", true);
		if (pfn)
			nRet = pfn(vxData, vyData, vxPeaks, vyPeaks, vnIndices, nDir, bUseSGderivativeForFindPeak, nSGPtsSmooth,  nPolyOrder);
		//--end of APPLY_NEW_OCMATH_FUNCTION_PROTOTYPE_WITH_SG_DERIV
		bResetSize = false;
		break;		
	//// end CLEAN_CENTRALIZE_CODE_AVOID_DATAPLOT_DEPENDENCE
	default:
		nRet = OE_NOERROR;
		break;
	}	
	if (nRet != OE_NOERROR)	
		//------ Folger 12/10/07 FIND_PEAKS_SHOULD_RETURN_OCMATH_ERROR_CODE
		//return XFERR_BAD_PARAM_FOR_FIND_PEAKS;		
		return nRet;
		//------
	
	if ( bResetSize ) /// Hong 11/26/07 v8.0754 CLEAN_CENTRALIZE_CODE_AVOID_DATAPLOT_DEPENDENCE
	{
		vxPeaks.SetSize(nPeakNum);
		vyPeaks.SetSize(nPeakNum);
		vnIndices.SetSize(nPeakNum);
	}

	if (nPeakNum ==0)
		//------ Folger 12/10/07 FIND_PEAKS_SHOULD_RETURN_OCMATH_ERROR_CODE
		//return XFERR_NO_PEAK_FOUND;
		return OE_NO_PEAK_FOUND;
		//------
	
	//Sandy 2008-11-21 add this for match the peak back to the original data without smooth before filtering peaks
	///------ Folger 09/27/2010 CODE_CLEANUP_ABOUT_FINDING_PEAKS
	//match_peaks_centers_by_index(vxData, vyBackUp, vxPeaks.GetSize(), vnIndices, vxPeaks, vyPeaks);		
	vector*		pvY = vyBackUp.GetSize() > 0 ? &vyBackUp : &vyData;
	match_peaks_centers_by_index(vxData, *pvY, vxPeaks.GetSize(), vnIndices, vxPeaks, vyPeaks);
	///------ End CODE_CLEANUP_ABOUT_FINDING_PEAKS
	
	//check the height of peak
	/// Hong 11/30/07 v8.0758 FIX_ERROR_TEST_VALUE
	//nRet = test_peaks(vxPeaks, vyPeaks, vnIndices, nTestMathod, dHeight);
	double dTestVal = 0;
	switch (nTestMathod)
	{
	case TEST_PEAK_HEIGHT:
		dTestVal = dHeight;
		break;
	case TEST_PEAK_NUMBER:
		dTestVal = dWidth;
		break;
	default:
		break;
	}
	/// Hong 12/20/07 v8.0773d IMPROVE_FILTER_PEAK_ALLOW_SPECIFY_FILTER_VALUE
	if ( pdFilterValue )
		dTestVal = *pdFilterValue;
	/// end IMPROVE_FILTER_PEAK_ALLOW_SPECIFY_FILTER_VALUE
	nRet = test_peaks(vxPeaks, vyPeaks, vnIndices, nTestMathod, dTestVal);
	/// end FIX_ERROR_TEST_VALUE
	//------ Folger 12/10/07 FIND_PEAKS_SHOULD_RETURN_OCMATH_ERROR_CODE
	//if (nRet != OE_NOERROR)
		//return XFERR_BAD_PARAM_FOR_FIND_PEAKS;
	//------
	
	/////sandy 2008-11-20 move from pa_peaks.oxf for nlfit also need
	//vector<uint> vn;
	//vxPeaks.Sort(SORT_ASCENDING, true, vn);
	//vyPeaks.Reorder(vn);
	//vnIndices.Reorder(vn);
	////end
	

	
	return nRet;
}
/// end CLEAN_CENTRALIZE_CODE_AVOID_DATAPLOT_DEPENDENCE

///------ Folger 03/18/10 QA81-15209 IMPROVE_PA_FIND_PEAKS_FOR_NONE_BASELINE
#define		FIND_PEAKS_WITHOUT_BASELINE(_dBase, _vxPeaks, _vyPeaks, _vPeaksInd, _dir) \
			vxTemp = vx, vyTemp = vy; \
			vby[0] = vby[1] = _dBase; \
			subtract_baseline(vxTemp, vyTemp, vbx, vby); \			
			nRet = find_peaks(vxTemp, vyTemp, _vxPeaks, _vyPeaks, _vPeaksInd, nFindMathod, dWidth, dHeight, nPtsSmooth, _dir, npts, bPercent, nTestMathod, pdFilterValue, \
				nSmoothDerivativeMethod, v2ndDeriv, nSGPtsSmooth, dFFTCutOff, nPolyOrder);	\
			if( OE_NO_PEAK_FOUND == nRet )	\
			{	\
				_vxPeaks.SetSize(0);	\
				_vyPeaks.SetSize(0);	\
				nRet = OE_NOERROR;		\
			}

int find_peaks_without_baseline(vector& vx, vector& vy, vector& vxPeaks, vector& vyPeaks, vector<int>& vnIndices, int nFindMathod,
					double& dWidth, double& dHeight, int nPtsSmooth, int nDir/* = BOTH_DIRECTION*/, int npts/* = 0*/, bool bPercent/* = false*/, int nTestMathod/* = -1*/, const double* pdFilterValue/* = NULL*/,
					int nSmoothDerivativeMethod/* = 0*/, vector& v2ndDeriv/* = NULL*/, int nSGPtsSmooth/* = 11*/, double dFFTCutOff/* = 0.2*/,  int nPolyOrder/* = 2*/)
{
	vector vbx(2), vby(2);
	double dxmin, dxmax;
	vx.GetMinMax(dxmin, dxmax);
	vbx[0] = dxmin;
	vbx[1] = dxmax;
	
	double dymin, dymax;
	vy.GetMinMax(dymin, dymax);
	
	vector		vxTemp, vyTemp;
	int			nRet = OE_NOERROR;
	if ( POSITIVE_DIRECTION == nDir )
	{
		FIND_PEAKS_WITHOUT_BASELINE(dymin, vxPeaks, vyPeaks, vnIndices, POSITIVE_DIRECTION);
	}
	else if ( NEGATIVE_DIRECTION == nDir )
	{
		FIND_PEAKS_WITHOUT_BASELINE(dymax, vxPeaks, vyPeaks, vnIndices, NEGATIVE_DIRECTION);
	}
	else
	{
		///Kyle 09/10/2010 ORG-998-P8 IN_BOTH_DIR_FAIL_TO_FIND_PEAKS_WHICH_CAN_BE_FOUND_IN_NEGATIVE_DIR
		double dWidthTemp = dWidth;
		double dHeightTemp = dHeight;
		///End IN_BOTH_DIR_FAIL_TO_FIND_PEAKS_WHICH_CAN_BE_FOUND_IN_NEGATIVE_DIR

		int		nSize = vx.GetSize();
		FIND_PEAKS_WITHOUT_BASELINE(dymin, vxPeaks, vyPeaks, vnIndices, POSITIVE_DIRECTION);
		if ( OE_NOERROR == nRet )
		{
			vector<int>	vnIndicesTemp(nSize);	
			vector		vxPeaksTemp(nSize), vyPeaksTemp(nSize);
			
			///Kyle 09/10/2010 ORG-998-P8 IN_BOTH_DIR_FAIL_TO_FIND_PEAKS_WHICH_CAN_BE_FOUND_IN_NEGATIVE_DIR
			dWidth = dWidthTemp;
			dHeight = dHeightTemp;
			///End IN_BOTH_DIR_FAIL_TO_FIND_PEAKS_WHICH_CAN_BE_FOUND_IN_NEGATIVE_DIR
			
			FIND_PEAKS_WITHOUT_BASELINE(dymax, vxPeaksTemp, vyPeaksTemp, vnIndicesTemp, NEGATIVE_DIRECTION);
			
			if ( OE_NOERROR == nRet )
			{
				vxPeaks.Append(vxPeaksTemp);
				vyPeaks.Append(vyPeaksTemp);
				vnIndices.Append(vnIndicesTemp);
			}
		}
	}

	return nRet;
}
///------ End IMPROVE_PA_FIND_PEAKS_FOR_NONE_BASELINE

//----- CPY 12/8/2007 QA80-10788 FIND_FLAT_REGIONS_IN_CURVE
// moved to ocmath by Cloud
/*
// return number of regions that met requirements of nMinBasePts, which is the number of points in the baseline region
int find_base_regions(const vector& vxData, const vector& vyData, int nMinBasePts, vector<int>& vBegs, vector<int>& vEnds, double dTol, double dMaxSearchSize, bool bUseSlope)
{
	int nSize = vyData.GetSize();
	int nMinSeg = 0.5 + nMinBasePts/3.;
	int i1 = 0;
	int i2;
	int jj = 0;
	
	while(i1 < nSize - nMinSeg)
	{
		int nRet = ocmath_check_linear(nSize, vxData, vyData, &i2, dMaxSearchSize, dTol, i1, true, bUseSlope);
		jj++;
		if( nRet < 0 )
			return nRet;
		if(i2 - i1 > nMinBasePts)
		{
		//	printf("%d: found base, i1=%d, i2 = %d\n", jj, i1, i2);
			vBegs.Add(i1);
			vEnds.Add(i2);
			i1 = i2 + 1;
		}
		else
		{
		//	printf("%d: not good enough base points, i1=%d, i2 = %d\n", jj, i1, i2);
			i1 += nMinSeg;
		}
	}
	return vEnds.GetSize();	
}
// caller is responsible for allocating enough space for pResults
int fit_linear_multi_regions(const vector& vxData, const vector& vyData, const vector<int>& vBegs, const vector<int>& vEnds, LRresults* pResults)
{
	int nSize = vxData.GetSize();
	FitParameter sFitParameter[2];
	RegStats sRegStats;
	int nCount = 0;
	int i1, i2;
	for(int ii = 0; ii < vBegs.GetSize(); ii++, pResults++)
	{
		i1 = vBegs[ii]; i2 = vEnds[ii];
		if(i2 - i1 < 2)
			continue;
		vector vx, vy;
		vxData.GetSubVector(vx, i1, i2);
		vyData.GetSubVector(vy, i1, i2);

		if( ocmath_linear_fit(vx, vy, vy.GetSize(), sFitParameter, NULL, 0, NULL, &sRegStats) != OE_NOERROR)
			return -(ii+1);
		
		nCount++;
		pResults->i1 = vBegs[ii];
		pResults->i2 = vEnds[ii];
		pResults->a = sFitParameter[0].Value;		//Intercept
		pResults->aErr = sFitParameter[0].Error;
		pResults->b = sFitParameter[1].Value;		//Slope
		pResults->bErr = sFitParameter[1].Error;
		pResults->Rvalue = sRegStats.Rvalue;
		pResults->AdjRSq = sRegStats.AdjRSq;			//Adjusted residuel sum of squares
	}
	return nCount;
}*/
//-----

bool match_peaks_centers_by_index(const vector& vxi,const vector& vyi, const int nPeaksNum, const vector<int>& vPeaksInd, vector& vxPeaks,vector& vyPeaks )
{
	if(vPeaksInd.GetSize()<nPeaksNum ||vxPeaks.GetSize()<nPeaksNum || vyPeaks.GetSize()<nPeaksNum )
		return false;
	
	///------ Folger 09/27/2010 ORG-1159 MOVE_match_peaks_centers_by_index_TO_VC_AS_OCMATH_FUNCTION
	/*
	for(int ii = 0; ii<nPeaksNum; ii++)
	{
		if(vxi.GetSize() < vPeaksInd[ii] || vyi.GetSize() < vPeaksInd[ii])
			return false;
		
		vxPeaks[ii] = vxi[vPeaksInd[ii]];
		vyPeaks[ii] = vyi[vPeaksInd[ii]];
	}	
	
	return true;
	*/
	return ocmath_match_peaks_centers_by_index(vxi, vyi, vxi.GetSize(), vPeaksInd, vxPeaks, vyPeaks, nPeaksNum) == OE_NOERROR;
	///------ End MOVE_match_peaks_centers_by_index_TO_VC_AS_OCMATH_FUNCTION
}

///Sandy 2007-6-12 add markers index output
///// Cloud 05/17/2007 ADD_DEFAULT_VALUE_WHEN_NOT_FIND_PEAK_FEET
//void get_peaks_data_from_parent_data(vector& vyi, vector& vxi, int nPeakNum, vector<int>& vPeaksInd, vector& vxPeaks, vector&  vyPeaks,
////					 vector<int>& vFeetInd, vector& vxLFeet, vector& vyLFeet, vector& vxRFeet, vector& vyRFeet)
					 //vector<int>& vFeetInd, vector& vxLFeet, vector& vyLFeet, vector& vxRFeet, vector& vyRFeet, const double* pLFeet, const double* pRFeet)
void get_peaks_info_from_index_within_maxwidth(vector& vyi, vector& vxi, int nPeakNum, vector<int>& vPeaksInd, vector& vxPeaks, vector&  vyPeaks,
					vector<int>& vFeetInd, vector& vxLFeet, vector& vyLFeet, vector& vxRFeet, vector& vyRFeet, const double* pLFeet, const double* pRFeet)
{
	double dLFeet, dRFeet;
	int iSize = vxi.GetSize();
	if (pLFeet==NULL)
		dLFeet = vxi[0];
	else
		dLFeet = *pLFeet;
	if (pRFeet==NULL)
		dRFeet = vxi[iSize-1];
	else
		dRFeet = *pRFeet;
/// End ADD_DEFAULT_VALUE_WHEN_NOT_FIND_PEAK_FEET
	vxPeaks.SetSize(nPeakNum);
	vxPeaks.SetSize(nPeakNum);
	vxLFeet.SetSize(nPeakNum);
	vyLFeet.SetSize(nPeakNum);
	vxRFeet.SetSize(nPeakNum);
	vyRFeet.SetSize(nPeakNum);
	
	for(int ii=0; ii<nPeakNum; ii++)
	{
		vxPeaks[ii] = vxi[vPeaksInd[ii]];
		vyPeaks[ii] = vyi[vPeaksInd[ii]];
		
		if(vFeetInd[ii*2] >= 0)
		{
			vxLFeet[ii] = vxi[vFeetInd[ii*2]];
			vyLFeet[ii] = vyi[vFeetInd[ii*2]];
		}
		/// Cloud 05/11/2007 set the feet to NANUM when cannot find feet
		else
		{
			/// Cloud 05/17/2007 ADD_DEFAULT_VALUE_WHEN_NOT_FIND_PEAK_FEET
			//vxLFeet[ii] = vyLFeet[ii] = NANUM;
			vxLFeet[ii] = vxPeaks[ii] - dLFeet;
			int iTmp = 0;
			while (iTmp<iSize && vxi[iTmp]<vxLFeet[ii])
				iTmp ++;
			if (iTmp >= iSize)
			{
				vxLFeet[ii] = vxi[0];
				vyLFeet[ii] = vyi[0];
				
				///Sandy 2007-6-12 add markers index output
				vFeetInd[ii*2] = 0;
			}
			else if (vxi[iTmp]==dLFeet || iTmp == 0)
			{
				vyLFeet[ii] = vyi[iTmp];
				vFeetInd[ii*2] = iTmp;
			}
			else
			{
				///Sandy 2007-6-12 add markers index output
				//vyLFeet[ii] = (vyi[iTmp-1] + vyi[iTmp]) / 2;
				vyLFeet[ii] = vyi[iTmp-1];
				vFeetInd[ii*2] = iTmp-1;
			}
			/// End ADD_DEFAULT_VALUE_WHEN_NOT_FIND_PEAK_FEET
		}
	
		if(vFeetInd[ii*2+1] >= 0)
		{
			vxRFeet[ii] = vxi[vFeetInd[ii*2+1]];
			vyRFeet[ii] = vyi[vFeetInd[ii*2+1]];
		}
		/// Cloud 05/11/2007 set the feet to NANUM when cannot find feet
		else
		{
			/// Cloud 05/17/2007 ADD_DEFAULT_VALUE_WHEN_NOT_FIND_PEAK_FEET
			//vxRFeet[ii] = vyRFeet[ii] = NANUM;
			vxRFeet[ii] = vxPeaks[ii] + dRFeet;
			int iTmp = 0;
			while (iTmp<iSize && vxi[iTmp]<vxRFeet[ii])
				iTmp ++;
			if (iTmp >= iSize-1)
			{
				vxRFeet[ii] = vxi[iSize-1];
				vyRFeet[ii] = vyi[iSize-1];
				///Sandy 2007-6-12 add markers index output
				vFeetInd[ii*2+1] = 0;
			}
			else if (vxi[iTmp]==dRFeet || iTmp == (iSize-2))
			{
				vyRFeet[ii] = vyi[iTmp];
				///Sandy 2007-6-12 add markers index output
				vFeetInd[ii*2+1] = iTmp;
			}
			else
			{
				///Sandy 2007-6-12 add markers index output
				//vyRFeet[ii] = (vyi[iTmp-1] + vyi[iTmp]) / 2;
				vyRFeet[ii] = vyi[iTmp+1];				
				vFeetInd[ii*2+1] = iTmp+1;
			}
			/// End ADD_DEFAULT_VALUE_WHEN_NOT_FIND_PEAK_FEET
		}
	}		
}

int compute_peaks_markers_all_infomation(const vector& vxOrigin, const vector& vyOrigin, 
	const vector& vxData, const vector& vyData, vector<int>& vnPeaksIndices, vector& vxPeaks, vector& vyPeaks, 
	double dMaxFullWidth, vector& vxLFeet, vector& vyLFeet,vector& vxRFeet, vector& vyRFeet, vector<int>& vMarkersInd) // = 0
{
	int nRet = OE_NOERROR;
	//if ( !wksRes )
		//return CER_NO_WORKSHEET;	
	double dFootHeight = get_feet_height_by_percent_of_total_height(vyData, 0.001);
	int nPeakNum = vxPeaks.GetSize();
	
	vector<uint> vn;
	vnPeaksIndices.Sort(SORT_ASCENDING, true, vn);
	vxPeaks.Reorder(vn);
	vyPeaks.Reorder(vn);
	
	double dHalfWidth = dMaxFullWidth / 2;
	
	//vector<int> vFeetInd(nPeakNum*2);
	vMarkersInd.SetSize(nPeakNum*2);
	nRet = ocmath_find_markers_of_peaks_by_height_and_width(vyData.GetSize(), vxData, vyData, nPeakNum, vnPeaksIndices, nPeakNum*2, vMarkersInd,  
														 dFootHeight, dHalfWidth, 0);
	if (nRet != OE_NOERROR)
		return nRet;
	
	get_peaks_info_from_index_within_maxwidth(vyOrigin, vxOrigin, nPeakNum, vnPeaksIndices, vxPeaks, vyPeaks, vMarkersInd, vxLFeet, vyLFeet, vxRFeet, vyRFeet, &dHalfWidth, &dHalfWidth);
	 
	return nRet;
}

/*
bool sort_points_by_base_derivative(const vector& vx, const vector& vy, vector& vbx, vector& vby)
{
	int nSegments = 8;
	if(vx.GetSize() <= nSegments|| vy.GetSize() <= nSegments || vx.GetSize() != vy.GetSize())
		return false;
	
	vby = vy;
	vbx = vx;
	vector vyTemp;
	vyTemp = vy;
	if(OE_NOERROR != ocmath_derivative(	vx, vyTemp, vx.GetSize(), DERV_PEAK_AS_ZERO))
		return false;
	
	vyTemp = abs(vyTemp);
	vector<uint> vnByDeriv;
	vyTemp.Sort(SORT_ASCENDING, false, vnByDeriv);//missvalue means large slope rate
	vby.Reorder(vnByDeriv);
	vbx.Reorder(vnByDeriv);
	
	int nWindowSize = vby.GetSize()/nSegments;
	
	//sort by height in segment
	for(int ii = 0; ii < nSegments; ii++)
	{
		vector vWinY, vWinX;
		vector vbySegmentAvg;
		
		
		vby.GetSubVector(vWinY, ii*nWindowSize, nWindowSize);
		vbx.GetSubVector(vWinX, ii*nWindowSize, nWindowSize);
		
		vector<uint> vnByHeight;
		double dSum, dAvg;
		vWinY.Sum(dSum);
		dAvg = dSum/nWindowSize;
		vector vAbsH;
		vAbsH = abs(vWinY - dAvg);
		vAbsH.Sort(SORT_ASCENDING, true, vnByHeight);
		vWinX.Reorder(vnByHeight);
		vWinY.Reorder(vnByHeight);
		
		vby.SetSubVector(vWinY, ii*nWindowSize);
		vbx.SetSubVector(vWinX, ii*nWindowSize);
		
	}
	

	return true;
}
*/
///move from xf
//void	snap_points_to_source_data(const vector& vsx, const vector& vsy, vector& vx, vector& vy)
//{
	//vector vbx(vsx.GetSize()), vby(vsx.GetSize());
	//for(int ii = 0; ii< vsx.GetSize(); ii++)
	//{
		//double dY;
		//double dX = vsx[ii];
		//if(0 == ocmath_interpolate(&dX, &dY, 1, vx, vy, vx.GetSize()))
		//{
			//vbx[ii] = vsx[ii];
			//vby[ii] = dY;
		//}
//
	//}
	//vx = vbx;
	//vy = vby;
//}

void	snap_points_to_source_data(const vector& vxSource, const vector& vySource, vector& vx, vector& vy)
{
	vector vTempX(vx.GetSize()), vTempY(vx.GetSize());
	vTempX = vx;
	if(0 == ocmath_interpolate(vTempX, vTempY, vTempX.GetSize(), vxSource, vySource, vySource.GetSize()))
	vx = vTempX;
	vy = vTempY;
}

//------ Folger 03/13/08 COMMENT_CODE_THAT_LEADS_TO_LINKING_ERROR
//this function makes linking error in NLFitSession, just comment out here

///Arvin 03/13/08 REPLICA_AUTO_INIT_PARAMS_FOR_SURFACE_FIT
//Just use same method as method in update_smooth_point to calculate smooth points

//------ Folger 04/18/08 QA80-11441 CENTRALIZE_CODE_OF_LOCAL_MAXIMUN_METHOD
//int smooth_points_calculation_for_finding_peak(const vector& vDependent)
int smooth_points_calculation_for_finding_peak(const vector& vDependent, int nMethod)
//------
{
	//------ Folger 04/18/08 QA80-11441 CENTRALIZE_CODE_OF_LOCAL_MAXIMUN_METHOD
	if ( nMethod == FIND_PEAK_LOCAL_MAX )
		return 0;
	//------
	
	//------ Sandy 2008-11-5 SET_SMOOTH_POINT_ZERO_IN_WINDOW_SEARCH_METHOD
	if ( nMethod == FIND_PEAK_WINDOW_SEARCH )
		return 0;
	//------
	
	int nSize = vDependent.GetSize();
	if(nSize < 1)
		return 0;
	
	double dRange;
	double dMin, dMax;
	vDependent.GetMinMax(dMin, dMax);
	dRange = dMax - dMin;
	//------ Folger 04/18/08 QA80-11441 CENTRALIZE_CODE_OF_LOCAL_MAXIMUN_METHOD
	//ocmath_replace_data_in_vector(nSize, vDependent, 0, NANUM);
	//vDependent.Trim();
	//------
	double dNoise = ocmath_get_noise_level(nSize, vDependent);
	int nSmoothPts = dNoise / (dRange*0.005) * SMOOTH_LEVEL;
	if(nSmoothPts <= 1)
		nSmoothPts = 0;
	if(nSmoothPts > nSize*0.2)
		nSmoothPts = nSize * 0.2;
	return nSmoothPts;
}

static double _real_value_from_percent(const vector& vData, double dPercent)
{
	if(vData.GetSize() < 1)
		return 0.0;
	double dMin, dMax;
	vData.GetMinMax(dMin, dMax);
	double dRange = abs(dMax - dMin);
	return dRange*dPercent/100.0;
}

///Arvin 03/26/08 RESET_REPLICA_NUMBER_WHEN_CAN_NOT_FIND_ENOUGH_PEAK
/*
static void _resize_vector(vector& vData, int nNeededSize)
{
	int nSize = vData.GetSize(); 
	vData.SetSize(nNeededSize);
	if(nSize < nNeededSize)
	{
		//duplicate last element
		vector vTemp(nNeededSize - nSize);
		double dValue = vData[nSize-1];
		vTemp = dValue;
		vData.SetSubVector(vTemp, nSize);
	}
}
*/
///end RESET_REPLICA_NUMBER_WHEN_CAN_NOT_FIND_ENOUGH_PEAK

static bool _get_contour_levels(const vector& vZ, vector& vLevels, int nNumLevels)
{
	if(nNumLevels < 2)
		return false;
	
	double			dZMin, dZMax;
	vZ.GetMinMax(dZMin, dZMax);
	if(is_missing_value(dZMin) || is_missing_value(dZMax) )
		return false;
	//----- CPY 3/24/08 FIND_PEAKS_BY_CONTOUR_IN_MAT_CASE
	// use better contour levels, in terms of number levels of contour lines
	//vLevels.Data(dZMin, dZMax, (dZMax - dZMin) / (nNumLevels-1));
	double zInc = (dZMax - dZMin) / (1.0 + nNumLevels);
	vLevels.Data(dZMin + zInc, dZMax - zInc, zInc);
	//-----
	return true;
}

static int  _get_min_integer(int nx, int ny, int* pnz = NULL)
{
	int nMin = min(nx, ny);
	if(pnz != NULL)
		return min(nMin, *pnz);
	return nMin;
}

static bool _check_good_Z_size(int nZSize, int nRows, int nCols)
{
	if(nZSize != nRows*nCols)
		return false;
	return true;
}

/// Iris 4/13/2009 QA80-13448 CHANGE_LOCAL_POINT_PERCENT_TO_LOCAL_POINTS, not place use this function now
/*
//Calculate local points after talking with jack
//nZSize = nRows * nCols  
static int _get_local_points(int nSize, double dPercent)
{
	//
	int nLocalPoints = nSize*(dPercent/100.0);
	return nLocalPoints;
}
*/
///end CHANGE_LOCAL_POINT_PERCENT_TO_LOCAL_POINTS

static int _find_2d_peak_by_1st_partial_derivative(const vector& vZ, uint nRows, uint nCols, vector<int>& vxPeakInd, vector<int>& vyPeakInd, DWORD dwDir, int nLeftPts = 1, int nRightPts = -1)
{
	int nSize = vZ.GetSize();
	if(!_check_good_Z_size(nSize, nRows, nCols))
		return -1;
	
	int nMaxNumPeak = nCols*nRows;
	vxPeakInd.SetSize(nMaxNumPeak);
	vyPeakInd.SetSize(nMaxNumPeak);
	vector vZCeter(nMaxNumPeak);
	return ocm_2d_find_peak_by_partial_derivative(vZ, nRows, nCols, vZCeter, vyPeakInd, vxPeakInd, nMaxNumPeak, nLeftPts, nRightPts, dwDir);
}

static int _find_2d_peak_by_local_maximum(const vector& vZ, int nRows, int nCols, vector<int>& vxPeakInd, vector<int>& vyPeakInd, DWORD dwDir, int nxLocalPts, int nyLocalPts)
{
	int nSize = vZ.GetSize();
	if(!_check_good_Z_size(nSize, nRows, nCols))
		return -1;
	
	int nMaxNumPeak = nCols*nRows;
	vxPeakInd.SetSize(nMaxNumPeak);
	vyPeakInd.SetSize(nMaxNumPeak);
	vector vZCenter(nSize);
	return ocm_2d_find_peak_by_local_maximum(vZ, nRows, nCols, vZCenter, vyPeakInd, vxPeakInd, nMaxNumPeak, nxLocalPts, nyLocalPts, dwDir);
}

static int _find_2d_peak_by_local_max_and_partial_derivative(const vector& vX, const vector& vY, const vector& vZ, vector& vXCenter, vector& vYCenter, vector& vZCenter, vector& vXWidth, vector& vYWidth, const FindPeakCtrlInfo* pCtrlInfo)
{
	uint nCols = vX.GetSize();
	uint nRows = vY.GetSize();
	int nZSize = vZ.GetSize();
	int nSize = _get_min_integer(nRows, nCols, &nZSize);
	if(nSize < 1)
		return OE_INVALID_SIZE;
	
	if(pCtrlInfo == NULL)
		return OE_NULL_POINTER;
	
	int nNumPeaks = 0;
	vector<int> vxPeakInd(nCols*nRows);
	vector<int> vyPeakInd(nCols*nRows);
	if(pCtrlInfo->nFindPeakMethod)
	{
		nNumPeaks = _find_2d_peak_by_1st_partial_derivative(vZ, nRows, nCols, vxPeakInd, vyPeakInd, pCtrlInfo->dwCtrl);
	}
	else
	{
		/// Iris 4/13/2009 QA80-13448 CHANGE_LOCAL_POINT_PERCENT_TO_LOCAL_POINTS
		//int nxLocalPts = _get_local_points(nCols, pCtrlInfo->dLocalPtsPerc);
		//int nyLocalPts = _get_local_points(nRows, pCtrlInfo->dLocalPtsPerc);
		int nxLocalPts = pCtrlInfo->nLocalPts;
		int nyLocalPts = pCtrlInfo->nLocalPts;
		///end CHANGE_LOCAL_POINT_PERCENT_TO_LOCAL_POINTS
		nNumPeaks = _find_2d_peak_by_local_maximum(vZ, nRows, nCols, vxPeakInd, vyPeakInd, pCtrlInfo->dwCtrl, nxLocalPts, nyLocalPts);	
	}
	
	if(nNumPeaks < 0)
		return nNumPeaks;
	
	vxPeakInd.SetSize(nNumPeaks);
	vyPeakInd.SetSize(nNumPeaks);
	vXCenter.SetSize(nNumPeaks);
	vYCenter.SetSize(nNumPeaks);
	vZCenter.SetSize(nNumPeaks);
	vXWidth.SetSize(nNumPeaks);
	vYWidth.SetSize(nNumPeaks);
	return ocm_2d_find_peak_parameter(nCols, nRows, vZ, vX, vY, nNumPeaks, vxPeakInd, vyPeakInd, vXCenter, vYCenter, vZCenter, vXWidth, vYWidth);
}

static int _find_2d_peak_by_contour_consolidation(const vector& vX, const vector& vY, const vector& vZ, vector& vXCenter, vector& vYCenter, vector& vZCenter, vector& vXWidth, vector& vYWidth, const FindPeakCtrlInfo* pCtrlInfo)
{
	int nZSize = vZ.GetSize();
	int nSize = _get_min_integer(vX.GetSize(), vY.GetSize(), &nZSize);
	if(nSize < 4 )
		return OE_INVALID_SIZE;
	
	if(pCtrlInfo == NULL)
		return OE_NULL_POINTER;

	vector vLevels;
	if(!_get_contour_levels(vZ, vLevels, pCtrlInfo->cPeakInfo.nNumZLevels))
		return -2;
	
	ContourSelect cs;
	cs.minPts = pCtrlInfo->cPeakInfo.nMinPts;
	cs.maxPts = -1;;
	cs.minArea = -1; // in fraction of total contour area bounding rect
	cs.maxArea = pCtrlInfo->cPeakInfo.dMaxArea; // in fraction of total contour area bounding rect
	
	cs.minRoundness = pCtrlInfo->cPeakInfo.dMinRoundness;
	cs.dwCtrl = pCtrlInfo->dwCtrl;
	cs.close = 1; // close contours only
	cs.minHeight = -1;
	cs.maxHeight = -1;
	
	int nSearchMethod = 0;// hiearichal tree
	//---------------- CPY 3/24/08 FIND_PEAKS_BY_CONTOUR_IN_MAT_CASE
	BOOL bXYZ = false;
	if(nSize == nZSize) // must be XYZ data
	{
		bXYZ = true;
		nSize = sqrt(nZSize); // assume nZSize = nRows*nCols;
		if(nSize < 25) 
			nSize = 25;
	}
	//----------------
	vXCenter.SetSize(nSize); 	vYCenter.SetSize(nSize); 
	vXWidth.SetSize(nSize); 	vYWidth.SetSize(nSize); 
	vZCenter.SetSize(nSize); 
	//---------------- CPY 3/24/08 FIND_PEAKS_BY_CONTOUR_IN_MAT_CASE
	//int nPeakFind = find_peaks_by_tri_contour_consolidation(vX, vY, vZ, nSize, vLevels, pCtrlInfo->cPeakInfo.nNumZLevels, vXCenter, vYCenter, vXWidth, vZCenter, nSize, &cs, nSearchMethod);
	int nPeaks;
	if(bXYZ)
		nPeaks = find_peaks_by_tri_contour_consolidation(vX, vY, vZ, nZSize, vLevels, pCtrlInfo->cPeakInfo.nNumZLevels, vXCenter, vYCenter, vXWidth, vYWidth, vZCenter, nSize, &cs, nSearchMethod);
	else
	{
		int nRows = vY.GetSize();
		int nCols = vX.GetSize();
		double xy[4];
		xy[0] = vX[0];
		xy[1] = vY[0];
		xy[2] = vX[nCols-1];
		xy[3] = vY[nRows-1];
		nPeaks = find_peaks_by_contour_consolidation(vZ, nRows, nCols, xy, vLevels, pCtrlInfo->cPeakInfo.nNumZLevels, vXCenter, vYCenter, vXWidth, vYWidth, vZCenter, nSize, &cs);
	}
	//---------------- end FIND_PEAKS_BY_CONTOUR_IN_MAT_CASE
	
	if(nPeaks < 0)
		return nPeaks;
	
	vXCenter.SetSize(nPeaks); 	vYCenter.SetSize(nPeaks); 
	vXWidth.SetSize(nPeaks); 	vYWidth.SetSize(nPeaks);
	vZCenter.SetSize(nPeaks); 
	return OE_NOERROR;
}

int init_2d_peak_parameters_for_replica_fitting(const vector& vxGrid, const vector& vyGrid, const vector& vzGrid, int nNumNeededPeaks, vector& vXCenter, vector& vYCenter, vector& vZCenter, vector& vXWidth, vector& vYWidth, const FindPeakCtrlInfo* pCtrlInfo)
{
	if(nNumNeededPeaks < 1)
		return OE_INVALID_SIZE;
	
	if(pCtrlInfo == NULL)
		return OE_NULL_POINTER;
	
	int nRet = OE_NOERROR;
	double 	dMinHeight = _real_value_from_percent(vzGrid, pCtrlInfo->dMinPeakHeight);
	switch(pCtrlInfo->nFindPeakMethod)
	{
	case FIND_2D_PEAK_CONTOUR_CONSOLIDATION:
		 nRet = _find_2d_peak_by_contour_consolidation(vxGrid, vyGrid, vzGrid, vXCenter, vYCenter, vZCenter, vXWidth, vYWidth, pCtrlInfo);
		break;
		
	case FIND_2D_PEAK_1ST_PARTIAL_DERIVATIVE:
	case FIND_2D_PEAK_LOCAL_MAXIMUM:
		nRet = _find_2d_peak_by_local_max_and_partial_derivative(vxGrid, vyGrid, vzGrid, vXCenter, vYCenter, vZCenter, vXWidth, vYWidth, pCtrlInfo);
		break;	
	default:
		return OE_INT_ARG_LT;
	}
	if(nRet != OE_NOERROR)
		return nRet;
	
	vector<uint> vInd;
	vector vzcTemp;
	///Sandy 2009-1-8 SPEED_UP_VECTOR_ABS
	//vzcTemp = abs(vZCenter);
	vzcTemp = vZCenter;
	vzcTemp.Abs();
	//end SPEED_UP_VECTOR_ABS
	vzcTemp.Sort(SORT_DESCENDING, TRUE, vInd);
	vXCenter.Reorder(vInd);
	vYCenter.Reorder(vInd);
	vZCenter.Reorder(vInd);
	vXWidth.Reorder(vInd);
	vYWidth.Reorder(vInd);
	int nNumPeaks = vzcTemp.GetSize();
	nRet = ocmath_replace_data_in_vector(nNumPeaks, vzcTemp, dMinHeight, NANUM, MATREPL_TEST_LESSTHAN);
	if(nRet != OE_NOERROR)
		return nRet;
	
	vzcTemp.Trim();
	nNumPeaks = vzcTemp.GetSize();
	vXCenter.SetSize(nNumPeaks);
	vYCenter.SetSize(nNumPeaks);
	vZCenter.SetSize(nNumPeaks);
	vXWidth.SetSize(nNumPeaks);
	vYWidth.SetSize(nNumPeaks);
	if(vXCenter.GetSize() < 1)
		return OE_NO_PEAK_FOUND;
	///Arvin 03/26/08 RESET_REPLICA_NUMBER_WHEN_CAN_NOT_FIND_ENOUGH_PEAK
	//_resize_vector(vXCenter, nNumNeededPeaks);
	//_resize_vector(vYCenter, nNumNeededPeaks);
	//_resize_vector(vZCenter, nNumNeededPeaks);
	//_resize_vector(vXWidth, nNumNeededPeaks);
	//_resize_vector(vYWidth, nNumNeededPeaks);
	//return OE_NOERROR;
	return nNumPeaks; //return number of found peaks
	///end RESET_REPLICA_NUMBER_WHEN_CAN_NOT_FIND_ENOUGH_PEAK
}

int	init_1d_peak_parameters_for_replica_fitting(const vector& vX, const vector& vY, int nNumNeededPeaks, vector& vXCenter, vector& vYCenter, vector& vXWidth, const FindPeakCtrlInfo* pCtrlInfo)
{
	int nSize = _get_min_integer(vX.GetSize(), vY.GetSize());
	if(nNumNeededPeaks < 1 || nSize < 1)
		return false;
	
	if(pCtrlInfo == NULL)
		return false;
	
	vector	vYPeaks(nSize), vXPeaks(nSize);
	vector<int>	vnPeakIndices(nSize);
	
	//------ Folger 04/18/08 QA80-11441 CENTRALIZE_CODE_OF_LOCAL_MAXIMUN_METHOD
	//int 	nSmoothPts = smooth_points_calculation_for_finding_peak(vY);
	int 	nSmoothPts = smooth_points_calculation_for_finding_peak(vY, pCtrlInfo->nFindPeakMethod);
	//------
	
	/// Iris 4/13/2009 QA80-13448 CHANGE_LOCAL_POINT_PERCENT_TO_LOCAL_POINTS
	//int 	nLocalPts = _get_local_points(nSize, pCtrlInfo->dLocalPtsPerc);
	int 	nLocalPts = pCtrlInfo->nLocalPts;
	///end CHANGE_LOCAL_POINT_PERCENT_TO_LOCAL_POINTS
	
	bool 	bPercent = true; //we always use percent value
	int 	nFilter = TEST_PEAK_HEIGHT; //always use height to test peak
	double 	dFilterValue = _real_value_from_percent(vY, pCtrlInfo->dMinPeakHeight);
/// Jack QA80-12525 DEGAULT_TO_USE_FFT_SMOOTH_SECOND_DERIV_METHOD
// default use FFT smoothed second derivative in NLFIT as before and dFFTCutoff is a valid argument for this method and set as default value as before
// for other arguments nSGPtsSmooth, nPolyOrder are passed for safty. 
// vector v2ndDeriv is needed, otherwise v2ndDeriv.SetSize(vyData.GetSize());
// in find_peaks_2nd_derivative_ex will run time
//	int nRet = find_peaks(vX, vY, vXPeaks, vYPeaks, vnPeakIndices, pCtrlInfo->nFindPeakMethod, pCtrlInfo->dWinWidth, pCtrlInfo->dWinHeight, nSmoothPts, pCtrlInfo->dwCtrl, nLocalPts, bPercent, nFilter, &dFilterValue); 
	vector v2ndDeriv;
	int nSGPtsSmooth = 3;
	double dFFTCutOff = 0.2;
	int nPolyOrder = 2; 
	int nRet = find_peaks(vX, vY, vXPeaks, vYPeaks, vnPeakIndices, pCtrlInfo->nFindPeakMethod, pCtrlInfo->dWinWidth, pCtrlInfo->dWinHeight, nSmoothPts, pCtrlInfo->dwCtrl, nLocalPts, bPercent, nFilter, &dFilterValue, DERIV_SMOOTH_FFT, v2ndDeriv, nSGPtsSmooth, dFFTCutOff, nPolyOrder); 
/// End	DEGAULT_TO_USE_FFT_SMOOTH_SECOND_DERIV_METHOD
	if(nRet != OE_NOERROR)
		return nRet;	
	if(vXPeaks.GetSize() < 1)
		return OE_NO_PEAK_FOUND;
		
	vYCenter = vYPeaks;
	vXCenter = vXPeaks;
	vXWidth.SetSize(vXCenter.GetSize());
	nRet = ocm_1d_find_peak_parameter(nSize, vX, vY, vXCenter.GetSize(), vnPeakIndices, vXCenter, vYCenter, vXWidth);
	if(nRet != OE_NOERROR)
		return nRet;
	///Arvin 03/26/08 RESET_REPLICA_NUMBER_WHEN_CAN_NOT_FIND_ENOUGH_PEAK
	//_resize_vector(vXCenter, nNumNeededPeaks);
	//_resize_vector(vYCenter, nNumNeededPeaks);
	//_resize_vector(vXWidth, nNumNeededPeaks);
	//return OE_NOERROR;
	return vXCenter.GetSize(); //return number of found peaks
	///end RESET_REPLICA_NUMBER_WHEN_CAN_NOT_FIND_ENOUGH_PEAK
}
/// end REPLICA_AUTO_INIT_PARAMS_FOR_SURFACE_FIT

//------ End COMMENT_CODE_THAT_LEADS_TO_LINKING_ERROR

///---Sim 06-06-2008 SEPARATE_AUTO_FIND_BASELINE_POINTS
// move from pa_basemode.oxf
#define BL_AUTO_FIND_DIFF_FROM_POLY_THRESHOLD 0.8
bool bl_auto_find_baseline_points(vector& vx, vector& vy, vector& vebx, vector& veby, int& npts, double dThreshold) // = BL_AUTO_FIND_THRESHOLD
{
	vebx.SetSize(vx.GetSize());
	veby.SetSize(vx.GetSize());
	int nNumBaselinePts = ocmath_find_baseline_part_by_small_curvature(vx.GetSize(),vx,vy,vebx,veby,dThreshold, BL_AUTO_FIND_DIFF_FROM_POLY_THRESHOLD);
	if(nNumBaselinePts<=1) 
	{
		///Sandy 2008-4-29 add default points(beginning and ending points) as baseline points if no auto points
		nNumBaselinePts = 2;
		vebx.SetSize(2);
		veby.SetSize(2);
		double dMin, dMax;
		uint nMin, nMax;
		vx.GetMinMax(dMin, dMax, &nMin, &nMax);
		vebx[0] = dMin;
		vebx[1] = dMax;
		veby[0] = vy[nMin];
		veby[1] = vy[nMax];	
		//end 2008-4-29
	}
	//
	vebx.SetSize(nNumBaselinePts);
	veby.SetSize(nNumBaselinePts);
	
	if(npts>nNumBaselinePts)
	{
		npts = nNumBaselinePts;
	}
	

	//Get npts well-proportioned baseline points
	vector<uint> vn;
	vebx.Sort(SORT_ASCENDING, true, vn);
	veby.Reorder(vn);
	
	//int nStep = max(1, (int)((double)nNumBaselinePts /npts + 0.5));
	int nStep = max(1, ((nNumBaselinePts-1) /npts));
	int iMax = (nNumBaselinePts-1)/nStep;
	int nOffset = 0, ii = 0, nn = 0;
	vector vOutbx(npts-1), vOutby(npts-1);
	do
	{
		//if(ii*nStep + nOffset> (nNumBaselinePts-2) )
		if( ii >= iMax )
		{
			nOffset++;
			ii = 0;	
		}
		
		ASSERT((ii*nStep + nOffset)<=(nNumBaselinePts-2));
		vOutbx[nn] = vebx[ii*nStep + nOffset];
		vOutby[nn] = veby[ii*nStep + nOffset];
		ii++;
		nn++;
	
	}
	while(nn < npts-1);

	vOutbx.Add(vebx[nNumBaselinePts - 1]);
	vOutby.Add(veby[nNumBaselinePts - 1]);
	
	vebx = vOutbx;
	veby = vOutby;
	
	return true;
}
///---END SEPARATE_AUTO_FIND_BASELINE_POINTS
int get_sub_range_from_xy(vector& vx, vector& vy, double dBeginX, double dEndX, int& nBeginX, int& nEndX)
{
	if(vx.GetSize() <= 0 || vy.GetSize() <= 0 || vx.GetSize() != vy.GetSize())
		return CER_INVALID_SIZE;
	
	vector<uint> vn;
	vx.Sort(SORT_ASCENDING, true, vn);
	vy.Reorder(vn);
	
	vector<uint> vecIndex;
	int nFound = vx.Find(vecIndex, dBeginX, dEndX);
    if( -1 == nFound ||  0 == nFound)
    {
    	return XFERR_INVALID_RANGE;
    }
    
	if(vecIndex.GetSize() <= 2)
		return CER_INVALID_SIZE;
	
    int nOrgSize = vx.GetSize();
    int nIndSize = vecIndex.GetSize();
	
	nBeginX = (vecIndex[0] > 0? vecIndex[0] : 1);
	nEndX = (vecIndex[nIndSize-1] < (nOrgSize-1)? vecIndex[nIndSize-1]: (nOrgSize-1));
	
	vector vyTemp, vxTemp;
	
	vx.GetSubVector(vxTemp, nBeginX, nEndX);
	vy.GetSubVector(vyTemp, nBeginX, nEndX);

	vy = vyTemp;
	vx = vxTemp;
	
	return CER_NO_ERROR;

}
///Sandy 2008-9-11 add local baseline 
int get_local_baseline_by_interp(const vector& vx, const vector& vy, vector& vxLocalBaseline, vector& vyLocalBaseline, double dLeft, double dRight, int nType, int& nLeft, int& nRight)
{
	vector vyTemp, vxTemp;
	vyTemp = vy;
	vxTemp = vx;
	
	int nBeginX, nEndX;
	int nRet = get_sub_range_from_xy(vxTemp, vyTemp, dLeft, dRight, nBeginX, nEndX);
	if(nRet != CER_NO_ERROR)
		return nRet;
	
	int nSize = vyTemp.GetSize();
	vxLocalBaseline = vxTemp;
	vyLocalBaseline = vyTemp;
	
	//remove the data inside the sub range.
	vyTemp = vy;
	vxTemp = vx;
	vyTemp.RemoveAt(nBeginX,nSize );
	vxTemp.RemoveAt(nBeginX,nSize );
	
	
	if(nLeft!=NULL)
		nLeft = nBeginX;
	if(nRight!=NULL)
		nRight = nEndX;
	
	int nInterpType;
	switch(nType)
	{
	case LOCAL_BASELINE_LINE:
		nInterpType = INTERP_TYPE_LINEAR;
		break;
	case LOCAL_BASELINE_SPLINE:
		nInterpType = INTERP_TYPE_SPLINE;
		break;
	}
	
	nRet = ocmath_interpolate(vxLocalBaseline, vyLocalBaseline, nSize, vxTemp, vyTemp, vxTemp.GetSize(), nInterpType);
	if(0 != nRet)
	{
		return nRet;
	}
	
	return true;		

}



/// Jack QA-12334 10/09/2008 ADD_ONE_PEAK_MATRIX_DATA_INITILIZE_CODE
// for usage in one peak matrix data initial code
bool get_xz_yz_curves_at_max_min_z_peak_from_matrix_data( Curve& x_curve , Curve& y_curve,  const Matrix& mzData)
{
	int nCols = mzData.GetNumCols();
	int nRows = mzData.GetNumRows();
	ASSERT(nCols>1&&nRows>1);

	// Prepare X,Y data obtained from the matrix
	vector x_data(nCols);  
	vector y_data(nRows);
	double dTempMin=mzData.GetXMin();
	double dTempMax=mzData.GetXMax();
	x_data.Data(dTempMin,dTempMax,(dTempMax-dTempMin)/(nCols-1));
	
	dTempMin=mzData.GetYMin();
	dTempMax=mzData.GetYMax();
	y_data.Data(dTempMin,dTempMax,(dTempMax-dTempMin)/(nRows-1));
	
	double dPosPeakZ, dNegPeakZ;
	int nPosPeakRowIndex, nPosPeakColIndex, nNegPeakRowIndex, nNegPeakColIndex;
	int PeakRowIndex, PeakColIndex;
	
	int nRet = ocm_2d_find_largest_neg_pos_peak_in_matrix(mzData, nRows, nCols, &dPosPeakZ, &nPosPeakRowIndex, &nPosPeakColIndex, &dNegPeakZ, &nNegPeakRowIndex, &nNegPeakColIndex);
	if(nRet<0)
	{
		return false;
	}
	
	PeakRowIndex = abs(dPosPeakZ)>abs(dNegPeakZ) ?  nPosPeakRowIndex  : nNegPeakRowIndex;
	PeakColIndex = abs(dPosPeakZ)>abs(dNegPeakZ) ?  nPosPeakColIndex  : nNegPeakColIndex;
	
	vector vPeakXZProfile(nCols);                     // Get the x,y or (row, col) profile in the largest peak position, and convert it into x-z,y-z curves
	vector vPeakYZProfile(nRows);
	mzData.GetRow(vPeakXZProfile, PeakRowIndex);
	mzData.GetColumn(vPeakYZProfile,PeakColIndex);
	
	Curve x_z_curve(x_data, vPeakXZProfile);
	x_curve.Create(x_z_curve.GetSize());
	x_curve = x_z_curve;
	Curve y_z_curve(y_data, vPeakYZProfile);
	y_curve.Create(y_z_curve.GetSize());
	y_curve = y_z_curve;
	
	return true;
}

/// End ADD_ONE_PEAK_MATRIX_DATA_INITILIZE_CODE

///Kyle 03/11/2010 PICK_PEAK_ROI_TOOL_SHARES_UTILS_FUNCTION_WITH_PA

#define _AUTO_FIND_THRESHOLD 0.05
#define _MIN_BASE_PTS 2
#define _AUTO_FIND_DIFF_FROM_POLY_THRESHOLD 0.8


bool auto_find_baseline_anchor_points(vector& vx, vector& vy, vector& vebx, vector& veby, int& npts)
{
	if(npts < _MIN_BASE_PTS)
		return false;
	
	vebx.SetSize(vx.GetSize());
	veby.SetSize(vx.GetSize());
	int nNumBaselinePts = ocmath_find_baseline_part_by_small_curvature(vx.GetSize(),vx,vy,vebx,veby,_AUTO_FIND_THRESHOLD, _AUTO_FIND_DIFF_FROM_POLY_THRESHOLD);
	if(nNumBaselinePts < _MIN_BASE_PTS) 
	{
		///Sandy 2008-4-29 add default points(beginning and ending points) as baseline points if no auto points
		nNumBaselinePts = _MIN_BASE_PTS;
		vebx.SetSize(_MIN_BASE_PTS);
		veby.SetSize(_MIN_BASE_PTS);
		double dMin, dMax;
		uint nMin, nMax;
		vx.GetMinMax(dMin, dMax, &nMin, &nMax);
		vebx[0] = dMin;
		vebx[1] = dMax;
		veby[0] = vy[nMin];
		veby[1] = vy[nMax];	
		//end 2008-4-29
	}
	//
	vebx.SetSize(nNumBaselinePts);
	veby.SetSize(nNumBaselinePts);
	
	if(npts>nNumBaselinePts)
	{
		npts = nNumBaselinePts;
	}
	

	//Get npts well-proportioned baseline points
	vector<uint> vn;
	vebx.Sort(SORT_ASCENDING, true, vn);
	veby.Reorder(vn);
	
	//int nStep = max(1, (int)((double)nNumBaselinePts /npts + 0.5));
	int nStep = max(1, ((nNumBaselinePts-1) /npts));
	int iMax = (nNumBaselinePts-1)/nStep;
	int nOffset = 0, ii = 0, nn = 0;
	vector vOutbx(npts-1), vOutby(npts-1);
	do
	{
		if( ii >= iMax )
		{
			nOffset++;
			ii = 0;	
		}
		
		ASSERT((ii*nStep + nOffset)<=(nNumBaselinePts-2));
		vOutbx[nn] = vebx[ii*nStep + nOffset];
		vOutby[nn] = veby[ii*nStep + nOffset];
		ii++;
		nn++;
	
	}
	while(nn < npts-1);

	vOutbx.Add(vebx[nNumBaselinePts - 1]);
	vOutby.Add(veby[nNumBaselinePts - 1]);
	
	vebx = vOutbx;
	veby = vOutby;
	
	return true;
}

bool compute_peaks_number_by_filter_height(const vector& vx,const vector& vy, double dHeightThres, int& iPeakNum)
{

	iPeakNum = vx.GetSize();
	vector vxPeaks(iPeakNum), vyPeaks(iPeakNum);
	vector<int> vnIndices(iPeakNum);
	
	//if(OE_NOERROR != ocmath_find_peaks_1st_derivative(&iPeakNum, vx, vy, vxPeaks, vyPeaks, vnIndices, PKF_BOTH_DIRECTION, 0))
	if(OE_NOERROR != ocmath_find_peaks_1st_derivative(&iPeakNum, vx, vy, vxPeaks, vyPeaks, vnIndices, PKF_BOTH_DIRECTION, false, 0))
		return false;
	
	vxPeaks.SetSize(iPeakNum);
	vyPeaks.SetSize(iPeakNum);
	vnIndices.SetSize(iPeakNum);
	if(OE_NOERROR != ocmath_test_peaks_by_height(&iPeakNum, vxPeaks, vyPeaks, vnIndices, dHeightThres))
		return false;
	
	return true;
}
///End PICK_PEAK_ROI_TOOL_SHARES_UTILS_FUNCTION_WITH_PA

///------ Folger 09/27/2010 CODE_CLEANUP_ABOUT_FINDING_PEAKS
BOOL	check_sort_data_for_find_peaks(vector& vY, vector& vX)
{
	if ( ocmath_is_monotonic(vX, vX.GetSize(), false) == MONO_NOT )
	{
		vector<uint> vn;
		vX.Sort(SORT_ASCENDING, true, vn);
		vY.Reorder(vn);
	}

	return TRUE;
}
///------ End CODE_CLEANUP_ABOUT_FINDING_PEAKS