/*------------------------------------------------------------------------------*
 * File Name: XYZ2Mat.c															*
 * Creation: Sim 02-27-2009														*
 * Purpose: OriginC Source C file												*
 * Copyright (c) ABCD Corp.	2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010		*
 * All Rights Reserved															*
 * 																				*
 * Modification Log:															*
 * Max 6/1/09 v8.1027 USE_A_BETTER_ERR_MSG										*
 * Sim 09-25-2009 QA80-13783 CHANGE_PROTOTYPE_AND_ALGORITHM_FOR_EXAMINATION		*
 * Fisher 07/10/09 QA80-13622 REMOVE_DATA_SIZE_LIMITATION						*
 *	Fisher 07/20/09	QA80-13971	XYZ_GRIDDING_INIT_VAL_IMPROVEMENT				* 
 *	Sim 09-16-2009 QA81-11497-P7 ADD_MAXIMUM_FOR_RANDOM_KRIGING_METHOD			*
 *	Fisher 09/16/09 Qa80-14310 INCORRECT_ARRAY_STEP_FINDING 					*
 *	Sim 09-27-2009 QA81-14137 HIDE_COUNTS_OF_STEP_ZERO_WHICH_IS_NO_NEED			*
 *	Sim 10-10-2009 QA81-11497/14407 SUPPORT_NO_MAXIMUM_LIMIT_FOR_RANDOM_KRIGING_METHOD
 *	Sim 02-10-2010 QA81-12191 SUPPORT_SEL_NONE_REMOVE_DUPLICATE_FOR_LARGE_DATA	*
 *------------------------------------------------------------------------------*/
 
////////////////////////////////////////////////////////////////////////////////////
// Including the system header file Origin.h should be sufficient for most Origin
// applications and is recommended. Origin.h includes many of the most common system
// header files and is automatically pre-compiled when Origin runs the first time.
// Programs including Origin.h subsequently compile much more quickly as long as
// the size and number of other included header files is minimized. All NAG header
// files are now included in Origin.h and no longer need be separately included.
//
// Right-click on the line below and select 'Open "Origin.h"' to open the Origin.h
// system header file.
#include <Origin.h>
////////////////////////////////////////////////////////////////////////////////////

//#pragma labtalk(0) // to disable OC functions for LT calling.

////////////////////////////////////////////////////////////////////////////////////
// Include your own header files here.
#include <wks2mat.h>
#include <OC_nag8.h>
#include <Nag_utils.h>
#include <stats_utils.h>

#include <GetNBox.h>

#include "XYZ2Mat.h"

////////////////////////////////////////////////////////////////////////////////////
// Start your functions here.
#ifndef _CAT
#define _CAT "Gridding"
#endif
#define STR_RANDOM_METHOD 			_L("random")
#define STR_SPARSE_METHOD			_L("sparse")
#define STR_REGULAR_METHOD			_LC("regular", _CAT)
#define STR_SPARSE_OR_RANDOM_METHOD	_L("sparse or random")

#define SMALL_RANDOM_DATA_SIZE 4
//#define LARGE_DATASET_NUM_DATA_PTS  4000		/// Fisher 07/10/09 QA80-13622 REMOVE_DATA_SIZE_LIMITATION


#define IS_INT_AUTO(_int)	( 1 == _int )

#define SAFE_CHECK_RET_NULL(_point) \
	if ( NULL == _point ) \
	{ \
		ASSERT(FALSE); \
		return; \
	} 

#define SAFE_CHECK_RET(_point, _ret) \
	if ( NULL == _point ) \
	{ \
		ASSERT(FALSE); \
		return _ret; \
	} 


#define RICHCALL(_call, _return, _no_error) \
	{ \
		if ( _return == _no_error ) \
			_return = _call; \
	}

int XYZGriddingMathLib::DoGridding(const vector& vXInput, const vector& vYInput, const vector& vZInput, matrix& mat, const XYZGriddingSettings *pSettings)
{
	if ( NULL == pSettings )
	{
		error_report("pSettings is NULL!!");
		return OE_UNKOWN_ERROR;
	}

	vector vX, vY, vZ;
	vX = vXInput;
	vY = vYInput;
	vZ = vZInput;
	
	int nSize;
	nSize = PreprocessData(vX, vY, vZ, pSettings);
	if ( nSize <= 0 )
		return OE_UNKOWN_ERROR;
	
	XYZGrdiddingDataInfo datainfo;
	//UpdateDataInfo(&datainfo, vX, vY, vZ, pDataExamination);
	UpdateDataInfo(&datainfo, vX, vY, vZ, pSettings);
	
	XYZGriddingDataExaminationSettings *pDataExamination = &(pSettings->settingDataExamination);
	XYZGriddingMethodSettings *pMethod = &(pSettings->settingMethod);
	XYZGriddingRangeRestrictionSettings *pRangeRestriction = &(pSettings->settingRangeRestriction);

	int nMethod = pMethod->nMethod;
	int nExamineMethod = datainfo.nDataType;
	if (XYZ2MAT_METHOD_REGULAR == nMethod)
	{
		if(nExamineMethod == Examine_XYZ_Random || nExamineMethod == Examine_XYZ_Sparse)
			return OE_UNKNOWN_METHOD; // Sim, need better error
	}
	else if(XYZ2MAT_METHOD_SPARSE == nMethod)
	{
		if(nExamineMethod == Examine_XYZ_Random)
			return OE_UNKNOWN_METHOD; // Sim, need better error
	}
	
	
	double dXMin = datainfo.dXMin;
	double dXMax = datainfo.dXMax;
	double dYMin = datainfo.dYMin;
	double dYMax = datainfo.dYMax;
	double dXStep = datainfo.dXStep;
	double dYStep = datainfo.dYStep;
	
	int nRows, nCols;
	nRows = pMethod->nRows;
	nCols = pMethod->nColumns;

	// cols and rows of matrix not auto, so need to set step
	if ( !IS_INT_AUTO(pMethod->nAutoColumns) && nCols > 1 ) 
		dXStep = (dXMax - dXMin) / (nCols - 1);
	if ( !IS_INT_AUTO(pMethod->nAutoRows) && nRows > 1 ) 
		dYStep = (dYMax - dYMin) / (nRows - 1);
	
	mat.SetSize(nRows, nCols);
	mat = 0;

	nSize = datainfo.nSize;
	///---Sim 09-25-2009 QA80-13783 CHANGE_PROTOTYPE_AND_ALGORITHM_FOR_EXAMINATION
	//double dPrecision = pDataExamination->dPrecision;
	double dXPrecision = pDataExamination->dXPrecision;
	double dYPrecision = pDataExamination->dYPrecision;
	///---END QA80-13783 CHANGE_PROTOTYPE_AND_ALGORITHM_FOR_EXAMINATION
	
	switch(nMethod)
	{
		case XYZ2MAT_METHOD_REGULAR:
			return ocmath_convert_regular_xyz_to_matrix(nSize, vX, vY, vZ, mat, dXMin, dXStep, nCols, dYMin, dYStep, nRows);
	   	case XYZ2MAT_METHOD_SPARSE:
			///---Sim 09-25-2009 QA80-13783 CHANGE_PROTOTYPE_AND_ALGORITHM_FOR_EXAMINATION
		   	//return ocmath_convert_sparse_xyz_to_matrix(nSize, vX, vY, vZ, mat, dXMin, dXStep, nCols, dYMin, dYStep, nRows, dPrecision);
		   	return ocmath_convert_sparse_xyz_to_matrix(nSize, vX, vY, vZ, mat, dXMin, dXStep, nCols, dYMin, dYStep, nRows, dXPrecision, dYPrecision);
			///---END QA80-13783 CHANGE_PROTOTYPE_AND_ALGORITHM_FOR_EXAMINATION
		default:
			break;
	}

	vector vxGrid(nRows*nCols), vyGrid(nRows*nCols);
	int nRet;
	nRet = ocmath_mat_to_regular_xyz(NULL, nRows, nCols, dXMin, dXMax, dYMin, dYMax, vxGrid, vyGrid, NULL);
	if (  nRet < OE_NOERROR ) // nRet > 0, means size
		return nRet;

	switch(nMethod)
	{
	   	case XYZ2MAT_METHOD_RANDOM_RENKA_CLINE:
           	return xyz_gridding_nag(vX, vY, vZ, vxGrid, vyGrid, mat);
		case XYZ2MAT_METHOD_RANDOM_SHEPARD:
        	int nq = pMethod->nQILF;
        	int nw = pMethod->nWFLF;
        	int method = RANDOM_SHEPARD_METHOD;
        	
        	return xyz_gridding_nag(vX, vY, vZ, vxGrid, vyGrid, mat, method, nq, nw);
		case XYZ2MAT_METHOD_RANDOM_TPS:
		   	double dReg;
		   	ocmath_strTPS stTPS;
		   	double dSmooth = pMethod->dTPSSmoothing;
		   	
		   	int nRet = OE_NOERROR;
		   	RICHCALL(ocmath_tps_fit(nSize, vX, vY, vZ, dSmooth, &stTPS, &dReg), nRet, OE_NOERROR)
		   	RICHCALL(ocmath_tps_eval(nRows * nCols, vxGrid, vyGrid, mat, &stTPS), nRet, OE_NOERROR)
		   	
		   	ocmath_tps_free(&stTPS);
		   	return nRet;
	   case XYZ2MAT_METHOD_RANDOM_KRIGING:
			int noctMin = pMethod->nMinPoints;
			///---Sim 10-10-2009 QA81-11497/14407 SUPPORT_NO_MAXIMUM_LIMIT_FOR_RANDOM_KRIGING_METHOD
			//int noctMax = pMethod->nMaxPoints; ///---Sim 09-16-2009 QA81-11497-P7 ADD_MAXIMUM_FOR_RANDOM_KRIGING_METHOD
			int noctMax = IS_INT_AUTO(pMethod->nAutoMaxPoints) ? -1 : pMethod->nMaxPoints; ///---Sim 09-16-2009 QA81-11497-P7 ADD_MAXIMUM_FOR_RANDOM_KRIGING_METHOD
			///---END QA81-11497/14407 SUPPORT_NO_MAXIMUM_LIMIT_FOR_RANDOM_KRIGING_METHOD
			double radius = pMethod->dSearchRadius;
			double dSmooth = pMethod->dCorrelationSmoothing;
			
			vector vxTempGrid, vyTempGrid;
			double xmin, xmax, ymin, ymax;
			vX.GetMinMax(xmin, xmax);
			vY.GetMinMax(ymin, ymax);
			vxTempGrid.Data(xmin, xmax, (xmax-xmin)/(nCols-1));
			vyTempGrid.Data(ymin, ymax, (ymax-ymin)/(nRows-1));
			
			///---Sim 09-16-2009 QA81-11497-P7 ADD_MAXIMUM_FOR_RANDOM_KRIGING_METHOD
			//return ocmath_2d_kriging_grid(nSize, vX, vY, vZ, noctMin, radius, dSmooth, nCols, vxTempGrid, nRows, vyTempGrid, mat);
			return ocmath_2d_kriging_grid(nSize, vX, vY, vZ, noctMin, radius, dSmooth, nCols, vxTempGrid, nRows, vyTempGrid, mat, noctMax);
			///---END QA81-11497-P7 ADD_MAXIMUM_FOR_RANDOM_KRIGING_METHOD
		case XYZ2MAT_METHOD_WEIGHTED_AVERAGE:
		  	double dRadius = pMethod->dAverageRadius;
		  	return ocmath_gridding_weighted_average(nSize, vX, vY, vZ, nRows*nCols, vxGrid, vyGrid, mat, dRadius, WEIGHTED_AVERAGE_SQUARE);
		default:
		  	break;
	}
	return OE_NOERROR;
}

