Skip to content

Commit c89fe4c

Browse files
committed
Updates to add feature for issue #63
Updates to add feature for issue #63
1 parent b0c3471 commit c89fe4c

8 files changed

Lines changed: 456 additions & 245 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
[package]
33
name = "whitebox_tools"
4-
version = "1.1.1"
4+
version = "1.2.0"
55
authors = ["John Lindsay <jlindsay@uoguelph.ca>"]
66
description = "A library for analyzing geospatial data."
77
keywords = ["geospatial", "GIS", "remote sensing", "geomatics", "image processing", "lidar", "spatial analysis"]

readme.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ Version 1.1.1 (XX-XX-20XX)
7777
- The watershed tool now accepts either a set of vector points or a raster for the pour points
7878
file. If a raster is specified, all non-zero, non-NoData valued cells will be considered
7979
outlet cells and the watershed labels will be assigned based on these values.
80+
- The D8 and D-infinity flow accumulation tools now take either an input DEM or a flow pointer raster
81+
as inputs.
8082

8183
Version 1.1.0 (09-12-2019)
8284
- Added the BreachDepressionsLeastCost tool, which performs a modified form of the Lindsay

src/tools/hydro_analysis/d8_flow_accum.rs

Lines changed: 218 additions & 102 deletions
Large diffs are not rendered by default.

src/tools/hydro_analysis/dinf_flow_accum.rs

Lines changed: 139 additions & 120 deletions
Large diffs are not rendered by default.

src/tools/hydro_analysis/fd8_flow_accum.rs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
This tool is part of the WhiteboxTools geospatial analysis library.
33
Authors: Dr. John Lindsay
44
Created: 26/06/2017
5-
Last Modified: 21/11/2019
5+
Last Modified: 21/02/2020
66
License: MIT
77
*/
88

