|
2 | 2 | This tool is part of the WhiteboxTools geospatial analysis library.
|
3 | 3 | Authors: Dr. John Lindsay
|
4 | 4 | Created: 28/06/2017
|
5 |
| -Last Modified: 18/10/2019 |
| 5 | +Last Modified: 26/10/2023 |
6 | 6 | License: MIT
|
7 | 7 |
|
8 | 8 | NOTES: This tool provides a full workflow D8 flow operation. This includes removing depressions, calculating
|
@@ -92,6 +92,15 @@ impl FlowAccumulationFullWorkflow {
|
92 | 92 | optional: true,
|
93 | 93 | });
|
94 | 94 |
|
| 95 | + parameters.push(ToolParameter { |
| 96 | + name: "Corrected flow pointer".to_owned(), |
| 97 | + flags: vec!["--correct_pntr".to_owned()], |
| 98 | + description: "Optional flag to apply corerections that limit potential artifacts in the flow pointer.".to_owned(), |
| 99 | + parameter_type: ParameterType::Boolean, |
| 100 | + default_value: None, |
| 101 | + optional: true, |
| 102 | + }); |
| 103 | + |
95 | 104 | parameters.push(ToolParameter {
|
96 | 105 | name: "Log-transform the output?".to_owned(),
|
97 | 106 | flags: vec!["--log".to_owned()],
|
@@ -183,6 +192,7 @@ impl WhiteboxTool for FlowAccumulationFullWorkflow {
|
183 | 192 | let mut pntr_file = String::new();
|
184 | 193 | let mut accum_file = String::new();
|
185 | 194 | let mut out_type = String::from("sca");
|
| 195 | + let mut correct_pntr = false; |
186 | 196 | let mut log_transform = false;
|
187 | 197 | let mut clip_max = false;
|
188 | 198 | let mut esri_style = false;
|
@@ -246,6 +256,10 @@ impl WhiteboxTool for FlowAccumulationFullWorkflow {
|
246 | 256 | } else {
|
247 | 257 | out_type = String::from("ca");
|
248 | 258 | }
|
| 259 | + } else if vec[0].to_lowercase() == "-correct_pntr" || vec[0].to_lowercase() == "--correct_pntr" { |
| 260 | + if vec.len() == 1 || !vec[1].to_string().to_lowercase().contains("false") { |
| 261 | + correct_pntr = true; |
| 262 | + } |
249 | 263 | } else if vec[0].to_lowercase() == "-log" || vec[0].to_lowercase() == "--log" {
|
250 | 264 | if vec.len() == 1 || !vec[1].to_string().to_lowercase().contains("false") {
|
251 | 265 | log_transform = true;
|
@@ -610,7 +624,128 @@ impl WhiteboxTool for FlowAccumulationFullWorkflow {
|
610 | 624 | Err(e) => return Err(e),
|
611 | 625 | };
|
612 | 626 |
|
613 |
| - // calculate the number of inflowing cells |
| 627 | + if correct_pntr { |
| 628 | + let (mut dir, mut dir_n, mut dir_no, mut new_val, mut old_val): (i8, i8, i8, i8, i8); |
| 629 | + let (mut l1, mut l2, mut r1, mut r2): (i8, i8, i8, i8); |
| 630 | + let (mut zl, mut zr, mut zn): (f64, f64, f64); |
| 631 | + let mut count: isize; |
| 632 | + let mut resolved: bool; |
| 633 | + for row in 1..(rows-1) { // buffer the edges |
| 634 | + for col in 1..(columns-1) { |
| 635 | + // flow_dir is the n-index of the flow revicing cell |
| 636 | + dir = flow_dir.get_value(row, col); |
| 637 | + old_val = dir; |
| 638 | + if dir >= 0 { |
| 639 | + // error 1: zig-zag where two flow directions intersect at 90deg angles |
| 640 | + // because scan order is top down, crosses should only occur on the bottom half |
| 641 | + l1 = dir + 7 - (8 * (dir + 7 > 7) as i8); |
| 642 | + r1 = dir + 1 - (8 * (dir + 1 > 7) as i8); |
| 643 | + l2 = r1 + 5 - (8 * (r1 + 5 > 7) as i8); |
| 644 | + r2 = l1 + 3 - (8 * (l1 + 3 > 7) as i8); |
| 645 | + dir_n = flow_dir.get_value(row + dy[l1 as usize], col + dx[l1 as usize]); // left |
| 646 | + zl = output.get_value(row + dy[l1 as usize], col + dx[l1 as usize]); |
| 647 | + dir_no = flow_dir.get_value(row + dy[r1 as usize], col + dx[r1 as usize]); // right |
| 648 | + zr = output.get_value(row + dy[r1 as usize], col + dx[r1 as usize]); |
| 649 | + zn = output.get_value(row + dy[dir as usize], col + dx[dir as usize]); |
| 650 | + if dir_n == r2 && zr != nodata && zr <= zn { // left -> right cross && not nodata && is lower |
| 651 | + new_val = r1; |
| 652 | + } else if dir_no == l2 && zl != nodata && zl <= zn { // right -> left cross && not nodata && is lower |
| 653 | + new_val = l1; |
| 654 | + } else { // keep original value |
| 655 | + new_val = dir; |
| 656 | + } |
| 657 | + |
| 658 | + if new_val != dir && new_val % 2 == 0 && [0,6,7].contains(&new_val) { // make sure new val doesn't create error 1 where it can't be corrected |
| 659 | + l1 = new_val + 7 - (8 * (new_val + 7 > 7) as i8); |
| 660 | + r1 = new_val + 1 - (8 * (new_val + 1 > 7) as i8); |
| 661 | + l2 = r1 + 5 - (8 * (r1 + 5 > 7) as i8); |
| 662 | + r2 = l1 + 3 - (8 * (l1 + 3 > 7) as i8); |
| 663 | + dir_n = flow_dir.get_value(row + dy[l1 as usize], col + dx[l1 as usize]); // left |
| 664 | + dir_no = flow_dir.get_value(row + dy[r1 as usize], col + dx[r1 as usize]); // right |
| 665 | + if dir_n == r2 || dir_no == l2 { // avoid new error, roll back |
| 666 | + new_val = old_val; |
| 667 | + } |
| 668 | + } |
| 669 | + |
| 670 | + // setting value here preserves solutions from error 1 but prevents this scan from beng parallelized |
| 671 | + flow_dir.set_value(row, col, new_val); |
| 672 | + |
| 673 | + // error 2: overshoot where flow points to a cell that points back into the original neighbourhood |
| 674 | + resolved = false; |
| 675 | + count = 0; |
| 676 | + dir = new_val; |
| 677 | + while !resolved && dir >= 0 { // search until outflow is found, else keep original value. |
| 678 | + // find the flow reviever n-index. |
| 679 | + dir_n = flow_dir.get_value(row + dy[dir as usize], col + dx[dir as usize]); |
| 680 | + if dir_n >= 0 { |
| 681 | + old_val = dir; // always set to the last valid direction |
| 682 | + |
| 683 | + // flow within these bounds flow back into the original neighbourhood. |
| 684 | + l1 = dir + 5 - (8 * (dir + 5 > 7) as i8); |
| 685 | + r1 = dir + 3 - (8 * (dir + 3 > 7) as i8); |
| 686 | + l2 = dir + 6 - (8 * (dir + 6 > 7) as i8); |
| 687 | + r2 = dir + 2 - (8 * (dir + 2 > 7) as i8); |
| 688 | + |
| 689 | + if dir % 2 == 0 { // diagonal |
| 690 | + if dir_n == l1 { |
| 691 | + new_val = r1 + 4 - (8 * (r1 + 4 > 7) as i8); |
| 692 | + } else if dir_n == r1 { |
| 693 | + new_val = l1 + 4 - (8 * (l1 + 4 > 7) as i8); |
| 694 | + } else { |
| 695 | + new_val = dir; |
| 696 | + resolved = true; |
| 697 | + } |
| 698 | + } else { // cardinal |
| 699 | + if dir_n == l1 { |
| 700 | + new_val = r2 + 4 - (8 * (r2 + 4 > 7) as i8); |
| 701 | + } else if dir_n == r1 { |
| 702 | + new_val = l2 + 4 - (8 * (l2 + 4 > 7) as i8); |
| 703 | + } else if dir_n == l2 { |
| 704 | + new_val = r1 + 4 - (8 * (r1 + 4 > 7) as i8); |
| 705 | + } else if dir_n == r2 { |
| 706 | + new_val = l1 + 4 - (8 * (l1 + 4 > 7) as i8); |
| 707 | + } else { |
| 708 | + new_val = dir; |
| 709 | + resolved = true; |
| 710 | + }; |
| 711 | + } |
| 712 | + |
| 713 | + if new_val != dir && new_val % 2 == 0 && [0,6,7].contains(&new_val) { // make sure new val doesn't create error 1 where it can't be corrected |
| 714 | + l1 = new_val + 7 - (8 * (new_val + 7 > 7) as i8); |
| 715 | + r1 = new_val + 1 - (8 * (new_val + 1 > 7) as i8); |
| 716 | + l2 = r1 + 5 - (8 * (r1 + 5 > 7) as i8); |
| 717 | + r2 = l1 + 3 - (8 * (l1 + 3 > 7) as i8); |
| 718 | + dir_n = flow_dir.get_value(row + dy[l1 as usize], col + dx[l1 as usize]); // left |
| 719 | + dir_no = flow_dir.get_value(row + dy[r1 as usize], col + dx[r1 as usize]); // right |
| 720 | + if dir_n == r2 || dir_no == l2 { // roll back |
| 721 | + new_val = old_val; |
| 722 | + resolved = true; |
| 723 | + } |
| 724 | + } |
| 725 | + } else { // roll back |
| 726 | + new_val = old_val; |
| 727 | + resolved = true; |
| 728 | + } |
| 729 | + if count > 7 { // stuck in a loop, use original flow_dir |
| 730 | + new_val = flow_dir.get_value(row, col); |
| 731 | + resolved = true; |
| 732 | + } |
| 733 | + dir = new_val; |
| 734 | + count += 1; |
| 735 | + } |
| 736 | + flow_dir.set_value(row, col, new_val); |
| 737 | + } |
| 738 | + } |
| 739 | + if verbose { |
| 740 | + progress = (100.0_f64 * row as f64 / (rows - 1) as f64) as usize; |
| 741 | + if progress != old_progress { |
| 742 | + println!("Correcting flow direction: {}%", progress); |
| 743 | + old_progress = progress; |
| 744 | + } |
| 745 | + } |
| 746 | + } |
| 747 | + } |
| 748 | + |
614 | 749 | let flow_dir = Arc::new(flow_dir);
|
615 | 750 | let mut num_inflowing: Array2D<i8> = Array2D::new(rows, columns, -1, -1)?;
|
616 | 751 |
|
|
0 commit comments