int XYZGriddingMathLib::DoGridding(const vector& vX, const vector& vY, const vector& vZ, Matrix& Mat, const XYZGriddingSettings *pSettings)
{
	matrix mat;
	int nRet = DoGridding(vX, vY, vZ, mat, pSettings);
	if ( OE_NOERROR == nRet )
	{
		Mat = mat;
		
		XYZGrdiddingDataInfo datainfo;
		if ( UpdateDataInfo(&datainfo, vX, vY, vZ, pSettings) )
		{
			SetMatrixXYInfo(Mat, &datainfo);
		}
	}
	
	return nRet;
}


bool XYZGriddingMathLib::CreateGridLine(vector& vXLine, vector& vYLine, double dXBegin, double dXEnd, double dYBegin, double dYEnd, double dStep, bool bVertical)
{
	if ( bVertical )
		return CreateGridLine(vXLine, vYLine, dXBegin, dXEnd, dYBegin, dYEnd, dStep);
	else
		return CreateGridLine(vYLine, vXLine, dYBegin, dYEnd, dXBegin, dXEnd, dStep);
}

//------------------------------------------
/*
	vA,						vB
	
	(A Begin,				B Begin),
	(A Begin,				B End),
	(missing),
	(A Begin + (A Step)*1,	B Begin),
	(A Begin + (A Step)*1,	B END),
	(missing),
	(A Begin + (A Step)*2,	B Begin),
	(A Begin + (A Step)*2,	B END),
	(missing),
	...
	(A End,					B Begin),
	(A End,					B End),
	(missing),
*/
//------------------------------------------
bool XYZGriddingMathLib::CreateGridLine(vector& vA, vector& vB, double dABegin, double dAEnd, double dBBegin, double dBEnd, double dAStep)
{
	if( 0 == dAStep )
		dAStep = 1;
	
	if( dAEnd < dABegin ) // swap
	{
		double dTemp;
		dTemp = dABegin;
		dABegin = dAEnd;
		dAEnd = dTemp;
	}
	
	int nTotalXNum = ROUND((dAEnd - dABegin)/dAStep) + 1; // consider two side of border
	if( nTotalXNum <= 0 )
		return false;
	
	matrix mat(nTotalXNum, 3);

	vector vecNAN(nTotalXNum);
	double dbNAN = NANUM;
	vecNAN = dbNAN;

	vA.Data(dABegin, dAEnd, dAStep);
	vA.SetSize(nTotalXNum);//
	vA.Append(vA);
	vA.Append(vecNAN);

	mat.SetByVector(vA, false);
	vA.SetSize(0);
	mat.GetAsVector(vA, true);

	vB.SetSize(nTotalXNum);
	vB = dBBegin;
	vector vec(nTotalXNum);
	vec = dBEnd;
	vB.Append(vec);
	vB.Append(vecNAN);

	mat.SetByVector(vB, false);
	vB.SetSize(0);
	mat.GetAsVector(vB, true);
	
	return true;
}

#define	ROUGH_NUM_HISTOGRAM	20
///---Sim 09-27-2009 QA81-14137 HIDE_COUNTS_OF_STEP_ZERO_WHICH_IS_NO_NEED
//bool XYZGriddingMathLib::CreateStepsStat(vector& vSteps, vector& vCounts, const vector& vPoints)
bool XYZGriddingMathLib::CreateStepsStat(vector& vSteps, vector& vCounts, const vector& vPoints, bool bHideNoStep) // = false
///---END QA81-14137 HIDE_COUNTS_OF_STEP_ZERO_WHICH_IS_NO_NEED
{
	vector vDiffs;
	
	vector vSortedPoints;
	vSortedPoints = vPoints;
	vSortedPoints.Sort();
	vSortedPoints.Trim();
	vSortedPoints.Difference(vDiffs);
	
	///---Sim 09-27-2009 QA81-14137 HIDE_COUNTS_OF_STEP_ZERO_WHICH_IS_NO_NEED
	if ( bHideNoStep )
	{
		vector<uint> vuIndex;
		if ( 0 < vDiffs.Find(vuIndex, 0) )
		{
			vector<int> vIndex;
			vIndex = vuIndex;
			vDiffs.RemoveAt(vIndex);
		}		
	}	
	///---END QA81-14137 HIDE_COUNTS_OF_STEP_ZERO_WHICH_IS_NO_NEED
	
	double dMin, dMax;
	double dInc;
	vDiffs.GetMinMax(dMin,dMax);
	RoundLimits(&dMin, &dMax, &dInc, ROUGH_NUM_HISTOGRAM);
	
	FreqCountOptions stOption;
	stOption.FromMin = dMin - dInc/2;
	stOption.ToMax = dMax + dInc/2;
	stOption.StepSize = dInc;
	stOption.IncludeLTMin = false;
	stOption.IncludeGEMax = false;
	
	return ( STATS_NO_ERROR == stats_frequency_count(vDiffs, stOption, vSteps, vCounts) );
}

int  XYZGriddingMathLib::FindXYInRect(int nSize, const vector& vX, const vector& vY, vector<uint>& vnIndices, double dXMin, double dYMin, double dXMax, double dYMax)
{
	return ocmath_find_xy_in_rect(nSize, vX, vY, vnIndices, dXMin, dYMin, dXMax, dYMax);
}

#define TOOLS_SIZE_PERCENT		0.05
void XYZGriddingMathLib::IncreaseIncludedSize(double &dXMin, double& dXMax, double& dYMin, double& dYMax)
{
	double dLengthInc = (dXMax - dXMin) * TOOLS_SIZE_PERCENT;
	double dHeightInc = (dYMax - dYMin) * TOOLS_SIZE_PERCENT;
	
	dXMin -= dLengthInc;
	dXMax += dLengthInc;
	dYMin -= dHeightInc;
	dYMax += dHeightInc;
}

