Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion toolbox/@FLOWobj/flipdir.m
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
if isempty(options.weights)
A = flowacc(FD);
w = A.Z(FD.ix).*FD.fraction;
elseif ischar(options.weights)
elseif ischar(options.weights) || isstring(options.weights)
switch lower(options.weights)
case 'rand'
w = rand(size(FD.fraction));
Expand Down
109 changes: 109 additions & 0 deletions toolbox/@FLOWobj/reweight.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
function FD = reweight(FD,DEM,beta,options)

%REWEIGHT Re-calculate flow weights in a multiple flow direction FLOWobj
%
% Syntax
%
% FD = reweight(FD,DEM,beta)
% FD = reweight(FD,DEM,beta,pn,pv,...)
%
% Description
%
% The function reweight takes a multiple flow direction object FD and
% re-calculates the proportions at which flow is distributed from each
% pixel to its downstream neighbors. By default, proportions in FD
% calculated with FLOWobj(DEM,'multi') are proportional to slope, so
% that beta = 1.
%
% Reweight recalculates the slopes based on the DEM and then uses beta
% to reweight and normalizes the edges of the flow network. This is the
% approach taken by Holmgren (1994).
%
% Note that reweight does not change the topology of the flow network
% so that no links are added nor removed. If slopes between two nodes
% in the network are zero or negative, their slope is adjusted to have
% a very small value (0.1 * the smallest non-negative slope value).
%
% Input arguments
%
% FD FLOWobj (multiple flow directions)
% DEM Digital elevation model (GRIDobj)
% beta exponent >= 0
%
% Parameter name/value pairs
%
% minslope scalar (0.1). This indicates the multiplier used to
% derive the minimum slope value for links that have zero
% or negative slopes.
% stable false or true. Uses a numerically stable approach when
% using large exponents. By default false, but if beta > 5,
% then the stable approach is chosen.
%
% Output arguments
%
% FD FLOWobj
%
% Example
%
% DEM = GRIDobj('srtm_bigtujunga30m_utm11.tif');
% FD = FLOWobj(DEM,'multi');
% FD1 = reweight(FD,DEM,0);
% FD2 = reweight(FD,DEM,10);
% A1 = flowacc(FD1);
% A2 = flowacc(FD2);
% tiledlayout(1,2,"TileSpacing","compact");
% ax(1) = nexttile; imageschs(DEM,log(A1),'colormap',flowcolor);
% ax(2) = nexttile; imageschs(DEM,log(A2),'colormap',flowcolor);
% linkaxes(ax,'xy');
% ext = {[3.7769e+05 3.8353e+05] [3.7911e+06 3.7948e+06]};
% setextent(ext,ax(1))
%
% See also: FLOWobj, FLOWobj/multi_normalize
%
% Author: Wolfgang Schwanghart (schwangh[at]uni-potsdam.de)
% Date: 6. April, 2026

arguments
FD FLOWobj
DEM GRIDobj
beta (1,1) {mustBeNonnegative}
options.minslope (1,1) {mustBeNonnegative} = 0.1
options.stable (1,1) = beta > 5
end

[X,Y] = getcoordinates(DEM,'mat');
dz = double(DEM.Z(FD.ix)) - double(DEM.Z(FD.ixc));
dx = sqrt((X(FD.ix) - X(FD.ixc)).^2 + ...
(Y(FD.ix) - Y(FD.ixc)).^2);
FD.fraction = dz./dx;
minNonZeroFrac = min(FD.fraction(FD.fraction>0));
FD.fraction = max(FD.fraction,minNonZeroFrac*0.1);

if ~options.stable
FD.fraction = FD.fraction.^beta;
FD = multi_normalize(FD);
else
% [~,~,locb] = unique(FD.ix);
% [W,maxY] = splitapply(@(x) normfun(x,beta),FD.fraction,locb);
% FD.fraction = exp(beta.*log(FD.fraction) - maxY(locb))./W(locb);
W = accumarray(FD.ix,FD.fraction,[numel(DEM.Z) 1],@(x) normfun(x,beta));
maxY = accumarray(FD.ix,FD.fraction,[numel(DEM.Z) 1],@(x) normfun2(x,beta));
FD.fraction = exp(beta.*log(FD.fraction) - maxY(FD.ix))./W(FD.ix);

