Thursday, 22 November 2018

arcgis desktop - Integrating Whitebox GAT (free and open) with ArcMap UI?



Whitebox Geospatial Analysis Tools


I wrote a number of ArcGIS VBA automations in grad school; however, they're fully dependent on the ArcGIS Spatial Analyst extension, which is not only closed-source but expensive to the point of deterrence.


Since VBA is deprecated and since some researchers at the U still use my VBA tools, I thought it would be fun to rewrite them in .Net. But now, with more experience, I further realize it would be more appropriate for academic use if those utilities consumed open algorithms.


With this in mind, I'm considering Whitebox GAT as a potential stand-in for the Spatial Analyst hydrology tools, and I'm curious if there are any success stories or time-saving "gotchas" related to ArcGIS/Whitebox integration.


I anticipate several folks will want to counter-suggest implementing Saga, GRASS, R, et cetera. If this is your position, please describe why pursuing a Whitebox integration would be unwise. For example, does it only support a few input formats, has it poor handling of large (1-2 GB+) files, etc.




I did some playing around with the Whitebox UI, and with the help of their tutorials, it wasn't difficult to pre-process a 30-meter DEM I had laying around. Next, after lining-up the hydro rasters, I created a pour point and rendered its watershed. This was enough to get a feel for the Whitebox user experience.


Whitebox is extendable and/or consumable using .Net or Python. Having accomplished some basics in the Whitebox UI, I thought I'd chain together the typical DEM pre-processing tasks with a simple .Net automation (no ArcMap just yet). DEM pre-processing usually means the following:




  1. set no data value (Whitebox needs this, but Arc never did)

  2. fill sinks

  3. create a flow direction raster

  4. create a flow accumulation raster


I put together the following Windows Form "application" (aka WhiteboxDaisyChain). It takes a system directory containing an ArcGIS Grid (.FLT) and performs the tasks noted above. If you want to try this, you'll need to download the compiled binaries, unzip, then copy all the .dll files from ..\WhiteboxGAT_1_0_7\Plugins into your project -- I put everything in ..\WhiteboxDaisyChain\Whitebox. However, this example only needs the four DLLs mentioned at the top of the code sample.




using System;
using System.Collections.Generic;
using System.ComponentModel;

using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

// 1) Create a new Windows Form
// 2) Put all these in a Whitebox folder in the C# project root.
// 3) Add project references to the following and create using statements:


using Interfaces; // requires Add Reference: Interfaces.dll
using ImportExport; // requires Add Reference: ImportExport.dll
using ConversionTools; // requires Add Reference: ConversionTools.dll
using flow; // requires Add Reference: flow.dll


namespace WhiteboxDaisyChain
{
// 4) Prepare to implement the IHost interface.
// 5) Right-click IHost, select "Implement interface.."

public partial class UI : Form, IHost
{

// 6) Add a BackgroundWorker object.
private BackgroundWorker worker;

public UI()
{
InitializeComponent();


// 7) Instantiate the worker and set "WorkerReportsProgress".
worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
}


// 8) Use some event to set things in motion.. i.e. Button click.
private void button1_Click(object sender, EventArgs e)
{
progressLabel.Text = "Running..";


// This is the path containing my ArcGrid .FLT.
// All processing will unfold to this directory.
string path = "C:\\xData\\TutorialData\\DemWhitebox\\";

string[] fltArgs = new string[1];
fltArgs[0] = path + "greene30.flt"; // in: Arc floating point grid

// creates a raster in Whitebox data model
ImportArcGrid importAG = new ImportArcGrid();

importAG.Initialize(this as IHost);
importAG.Execute(fltArgs, worker); // out: path + "greene30.dep"

// set the nodata value on the DEM
string[] noDataArgs = new string[2];
noDataArgs[0] = path + "greene30.dep"; // in: my raw DEM
noDataArgs[1] = "-9999"; // mine used -9999 as nodata value

SetNoData setNoData = new SetNoData();
setNoData.Initialize(this as IHost);

setNoData.Execute(noDataArgs, worker); // out: path + "greene30.dep"

// fill sinks in the DEM
string[] fillSinksArgs = new string[4];
fillSinksArgs[0] = path + "greene30.dep"; // in: my DEM with NoData Fixed
fillSinksArgs[1] = path + "greene30_fill.dep"; // out: my DEM filled
fillSinksArgs[2] = "50"; // the dialog default
fillSinksArgs[3] = "0.01"; // the dialog default

FillDepsBySize fillSinks = new FillDepsBySize();

fillSinks.Initialize(this as IHost);
fillSinks.Execute(fillSinksArgs, worker);

// create a flow direction raster
string[] flowDirArgs = new string[2];
flowDirArgs[0] = path + "greene30_fill.dep"; // in: my Filled DEM
flowDirArgs[1] = path + "greene30_dir.dep"; // out: flow direction raster

FlowPointerD8 flowDirD8 = new FlowPointerD8();
flowDirD8.Initialize(this as IHost);

flowDirD8.Execute(flowDirArgs, worker);

// create a flow accumulation raster
string[] flowAccArgs = new string[4];
flowAccArgs[0] = path + "greene30_dir.dep"; // in: my Flow Direction raster
flowAccArgs[1] = path + "greene30_acc.dep"; // out: flow accumulation raster
flowAccArgs[2] = "Specific catchment area (SCA)"; // a Whitebox dialog input
flowAccArgs[3] = "false"; // a Whitebox dialog input

FlowAccumD8 flowAccD8 = new FlowAccumD8();

flowAccD8.Initialize(this as IHost);
flowAccD8.Execute(flowAccArgs, worker);

progressLabel.Text = "";
progressLabel.Text = "OLLEY-OLLEY-OXEN-FREE!";
}



/* IHost Implementation Methods Below Here */


public string ApplicationDirectory
{
get { throw new NotImplementedException(); }
}

public void ProgressBarLabel(string label)
{
this.progressLabel.Text = "";
this.progressLabel.Text = label; // This is the only one I used.

}

public string RecentDirectory
{
get
{
throw new NotImplementedException();
}
set
{

throw new NotImplementedException();
}
}

public bool RunInSynchronousMode
{
get
{
throw new NotImplementedException();
}

set
{
throw new NotImplementedException();
}
}

public void RunPlugin(string PluginClassName)
{
throw new NotImplementedException();
}


public void SetParameters(string[] ParameterArray)
{
throw new NotImplementedException();
}

public void ShowFeedback(string strFeedback, string Caption = "GAT Message")
{
throw new NotImplementedException();
}

}
}

So far I'm digging this, but I don't yet have a real success story or any show-stoppers to describe.. My next goal will be interactively submitting pour points from ArcMap. Basically, I want to click the map ..get the watershed.




No comments:

Post a Comment

arcpy - Changing output name when exporting data driven pages to JPG?

Is there a way to save the output JPG, changing the output file name to the page name, instead of page number? I mean changing the script fo...