int XYZGriddingMathLib::PreprocessData(vector& vX, vector& vY, vector& vZ, const XYZGriddingSettings *pSettings)
{
	SAFE_CHECK_RET(pSettings, -1);
	
	bool bRet = true;
	RICHCALL(TrimMissingData(vX, vY, vZ), bRet, true);
	RICHCALL(TrimUnSelectedData(vX, vY, vZ, &(pSettings->settingRangeRestriction)), bRet, true);
	RICHCALL(TrimDuplicatedData(vX, vY, vZ, &(pSettings->settingDataExamination)), bRet, true);
	
	if ( !bRet )
		return -1;

	ASSERT( vX.GetSize() == vY.GetSize() && vX.GetSize() == vZ.GetSize() );
	return vX.GetSize();
}

bool XYZGriddingMathLib::TrimMissingData(vector& vX, vector& vY, vector& vZ)
{
	return trim_independent(vX, vY, vZ);
}
bool XYZGriddingMathLib::TrimUnSelectedData(vector& vX, vector& vY, vector& vZ, const XYZGriddingRangeRestrictionSettings *pRangeRestriction)
{
	if ( NULL == pRangeRestriction )
		return false;

	if ( !pRangeRestriction->bUse )
		return true; // not set range
	
	double dXMin, dXMax, dYMin, dYMax;
	vX.GetMinMax(dXMin, dXMax);
	vY.GetMinMax(dYMin, dYMax);
	if ( !IS_INT_AUTO(pRangeRestriction->nAutoXMin) )
		dXMin = pRangeRestriction->dXMin;
	if ( !IS_INT_AUTO(pRangeRestriction->nAutoXMax) )
		dXMax = pRangeRestriction->dXMax;
	if ( !IS_INT_AUTO(pRangeRestriction->nAutoYMin) )
		dYMin = pRangeRestriction->dYMin;
	if ( !IS_INT_AUTO(pRangeRestriction->nAutoYMax) )
		dYMax = pRangeRestriction->dYMax;
	
	ASSERT( vX.GetSize() == vY.GetSize() && vX.GetSize() == vZ.GetSize() );
	int nPts = vX.GetSize();
	vector<uint> vnSelIndices(nPts);
	int nSelPts = ocmath_find_xy_in_rect(nPts, vX, vY, vnSelIndices, dXMin, dYMin, dXMax, dYMax);
	if ( nSelPts < 0 )
	{
		// Sim, 06-30-2009
		// better to dump error message, like dXMin > dXMax etc.
		//nSelPts = 0; // but in this case, just return none data is ok.
		return true; // or return all datas also is ok.
	}

	if(nSelPts >= nPts)
		return true;	//select all
	
	vnSelIndices.SetSize(nSelPts);
	if( 0 <= nSelPts )
	{
		ocmath_d_copy(nSelPts, vnSelIndices, vX, vX, vX.GetSize());
		ocmath_d_copy(nSelPts, vnSelIndices, vY, vY, vY.GetSize());
		ocmath_d_copy(nSelPts, vnSelIndices, vZ, vZ, vZ.GetSize());
		vX.SetSize(nSelPts);
		vY.SetSize(nSelPts);
		vZ.SetSize(nSelPts);
	}
	else
		return false;
	
	return true;
}
bool XYZGriddingMathLib::TrimDuplicatedData(vector& vX, vector& vY, vector& vZ, const XYZGriddingDataExaminationSettings *pDataExamination)
{
	if ( NULL == pDataExamination )
		return false;
	
	// duplicate code
	///---Sim 09-25-2009 QA80-13783 CHANGE_PROTOTYPE_AND_ALGORITHM_FOR_EXAMINATION
	//double dPrecision = pDataExamination->dPrecision;
	double dXPrecision = pDataExamination->dXPrecision;
	double dYPrecision = pDataExamination->dYPrecision;
	///---END QA80-13783 CHANGE_PROTOTYPE_AND_ALGORITHM_FOR_EXAMINATION
	int nReplaceBy = pDataExamination->nRemoveDuplicate;
	
	int nSize = vX.GetSize();
	
	if(nReplaceBy != Remove_None)
	{
		///---Sim 09-25-2009 QA80-13783 CHANGE_PROTOTYPE_AND_ALGORITHM_FOR_EXAMINATION
		//nSize = ocmath_xyz_remove_duplicates(nSize, vX, vY, vZ, nReplaceBy, dPrecision, dPrecision);
		nSize = ocmath_xyz_remove_duplicates(nSize, vX, vY, vZ, nReplaceBy, dXPrecision, dYPrecision);
		///---END QA80-13783 CHANGE_PROTOTYPE_AND_ALGORITHM_FOR_EXAMINATION
		if (nSize >= 0)
		{
			vX.SetSize(nSize);
			vY.SetSize(nSize);
			vZ.SetSize(nSize);
		}
	}
	
	return true;	
}

//bool XYZGriddingMathLib::UpdateDataInfo(XYZGrdiddingDataInfo* pDataInfo, const vector& vX, const vector& vY, const vector& vZ, const XYZGriddingDataExaminationSettings *pDataExamination)
bool XYZGriddingMathLib::UpdateDataInfo(XYZGrdiddingDataInfo* pDataInfo, const vector& vX, const vector& vY, const vector& vZ, const XYZGriddingSettings *pSettings)
{
	//if ( NULL == pDataInfo || NULL == pDataExamination )
	if ( NULL == pDataInfo || NULL == pSettings )
	{
		ASSERT(FALSE);
		return false;
	}
	
	ASSERT( vX.GetSize() == vY.GetSize() && vX.GetSize() == vZ.GetSize() );
	
	vector _vX, _vY, _vZ;
	_vX = vX;
	_vY = vY;
	_vZ = vZ;
	
	PreprocessData(_vX, _vY, _vZ, pSettings);
	
	XYZGriddingDataExaminationSettings *pDataExamination = &(pSettings->settingDataExamination);
	int nSize = _vX.GetSize();
	///---Sim 09-25-2009 QA80-13783 CHANGE_PROTOTYPE_AND_ALGORITHM_FOR_EXAMINATION
	//double dPrecision = pDataExamination->dPrecision;
	//double dXStepTol = pDataExamination->dXStepTol;
	//double dYStepTol = pDataExamination->dYStepTol;
	double dXPrecision = pDataExamination->dXPrecision;
	double dYPrecision = pDataExamination->dYPrecision;
	///---END QA80-13783 CHANGE_PROTOTYPE_AND_ALGORITHM_FOR_EXAMINATION
	int nRemoveDuplicate = pDataExamination->nRemoveDuplicate; ///---Sim 02-10-2010 QA81-12191 SUPPORT_SEL_NONE_REMOVE_DUPLICATE_FOR_LARGE_DATA
	double dXMin, dXMax, dYMin, dYMax;
	double dXStep, dYStep;
	
	///---Sim 09-25-2009 QA80-13783 CHANGE_PROTOTYPE_AND_ALGORITHM_FOR_EXAMINATION
	//int nDataType = ocmath_xyz_examine_data_ex(nSize, _vX, _vY, _vZ, dPrecision, NULL, &dXMin, &dXStep, &dXMax, &dYMin, &dYStep, &dYMax, false, Remove_With_Mean, dXStepTol, dXStepTol);
	///---Sim 02-10-2010 QA81-12191 SUPPORT_SEL_NONE_REMOVE_DUPLICATE_FOR_LARGE_DATA
	//int nDataType = ocmath_xyz_examine_data(nSize, _vX, _vY, _vZ, dXPrecision, dYPrecision, NULL, &dXMin, &dXStep, &dXMax, &dYMin, &dYStep, &dYMax, false, Remove_With_Mean);
	int nDataType = ocmath_xyz_examine_data(nSize, _vX, _vY, _vZ, dXPrecision, dYPrecision, NULL, &dXMin, &dXStep, &dXMax, &dYMin, &dYStep, &dYMax, false, nRemoveDuplicate);
	///---END QA81-12191 SUPPORT_SEL_NONE_REMOVE_DUPLICATE_FOR_LARGE_DATA
	///---END QA80-13783 CHANGE_PROTOTYPE_AND_ALGORITHM_FOR_EXAMINATION
	
	pDataInfo->nDataType = nDataType;
	pDataInfo->nSize = _vX.GetSize();
	pDataInfo->dXMin = dXMin;
	pDataInfo->dXMax = dXMax;
	pDataInfo->dYMin = dYMin;
	pDataInfo->dYMax = dYMax;
	pDataInfo->dXStep = dXStep;
	pDataInfo->dYStep = dYStep;
	
	return true;
}

bool XYZGriddingMathLib::IsLargeDataSet(const XYZGriddingSettings *pSettings, const XYZGrdiddingDataInfo* pDataInfo)
{
	if ( !pSettings || !pDataInfo )
	{
		ASSERT(FALSE);
		return false;
	}
	
	int nMethod = pSettings->settingMethod.nMethod;
	int nSize = pDataInfo->nSize;
	
	/// Fisher 07/10/09 QA80-13622 REMOVE_DATA_SIZE_LIMITATION
	/*
    bool bLargeDataSet =
    	( ( nSize > LARGE_DATASET_NUM_DATA_PTS )
    	&& ( nMethod == XYZ2MAT_METHOD_RANDOM_SHEPARD || nMethod == XYZ2MAT_METHOD_RANDOM_TPS || nMethod == XYZ2MAT_METHOD_RANDOM_KRIGING ) );
    */
    double dd;
    LT_get_var("@TCS", &dd);
    int nMaxNumPtsFor = dd;
    bool bLargeDataSet = ( ( nSize > nMaxNumPtsFor )
    					&& ( nMethod == XYZ2MAT_METHOD_RANDOM_TPS ) );
    /// eND REMOVE_DATA_SIZE_LIMITATION
    
    return bLargeDataSet;
}