end

end

function [sumw,maxy] = normfun(x,beta)
y = beta * log(x);
maxy = max(y);
y = y - maxy;
w = exp(y);
% w = w / sum(w);
sumw = sum(w);
end

function maxy = normfun2(x,beta)
y = beta * log(x);
maxy = max(y);
end
8 changes: 2 additions & 6 deletions toolbox/@GRIDobj/getcoordinates.m
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,6 @@
[x,y] = meshgrid(x,y);
case 'GRIDobj'
[x,y] = meshgrid(x,y);
X = GRIDobj(DEM);
X.Z = x;
Y = GRIDobj(DEM);
Y.Z = y;
x = X;
y = Y;
x = GRIDobj(DEM,x);
y = GRIDobj(DEM,y);
end
19 changes: 12 additions & 7 deletions toolbox/@GRIDobj/getoutline.m
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
%
%
% Author: Wolfgang Schwanghart (schwangh[at]uni-potsdam.de)
% Date: 30. May, 2024
% Date: 20. April, 2026


arguments (Input)
Expand All @@ -61,13 +61,14 @@
nnan = options.shownans && any(I);

if ~nnan
csh = DEM.cellsize/2;
[x,y] = getcoordinates(DEM);
maxx = max(x)+csh/2;
minx = min(x)-csh/2;

maxy = max(y)+csh/2;
miny = min(y)-csh/2;
[x,y] = getcoordinates(DEM);

csh = DEM.cellsize/2;
maxx = max(x)+csh;
minx = min(x)-csh;
maxy = max(y)+csh;
miny = min(y)-csh;

x = [minx minx maxx maxx minx];
y = [miny maxy maxy miny miny];
Expand All @@ -79,15 +80,19 @@
GT.Properties.VariableNames = {'Lat','Lon'};
GT = table2geotable(GT,"CoordinateReferenceSystem",DEM.georef.GeographicCRS,...
"GeometryType","polygon");
GT = removevars(GT,["Lat" "Lon"]);

elseif isProjected(DEM)
GT = table(x,y);
GT.Properties.VariableNames = {'X','Y'};
GT = table2geotable(GT,"CoordinateReferenceSystem",DEM.georef.ProjectedCRS,...
"GeometryType","polygon");
GT = removevars(GT,["X" "Y"]);
else
GT = table(x,y);
GT.Properties.VariableNames = {'X','Y'};
GT = table2geotable(GT,"GeometryType","polygon");
GT = removevars(GT,["X" "Y"]);

end
else
Expand Down
57 changes: 29 additions & 28 deletions toolbox/@GRIDobj/inpaintnans.m
Original file line number Diff line number Diff line change
Expand Up @@ -331,32 +331,33 @@
% DEMi GRIDobj with
%


I = isnan(DEM.Z);
sq2 = sqrt(2);
w = 1./[sq2 1 sq2; ...
1 0 1; ...
sq2 1 sq2];
w = w(:);

Z = nlfilter(DEM.Z,[3 3],@fun);
DEM.Z = Z;

function b = fun(a)

a = a(:);
if ~isnan(a(5))
b = a(5);
return
end

I = isnan(a);
if all(I)
b = nan;
return
end

I = ~I;
b = sum(a(I).*(w(I)./sum(w(I))));
end
DEM.Z = fillmissing2(DEM.Z,"movmean",3);