@@ -317,9 +317,15 @@ impl WhiteboxTool for FD8FlowAccumulation {
317317
let cell_size_y = input.configs.resolution_y;
318318
let diag_cell_size = (cell_size_x * cell_size_x + cell_size_y * cell_size_y).sqrt();
319319

320-
// calculate the number of inflowing cells
320+
let mut output = Raster::initialize_using_file(&output_file, &input);
321+
output.reinitialize_values(1.0);
322+
let mut stack = Vec::with_capacity((rows * columns) as usize);
323+
let mut num_solved_cells = 0;
324+
let mut interior_pit_found = false;
321325
let mut num_inflowing: Array2D<i8> = Array2D::new(rows, columns, -1, -1)?;
322326
let num_procs = num_cpus::get() as isize;
327+
328+
// calculate the number of inflowing cells
323329
let (tx, rx) = mpsc::channel();
324330
for tid in 0..num_procs {
325331
let input = input.clone();
@@ -328,16 +334,18 @@ impl WhiteboxTool for FD8FlowAccumulation {
328334
let d_x = [1, 1, 1, 0, -1, -1, -1, 0];
329335
let d_y = [-1, 0, 1, 1, 1, 0, -1, -1];
330336
let mut z: f64;
337+
let mut zn: f64;
331338
let mut count: i8;
332339
let mut interior_pit_found = false;
333340
for row in (0..rows).filter(|r| r % num_procs == tid) {
334341
let mut data: Vec<i8> = vec![-1i8; columns as usize];
335342
for col in 0..columns {
336-
z = input[(row, col)];
343+
z = input.get_value(row, col);
337344
if z != nodata {
338345
count = 0i8;
339346
for i in 0..8 {
340-
if input[(row + d_y[i], col + d_x[i])] > z {
347+
zn = input.get_value(row + d_y[i], col + d_x[i]);
348+
if zn > z && zn != nodata {
341349
count += 1;
342350
}
343351
}
@@ -352,11 +360,6 @@ impl WhiteboxTool for FD8FlowAccumulation {
352360
});
353361
}
354362

355-
let mut output = Raster::initialize_using_file(&output_file, &input);
356-
output.reinitialize_values(1.0);
357-
let mut stack = Vec::with_capacity((rows * columns) as usize);
358-
let mut num_solved_cells = 0;
359-
let mut interior_pit_found = false;
360363
for r in 0..rows {
361364
let (row, data, pit) = rx.recv().expect("Error receiving data from thread.");
362365
num_inflowing.set_row_data(row, data);

src/tools/hydro_analysis/insert_dams.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
This tool is part of the WhiteboxTools geospatial analysis library.
33
Authors: Dr. John Lindsay
44
Created: 19/02/2020
5-
Last Modified: 19/02/2020
5+
Last Modified: 20/02/2020
66
License: MIT
77
*/
88

@@ -251,10 +251,11 @@ impl WhiteboxTool for InsertDams {
251251
let (mut target_row, mut target_col): (isize, isize);
252252
let mut profile_intersects_target: bool;
253253
let mut max_dam_height: f64;
254+
let mut dam_z: f64;
254255
let mut target_cell: usize;
255256
let (mut dam_row, mut dam_col): (isize, isize);
256257
let mut dam_dir: usize;
257-
let mut best_dam_profile_filled = vec![0f64; dam_profile_length];
258+
let mut best_dam_profile_filled: Vec<f64>; // = vec![0f64; dam_profile_length];
258259
/* Calculate dam heights
259260
Each cell will be assigned the altitude (ASL) of the highest dam that
260261
passes through the cell. Potential dams are calculated for each
@@ -264,14 +265,18 @@ impl WhiteboxTool for InsertDams {
264265
let record = dam_pts.get_record(record_num);
265266
target_row = input.get_row_from_y(record.points[0].y);
266267
target_col = input.get_column_from_x(record.points[0].x);
268+
dam_z = input.get_value(target_row, target_col);
267269
dam_row = 0;
268270
dam_col = 0;
269271
dam_dir = 0;
270272
max_dam_height = f64::MIN;
273+
// dam_z = f64::MIN;
274+
best_dam_profile_filled = vec![0f64; dam_profile_length];
271275
for row in (target_row-half_dam_length as isize)..=(target_row+half_dam_length as isize) {
272276
for col in (target_col-half_dam_length as isize)..=(target_col+half_dam_length as isize) {
273277
z = input.get_value(row, col);
274278
if z != nodata {
279+
// dam_z = z;
275280
for dir in 0..4 {
276281
profile_intersects_target = false;
277282
target_cell = 0;
@@ -350,7 +355,7 @@ impl WhiteboxTool for InsertDams {
350355
}
351356
}
352357

353-
if max_dam_height > f64::MIN {
358+
if max_dam_height > f64::MIN && max_dam_height > dam_z {
354359
// perform the actual damming
355360
perp_dir1 = perpendicular1[dam_dir];
356361
perp_dir2 = perpendicular2[dam_dir];
@@ -419,7 +424,10 @@ impl WhiteboxTool for InsertDams {
419424
}
420425
}
421426
} else {
422-
// Error: no dam was found that covered the point
427+
// No dam was found that covered the point
428+
if verbose {
429+
println!("Warning: No dam could be identified for Point {} due to its position in non-impoundable terrain.", record_num+1);
430+
}
423431
}
424432

425433
if verbose {

whitebox_tools.py

Lines changed: 71 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,7 @@ def list_tools(self, keywords=[]):
382382

383383

384384

385+
385386

386387

387388
##############
@@ -648,6 +649,20 @@ def raster_to_vector_points(self, i, output, callback=None):
648649
args.append("--output='{}'".format(output))
649650
return self.run_tool('raster_to_vector_points', args, callback) # returns 1 if error
650651

652+
def raster_to_vector_polygons(self, i, output, callback=None):
653+
"""Converts a raster dataset to a vector of the POLYGON shapetype.
654+
655+
Keyword arguments:
656+
657+
i -- Input raster file.
658+
output -- Output vector polygons file.
659+
callback -- Custom function for handling tool text outputs.
660+
"""
661+
args = []
662+
args.append("--input='{}'".format(i))
663+
args.append("--output='{}'".format(output))
664+
return self.run_tool('raster_to_vector_polygons', args, callback) # returns 1 if error
665+
651666
def reinitialize_attribute_table(self, i, callback=None):
652667
"""Reinitializes a vector's attribute table deleting all fields but the feature ID (FID).
653668
@@ -3372,24 +3387,28 @@ def burn_streams_at_roads(self, dem, streams, roads, output, width=None, callbac
33723387
if width is not None: args.append("--width='{}'".format(width))
33733388
return self.run_tool('burn_streams_at_roads', args, callback) # returns 1 if error
33743389

3375-
def d8_flow_accumulation(self, dem, output, out_type="cells", log=False, clip=False, callback=None):
3376-
"""Calculates a D8 flow accumulation raster from an input DEM.
3390+
def d8_flow_accumulation(self, i, output, out_type="cells", log=False, clip=False, pntr=False, esri_pntr=False, callback=None):
3391+
"""Calculates a D8 flow accumulation raster from an input DEM or flow pointer.
33773392
33783393
Keyword arguments:
33793394
3380-
dem -- Input raster DEM file.
3395+
i -- Input raster DEM or D8 pointer file.
33813396
output -- Output raster file.
33823397
out_type -- Output type; one of 'cells' (default), 'catchment area', and 'specific contributing area'.
33833398
log -- Optional flag to request the output be log-transformed.
33843399
clip -- Optional flag to request clipping the display max by 1%.
3400+
pntr -- Is the input raster a D8 flow pointer rather than a DEM?.
3401+
esri_pntr -- Input D8 pointer uses the ESRI style scheme.
33853402
callback -- Custom function for handling tool text outputs.
33863403
"""
33873404
args = []
3388-
args.append("--dem='{}'".format(dem))
3405+
args.append("--input='{}'".format(i))
33893406
args.append("--output='{}'".format(output))
33903407
args.append("--out_type={}".format(out_type))
33913408
if log: args.append("--log")
33923409
if clip: args.append("--clip")
3410+
if pntr: args.append("--pntr")
3411+
if esri_pntr: args.append("--esri_pntr")
33933412
return self.run_tool('d8_flow_accumulation', args, callback) # returns 1 if error
33943413

33953414
def d8_mass_flux(self, dem, loading, efficiency, absorption, output, callback=None):
@@ -3428,26 +3447,28 @@ def d8_pointer(self, dem, output, esri_pntr=False, callback=None):
34283447
if esri_pntr: args.append("--esri_pntr")
34293448
return self.run_tool('d8_pointer', args, callback) # returns 1 if error
34303449

3431-
def d_inf_flow_accumulation(self, dem, output, out_type="Specific Contributing Area", threshold=None, log=False, clip=False, callback=None):
3450+
def d_inf_flow_accumulation(self, i, output, out_type="Specific Contributing Area", threshold=None, log=False, clip=False, pntr=False, callback=None):
34323451
"""Calculates a D-infinity flow accumulation raster from an input DEM.
34333452
34343453
Keyword arguments:
34353454
3436-
dem -- Input raster DEM file.
3455+
i -- Input raster DEM or D-infinity pointer file.
34373456
output -- Output raster file.
34383457
out_type -- Output type; one of 'cells', 'sca' (default), and 'ca'.
34393458
threshold -- Optional convergence threshold parameter, in grid cells; default is inifinity.
34403459
log -- Optional flag to request the output be log-transformed.
34413460
clip -- Optional flag to request clipping the display max by 1%.
3461+
pntr -- Is the input raster a D8 flow pointer rather than a DEM?.
34423462
callback -- Custom function for handling tool text outputs.
34433463
"""
34443464
args = []
3445-
args.append("--dem='{}'".format(dem))
3465+
args.append("--input='{}'".format(i))
34463466
args.append("--output='{}'".format(output))
34473467
args.append("--out_type={}".format(out_type))
34483468
if threshold is not None: args.append("--threshold='{}'".format(threshold))
34493469
if log: args.append("--log")
34503470
if clip: args.append("--clip")
3471+
if pntr: args.append("--pntr")
34513472
return self.run_tool('d_inf_flow_accumulation', args, callback) # returns 1 if error
34523473

34533474
def d_inf_mass_flux(self, dem, loading, efficiency, absorption, output, callback=None):
@@ -3830,6 +3851,24 @@ def impoundment_size_index(self, dem, output, damlength, out_type="depth", callb
38303851
args.append("--damlength='{}'".format(damlength))
38313852
return self.run_tool('impoundment_size_index', args, callback) # returns 1 if error
38323853

3854+
def insert_dams(self, dem, dam_pts, output, damlength, callback=None):
3855+
"""Calculates the impoundment size resulting from damming a DEM.
3856+
3857+
Keyword arguments:
3858+
3859+
dem -- Input raster DEM file.
3860+
dam_pts -- Input vector dam points file.
3861+
output -- Output file.
3862+
damlength -- Maximum length of the dam.
3863+
callback -- Custom function for handling tool text outputs.
3864+
"""
3865+
args = []
3866+
args.append("--dem='{}'".format(dem))
3867+
args.append("--dam_pts='{}'".format(dam_pts))
3868+
args.append("--output='{}'".format(output))
3869+
args.append("--damlength='{}'".format(damlength))
3870+
return self.run_tool('insert_dams', args, callback) # returns 1 if error
3871+
38333872
def isobasins(self, dem, output, size, callback=None):
38343873
"""Divides a landscape into nearly equal sized drainage basins (i.e. watersheds).
38353874
@@ -3894,6 +3933,30 @@ def max_upslope_flowpath_length(self, dem, output, callback=None):
38943933
args.append("--output='{}'".format(output))
38953934
return self.run_tool('max_upslope_flowpath_length', args, callback) # returns 1 if error
38963935

3936+
def md_inf_flow_accumulation(self, dem, output, out_type="specific contributing area", exponent=1.1, threshold=None, log=False, clip=False, callback=None):
3937+
"""Calculates an FD8 flow accumulation raster from an input DEM.
3938+
3939+
Keyword arguments:
3940+
3941+
dem -- Input raster DEM file.
3942+
output -- Output raster file.
3943+
out_type -- Output type; one of 'cells', 'specific contributing area' (default), and 'catchment area'.
3944+
exponent -- Optional exponent parameter; default is 1.1.
3945+
threshold -- Optional convergence threshold parameter, in grid cells; default is inifinity.
3946+
log -- Optional flag to request the output be log-transformed.
3947+
clip -- Optional flag to request clipping the display max by 1%.
3948+
callback -- Custom function for handling tool text outputs.
3949+
"""
3950+
args = []
3951+
args.append("--dem='{}'".format(dem))
3952+
args.append("--output='{}'".format(output))
3953+
args.append("--out_type={}".format(out_type))
3954+
args.append("--exponent={}".format(exponent))
3955+
if threshold is not None: args.append("--threshold='{}'".format(threshold))
3956+
if log: args.append("--log")
3957+
if clip: args.append("--clip")
3958+
return self.run_tool('md_inf_flow_accumulation', args, callback) # returns 1 if error
3959+
38973960
def num_inflowing_neighbours(self, dem, output, callback=None):
38983961
"""Computes the number of inflowing neighbours to each cell in an input DEM based on the D8 algorithm.
38993962
@@ -4092,7 +4155,7 @@ def watershed(self, d8_pntr, pour_pts, output, esri_pntr=False, callback=None):
40924155
Keyword arguments:
40934156
40944157
d8_pntr -- Input D8 pointer raster file.
4095-
pour_pts -- Input vector pour points (outlet) file.
4158+
pour_pts -- Input pour points (outlet) file.
40964159
output -- Output raster file.
40974160
esri_pntr -- D8 pointer uses the ESRI style scheme.
40984161
callback -- Custom function for handling tool text outputs.

0 commit comments

Comments
 (0)