bool XYZGriddingMathLib::SetMatrixXYInfo(Matrix& Mat, const XYZGrdiddingDataInfo* pDataInfo)
{
	if ( !Mat || NULL == pDataInfo )
		return false;
	
	bool bRet = true;
	bRet &= Mat.SetXMin(pDataInfo->dXMin);
	bRet &= Mat.SetXMax(pDataInfo->dXMax);
	bRet &= Mat.SetYMin(pDataInfo->dYMin);
	bRet &= Mat.SetYMax(pDataInfo->dYMax);
	
	return bRet;
}

////////////////////////////////////////////////////////////////////////////
static XYZGriddingMathLibCache s_XYZGriddingMathLibCache;
XYZGriddingMathLibCache* get_xyz_gridding_cache_pointer()
{
	return &s_XYZGriddingMathLibCache;
}

XYZGriddingMathLibCache::XYZGriddingMathLibCache()
{
	SetDirty();
}
void XYZGriddingMathLibCache::SetDirty(DWORD dwDirtyBits)
{
	m_bDirtyGridding = ( dwDirtyBits & DIRTY_XYZ_GRID_RESULT );
	
	m_bDirtyPreprocess = ( dwDirtyBits & DIRTY_XYZ_GRID_PRE_PROCESS );
	
	m_bDirtyDataInfo = ( dwDirtyBits & DIRTY_XYZ_GRID_DATA_INFO );
}


///Sophy 9/6/2010 ORG-849 SUPPORT_PLOT_XYZ_FROM_WORKSHEET_WITH_GRIDDING
int	XYZGriddingMathLibCache::DoGridding(const vector& vX, const vector& vY, const vector& vZ, Worksheet& wks, const XYZGriddingSettings *pSettings)
{
	matrix mat;
	int nRet = DoGridding(vX, vY, vZ, mat, pSettings);
	if ( nRet != OE_NOERROR )
		return nRet;
	int nR1 = 1, nR2 = mat.GetNumRows(), nC1 = 1, nC2 = mat.GetNumCols(); //Z data range
	wks.SetSize(nR2 + 1, nC2 + 1);
	
	//generate xy data
	XYZGrdiddingDataInfo dtInfo;
	UpdateDataInfo(&dtInfo, vX, vY, vZ, pSettings);
	//update X/Y step according to number of rows & columns
	dtInfo.dXStep = (nC2 <= 1) ? 0 : (dtInfo.dXMax - dtInfo.dXMin) / (nC2 - 1);
	dtInfo.dYStep = (nR2 <= 1) ? 0 : (dtInfo.dYMax - dtInfo.dYMin) / (nR2 - 1);
	
	vector vmX, vmY;
	vmX.Data(dtInfo.dXMin, dtInfo.dXMax, dtInfo.dXStep);
	vmY.Data(dtInfo.dYMin, dtInfo.dYMax, dtInfo.dYStep);
	
	//copy data to worksheet.
	DataRange drX;
	drX.Add("X", wks, nR1 - 1, nC1, nR1 - 1, nC2);
	drX.SetData(vmX);
	DataRange drY;
	drY.Add("X", wks, nR1, nC1 - 1, nR2, nC1 - 1);
	drY.SetData(vmY);
	mat.CopyTo(wks, 0, 0, -1, -1, nR1, nC1, FALSE, FALSE);
	wks.SetCell(0, 0, ""); //clear the first cell
	return OE_NOERROR;
}
///end SUPPORT_PLOT_XYZ_FROM_WORKSHEET_WITH_GRIDDING
// only for call base class overload function with param Matrix& Mat, else will incorrectly go to which one with param matrix& mat
int XYZGriddingMathLibCache::DoGridding(const vector& vX, const vector& vY, const vector& vZ, Matrix& Mat, const XYZGriddingSettings *pSettings)
{
	return XYZGriddingMathLib::DoGridding(vX, vY, vZ, Mat, pSettings);
}

int XYZGriddingMathLibCache::DoGridding(const vector& vX, const vector& vY, const vector& vZ, matrix& mat, const XYZGriddingSettings *pSettings)
{
	if ( !m_bDirtyGridding ) // using cache
	{
		mat = m_mat;
		return OE_NOERROR;
	}

	int nRet = XYZGriddingMathLib::DoGridding(vX, vY, vZ, mat, pSettings);
	if ( OE_NOERROR == nRet )
	{
		m_mat = mat;
		m_bDirtyGridding = false;
	}
	
	return nRet;
}
int XYZGriddingMathLibCache::PreprocessData(vector& vX, vector& vY, vector& vZ, const XYZGriddingSettings *pSettings)
{
	if ( !m_bDirtyPreprocess ) // using cache
	{
		vX = m_vXPreprocessed;
		vY = m_vYPreprocessed;
		vZ = m_vZPreprocessed;
		return vX.GetSize();
	}

	int nSize = XYZGriddingMathLib::PreprocessData(vX, vY, vZ, pSettings);
	if ( nSize >= 0 )
	{
		m_vXPreprocessed = vX;
		m_vYPreprocessed = vY;
		m_vZPreprocessed = vZ;
		m_bDirtyPreprocess = false;
	}
	
	return nSize;
}
bool XYZGriddingMathLibCache::UpdateDataInfo(XYZGrdiddingDataInfo* pDataInfo, const vector& vX, const vector& vY, const vector& vZ, const XYZGriddingSettings *pSettings)
{
	if ( !m_bDirtyDataInfo ) // using cache
	{
		*pDataInfo = m_datainfo;
		return true;
	}

	bool bRet = XYZGriddingMathLib::UpdateDataInfo(pDataInfo, vX, vY, vZ, pSettings);
	if ( bRet > 0 )
	{
		m_datainfo = *pDataInfo;
		m_bDirtyDataInfo = false;
	}
	
	return bRet;
}

////////////////////////////////////////////////////////////////////////////////////////////
void XYZGriddingDataExaminationSettings::UpdateGUI(TreeNode& trGUI, bool bToGUI)
{
	if ( !trGUI.ExamData )
	{
		GETN_USE(trGUI)
		
		GETN_BEGIN_BRANCH(ExamData, _L("Data Examination"))							GETN_ID_BRANCH(IDE_XYZ2MAT_EXAM_DATA)
	
			///---Sim 09-25-2009 QA80-13783 CHANGE_PROTOTYPE_AND_ALGORITHM_FOR_EXAMINATION
			//GETN_NUM(Precision, _L("Tolerance"), 1.0E-8)													GETN_ID(IDE_XYZ2MAT_PRECISION)
				//GETN_OPTION_DISPLAY_FORMAT("e%f")
			GETN_NUM(XPrecision, _L("X Tolerance"), 1.0E-8)													GETN_ID(IDE_XYZ2MAT_X_PRECISION)
				GETN_OPTION_DISPLAY_FORMAT("e%f")
			GETN_NUM(YPrecision, _L("Y Tolerance"), 1.0E-8)													GETN_ID(IDE_XYZ2MAT_Y_PRECISION)
				GETN_OPTION_DISPLAY_FORMAT("e%f")
			///---END QA80-13783 CHANGE_PROTOTYPE_AND_ALGORITHM_FOR_EXAMINATION
			///---Sim 02-10-2010 QA81-12191 SUPPORT_SEL_NONE_REMOVE_DUPLICATE_FOR_LARGE_DATA
			//GETN_LIST(RemoveDuplicate, _L("Replace Duplicates With"), 0, _L("Mean|Median|Minimum|Maximum|Sum"))	GETN_ID(IDE_XYZ2MAT_REMOVE_DUPL_BY)
			GETN_LIST(RemoveDuplicate, _L("Replace Duplicates With"), 0, _L("Mean|Median|Minimum|Maximum|Sum|None"))	GETN_ID(IDE_XYZ2MAT_REMOVE_DUPL_BY)
			///---END QA81-12191 SUPPORT_SEL_NONE_REMOVE_DUPLICATE_FOR_LARGE_DATA
			
			///---Sim 09-25-2009 QA80-13783 CHANGE_PROTOTYPE_AND_ALGORITHM_FOR_EXAMINATION
			//GETN_NUM(XStepTol, _L("X Even Spacing Tolerance (Multiple of Deviation)"), 1 )													GETN_ID(IDE_XYZ2MAT_XSTEPTOLERANCE)
			//GETN_NUM(YStepTol, _L("Y Even Spacing Tolerance (Multiple of Deviation)"), 1 )													GETN_ID(IDE_XYZ2MAT_YSTEPTOLERANCE)
			///---END QA80-13783 CHANGE_PROTOTYPE_AND_ALGORITHM_FOR_EXAMINATION
			
		GETN_END_BRANCH(ExamData)
	}
	
	TreeNode trExamData = trGUI.ExamData;
	
	// need optimize to struct with ID
	///---Sim 09-25-2009 QA80-13783 CHANGE_PROTOTYPE_AND_ALGORITHM_FOR_EXAMINATION
	if ( bToGUI )
	{
		//trExamData.Precision.dVal = dPrecision;
		//trExamData.RemoveDuplicate.nVal = nRemoveDuplicate;
		//trExamData.XStepTol.dVal = dXStepTol;
		//trExamData.YStepTol.dVal = dYStepTol;
		trExamData.XPrecision.dVal = dXPrecision;
		trExamData.YPrecision.dVal = dYPrecision;
		trExamData.RemoveDuplicate.nVal = nRemoveDuplicate;
	}
	else
	{
		//dPrecision = trExamData.Precision.dVal;
		//nRemoveDuplicate = trExamData.RemoveDuplicate.nVal;
		//dXStepTol = trExamData.XStepTol.dVal;
		//dYStepTol = trExamData.YStepTol.dVal;
		dXPrecision = trExamData.XPrecision.dVal;
		dYPrecision = trExamData.YPrecision.dVal;
		nRemoveDuplicate = trExamData.RemoveDuplicate.nVal;
	}
	///---END QA80-13783 CHANGE_PROTOTYPE_AND_ALGORITHM_FOR_EXAMINATION
}

