bool CProfileFromPoints::On_Execute(void){
	
	CSG_Table* pTable;	
	CSG_Table* pProfileTable;
	CSG_Table_Record* pRecord;
	CSG_Grid* pGrid;	
	int iXField, iYField;	
	int i;
	int x1,x2,y1,y2;
	float fPartialDist;
	float fDist = 0;


	pGrid = Parameters("GRID")->asGrid();
	pTable = Parameters("TABLE")->asTable();
	pProfileTable = Parameters("RESULT")->asTable();
	iXField = Parameters("X")->asInt();
	iYField = Parameters("Y")->asInt();	
	
	pProfileTable->Create((CSG_Table*)NULL);
	pProfileTable->Set_Name(_TL("Profile"));
	pProfileTable->Add_Field(_TL("Distance"), SG_DATATYPE_Double);
	pProfileTable->Add_Field("Z", SG_DATATYPE_Double);

	for (i = 0; i < pTable->Get_Record_Count()-1; i++){
		
		x1=(int)(0.5 + (pTable->Get_Record(i  )->asDouble(iXField) - pGrid->Get_XMin()) / pGrid->Get_Cellsize());
		x2=(int)(0.5 + (pTable->Get_Record(i+1)->asDouble(iXField) - pGrid->Get_XMin()) / pGrid->Get_Cellsize());
		y1=(int)(0.5 + (pTable->Get_Record(i  )->asDouble(iYField) - pGrid->Get_YMin()) / pGrid->Get_Cellsize());			
		y2=(int)(0.5 + (pTable->Get_Record(i+1)->asDouble(iYField) - pGrid->Get_YMin()) / pGrid->Get_Cellsize());			

        int x = x1, y = y1, D = 0, HX = x2 - x1, HY = y2 - y1,
                c, M, xInc = 1, yInc = 1, iLastX = x1, iLastY = y1;

        if (HX < 0) {
            xInc = -1;
            HX = -HX;
        }//if
        if (HY < 0) {
            yInc = -1;
            HY = -HY;
        }//if
        if (HY <= HX) {
            c = 2 * HX;
            M = 2 * HY;
            for (;;) {                
                fPartialDist = (float)(M_GET_LENGTH(x-iLastX, y-iLastY) * pGrid->Get_Cellsize());
                if (pGrid->is_InGrid(x,y) && fPartialDist){
					fDist+=fPartialDist;
                	pRecord = pProfileTable->Add_Record();
					pRecord->Set_Value(0, fDist);
					pRecord->Set_Value(1, pGrid->asFloat(x,y));
                }//if
                iLastX = x;
                iLastY = y;
                if (x == x2) {
                    break;
                }// if
                x += xInc;
                D += M;
                if (D > HX) {
                    y += yInc;
                    D -= c;
                }// if
            }// for
        }// if
        else {
            c = 2 * HY;
            M = 2 * HX;
            for (;;) {
                fPartialDist = (float)(M_GET_LENGTH(x-iLastX, y-iLastY) * pGrid->Get_Cellsize());
                if (pGrid->is_InGrid(x,y) && fPartialDist){
					fDist+=fPartialDist;
                	pRecord = pProfileTable->Add_Record();
					pRecord->Set_Value(0, fDist);
					pRecord->Set_Value(1, pGrid->asFloat(x,y));
                }//if
                iLastX = x;
                iLastY = y;
                if (y == y2) {
                    break;
                }// if
                y += yInc;
                D += M;
                if (D > HY) {
                    x += xInc;
                    D -= c;
                }// if
            }// for
        }// else        
     
	}//for

	return true;

}// method
//---------------------------------------------------------
bool CFilter_3x3::On_Execute(void)
{
	//-----------------------------------------------------
	CSG_Table	*pFilter	= Parameters("FILTER")->asTable()
		? Parameters("FILTER"    )->asTable()
		: Parameters("FILTER_3X3")->asTable();

	if( pFilter->Get_Count() < 1 || pFilter->Get_Field_Count() < 1 )
	{
		Error_Set(_TL("invalid filter matrix"));

		return( false );
	}

	//-----------------------------------------------------
	CSG_Matrix	Filter(pFilter->Get_Field_Count(), pFilter->Get_Count());

	{
		for(int iy=0; iy<Filter.Get_NY(); iy++)
		{
			CSG_Table_Record	*pRecord	= pFilter->Get_Record(iy);

			for(int ix=0; ix<Filter.Get_NX(); ix++)
			{
				Filter[iy][ix]	= pRecord->asDouble(ix);
			}
		}
	}

	int	nx	= (Filter.Get_NX() - 1) / 2;
	int	ny	= (Filter.Get_NY() - 1) / 2;

	//-----------------------------------------------------
	CSG_Grid	*pInput 	= Parameters("INPUT" )->asGrid();
	CSG_Grid	*pResult	= Parameters("RESULT")->asGrid();

	if( !pResult || pResult == pInput )
	{
		pResult	= SG_Create_Grid(pInput);
	}
	else
	{
		pResult->Fmt_Name("%s [%s]", pInput->Get_Name(), _TL("Filter"));

		pResult->Set_NoData_Value(pInput->Get_NoData_Value());
	}

	//-----------------------------------------------------
	bool	bAbsolute	= Parameters("ABSOLUTE")->asBool();

	for(int y=0; y<Get_NY() && Set_Progress(y); y++)
	{
		#pragma omp parallel for
		for(int x=0; x<Get_NX(); x++)
		{
			double	s	= 0.0;
			double	n	= 0.0;

			if( pInput->is_InGrid(x, y) )
			{
				for(int iy=0, jy=y-ny; iy<Filter.Get_NY(); iy++, jy++)
				{
					for(int ix=0, jx=x-nx; ix<Filter.Get_NX(); ix++, jx++)
					{
						if( pInput->is_InGrid(jx, jy) )
						{
							s	+=      Filter[iy][ix] * pInput->asDouble(jx, jy);
							n	+= fabs(Filter[iy][ix]);
						}
					}
				}
			}

			if( n > 0.0 )
			{
				pResult->Set_Value(x, y, bAbsolute ? s : s / n);
			}
			else
			{
				pResult->Set_NoData(x, y);
			}
		}
	}

	//-----------------------------------------------------
	if( !Parameters("RESULT")->asGrid() || Parameters("RESULT")->asGrid() == pInput )
	{
		pInput->Assign(pResult);

		delete(pResult);

		DataObject_Update(pInput);
	}

	return( true );
}
//---------------------------------------------------------
CSG_Shape * CWatersheds_ext::Get_Basin(CSG_Grid *pBasins, CSG_Shapes *pPolygons)
{
	int			x, y, nEdges, Basin_ID;
	CSG_Grid	Edge;
	CSG_Shape	*pPolygon	= NULL;

	Basin_ID	= 1 + pPolygons->Get_Count();

	//-----------------------------------------------------
	Edge.Create(SG_DATATYPE_Char, 2 * Get_NX() + 1, 2 * Get_NY() + 1, 0.5 * Get_Cellsize(), Get_XMin() - 0.5 * Get_Cellsize(), Get_YMin() - 0.5 * Get_Cellsize());
	Edge.Set_NoData_Value(0);

	for(y=0, nEdges=0; y<Get_NY() && Process_Get_Okay(); y++)
	{
		for(x=0; x<Get_NX(); x++)
		{
			if( pBasins->asInt(x, y) == Basin_ID )
			{
				for(int i=0; i<8; i+=2)
				{
					int	ix	= Get_xTo(i, x);
					int	iy	= Get_yTo(i, y);

					if( !is_InGrid(ix, iy) || pBasins->asInt(ix, iy) != Basin_ID )
					{
						ix	= 1 + 2 * x;
						iy	= 1 + 2 * y;

						Edge.Set_Value(               ix,                 iy ,  1);
						Edge.Set_Value(Get_xTo(i    , ix), Get_yTo(i    , iy), -1);
						Edge.Set_Value(Get_xTo(i - 1, ix), Get_yTo(i - 1, iy), -1);

						nEdges++;
					}
				}
			}
		}
	}

	//-----------------------------------------------------
	if( nEdges > 0 )
	{
		for(int yEdge=0; yEdge<Edge.Get_NY(); yEdge++)	for(int xEdge=0; xEdge<Edge.Get_NX(); xEdge++)
		{
			int	i	= 4;

			if( Edge.asInt(xEdge, yEdge) == 1 && Edge.asInt(Get_xTo(i, xEdge), Get_yTo(i, yEdge)) == -1 )
			{
				if( pPolygon == NULL )
				{
					pPolygon	= pPolygons->Add_Shape();
				}

				int	iPart	= pPolygon->Get_Part_Count();
				int	xFirst	= x	= Get_xTo(i, xEdge);
				int	yFirst	= y	= Get_yTo(i, yEdge);
				i	= i + 2;

				pPolygon	->Add_Point(Edge.Get_System().Get_Grid_to_World(x, y), iPart);

				do
				{
					int	ix	= Get_xTo(i + 2, x);
					int	iy	= Get_yTo(i + 2, y);

					if( Edge.is_InGrid(ix, iy) && Edge.asInt(ix, iy) == -1 )			// go right ?
					{
						pPolygon->Add_Point(Edge.Get_System().Get_Grid_to_World(x, y), iPart);

						i	= (i + 2) % 8;
					}
					else
					{
						if( Edge.asInt(ix, iy) == 1 )
						{
							Edge.Set_NoData(ix, iy);	// erase class id in right cells
						}

						ix	= Get_xTo(i, x);
						iy	= Get_yTo(i, y);

						if( Edge.is_InGrid(ix, iy) && Edge.asInt(ix, iy) == -1 )		// go ahead ?
						{
							// nop
						}
						else
						{
							ix	= Get_xTo(i + 6, x);
							iy	= Get_yTo(i + 6, y);

							if( Edge.is_InGrid(ix, iy) && Edge.asInt(ix, iy) == -1 )	// go left ?
							{
								pPolygon->Add_Point(Edge.Get_System().Get_Grid_to_World(x, y), iPart);

								i	= (i + 6) % 8;
							}
							else
							{
								return( false );
							}
						}
					}

					x	= ix;
					y	= iy;
				}
				while( x != xFirst || y != yFirst );

				pPolygon->Add_Point(Edge.Get_System().Get_Grid_to_World(x, y), iPart);
			}
		}
	}

	//-----------------------------------------------------
	return( pPolygon );
}
//---------------------------------------------------------
bool CGrid_PCA_Focal::On_Execute(void)
{
	int		i;

	//-----------------------------------------------------
	CSG_Grid_Cell_Addressor	Kernel;

	Kernel.Set_Radius(
		Parameters("KERNEL_RADIUS")->asInt(),
		Parameters("KERNEL_TYPE"  )->asInt() == 0
	);

	CSG_Parameter_Grid_List	*pPCA, *pGrids	= Parameters("BASE")->asGridList();

	pGrids->Del_Items();

	for(i=0; i<Kernel.Get_Count()-1; i++)
	{
		CSG_Grid	*pGrid	= SG_Create_Grid(Get_System());

		if( !pGrid )
		{
			Error_Set(_TL("failed to allocate memory"));

			for(i=0; i<pGrids->Get_Grid_Count(); i++)
			{
				delete(pGrids->Get_Grid(i));
			}

			pGrids->Del_Items();

			return( false );
		}

		pGrid->Fmt_Name("x(%d)-y(%d)", Kernel.Get_X(i + 1), Kernel.Get_Y(i + 1));

		pGrids->Add_Item(pGrid);
	}

	//-----------------------------------------------------
	CSG_Grid	*pGrid	= Parameters("GRID")->asGrid();

	for(int y=0; y<Get_NY() && Set_Progress(y); y++)
	{
		#pragma omp parallel for private(i)
		for(int x=0; x<Get_NX(); x++)
		{
			if( pGrid->is_NoData(x, y) )
			{
				for(i=0; i<pGrids->Get_Grid_Count(); i++)
				{
					pGrids->Get_Grid(i)->Set_NoData(x, y);
				}
			}
			else
			{
				double	z	= pGrid->asDouble(x, y);

				for(i=0; i<pGrids->Get_Grid_Count(); i++)
				{
					int	ix	= Kernel.Get_X(i + 1, x);
					int	iy	= Kernel.Get_Y(i + 1, y);

					pGrids->Get_Grid(i)->Set_Value(x, y, pGrid->is_InGrid(ix, iy) ? z - pGrid->asDouble(ix, iy) : 0.0);
				}
			}
		}
	}

	//-----------------------------------------------------
	bool	bResult;

	CSG_Parameters	PCA_Parms;

	SG_RUN_TOOL_KEEP_PARMS(bResult, "statistics_grid", 8, PCA_Parms,	// pca analysis for grids
			SG_TOOL_PARAMETER_SET("GRIDS"     , Parameters("BASE"      ))
		&&	SG_TOOL_PARAMETER_SET("METHOD"    , Parameters("METHOD"    ))
		&&	SG_TOOL_PARAMETER_SET("EIGEN"     , Parameters("EIGEN"     ))
		&&	SG_TOOL_PARAMETER_SET("COMPONENTS", Parameters("COMPONENTS")->asInt())
	);

	if( !Parameters("BASE_OUT")->asBool() )
	{
		for(i=0; i<pGrids->Get_Grid_Count(); i++)
		{
			delete(pGrids->Get_Grid(i));
		}

		pGrids->Del_Items();
	}

	//-----------------------------------------------------
	pGrids	= Parameters("PCA")->asGridList();
	pPCA	= PCA_Parms ("PCA")->asGridList();

	if( !Parameters("OVERWRITE")->asBool() || (pGrids->Get_Grid_Count() > 0 && !Get_System().is_Equal(pGrids->Get_Grid(0)->Get_System())) )
	{
		pGrids->Del_Items();
	}

	for(i=0; i<pPCA->Get_Grid_Count(); i++)
	{
		if( pGrids->Get_Grid(i) )
		{
			pGrids->Get_Grid(i)->Assign(pPCA->Get_Grid(i));

			delete(pPCA->Get_Grid(i));
		}
		else
		{
			pGrids->Add_Item(pPCA->Get_Grid(i));
		}

		pGrids->Get_Grid(i)->Fmt_Name("%s [PC%0*d]", pGrid->Get_Name(), pPCA->Get_Grid_Count() < 10 ? 1 : 2, i + 1);
	}

	//-----------------------------------------------------
	return( bResult );
}