/////////////////////////////////////////////////////////// // // // SAGA // // // // System for Automated Geoscientific Analyses // // // // Application Programming Interface // // // // Library: SAGA_API // // // //-------------------------------------------------------// // // // grid_operation.cpp // // // // Copyright (C) 2005 by Olaf Conrad // // // //-------------------------------------------------------// // // // This file is part of 'SAGA - System for Automated // // Geoscientific Analyses'. // // // // This library is free software; you can redistribute // // it and/or modify it under the terms of the GNU Lesser // // General Public License as published by the Free // // Software Foundation, either version 2.1 of the // // License, or (at your option) any later version. // // // // This library is distributed in the hope that it will // // be useful, but WITHOUT ANY WARRANTY; without even the // // implied warranty of MERCHANTABILITY or FITNESS FOR A // // PARTICULAR PURPOSE. See the GNU Lesser General Public // // License for more details. // // // // You should have received a copy of the GNU Lesser // // General Public License along with this program; if // // not, see . // // // //-------------------------------------------------------// // // // contact: Olaf Conrad // // Institute of Geography // // University of Goettingen // // Goldschmidtstr. 5 // // 37077 Goettingen // // Germany // // // // e-mail: oconrad@saga-gis.org // // // /////////////////////////////////////////////////////////// //--------------------------------------------------------- #include #include "grid.h" /////////////////////////////////////////////////////////// // // // Data Assignments - Value // // // /////////////////////////////////////////////////////////// //--------------------------------------------------------- void CSG_Grid::Assign_NoData(void) { double Value = Get_NoData_Value(); #pragma omp parallel for for(sLong i=0; iis_Valid() && pObject->Get_ObjectType() == Get_ObjectType() && Assign((CSG_Grid *)pObject, GRID_RESAMPLING_Undefined) ); } bool CSG_Grid::Assign(CSG_Grid *pGrid, TSG_Grid_Resampling Interpolation) { //----------------------------------------------------- if( !is_Valid() || !pGrid || !pGrid->is_Valid() || is_Intersecting(pGrid->Get_Extent()) == INTERSECTION_None ) { return( false ); } bool bResult = false; //--------------------------------------------------------- if( m_System == pGrid->m_System ) { for(int y=0; yis_NoData(x, y) ) { Set_NoData(x, y); } else { Set_Value(x, y, pGrid->asDouble(x, y)); } } } bResult = true; } else if( Get_Cellsize() == pGrid->Get_Cellsize() // No-Scaling... && fmod(Get_XMin() - pGrid->Get_XMin(), Get_Cellsize()) == 0. && fmod(Get_YMin() - pGrid->Get_YMin(), Get_Cellsize()) == 0. ) { bResult = _Assign_Interpolated(pGrid, GRID_RESAMPLING_NearestNeighbour); } //--------------------------------------------------------- else switch( Interpolation ) { case GRID_RESAMPLING_NearestNeighbour: case GRID_RESAMPLING_Bilinear: case GRID_RESAMPLING_BicubicSpline: case GRID_RESAMPLING_BSpline: bResult = _Assign_Interpolated(pGrid, Interpolation); break; case GRID_RESAMPLING_Mean_Nodes: case GRID_RESAMPLING_Mean_Cells: bResult = _Assign_MeanValue (pGrid, Interpolation != GRID_RESAMPLING_Mean_Nodes); break; case GRID_RESAMPLING_Minimum: case GRID_RESAMPLING_Maximum: bResult = _Assign_ExtremeValue(pGrid, Interpolation == GRID_RESAMPLING_Maximum); break; case GRID_RESAMPLING_Majority: bResult = _Assign_Majority (pGrid); break; default: if( Get_Cellsize() < pGrid->Get_Cellsize() ) // Down-Scaling... { bResult = _Assign_Interpolated(pGrid, GRID_RESAMPLING_BSpline); } else // Up-Scaling... { bResult = _Assign_MeanValue(pGrid, Interpolation != GRID_RESAMPLING_Mean_Nodes); } break; } //--------------------------------------------------------- if( bResult ) { Set_Unit(pGrid->Get_Unit()); if( pGrid->Get_Projection().is_Okay() ) { Get_Projection() = pGrid->Get_Projection(); } Get_History() = pGrid->Get_History(); } //--------------------------------------------------------- SG_UI_Process_Set_Ready(); return( bResult ); } //--------------------------------------------------------- bool CSG_Grid::_Assign_Interpolated(CSG_Grid *pGrid, TSG_Grid_Resampling Interpolation) { double py = Get_YMin(); for(int y=0; yGet_Value(Get_XMin() + x * Get_Cellsize(), py, z, Interpolation) ) { Set_Value(x, y, z); } else { Set_NoData(x, y); } } } return( true ); } //--------------------------------------------------------- bool CSG_Grid::_Assign_ExtremeValue(CSG_Grid *pGrid, bool bMaximum) { if( Get_Cellsize() < pGrid->Get_Cellsize() ) { return( false ); } //----------------------------------------------------- Assign_NoData(); double ax = 0.5 + (pGrid->Get_XMin() - Get_XMin()) / Get_Cellsize(); double py = 0.5 + (pGrid->Get_YMin() - Get_YMin()) / Get_Cellsize(); double d = pGrid->Get_Cellsize() / Get_Cellsize(); for(int y=0; yGet_NY() && SG_UI_Process_Set_Progress(y, pGrid->Get_NY()); y++, py+=d) { int iy = (int)floor(py); if( iy >= 0 && iy < Get_NY() ) { #pragma omp parallel for for(int x=0; xGet_NX(); x++) { if( !pGrid->is_NoData(x, y) ) { int ix = (int)floor(ax + x * d); if( ix >= 0 && ix < Get_NX() ) { double z = pGrid->asDouble(x, y); if( is_NoData(ix, iy) || (bMaximum == true && z > asDouble(ix, iy)) || (bMaximum == false && z < asDouble(ix, iy)) ) { Set_Value(ix, iy, z); } } } } } } //----------------------------------------------------- return( true ); } //--------------------------------------------------------- bool CSG_Grid::_Assign_MeanValue(CSG_Grid *pGrid, bool bAreaProportional) { if( Get_Cellsize() < pGrid->Get_Cellsize() ) { return( false ); } //----------------------------------------------------- double d = Get_Cellsize() / pGrid->Get_Cellsize(); double ox = (Get_XMin(true) - pGrid->Get_XMin()) / pGrid->Get_Cellsize(); double py = (Get_YMin(true) - pGrid->Get_YMin()) / pGrid->Get_Cellsize(); for(int y=0; y= 0 && iy < pGrid->Get_NY() ) { for(int ix=ax; ix<=bx; ix++) { if( ix >= 0 && ix < pGrid->Get_NX() && !pGrid->is_NoData(ix, iy) ) { if( bAreaProportional ) { CSG_Rect r(ix - 0.5, iy - 0.5, ix + 0.5, iy + 0.5); if( r.Intersect(rMean) ) { s.Add_Value(pGrid->asDouble(ix, iy), r.Get_Area()); } } else { s.Add_Value(pGrid->asDouble(ix, iy)); } } } } } //--------------------------------------------- if( s.Get_Count() > 0 ) { Set_Value(x, y, s.Get_Mean()); } else { Set_NoData(x, y); } } } //----------------------------------------------------- return( true ); } /////////////////////////////////////////////////////////// // // /////////////////////////////////////////////////////////// //--------------------------------------------------------- bool CSG_Grid::_Assign_Majority(CSG_Grid *pGrid) { if( Get_Cellsize() < pGrid->Get_Cellsize() ) { return( false ); } //----------------------------------------------------- Set_NoData_Value(pGrid->Get_NoData_Value()); Assign_NoData(); //----------------------------------------------------- int ay, by = (int)(1. + (((0 - 0.5) * Get_Cellsize() + Get_YMin()) - pGrid->Get_YMin()) / pGrid->Get_Cellsize()); for(int y=0; yGet_YMin()) / pGrid->Get_Cellsize()); if( ay < pGrid->Get_NY() && by > 0 ) { if( ay < 0 ) { ay = 0; } if( by > pGrid->Get_NY() ) { by = pGrid->Get_NY(); } int ax, bx = (int)(1. + (((0 - 0.5) * Get_Cellsize() + Get_XMin()) - pGrid->Get_XMin()) / pGrid->Get_Cellsize()); for(int x=0; xGet_XMin()) / pGrid->Get_Cellsize()); if( ax < pGrid->Get_NX() && bx > 0 ) { CSG_Unique_Number_Statistics s; if( ax < 0 ) { ax = 0; } if( bx > pGrid->Get_NX() ) { bx = pGrid->Get_NX(); } for(int iy=ay; iyis_NoData(ix, iy) ) { s += pGrid->asDouble(ix, iy); } } } int n; double z; if( s.Get_Majority(z, n) )//&& n > 1 ) { Set_Value(x, y, z); } } } } } //----------------------------------------------------- return( true ); } /////////////////////////////////////////////////////////// // // // Operatoren // // // /////////////////////////////////////////////////////////// //--------------------------------------------------------- CSG_Grid & CSG_Grid::operator = (const CSG_Grid &Grid) { Assign((CSG_Grid *)&Grid, GRID_RESAMPLING_Undefined); return( *this ); } CSG_Grid & CSG_Grid::operator = (double Value) { Assign(Value); return( *this ); } //--------------------------------------------------------- CSG_Grid CSG_Grid::operator + (const CSG_Grid &Grid) const { CSG_Grid g(*this); return( g._Operation_Arithmetic(Grid, GRID_OPERATION_Addition) ); } CSG_Grid CSG_Grid::operator + (double Value) const { CSG_Grid g(*this); return( g._Operation_Arithmetic(Value, GRID_OPERATION_Addition) ); } CSG_Grid & CSG_Grid::operator += (const CSG_Grid &Grid) { return( _Operation_Arithmetic(Grid, GRID_OPERATION_Addition) ); } CSG_Grid & CSG_Grid::operator += (double Value) { return( _Operation_Arithmetic(Value, GRID_OPERATION_Addition) ); } CSG_Grid & CSG_Grid::Add (const CSG_Grid &Grid) { return( _Operation_Arithmetic(Grid, GRID_OPERATION_Addition) ); } CSG_Grid & CSG_Grid::Add (double Value) { return( _Operation_Arithmetic(Value, GRID_OPERATION_Addition) ); } //--------------------------------------------------------- CSG_Grid CSG_Grid::operator - (const CSG_Grid &Grid) const { CSG_Grid g(*this); return( g._Operation_Arithmetic(Grid, GRID_OPERATION_Subtraction) ); } CSG_Grid CSG_Grid::operator - (double Value) const { CSG_Grid g(*this); return( g._Operation_Arithmetic(Value, GRID_OPERATION_Subtraction) ); } CSG_Grid & CSG_Grid::operator -= (const CSG_Grid &Grid) { return( _Operation_Arithmetic(Grid, GRID_OPERATION_Subtraction) ); } CSG_Grid & CSG_Grid::operator -= (double Value) { return( _Operation_Arithmetic(Value, GRID_OPERATION_Subtraction) ); } CSG_Grid & CSG_Grid::Subtract (const CSG_Grid &Grid) { return( _Operation_Arithmetic(Grid, GRID_OPERATION_Subtraction) ); } CSG_Grid & CSG_Grid::Subtract (double Value) { return( _Operation_Arithmetic(Value, GRID_OPERATION_Subtraction) ); } //--------------------------------------------------------- CSG_Grid CSG_Grid::operator * (const CSG_Grid &Grid) const { CSG_Grid g(*this); return( g._Operation_Arithmetic(Grid, GRID_OPERATION_Multiplication) ); } CSG_Grid CSG_Grid::operator * (double Value) const { CSG_Grid g(*this); return( g._Operation_Arithmetic(Value, GRID_OPERATION_Multiplication) ); } CSG_Grid & CSG_Grid::operator *= (const CSG_Grid &Grid) { return( _Operation_Arithmetic(Grid, GRID_OPERATION_Multiplication) ); } CSG_Grid & CSG_Grid::operator *= (double Value) { return( _Operation_Arithmetic(Value, GRID_OPERATION_Multiplication) ); } CSG_Grid & CSG_Grid::Multiply (const CSG_Grid &Grid) { return( _Operation_Arithmetic(Grid, GRID_OPERATION_Multiplication) ); } CSG_Grid & CSG_Grid::Multiply (double Value) { return( _Operation_Arithmetic(Value, GRID_OPERATION_Multiplication) ); } //--------------------------------------------------------- CSG_Grid CSG_Grid::operator / (const CSG_Grid &Grid) const { CSG_Grid g(*this); return( g._Operation_Arithmetic(Grid, GRID_OPERATION_Division) ); } CSG_Grid CSG_Grid::operator / (double Value) const { CSG_Grid g(*this); return( g._Operation_Arithmetic(Value, GRID_OPERATION_Division) ); } CSG_Grid & CSG_Grid::operator /= (const CSG_Grid &Grid) { return( _Operation_Arithmetic(Grid, GRID_OPERATION_Division) ); } CSG_Grid & CSG_Grid::operator /= (double Value) { return( _Operation_Arithmetic(Value, GRID_OPERATION_Division) ); } CSG_Grid & CSG_Grid::Divide (const CSG_Grid &Grid) { return( _Operation_Arithmetic(Grid, GRID_OPERATION_Division) ); } CSG_Grid & CSG_Grid::Divide (double Value) { return( _Operation_Arithmetic(Value, GRID_OPERATION_Division) ); } /////////////////////////////////////////////////////////// // // // Operatoren // // // /////////////////////////////////////////////////////////// //--------------------------------------------------------- CSG_Grid & CSG_Grid::_Operation_Arithmetic(const CSG_Grid &Grid, TSG_Grid_Operation Operation) { if( is_Intersecting(Grid.Get_Extent()) ) { TSG_Grid_Resampling Interpolation = Get_Cellsize() == Grid.Get_Cellsize() && fmod(Get_XMin() - Grid.Get_XMin(), Get_Cellsize()) == 0. && Get_Cellsize() == Grid.Get_Cellsize() && fmod(Get_YMin() - Grid.Get_YMin(), Get_Cellsize()) == 0. ? GRID_RESAMPLING_NearestNeighbour : GRID_RESAMPLING_BSpline; #pragma omp parallel for for(int y=0; y 0. ) { double Min = Get_Min(); double Max = Get_Max(); #pragma omp parallel for for(int y=0; y 0. ) { double Min = Get_Min (); double Range = Get_Range(); #pragma omp parallel for for(int y=0; y 0. ) { double Mean = Get_Mean (); double StdDev = Get_StdDev(); #pragma omp parallel for for(int y=0; y 0. ) { #pragma omp parallel for for(int y=0; y 0.) && (Direction < 0 || dzMax < dz) ) { dzMax = dz; Direction = i; } } else if( bNoEdges ) { return( -1 ); } } } return( Direction ); } //--------------------------------------------------------- /** * Calculates the gradient of a cell interpreting all grid cell values * as elevation surface. Calculation uses the formulas proposed * by Zevenbergen & Thorne (1986). Slope and aspect values are calculated * in radians. Aspect is zero for the North direction and increases * clockwise. */ //--------------------------------------------------------- bool CSG_Grid::Get_Gradient(int x, int y, double &Slope, double &Aspect) const { if( is_InGrid(x, y) ) { double z = asDouble(x, y), dz[4]; for(int i=0, iDir=0, ix, iy; i<4; i++, iDir+=2) { if( is_InGrid( ix = m_System.Get_xTo (iDir, x), iy = m_System.Get_yTo (iDir, y)) ) { dz[i] = asDouble(ix, iy) - z; } else if( is_InGrid( ix = m_System.Get_xFrom(iDir, x), iy = m_System.Get_yFrom(iDir, y)) ) { dz[i] = z - asDouble(ix, iy); } else { dz[i] = 0.; } } double G = (dz[0] - dz[2]) / (2. * Get_Cellsize()); double H = (dz[1] - dz[3]) / (2. * Get_Cellsize()); Slope = atan(sqrt(G*G + H*H)); Aspect = G != 0. ? M_PI_180 + atan2(H, G) : H > 0. ? M_PI_270 : H < 0. ? M_PI_090 : -1.; return( true ); } Slope = 0.; Aspect = -1.; return( false ); } //--------------------------------------------------------- /** * Calculates the gradient for the given world coordinate. * Calculation uses the formulas proposed by Zevenbergen & Thorne (1986). * Slope and aspect values are calulated in radians. * Aspect is zero for the North direction and increases clockwise. */ //--------------------------------------------------------- bool CSG_Grid::Get_Gradient(double x, double y, double &Slope, double &Aspect, TSG_Grid_Resampling Interpolation) const { double z, iz, dz[4]; if( Get_Value(x, y, z, Interpolation) ) { for(int i=0, iDir=0; i<4; i++, iDir+=2) { if( Get_Value( x + Get_Cellsize() * m_System.Get_xTo (iDir), y + Get_Cellsize() * m_System.Get_yTo (iDir), iz, Interpolation) ) { dz[i] = iz - z; } else if( Get_Value( x + Get_Cellsize() * m_System.Get_xFrom(iDir), y + Get_Cellsize() * m_System.Get_yFrom(iDir), iz, Interpolation) ) { dz[i] = z - iz; } else { dz[i] = 0.; } } double G = (dz[0] - dz[2]) / (2. * Get_Cellsize()); double H = (dz[1] - dz[3]) / (2. * Get_Cellsize()); Slope = atan(sqrt(G*G + H*H)); Aspect = G != 0. ? M_PI_180 + atan2(H, G) : H > 0. ? M_PI_270 : H < 0. ? M_PI_090 : -1.; return( true ); } Slope = 0.; Aspect = -1.; return( false ); } //--------------------------------------------------------- /** * Calculates the gradient for the given world coordinate. * Calculation uses the formulas proposed by Zevenbergen & Thorne (1986). * Slope and aspect values are calculated in radians. * Aspect is zero for the North direction and increases clockwise. */ //--------------------------------------------------------- bool CSG_Grid::Get_Gradient(const TSG_Point &p, double &Incline, double &Azimuth, TSG_Grid_Resampling Interpolation) const { return( Get_Gradient(p.x, p.y, Incline, Azimuth, Interpolation) ); } /////////////////////////////////////////////////////////// // // // // // // /////////////////////////////////////////////////////////// //---------------------------------------------------------