///---Sim 10-10-2009 QA81-11497/14407 SUPPORT_NO_MAXIMUM_LIMIT_FOR_RANDOM_KRIGING_METHOD
static bool maxpoints_event(TreeNode& myTree, int nRow, int nCol, TreeNode& trNode, DWORD dwCntrl, int nType, WndContainer& theDlg)
{
	///---Sim 10-10-2009 QA81-11497/14407 SUPPORT_NO_MAXIMUM_LIMIT_FOR_RANDOM_KRIGING_METHOD
	int nAutoMaxPoints = octree_get_auto_support(&trNode);
	int nOldValue;
	if ( IS_INT_AUTO(nAutoMaxPoints) )
	{
		if ( !trNode.GetAttribute(STR_DATA_ATTRIB, nOldValue) )
		{	// manual to auto
			trNode.SetAttribute(STR_DATA_ATTRIB, trNode.nVal);
			trNode.strVal = STR_AUTO;
		}
	}
	else
	{
		if ( trNode.GetAttribute(STR_DATA_ATTRIB, nOldValue) )
		{	// auto to manual
			trNode.nVal = nOldValue;
			trNode.RemoveAttribute(STR_DATA_ATTRIB);
		}
	}
	
	return true;
}
///---END QA81-11497/14407 SUPPORT_NO_MAXIMUM_LIMIT_FOR_RANDOM_KRIGING_METHOD

void XYZGriddingMethodSettings::UpdateGUI(TreeNode& trGUI, bool bToGUI)
{
	if ( !trGUI.ConvertToMatrix )
	{
		GETN_USE(trGUI)
	
		GETN_BEGIN_BRANCH(ConvertToMatrix, _L("Gridding Method and Parameters"))	GETN_ID_BRANCH(IDE_XYZ2MAT_CONVERT_TO_MAT)
		GETN_OPTION_BRANCH(GETNBRANCH_OPEN)
		GETN_COMBO_BRANCH(XYZ2MAT_METHOD_AUTO, _LC("Regular|Sparse|Random (Renka Cline)|Random (Shepard)|Random (Thin Plate Spline)|Random (Kriging Correlation)|Random (Weighted Average)", _CAT))
		
			GETN_NUM(columns, _L("Columns"), 20)								GETN_ID(IDE_XYZ2MAT_PARA_COLUMNS)
				//GETN_ADD_AUTO(true)
			GETN_NUM(rows, _L("Rows"), 20)										GETN_ID(IDE_XYZ2MAT_PARA_ROWS)
				//GETN_ADD_AUTO(true)
			GETN_NUM(QILF, _L("Quadratic Interpolant Locality Factor"), 18)		GETN_ID(IDE_XYZ2MAT_PARA_QILF)
				GETN_OPTION_DISPLAY_FORMAT("%d")
			GETN_NUM(WFLF, _L("Weight Function Locality Factor"), 9)			GETN_ID(IDE_XYZ2MAT_PARA_WFLF)
				GETN_OPTION_DISPLAY_FORMAT("%d")
			GETN_NUM(searchradius, _L("Search Radius"), 2.0)					GETN_ID(IDE_XYZ2MAT_PARA_SEARCH_RADIUS)
			GETN_NUM(averadius, _L("Search Radius"), 2.0)						GETN_ID(IDE_XYZ2MAT_PARAMETERS)			///Leo 2005-12-29 ADD_WEIGHTED_AVERAGE_FROM_75
			GETN_NUM(minipoints, _L("Minimum Points"), 10)						GETN_ID(IDE_XYZ2MAT_PARA_MINI_POINTS)
			GETN_NUM(maxipoints, _L("Maximum Points"), 100)						GETN_ID(IDE_XYZ2MAT_PARA_MAXI_POINTS) ///---Sim 09-16-2009 QA81-11497-P7 ADD_MAXIMUM_FOR_RANDOM_KRIGING_METHOD
				GETN_OPTION_DISPLAY_FORMAT("%d")
				GETN_OPTION_EVENT_EX(maxpoints_event) ///---Sim 10-10-2009 QA81-11497/14407 SUPPORT_NO_MAXIMUM_LIMIT_FOR_RANDOM_KRIGING_METHOD
			GETN_NUM(CorrelationSmoothing, _L("Smoothing"), 1.0)				GETN_ID(IDE_XYZ2MAT_PARA_CORRE_SMOOTHING)
			GETN_NUM(TPSSmoothing, _L("Smoothing"), 0.0)						GETN_ID(IDE_XYZ2MAT_PARA_TPS_SMOOTHING)
			GETN_LIST(extrapolation, _L("Extrapolation"), 0, _L("Extrapolate|Missing Values|Zero|Mimimum|Maximum|Mean|Custom Value"))	GETN_ID(IDE_XYZ2MAT_PARA_EXTRAPOLATION)
			GETN_NUM(outsizevalue, _L("Outside Value"), 0.0)					GETN_ID(IDE_XYZ2MAT_PARA_OUTSIDE_VAL)
			GETN_NUM(tolerance, _L("Tolerance"), 5E-3)						GETN_ID(IDE_XYZ2MAT_PARA_TOLERANCE)
				GETN_OPTION_DISPLAY_FORMAT("e%f")

		GETN_END_BRANCH(ConvertToMatrix)
	}
	
	TreeNode trConvertToMatrix = trGUI.ConvertToMatrix;
	
	TreeNode trTemp;
	// need optimize to struct with ID
	if ( bToGUI )
	{
		trConvertToMatrix.Use = nMethod;
		
		trConvertToMatrix.columns.nVal = nColumns;
		trTemp = trConvertToMatrix.columns;
		octree_set_auto_support(&trTemp, nAutoColumns);
		
		trConvertToMatrix.rows.nVal = nRows;
		trTemp = trConvertToMatrix.rows;
		octree_set_auto_support(&trTemp, nAutoRows);
		
		trConvertToMatrix.QILF.nVal = nQILF;
		trConvertToMatrix.WFLF.nVal = nWFLF;
		trConvertToMatrix.searchradius.dVal = dSearchRadius;
		trConvertToMatrix.averadius.dVal = dAverageRadius;
		trConvertToMatrix.minipoints.nVal = nMinPoints;
		///---Sim 10-10-2009 QA81-11497/14407 SUPPORT_NO_MAXIMUM_LIMIT_FOR_RANDOM_KRIGING_METHOD
		//trConvertToMatrix.maxipoints.nVal = nMaxPoints; ///---Sim 09-16-2009 QA81-11497-P7 ADD_MAXIMUM_FOR_RANDOM_KRIGING_METHOD
		if ( IS_INT_AUTO(nAutoMaxPoints) )
		{
			trConvertToMatrix.maxipoints.strVal = STR_AUTO;
			trConvertToMatrix.maxipoints.SetAttribute(STR_DATA_ATTRIB, nMaxPoints);
		}
		else
		{
			trConvertToMatrix.maxipoints.nVal = nMaxPoints;
		}
		trTemp = trConvertToMatrix.maxipoints;
		octree_set_auto_support(&trTemp, nAutoMaxPoints);
		///---END QA81-11497/14407 SUPPORT_NO_MAXIMUM_LIMIT_FOR_RANDOM_KRIGING_METHOD
		
		trConvertToMatrix.CorrelationSmoothing.dVal = dCorrelationSmoothing;
		trConvertToMatrix.TPSSmoothing.dVal = dTPSSmoothing;
		trConvertToMatrix.extrapolation.nVal = nExtrapolation;
		trConvertToMatrix.outsizevalue.dVal = dOutsideValue;
		trConvertToMatrix.tolerance.dVal = dTolerance;
		
		UpdateShow(trConvertToMatrix);
	}
	else
	{
		nMethod = trConvertToMatrix.Use;
		
		nColumns = trConvertToMatrix.columns.nVal;
		trTemp = trConvertToMatrix.columns;
		nAutoColumns = octree_get_auto_support(&trTemp);
		
		nRows = trConvertToMatrix.rows.nVal;
		trTemp = trConvertToMatrix.rows;
		nAutoRows = octree_get_auto_support(&trTemp);
		
		nQILF = trConvertToMatrix.QILF.nVal;
		nWFLF = trConvertToMatrix.WFLF.nVal;
		dSearchRadius = trConvertToMatrix.searchradius.dVal;
		dAverageRadius = trConvertToMatrix.averadius.dVal;
		nMinPoints = trConvertToMatrix.minipoints.nVal;
		///---Sim 10-10-2009 QA81-11497/14407 SUPPORT_NO_MAXIMUM_LIMIT_FOR_RANDOM_KRIGING_METHOD
		//nMaxPoints = trConvertToMatrix.maxipoints.nVal; ///---Sim 09-16-2009 QA81-11497-P7 ADD_MAXIMUM_FOR_RANDOM_KRIGING_METHOD
		trTemp = trConvertToMatrix.maxipoints;
		nAutoMaxPoints = octree_get_auto_support(&trTemp);
		if ( IS_INT_AUTO(nAutoMaxPoints) )
			trConvertToMatrix.maxipoints.GetAttribute(STR_DATA_ATTRIB, nMaxPoints);
		else
			nMaxPoints = trConvertToMatrix.maxipoints.nVal;
		///---END QA81-11497/14407 SUPPORT_NO_MAXIMUM_LIMIT_FOR_RANDOM_KRIGING_METHOD
		dCorrelationSmoothing = trConvertToMatrix.CorrelationSmoothing.dVal;
		dTPSSmoothing = trConvertToMatrix.TPSSmoothing.dVal;
		nExtrapolation = trConvertToMatrix.extrapolation.nVal;
		dOutsideValue = trConvertToMatrix.outsizevalue.dVal;
		dTolerance = trConvertToMatrix.tolerance.dVal;
	}
}
void XYZGriddingMethodSettings::UpdateShow(TreeNode& trConvertToMatrix)
{
	TreeNode trParas = trConvertToMatrix;

	foreach(TreeNode trPara in trParas.Children)
		trPara.Show = false;

	if( XYZ2MAT_METHOD_REGULAR == nMethod )
	{
		//this method don't have parameters
	}
	else
	{
		trParas.columns.Show = true;
		trParas.rows.Show = true;
	
		switch(nMethod)
		{
		case XYZ2MAT_METHOD_RANDOM_RENKA_CLINE:
			break;
		case XYZ2MAT_METHOD_RANDOM_SHEPARD:
			trParas.QILF.Show = true;
			trParas.WFLF.Show = true;
			break;
		case XYZ2MAT_METHOD_RANDOM_TPS:
			trParas.TPSSmoothing.Show = true;
			trParas.extrapolation.Show = true;
			
			TreeNode trExtrapolate = trParas.extrapolation;
			TreeNode trTolerance = trParas.tolerance;
			TreeNode trOutsizevalue = trParas.outsizevalue;
			switch( nExtrapolation )
			{
			case XYZ2MAT_REPLACE_BY_EXTRAPOLATE:
				trTolerance.Show = false;
				trOutsizevalue.Show = false;
				break;
			case XYZ2MAT_REPLACE_BY_CUSTOM_VALUE:
				trTolerance.Show = true;
				trOutsizevalue.Show = true;
				break;
			default:
				trTolerance.Show = true;
				trOutsizevalue.Show = false;
				break;
			}
			break;
		case XYZ2MAT_METHOD_RANDOM_KRIGING:
			trParas.searchradius.Show = true;
			trParas.minipoints.Show = true;
			trParas.maxipoints.Show = true; ///---Sim 09-16-2009 QA81-11497-P7 ADD_MAXIMUM_FOR_RANDOM_KRIGING_METHOD
			trParas.CorrelationSmoothing.Show = true;
			break;
		case XYZ2MAT_METHOD_WEIGHTED_AVERAGE:
			trParas.averadius.Show = true;
			break;
		default:
			break;
		}
	}
}