% I = isnan(DEM.Z);
% sq2 = sqrt(2);
% w = 1./[sq2 1 sq2; ...
% 1 0 1; ...
% sq2 1 sq2];
% w = w(:);
%
% Z = nlfilter(DEM.Z,[3 3],@fun);
% DEM.Z = Z;
%
% function b = fun(a)
%
% a = a(:);
% if ~isnan(a(5))
% b = a(5);
% return
% end
%
% I = isnan(a);
% if all(I)
% b = nan;
% return
% end
%
% I = ~I;
% b = sum(a(I).*(w(I)./sum(w(I))));
% end
end
36 changes: 24 additions & 12 deletions toolbox/@GRIDobj/pad.m
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@
% Input arguments
%
% DEM GRIDobj
% px amount of padding on each of the four edges of the grid.
% For px=1 the resulting size of DEMp is DEM.size+2.
% px scalar or 1x4 vector indicating the amount of padding on each
% of the four edges of the grid. For px=1 the resulting size of
% DEMp is DEM.size+2. If px is a vector, then elements indicate
% the amount of padding in [north south west east] direction.
% val pad value (default=0). This value does not have any effects
% if px<0.
%
Expand All @@ -46,18 +48,22 @@

arguments
DEM GRIDobj
px {mustBeNumeric} = 1
px (1,4) {mustBeNumeric} = 1
val {mustBeScalarOrEmpty} = 0
end

if px == 0
% If all px are zero, we can return the original GRIDobj
if all(px == 0)
return
end

px = sign(px)*ceil(abs(px));
% Make sure that we have integer values
px = sign(px).*ceil(abs(px));

% new size of output grid
newsize = DEM.size + px*2;
% px(1): north px(2):south px(3): west px(4): east
newsize = [DEM.size(1) + px(1) + px(2) ...
DEM.size(2) + px(3) + px(4)];

% check if size is negative and issue an error
if any(newsize < 0)
Expand All @@ -75,16 +81,22 @@
end

% transfer values to new array
if px>0
Znew(px+1:end-px,px+1:end-px) = DEM.Z;
elseif px<0
if all(px>0)
Znew(px(1)+1:end-px(2),px(3)+1:end-px(4)) = DEM.Z;
elseif all(px<0)
abspx = abs(px);
Znew = DEM.Z(abspx+1:end-abspx,abspx+1:end-abspx);
Znew = DEM.Z(abspx(1)+1:end-abspx(2),abspx(3)+1:end-abspx(4));
else
pxpos = max(px,0);
pxneg = -min(px,0);

Znew(pxpos(1)+1:end-pxpos(2),pxpos(3)+1:end-pxpos(4)) = ...
DEM.Z(pxneg(1)+1:end-pxneg(2),pxneg(3)+1:end-pxneg(4));
end

% adjust referencing
DEM.Z = Znew;
DEM.wf(:,3) = DEM.wf(:,3) -px.*[DEM.wf(1,1) DEM.wf(2,2)]';
DEM.wf(:,3) = DEM.wf(:,3) -[px(3) px(1)]'.*[DEM.wf(1,1) DEM.wf(2,2)]';
DEM.size = size(DEM.Z);

if ~isempty(DEM.georef)
Expand All @@ -106,7 +118,7 @@
case 'map.rasterref.MapCellsReference'
Rnew = maprasterref(DEM.wf,DEM.size,R.RasterInterpretation);
case 'map.rasterref.GeographicCellsReference'
Rnew = georasterref(DEM.wf,DEM.size,R.RasterInterpretation);
Rnew = georasterref(DEM.wf,DEM.size,R.RasterInterpretation);
end
end

Expand Down
2 changes: 1 addition & 1 deletion toolbox/@PPS/PPS.m
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@
elseif isa(PS,'geoshape')
lat = PS.Latitude;
lon = PS.Longitude;
[X1,Y1] = mfwdtran(P.S.georef.mstruct,lat,lon);
[X1,Y1] = projfwd(P.S.georef.ProjectedCRS,lat,lon);
end
[X,Y] = STREAMobj2XY(P.S);
[Xi,Yi] = polyxpoly(X1,Y1,X,Y);
Expand Down
3 changes: 3 additions & 0 deletions toolbox/@STREAMobj/crs.m
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,9 @@
% a special case. The stream network needs at least three nodes in a row. If
% there are less, the second derivative matrix is empty, and crs uses
% quantile carving instead
if isnan(options.mingradient)
options.mingradient = 0;
end
zs = quantcarve(S,z,options.tau,...
'split',options.split,...
'mingradient',options.mingradient,...
Expand Down
Loading