void XYZGriddingRangeRestrictionSettings::UpdateGUI(TreeNode& trGUI, bool bToGUI)
{
	if ( !trGUI.advanced.SelectRange )
	{
		GETN_USE(trGUI)
		
		GETN_BEGIN_BRANCH(advanced, _L("Advanced"))									GETN_ID_BRANCH(IDE_XYZ2MAT_ADVANCED_OPERATIONS)
			GETN_BEGIN_BRANCH(SelectRange, _L("Range Restriction"))					GETN_ID_BRANCH(IDE_XYZ2MAT_SELECT_RANGE)
			GETN_CHECKBOX_BRANCH(0)
			
				GETN_NUM(xmin, _L("X Minimum"), 0)				GETN_ID(IDE_XYZ2MAT_RANGE_XMIN)
					//GETN_ADD_AUTO(true)
				GETN_NUM(xmax, _L("X Maximum"), 0)				GETN_ID(IDE_XYZ2MAT_RANGE_XMAX)
					//GETN_ADD_AUTO(true)
				GETN_NUM(ymin, _L("Y Minimum"), 0)				GETN_ID(IDE_XYZ2MAT_RANGE_YMIN)
					//GETN_ADD_AUTO(true)
				GETN_NUM(ymax, _L("Y Maximum"), 0)				GETN_ID(IDE_XYZ2MAT_RANGE_YMAX)
					//GETN_ADD_AUTO(true)
					
			GETN_END_BRANCH(SelectRange)
		GETN_END_BRANCH(advanced)
	}
	
	TreeNode trSelectRange = trGUI.advanced.SelectRange;
	
	TreeNode trTemp;
	// need optimize to struct with ID
	if ( bToGUI )
	{
		trSelectRange.Use = bUse;
		
		trSelectRange.xmin.dVal = dXMin;
		trTemp = trSelectRange.xmin;
		octree_set_auto_support(&trTemp, nAutoXMin);
		
		trSelectRange.xmax.dVal = dXMax;
		trTemp = trSelectRange.xmax;
		octree_set_auto_support(&trTemp, nAutoXMax);
		
		trSelectRange.ymin.dVal = dYMin;
		trTemp = trSelectRange.ymin;
		octree_set_auto_support(&trTemp, nAutoYMin);
		
		trSelectRange.ymax.dVal = dYMax;
		trTemp = trSelectRange.ymax;
		octree_set_auto_support(&trTemp, nAutoYMax);
	}
	else
	{
		bUse = trSelectRange.Use;
		
		dXMin = trSelectRange.xmin.dVal;
		trTemp = trSelectRange.xmin;
		nAutoXMin = octree_get_auto_support(&trTemp);
		
		dXMax = trSelectRange.xmax.dVal;
		trTemp = trSelectRange.xmax;
		nAutoXMax = octree_get_auto_support(&trTemp);
		
		dYMin = trSelectRange.ymin.dVal;
		trTemp = trSelectRange.ymin;
		nAutoYMin = octree_get_auto_support(&trTemp);
		
		dYMax = trSelectRange.ymax.dVal;
		trTemp = trSelectRange.ymax;
		nAutoYMax = octree_get_auto_support(&trTemp);
	}
}

void XYZGriddingPreviewSettings::UpdateGUI(TreeNode& trGUI, bool bToGUI)
{
	if ( !trGUI.previewplottype )
	{
		GETN_USE(trGUI)
	
			GETN_LIST(previewplottype, _L("Preview Plot Type"), 1, _L("3D Color Map Surface|Contour - Color Fill|3D Wire Frame"))	GETN_ID(IDE_XYZ2MAT_PREVIEW_PLOT_TYPE)
	}

	// need optimize to struct with ID
	if ( bToGUI )
	{
		trGUI.previewplottype.nVal = nPreviewPlotType;
	}
	else
	{
		nPreviewPlotType = trGUI.previewplottype.nVal;
	}
}

void XYZGriddingSettings::UpdateGUI(TreeNode& trGUI, bool bToGUI)
{
	settingDataExamination.UpdateGUI(trGUI, bToGUI);
	settingMethod.UpdateGUI(trGUI, bToGUI);
	settingRangeRestriction.UpdateGUI(trGUI, bToGUI);
	settingPreview.UpdateGUI(trGUI, bToGUI);
}

void XYZGriddingSettings::OnChange(int nType, XYZGrdiddingDataInfo *pDataInfo)
{
	SAFE_CHECK_RET_NULL(pDataInfo);

	switch (nType)
	{
	// data is changed, update all
	case XYZ_CHANGE_INIT:
	case XYZ_CHANGE_DATA:
	case XYZ_CHANGE_EXAM:
		updateMethodFromDataType(pDataInfo);
	// maybe range selection auto is changed, update range from data if it is auto
	case XYZ_CHANGE_SEL_RANGE:
		updateRangeRestrictionFromMatrixRange(pDataInfo);
	// once range is enlarge (or retrench),
	// if numbers of cols or rows are auto, update them from data step;
	// if numbers of cols or rows are fixed, update data step (also and grid lines) from them;
	case XYZ_CHANGE_SEL_RANGE_USE:
	case XYZ_CHANGE_COLUMN_AND_ROW:
		smartUpdateMatrixRowColStep(pDataInfo);
		break;
	case XYZ_CHANGE_OTHER:
		break;
	default:
		break;
	}
}



/// Fisher 07/20/09	QA80-13971	XYZ_GRIDDING_INIT_VAL_IMPROVEMENT
/*
void XYZGriddingSettings::updateMatrixRowAndColFromStep(XYZGrdiddingDataInfo *pDataInfo)
{
	SAFE_CHECK_RET_NULL(pDataInfo);
	
	int nRows, nCols;
	if( Examine_XYZ_Random == pDataInfo->nDataType)
	{
		//Random data init rows and columns by this way
		int nSize = pDataInfo->nSize;
		if( nSize < SMALL_RANDOM_DATA_SIZE )
			nRows = nSize;
		else
			nRows = sqrt(nSize);
		nCols = nRows;
	}
	else
	{
		double dXMin = pDataInfo->dXMin;
		double dXMax = pDataInfo->dXMax;
		double dYMin = pDataInfo->dYMin;
		double dYMax = pDataInfo->dYMax;
		double dXStep = pDataInfo->dXStep;
		double dYStep = pDataInfo->dYStep;

		nCols = is_equal(dXStep, 0) ? 1 : ROUND(abs(dXMax - dXMin)/dXStep) + 1; // consider two side of border
		nRows = is_equal(dYStep, 0) ? 1 : ROUND(abs(dYMax - dYMin)/dYStep) + 1; // consider two side of border
	}
	
	if( XYZ2MAT_METHOD_REGULAR == settingMethod.nMethod || IS_INT_AUTO(settingMethod.nAutoColumns) )
		settingMethod.nColumns = nCols;
	if( XYZ2MAT_METHOD_REGULAR == settingMethod.nMethod || IS_INT_AUTO(settingMethod.nAutoRows) )
		settingMethod.nRows = nRows;
}
*/
#define 	LENGTH(_start_, _end_, _step_)	(is_equal((_step_), 0) ? 1 : ROUND(abs((_end_)-(_start_))/(_step_)) + 1)
void XYZGriddingSettings::updateMatrixRowAndColFromStep(XYZGrdiddingDataInfo *pDataInfo)
{
	SAFE_CHECK_RET_NULL(pDataInfo);
	
	int nRows, nCols;
	int nSize = pDataInfo->nSize;
	double dXMin = pDataInfo->dXMin;
	double dXMax = pDataInfo->dXMax;
	double dYMin = pDataInfo->dYMin;
	double dYMax = pDataInfo->dYMax;
	double dXStep = pDataInfo->dXStep;
	double dYStep = pDataInfo->dYStep;
	if( Examine_XYZ_Random == pDataInfo->nDataType)
	{
		//Random data init rows and columns by this way	
		/// Fisher 09/16/09 Qa80-14310 INCORRECT_ARRAY_STEP_FINDING
		if( !is_equal(dXStep, 0.0) && !is_equal(dYStep, 0.0) )
		{
			nCols = LENGTH(dXMin, dXMax, dXStep);	
			nRows = LENGTH(dYMin, dYMax, dYStep);
		}
		/// End INCORRECT_ARRAY_STEP_FINDING
		else if( !is_equal(dYStep, 0.0) )		// vx is evenly space
		{
			nCols = LENGTH(dXMin, dXMax, dXStep);
			nRows = ceil((double)nSize/nCols);
		}
		else if( !is_equal(dXStep, 0.0) )	// vy is evenly space
		{
			nRows = LENGTH(dYMin, dYMax, dYStep);
			nCols = ceil((double)nSize/nRows);
		}
		else						// both vx and vy are not evenly space
		{
			if( nSize < SMALL_RANDOM_DATA_SIZE )
				nRows = nSize;
			else
				nRows = sqrt(nSize);
			nCols = nRows;
		}
	}
	else
	{
		ASSERT( NANUM != dXStep && NANUM != dYStep );		
		nCols = LENGTH(dXMin, dXMax, dXStep); // consider two side of border
		nRows = LENGTH(dYMin, dYMax, dYStep); // consider two side of border
	}
		
	if( XYZ2MAT_METHOD_REGULAR == settingMethod.nMethod || IS_INT_AUTO(settingMethod.nAutoColumns) )
		settingMethod.nColumns = nCols;
	if( XYZ2MAT_METHOD_REGULAR == settingMethod.nMethod || IS_INT_AUTO(settingMethod.nAutoRows) )
		settingMethod.nRows = nRows;
}
#undef LENGTH
/// End XYZ_GRIDDING_INIT_VAL_IMPROVEMENT



void XYZGriddingSettings::updateMatrixStepFromRowAndCol(XYZGrdiddingDataInfo *pDataInfo)
{
	SAFE_CHECK_RET_NULL(pDataInfo);
	
	double dXMin = pDataInfo->dXMin;
	double dXMax = pDataInfo->dXMax;
	double dYMin = pDataInfo->dYMin;
	double dYMax = pDataInfo->dYMax;
	int nCols = settingMethod.nColumns;
	int nRows = settingMethod.nRows;
	
	pDataInfo->dXStep = (nCols <= 1) ? 0 : (dXMax - dXMin) / (nCols - 1);
	pDataInfo->dYStep = (nRows <= 1) ? 0 : (dYMax - dYMin) / (nRows - 1);
}

void XYZGriddingSettings::updateRangeRestrictionFromMatrixRange(XYZGrdiddingDataInfo *pDataInfo)
{
	SAFE_CHECK_RET_NULL(pDataInfo);
	
	double dXMin = pDataInfo->dXMin;
	double dXMax = pDataInfo->dXMax;
	double dYMin = pDataInfo->dYMin;
	double dYMax = pDataInfo->dYMax;
	
	XYZGRIDDING_MATH(IncreaseIncludedSize(dXMin, dXMax, dYMin, dYMax));

	if ( IS_INT_AUTO(settingRangeRestriction.nAutoXMin) )
		settingRangeRestriction.dXMin = dXMin;
	if ( IS_INT_AUTO(settingRangeRestriction.nAutoXMax) )
		settingRangeRestriction.dXMax = dXMax;
	if ( IS_INT_AUTO(settingRangeRestriction.nAutoYMin) )
		settingRangeRestriction.dYMin = dYMin;
	if ( IS_INT_AUTO(settingRangeRestriction.nAutoYMax) )
		settingRangeRestriction.dYMax = dYMax;
}

//void XYZGriddingSettings::updateMatrixRangeFromRangeRestriction(XYZGrdiddingDataInfo *pDataInfo)
//{
	//SAFE_CHECK_RET_NULL(pDataInfo);
	//
	//if ( settingRangeRestriction.bUse )
	//{
		//pDataInfo->dXMin = settingRangeRestriction.dXMin;
		//pDataInfo->dXMax = settingRangeRestriction.dXMax;
		//pDataInfo->dYMin = settingRangeRestriction.dYMin;
		//pDataInfo->dYMax = settingRangeRestriction.dYMax;
	//}
//}

void XYZGriddingSettings::updateMethodFromDataType(XYZGrdiddingDataInfo *pDataInfo)
{
	SAFE_CHECK_RET_NULL(pDataInfo);
	
	if ( XYZ2MAT_METHOD_AUTO == settingMethod.nMethod )
	{
		int nMethod;
		switch(pDataInfo->nDataType)
		{
		case Examine_XYZ_Regular:
			nMethod = XYZ2MAT_METHOD_REGULAR;
			break;
		case Examine_XYZ_Sparse:
			nMethod = XYZ2MAT_METHOD_SPARSE;
			break;
		case Examine_XYZ_Random:
			nMethod = XYZ2MAT_METHOD_RANDOM_RENKA_CLINE;
			break;
		default: // unknow data type
			//return;	//no change
			nMethod = XYZ2MAT_METHOD_RANDOM_SHEPARD;
			break;
		}
	
		settingMethod.nMethod = nMethod;
	}
}

void XYZGriddingSettings::smartUpdateMatrixRowColStep(XYZGrdiddingDataInfo *pDataInfo)
{
	SAFE_CHECK_RET_NULL(pDataInfo);
	
	// if number of columns or rows is auto, reset them by current step
	updateMatrixRowAndColFromStep(pDataInfo);
	// if not auto, above function do nothing, here reset step by number of columns or rows
	// if auto, just reset step again as same value
	updateMatrixStepFromRowAndCol(pDataInfo);
}
		
////////////////////////////////////////////////////////////////////////////////////////////
bool XYZGridding::SetInput(const XYZRange& drXYZ)
{
	checkInput(m_errInput, drXYZ);
	if ( !m_errInput.bHasNoError )
		return false;
	
	int nSize = getSourceData(drXYZ, m_vX, m_vY, m_vZ);
	if ( nSize < 0 )
		return false;
	
	return true;
}
bool XYZGridding::GetOutput(matrix& mat)
{
	mat = m_mat;
	return true;
}

int XYZGridding::DoGridding()
{
	if ( !m_errInput.bHasNoError || !m_errSetting.bHasNoError )
		return OE_BAD_PARAM;
	
	return XYZGRIDDING_MATH(DoGridding(m_vX, m_vY, m_vZ, m_mat, &m_Settings));
}

void XYZGridding::OnChange(int nType, ErrorInfo& err)
{
	m_mat.SetSize(0, 0);
	XYZGRIDDING_MATH(SetDirty()); // Sim, need improve for better dirty bits
	
	if ( !m_errInput.bHasNoError )
	{
		err = m_errInput;
		return;
	}
	
	bool bUpdateSettingByData = false;
	switch (nType)
	{
	case XYZ_CHANGE_INIT:
	case XYZ_CHANGE_DATA:
	case XYZ_CHANGE_EXAM:
		bUpdateSettingByData = true;
		break;
	case XYZ_CHANGE_SEL_RANGE_USE:
	case XYZ_CHANGE_SEL_RANGE:
		bUpdateSettingByData = true;
		break;
	case XYZ_CHANGE_COLUMN_AND_ROW:
		if ( IS_INT_AUTO(m_Settings.settingMethod.nAutoColumns) || IS_INT_AUTO(m_Settings.settingMethod.nAutoRows) )
			bUpdateSettingByData = true;
		break;
	default:
		break;
	};
	
	if ( bUpdateSettingByData )
		//UpdateDataInfo();
		XYZGRIDDING_MATH(UpdateDataInfo(&m_DataInfo, m_vX, m_vY, m_vZ, &m_Settings));
	
	m_Settings.OnChange(nType, &m_DataInfo);
	
	checkValidSetting(m_errSetting, m_Settings);
	err = m_errSetting;
}

//void XYZGridding::UpdateDataInfo()
//{
	//vector vX, vY, vZ;
	//int nSize = GetPreprocessData(vX, vY, vZ);
	//if ( nSize > 0 )
	//{
		//XYZGRIDDING_MATH(UpdateDataInfo(&m_DataInfo, vX, vY, vZ, &(m_Settings.settingDataExamination)));
	//}
//}

bool  XYZGridding::GetData(vector& vX, vector& vY, vector& vZ, bool bOriginal) // = true
{
	if ( bOriginal )
	{
		vX = m_vX;
		vY = m_vY;
		vZ = m_vZ;
		return true;
	}
	else
		return ( 0 <= GetPreprocessData(vX, vY, vZ) );
}

int XYZGridding::getSourceData(const XYZRange& drXYZ, vector& vX, vector& vY, vector& vZ)
{
	if ( !drXYZ || !drXYZ.IsValid() )
		return -1;
	
	if( !drXYZ.GetData(vZ, vY, vX) )
		return -1;

	return vX.GetSize();
}

int XYZGridding::GetPreprocessData(vector& vX, vector& vY, vector& vZ)
{
	vX = m_vX;
	vY = m_vY;
	vZ = m_vZ;
	
	return XYZGRIDDING_MATH(PreprocessData(vX, vY, vZ, &m_Settings));
}


void  XYZGridding::checkInput(ErrorInfo& err, const XYZRange& drXYZ)
{
	err.Clear();
	
	if( err.bHasNoError )
	{
		if ( !drXYZ || !drXYZ.IsValid() )
		{
			err.strErrMsg = CER_NOT_ONE_XYZRANGE;
			err.bHasNoError = false;
		}
	}
	
	if( err.bHasNoError )
	{
		vector vX, vY, vZ;
		int nSize = getSourceData(drXYZ, vX, vY, vZ);
		if ( nSize < 0 )
		{
			/// Max 6/1/09 v8.1027 USE_A_BETTER_ERR_MSG	
			//err.strErrMsg = XFERR_FAILED_GET_DATA_FROM_DATARANGE;
			err.strErrMsg = CER_NOT_ONE_XYZRANGE;
			/// END USE_A_BETTER_ERR_MSG
			err.bHasNoError = false;
		}
	}
	
	if( err.bHasNoError )
	{
		int nNumRanges = drXYZ.GetNumRanges();
		int r1, r2, c1, c2;
		Worksheet wks;
		for(int ii = 0; ii < nNumRanges-1; ii++)
		{
			drXYZ.GetRange(ii, r1, c1, r2, c2, wks);
			for(int jj = c1; jj <= c2; jj++)
			{
				if(wks.Columns(jj).GetInternalData() == FSI_COMPLEX || wks.Columns(jj).GetInternalData() == FSI_TEXT )
				{
					err.strErrMsg = CER_GRIDDING_NO_SUPPORT_COMPLEX_OR_TEXT_RANGE;
					err.bHasNoError = false;
					break;
				}
			}
		}
	}
}

void  XYZGridding::checkValidSetting(ErrorInfo& err, XYZGriddingSettings& settings)
{
	err.Clear();

	//vector vX, vY, vZ;
	////int nSize = GetPreprocessData(vX, vY, vZ);
	//GetPreprocessData(vX, vY, vZ);
	//
	//XYZGrdiddingDataInfo datainfo;
	//XYZGRIDDING_MATH(UpdateDataInfo(&datainfo, vX, vY, vZ, &(settings.settingDataExamination)));
	XYZGrdiddingDataInfo datainfo;
	XYZGRIDDING_MATH(UpdateDataInfo(&datainfo, m_vX, m_vY, m_vZ, &m_Settings));
	
	int nSize = datainfo.nSize;

	if( err.bHasNoError )
	{
		// Sim, no reason for don't support 1x1 matrix
		// As "Direct", "Expand" support 1 dimension
		if ( nSize < 2 )
		//if ( nSize < 1 )
		{
			err.strErrMsg = CER_GRIDDING_TOO_FEW_DATA;
			err.bHasNoError = false;
		}
	}
	
	if( err.bHasNoError )
	{
	    //int 	nMethod = settings.settingMethod.nMethod;
	    
		// special case when the data set has a large number of data points and the three methods are not suitable for usage
	    //bool bInvalid =
	    	//( ( nSize > LARGE_DATASET_NUM_DATA_PTS )
	    	//&& ( nMethod == XYZ2MAT_METHOD_RANDOM_SHEPARD || nMethod == XYZ2MAT_METHOD_RANDOM_TPS || nMethod == XYZ2MAT_METHOD_RANDOM_KRIGING ) );
	    bool bInvalid = XYZGRIDDING_MATH(IsLargeDataSet(&settings, &datainfo));
		if( bInvalid )
		{
			err.strErrMsg = CER_GRIDDING_INVALID_METHOD_FOR_LARGE_DATASET;	
			//err.bHasNoError = false;
		}
	}
	
	if( err.bHasNoError )
	{
		if ( 	settings.settingMethod.nColumns <= 0
			||	settings.settingMethod.nRows <= 0 )
		{
			err.strErrMsg = CER_GRIDDING_INVALID_CONVERTED_MATRIX;
			err.bHasNoError = false;
		}
	}

	if( err.bHasNoError )
	{
		int nMethod = settings.settingMethod.nMethod;
		int nExamineMethod = datainfo.nDataType;
		if (XYZ2MAT_METHOD_REGULAR == nMethod)
		{
			switch(nExamineMethod)
			{
			case Examine_XYZ_Random:
				err.strErrMsg = CER_GRIDDING_WRONG_GRIDDING_METHOD;
				err.strErrMsg += ":";
				err.strErrMsg += STR_RANDOM_METHOD;
				err.bHasNoError = false;
				break;
			case Examine_XYZ_Sparse:
				err.strErrMsg = CER_GRIDDING_WRONG_GRIDDING_METHOD;
				err.strErrMsg += ":";
				err.strErrMsg += STR_SPARSE_OR_RANDOM_METHOD;
				err.bHasNoError = false;
				break;
			}
		}
		else if(XYZ2MAT_METHOD_SPARSE == nMethod)
		{
			switch(nExamineMethod)
			{
			case Examine_XYZ_Random:
				err.strErrMsg = CER_GRIDDING_WRONG_GRIDDING_METHOD;
				err.strErrMsg += ":";
				err.strErrMsg += STR_RANDOM_METHOD;
				err.bHasNoError = false;
				break;
			}
		}
	}
}
