diff --git a/WBT/PRE/WhiteboxTools.py b/WBT/PRE/WhiteboxTools.py index a165241..3c9ddf0 100644 --- a/WBT/PRE/WhiteboxTools.py +++ b/WBT/PRE/WhiteboxTools.py @@ -174,6 +174,7 @@ tool_labels.append("Horizon Angle") tool_labels.append("Horton Stream Order") tool_labels.append("Hypsometric Analysis") +tool_labels.append("Hypsometrically Tinted Hillshade") tool_labels.append("Idw Interpolation") tool_labels.append("Ihs To Rgb") tool_labels.append("Image Autocorrelation") @@ -229,6 +230,7 @@ tool_labels.append("Lidar Rbf Interpolation") tool_labels.append("Lidar Remove Duplicates") tool_labels.append("Lidar Remove Outliers") +tool_labels.append("Lidar Rooftop Analysis") tool_labels.append("Lidar Segmentation") tool_labels.append("Lidar Segmentation Based Filter") tool_labels.append("Lidar Thin") @@ -286,6 +288,7 @@ tool_labels.append("Mosaic") tool_labels.append("Mosaic With Feathering") tool_labels.append("Multi Part To Single Part") +tool_labels.append("Multidirectional Hillshade") tool_labels.append("Multiply") tool_labels.append("Multiscale Elevation Percentile") tool_labels.append("Multiscale Roughness") @@ -603,6 +606,7 @@ def __init__(self): tools.append(Hillshade) tools.append(HorizonAngle) tools.append(HypsometricAnalysis) + tools.append(HypsometricallyTintedHillshade) tools.append(MaxAnisotropyDev) tools.append(MaxAnisotropyDevSignature) tools.append(MaxBranchLength) @@ -611,6 +615,7 @@ def __init__(self): tools.append(MaxElevDevSignature) tools.append(MaxElevationDeviation) tools.append(MinDownslopeElevChange) + tools.append(MultidirectionalHillshade) tools.append(MultiscaleElevationPercentile) tools.append(MultiscaleRoughness) tools.append(MultiscaleRoughnessSignature) @@ -792,6 +797,7 @@ def __init__(self): tools.append(LidarRbfInterpolation) tools.append(LidarRemoveDuplicates) tools.append(LidarRemoveOutliers) + tools.append(LidarRooftopAnalysis) tools.append(LidarSegmentation) tools.append(LidarSegmentationBasedFilter) tools.append(LidarThin) @@ -10745,6 +10751,145 @@ def execute(self, parameters, messages): return +class HypsometricallyTintedHillshade(object): + def __init__(self): + self.label = "Hypsometrically Tinted Hillshade" + self.description = "Creates an colour shaded relief image from an input DEM. View detailed help documentation on WhiteboxTools User Manual and source code on GitHub." + self.category = "Geomorphometric Analysis" + + def getParameterInfo(self): + dem = arcpy.Parameter( + displayName="Input DEM File", + name="dem", + datatype="GPRasterLayer", + parameterType="Required", + direction="Input") + + output = arcpy.Parameter( + displayName="Output File", + name="output", + datatype="DEFile", + parameterType="Required", + direction="Output") + output.filter.list = ["tif"] + + altitude = arcpy.Parameter( + displayName="Illumination Source Altitude (degrees)", + name="altitude", + datatype="GPDouble", + parameterType="Optional", + direction="Input") + + altitude.value = "45.0" + + hs_weight = arcpy.Parameter( + displayName="Hillshade Weight", + name="hs_weight", + datatype="GPDouble", + parameterType="Optional", + direction="Input") + + hs_weight.value = "0.5" + + brightness = arcpy.Parameter( + displayName="Brightness", + name="brightness", + datatype="GPDouble", + parameterType="Optional", + direction="Input") + + brightness.value = "0.5" + + atmospheric = arcpy.Parameter( + displayName="Atmospheric Effects", + name="atmospheric", + datatype="GPDouble", + parameterType="Optional", + direction="Input") + + atmospheric.value = "0.0" + + palette = arcpy.Parameter( + displayName="Palette", + name="palette", + datatype="GPString", + parameterType="Optional", + direction="Input") + palette.filter.type = "ValueList" + palette.filter.list = ['atlas', 'high_relief', 'arid', 'soft', 'muted', 'purple', 'viridi', 'gn_yl', 'pi_y_g', 'bl_yl_rd', 'deep'] + + palette.value = "atlas" + + reverse = arcpy.Parameter( + displayName="Reverse palette?", + name="reverse", + datatype="GPBoolean", + parameterType="Optional", + direction="Input") + + reverse.value = False + + zfactor = arcpy.Parameter( + displayName="Z Conversion Factor", + name="zfactor", + datatype="GPDouble", + parameterType="Optional", + direction="Input") + + zfactor.value = "1.0" + + full_mode = arcpy.Parameter( + displayName="Full 360-degree hillshade mode?", + name="full_mode", + datatype="GPBoolean", + parameterType="Optional", + direction="Input") + + full_mode.value = False + + params = [dem, output, altitude, hs_weight, brightness, atmospheric, palette, reverse, zfactor, full_mode] + + return params + + def updateParameters(self, parameters): + return + + def updateMessages(self, parameters): + for param in parameters: + param_str = param.valueAsText + if param_str is not None: + try: + desc = arcpy.Describe(param_str) + if (".gdb\\" in desc.catalogPath) or (".mdb\\" in desc.catalogPath): + param.setErrorMessage("Datasets stored in a Geodatabase are not supported.") + except: + param.clearMessage() + return + + def execute(self, parameters, messages): + dem = parameters[0].valueAsText + if dem is not None: + desc = arcpy.Describe(dem) + dem = desc.catalogPath + output = parameters[1].valueAsText + altitude = parameters[2].valueAsText + hs_weight = parameters[3].valueAsText + brightness = parameters[4].valueAsText + atmospheric = parameters[5].valueAsText + palette = parameters[6].valueAsText + reverse = parameters[7].valueAsText + zfactor = parameters[8].valueAsText + full_mode = parameters[9].valueAsText + old_stdout = sys.stdout + result = StringIO() + sys.stdout = result + wbt.hypsometrically_tinted_hillshade(dem=dem, output=output, altitude=altitude, hs_weight=hs_weight, brightness=brightness, atmospheric=atmospheric, palette=palette, reverse=reverse, zfactor=zfactor, full_mode=full_mode) + sys.stdout = old_stdout + result_string = result.getvalue() + messages.addMessage(result_string) + return + + class MaxAnisotropyDev(object): def __init__(self): self.label = "Max Anisotropy Dev" @@ -11394,6 +11539,93 @@ def execute(self, parameters, messages): return +class MultidirectionalHillshade(object): + def __init__(self): + self.label = "Multidirectional Hillshade" + self.description = "Calculates a multi-direction hillshade raster from an input DEM. View detailed help documentation on WhiteboxTools User Manual and source code on GitHub." + self.category = "Geomorphometric Analysis" + + def getParameterInfo(self): + dem = arcpy.Parameter( + displayName="Input DEM File", + name="dem", + datatype="GPRasterLayer", + parameterType="Required", + direction="Input") + + output = arcpy.Parameter( + displayName="Output File", + name="output", + datatype="DEFile", + parameterType="Required", + direction="Output") + output.filter.list = ["tif"] + + altitude = arcpy.Parameter( + displayName="Altitude (degrees)", + name="altitude", + datatype="GPDouble", + parameterType="Optional", + direction="Input") + + altitude.value = "45.0" + + zfactor = arcpy.Parameter( + displayName="Z Conversion Factor", + name="zfactor", + datatype="GPDouble", + parameterType="Optional", + direction="Input") + + zfactor.value = "1.0" + + full_mode = arcpy.Parameter( + displayName="Full 360-degree mode?", + name="full_mode", + datatype="GPBoolean", + parameterType="Optional", + direction="Input") + + full_mode.value = False + + params = [dem, output, altitude, zfactor, full_mode] + + return params + + def updateParameters(self, parameters): + return + + def updateMessages(self, parameters): + for param in parameters: + param_str = param.valueAsText + if param_str is not None: + try: + desc = arcpy.Describe(param_str) + if (".gdb\\" in desc.catalogPath) or (".mdb\\" in desc.catalogPath): + param.setErrorMessage("Datasets stored in a Geodatabase are not supported.") + except: + param.clearMessage() + return + + def execute(self, parameters, messages): + dem = parameters[0].valueAsText + if dem is not None: + desc = arcpy.Describe(dem) + dem = desc.catalogPath + output = parameters[1].valueAsText + altitude = parameters[2].valueAsText + zfactor = parameters[3].valueAsText + full_mode = parameters[4].valueAsText + old_stdout = sys.stdout + result = StringIO() + sys.stdout = result + wbt.multidirectional_hillshade(dem=dem, output=output, altitude=altitude, zfactor=zfactor, full_mode=full_mode) + sys.stdout = old_stdout + result_string = result.getvalue() + messages.addMessage(result_string) + return + + class MultiscaleElevationPercentile(object): def __init__(self): self.label = "Multiscale Elevation Percentile" @@ -25557,6 +25789,163 @@ def execute(self, parameters, messages): return +class LidarRooftopAnalysis(object): + def __init__(self): + self.label = "Lidar Rooftop Analysis" + self.description = "Identifies roof segments in a LiDAR point cloud. View detailed help documentation on WhiteboxTools User Manual and source code on GitHub." + self.category = "LiDAR Tools" + + def getParameterInfo(self): + i = arcpy.Parameter( + displayName="Input File", + name="i", + datatype="DEFile", + parameterType="Optional", + direction="Input") + i.filter.list = ["las", "zip"] + + buildings = arcpy.Parameter( + displayName="Input Building Footprint Polygon File", + name="buildings", + datatype="GPFeatureLayer", + parameterType="Required", + direction="Input") + buildings.filter.list = ["Polygon"] + + output = arcpy.Parameter( + displayName="Output Polygon File", + name="output", + datatype="DEShapefile", + parameterType="Required", + direction="Output") + output.filter.list = ["Polygon"] + + radius = arcpy.Parameter( + displayName="Search Radius", + name="radius", + datatype="GPDouble", + parameterType="Optional", + direction="Input") + + radius.value = "2.0" + + num_iter = arcpy.Parameter( + displayName="Number of Iterations", + name="num_iter", + datatype="GPLong", + parameterType="Optional", + direction="Input") + + num_iter.value = "50" + + num_samples = arcpy.Parameter( + displayName="Number of Sample Points", + name="num_samples", + datatype="GPLong", + parameterType="Optional", + direction="Input") + + num_samples.value = "10" + + threshold = arcpy.Parameter( + displayName="Inlier Threshold", + name="threshold", + datatype="GPDouble", + parameterType="Optional", + direction="Input") + + threshold.value = "0.15" + + model_size = arcpy.Parameter( + displayName="Acceptable Model Size", + name="model_size", + datatype="GPLong", + parameterType="Optional", + direction="Input") + + model_size.value = "15" + + max_slope = arcpy.Parameter( + displayName="Maximum Planar Slope", + name="max_slope", + datatype="GPDouble", + parameterType="Optional", + direction="Input") + + max_slope.value = "65.0" + + norm_diff = arcpy.Parameter( + displayName="Normal Difference Threshold", + name="norm_diff", + datatype="GPDouble", + parameterType="Optional", + direction="Input") + + norm_diff.value = "10.0" + + azimuth = arcpy.Parameter( + displayName="Azimuth (degrees)", + name="azimuth", + datatype="GPDouble", + parameterType="Optional", + direction="Input") + + azimuth.value = "180.0" + + altitude = arcpy.Parameter( + displayName="Altitude (degrees)", + name="altitude", + datatype="GPDouble", + parameterType="Optional", + direction="Input") + + altitude.value = "30.0" + + params = [i, buildings, output, radius, num_iter, num_samples, threshold, model_size, max_slope, norm_diff, azimuth, altitude] + + return params + + def updateParameters(self, parameters): + return + + def updateMessages(self, parameters): + for param in parameters: + param_str = param.valueAsText + if param_str is not None: + try: + desc = arcpy.Describe(param_str) + if (".gdb\\" in desc.catalogPath) or (".mdb\\" in desc.catalogPath): + param.setErrorMessage("Datasets stored in a Geodatabase are not supported.") + except: + param.clearMessage() + return + + def execute(self, parameters, messages): + i = parameters[0].valueAsText + buildings = parameters[1].valueAsText + if buildings is not None: + desc = arcpy.Describe(buildings) + buildings = desc.catalogPath + output = parameters[2].valueAsText + radius = parameters[3].valueAsText + num_iter = parameters[4].valueAsText + num_samples = parameters[5].valueAsText + threshold = parameters[6].valueAsText + model_size = parameters[7].valueAsText + max_slope = parameters[8].valueAsText + norm_diff = parameters[9].valueAsText + azimuth = parameters[10].valueAsText + altitude = parameters[11].valueAsText + old_stdout = sys.stdout + result = StringIO() + sys.stdout = result + wbt.lidar_rooftop_analysis(i=i, buildings=buildings, output=output, radius=radius, num_iter=num_iter, num_samples=num_samples, threshold=threshold, model_size=model_size, max_slope=max_slope, norm_diff=norm_diff, azimuth=azimuth, altitude=altitude) + sys.stdout = old_stdout + result_string = result.getvalue() + messages.addMessage(result_string) + return + + class LidarSegmentation(object): def __init__(self): self.label = "Lidar Segmentation" diff --git a/WBT/PRE/file_header.py b/WBT/PRE/file_header.py index 4a63390..b81b013 100644 --- a/WBT/PRE/file_header.py +++ b/WBT/PRE/file_header.py @@ -174,6 +174,7 @@ tool_labels.append("Horizon Angle") tool_labels.append("Horton Stream Order") tool_labels.append("Hypsometric Analysis") +tool_labels.append("Hypsometrically Tinted Hillshade") tool_labels.append("Idw Interpolation") tool_labels.append("Ihs To Rgb") tool_labels.append("Image Autocorrelation") @@ -229,6 +230,7 @@ tool_labels.append("Lidar Rbf Interpolation") tool_labels.append("Lidar Remove Duplicates") tool_labels.append("Lidar Remove Outliers") +tool_labels.append("Lidar Rooftop Analysis") tool_labels.append("Lidar Segmentation") tool_labels.append("Lidar Segmentation Based Filter") tool_labels.append("Lidar Thin") @@ -286,6 +288,7 @@ tool_labels.append("Mosaic") tool_labels.append("Mosaic With Feathering") tool_labels.append("Multi Part To Single Part") +tool_labels.append("Multidirectional Hillshade") tool_labels.append("Multiply") tool_labels.append("Multiscale Elevation Percentile") tool_labels.append("Multiscale Roughness") diff --git a/WBT/readme.txt b/WBT/readme.txt index c51b05f..0688d8f 100644 --- a/WBT/readme.txt +++ b/WBT/readme.txt @@ -1,636 +1,646 @@ -WhiteboxTools - -The main tool library is contained in the whitebox_tools (or whitebox_tools.exe on -MS Windows) file. This is a command-line program that can be run from a terminal, i.e. -command prompt. For details on usage, change the working directory (cd) to this folder -and type the following at the command prompt: - -./whitebox_tools --help - -The following commands are recognized: ---cd, --wd Changes the working directory; used in conjunction with --run flag. --h, --help Prints help information. --l, --license Prints the whitebox-tools license. ---listtools Lists all available tools. Keywords may also be used, --listtools slope. --r, --run Runs a tool; used in conjuction with --wd flag; -r="LidarInfo". ---toolbox Prints the toolbox associated with a tool; --toolbox=Slope. ---toolhelp Prints the help associated with a tool; --toolhelp="LidarInfo". ---toolparameters Prints the parameters (in json form) for a specific tool; --toolparameters="LidarInfo". --v Verbose mode. Without this flag, tool outputs will not be printed. ---viewcode Opens the source code of a tool in a web browser; --viewcode="LidarInfo". ---version Prints the version information. - -Example Usage: ->> ./whitebox-tools -r=lidar_info --cd="/path/to/data/" -i=input.las --vlr --geokeys - - -The WhiteboxTools library may also be called from Python automation scripts. The -whitebox_tools.py script can be used as an easy way of interfacing with the various -commands. See the user manual for more deails. To use this script, simply use the -following import: - -from whitebox_tools import WhiteboxTools - -wbt = WhiteboxTools() -wbt.work_dir = "/path/to/data/" # Sets the Whitebox working directory - -wbt.d_inf_flow_accumulation("DEM.dep", "output.dep", log=True) - - -Additionally, included in this directory is the WhiteboxTools Runner, a simple Tkinter -user-interface that allows users to run the WhiteboxTools tools, with convenience for -specifying tool parameters. To run this interface, simply type: - -python3 wb_runner.py - -Or, if Python 3 is the default Python intepreter: - -python wb_runner.py - -At the command prompt (after cd'ing to this folder, which contains the script). - -WhiteboxTools is distributed under a permissive MIT open-source license. See LICENSE.txt -for more details. - -****************** -* Release Notes: * -****************** - -Version 1.3.0 (07-06-2020) -- Tools will now output DEFLATE compressed GeoTIFFs when the --compress_rasters parameter is used. -- Added support for a newly developed compressed LiDAR data format, the ZLidar file. All tools - that accepted LAS file inputs and produced LAS outputs can now use '*.zlidar' files as well. I - have also added the LasToZlidar and ZlidarToLas tools to perform conversions. While the ZLidar - format does not yield compression rates quite as good as the popular LAZ file format, you can - expect ZLidar files to be between 20-30% of the size of the equivalent LAS file. A file - specification will be published in the near future to describe the open ZLidar data format. -- Added the AsciiToLas tool. -- Added the ContoursFromRaster tool for creating a vector contour coverage from a raster surface model (DEM). -- Added the ContoursFromPoints tool for creating a vector contour coverage from vector points. -- Added the UpdateNodataCells tool. -- Modified the Slope tool to optionally output in degrees, radians, or percent gradient. -- Modified the Mosaic tool, which now runs much faster with large numbers of input tiles. -- The vector-to-raster conversion tools now preserve input projections. -- Fixed a bug in the RasterToVectorPolygons tool. -- Fixed several bugs in the MergeTableWithCsv tool. -- Modified the FillMissingData tool to allow for the exclusion of edge-connected NoData cells from the operation. - This is better for irregular shaped DEMs that have large areas of NoData surrounding the valid data. -- The LidarConstructVectorTin tool has been depreciated. The tool was not creating the proper output. - Furthermore, since the number of points in the average LiDAR tile is usually many million, this tool - would usually produce Shapefiles that exceed the maximum allowable number of shape geometries. If - a vector TIN is required for a LiDAR point set, users should convert the file to a Shapefile and then - use the ConstructVectorTin tool instead. And of course, if you are interested in a raster TIN from a - LiDAR file, use the LidarTinGridding tool instead. -- FlattenLakes now handles multipart lake polygons. - -Version 1.2.0 (21-02-2020) -- Added the RasterToVectorPolygons tool, which now completes the raster-vector conversion tool set. -- Added the MultiscaleElevationPercentile tool. -- Added the AttributeCorrelationNeighbourhoodAnalysis tool. -- Added the RadialBasisFunctionInterpolation tool, which includes a thin-plate spline mode. -- Added the RasterPerimeter tool to measure the perimeter of raster polygons. -- Added the MDInfFlowAccumulation tool to perform the MD-infinity flow accumulation of Seibert - and McGlynn (2007). -- Added the InsertDams tool, which can be used to insert impoundment features at a set of points - of interest into a DEM. This tool can be used in combination with the ImpoundmentSizeIndex tool - to create artificial reservoirs/depressions. -- Added the HeightAboveGround tool, to normalize a LiDAR point cloud. Each point's z-value is - converted to the height above the nearest ground-classified point. -- Modified the LidarRbfInterpolation tool to improve efficiency. -- Fixed an issue with how floating point attributes were written in Shapefile attribute tables. -- Updated the LidarSegmentation tool, which now used RANSAC to fit planar models to points. -- Fixed an issue with the Reclass and ReclassFromFile tool that caused striping. -- The Relcass and ReclassFromFile tools now take 'min' and 'max' in the reclass string. -- The watershed tool now accepts either a set of vector points or a raster for the pour points - file. If a raster is specified, all non-zero, non-NoData valued cells will be considered - outlet cells and the watershed labels will be assigned based on these values. -- The D8 and D-infinity flow accumulation tools now take either an input DEM or a flow pointer raster - as inputs. - -Version 1.1.0 (09-12-2019) -- Added the BreachDepressionsLeastCost tool, which performs a modified form of the Lindsay - and Dhun (2015) impact minimizing breaching algorithm. This modified algorithm is very - efficient and can provide an excellent method for creating depressionless DEMs from large - DEMs, including those derived from LiDAR. It is particularly well suited to breaching - through road embankments, approximately the pathway of culverts. -- The FillDepressions tool algorithm has been completely re-developed. The new algorithm is - significantly faster than the previous method, which was based on the Wang and Lui method. - For legacy reasons, the previous tool has been retained and renamed FillDepressonsWangAndLui. - Notice that this new method also incorporates significantly improved flat area correction - that maintains general flowpaths of filled areas. -- The Sink and DepthInSink tools have been updated to use the new depression filling algorithm. -- Added the ClassifyBuildingsInLidar tool to reclassify LiDAR points within a LAS file - to the building class value (6) that are located within one or more building footprint - contained in an input polygon vector file. -- Added the NaturalNeighbourInterpolation tool for performing Sibson's (1981) interpolation - method on input point data. -- Added the UpslopeDepressionStorage tool to estimate the average upslope depression - storage capacity (DSC). -- Added the LidarRbfInterpolation tool for performing a radial basis function (RBF) interpolation - of LiDAR data sets. -- The WhiteboxTools Runner user interface has been significantly improved (many thanks to - Rachel Broders for these contributions). -- Fixed a bug in which the photometric interpretation was not being set by certain raster - decoders, including the SAGA encoder. This was causing an error when outputting GeoTIFF - files. -- Updated the ConstructVectorTIN and TINGridding tools to include a maximum triangle edge - length to help avoid the creation of spurious long and narrow triangles in convex regions - along the data boundaries. -- Added the ImageCorrelationNeighbourhoodAnalysis tool for performing correlation analysis - between two input rasters within roving search windows. The tool can be used to perform - Pearson's r, Spearman's Rho, or Kendall's Tau-b correlations. - -Version 1.0.2 (01-11-2019) -- Added the BurnStreamsAtRoads tool. -- Added a two-sample K-S test (TwoSampleKsTest) for comparing the distributions of two rasters. -- Added a Wilcoxon Signed-Rank test (WilcoxonSignedRankTest) for comparing two rasters. -- Added a paired-samples Student's t-test (PairedSampleTTest) for comparing two rasters. -- Added the inverse hyperbolic trig functions, i.e. the Arcosh, Arsinh, and Artanh tools. -- Renamed the LeeFilter to the LeeSigmaFilter. -- Renamed the RelativeStreamPowerIndex tool to StreamPowerIndex, to be more in-line with - other software. -- Fixed another bug related to the handling of Boolean tool parameters. - -Version 1.0.1 (20-10-2019) -- Boolean type tool parameters previously worked simply by the presence of the parameter flag. - This was causing problems with some WBT front-ends, particularly QGIS, where the parameters - were being provided to WBT as --flag=False. In this case, because the flag was present, it - was assumed to be True. All tools that have boolean parameters have been updated to handle - the case of --flag=False. This is a widespread modification that should fix the unexpected - behaviour of many tools in certain front-ends. -- Fixed a minor bug with the VectorPolygonToRaster tool. -- Fixed a bug in the DownstreamDistanceToStream tool. - -Version 1.0.0 (29-09-2019) -- Added support for reading and writing the BigTIFF format. This has resulted in numerous changes - throughout the codebase as a result of significant modification of ByteOrderReader and addition - of ByteOrderWriter. This change has touched almost every one of the raster format - encoders/decoders. -- Performance improvements have been made to the FlattenLakes (hydro-flattening) tool. -- Fixed a bug preventing the SplitColourComposite tool from reading the '--input' flag correctly. -- The ClipLidarToPolygon now issues a warning if the output LAS file does not contain any points - within the clipped region and does not output a file. Also, the LAS reader no longer panics - when it encounters a file with no points. Now it reads the header file, issues a warning, and - carries on, allowing the tools to handle the case of no points. -- ImageRegression can now optionally output a scatterplot. The scatterplot is based on a random - sample of a user-defined size. -- Added the CleanVector tool. -- ExtractRasterStatistics has been renamed ZonalStatistics to be more inline with other GIS, - including ArcGIS and QGIS. -- Added the median as a statistic that ZonalStatistics provides. -- Fixed a bug in the VectorPolygonsToRaster tool that sometimes mishandled polygon holes. -- Added the FilterLidarClasses tool to filter out points of user-specified classes. -- Added the LidarRansacPlanes tool to identify points belonging to planar surfaces. This tool - uses the RANSAC method, which is a robust modelling method that handles the presence of - numerous outlier points. -- The ClipLidarToPolygon tool has been parallelized. -- The LasToAscii and AsciiToLas tools have been updated to handle RGB colour data for points. -- Added the CsvPointsToVector tool to convert a CSV text table into a shapefile of vector points. - The table must contain x and y coordinate fields. -- The FeaturePreservingDenoise was renamed to FeaturePreservingSmoothing. The DrainagePreservingSmoothing - tool was removed. Use FeaturePreservingSmoothing instead. -- Added the ability to output the average number of point returns per pulse in the LidarPointStats tool. -- LidarTinGridding, LidarIdwIntarpolation, and LidarNearestNeighbourGridding now can interpolate the - return number, number of returns, and RGB colour data associated with points in a LAS file. -- Added the ModifyNoDataValue tool to change the NoData value in a raster. It updates the value in - the raster header and then modifies each grid cell in the raster containing the old NoData value - to the new value. This operation overwrites the existing raster. -- Fixed an issue with GeoTIFF NoData values that impacted many tools. NoData values were not interpreted - correctly when they were very large positive or negative values (near the min/max of an f32). - -Version 0.16.0 (24-05-2019) -- Added the MergeLineSegments and SphericalStdDevOfNormals tools. -- Fixed a bug with reading LAS files with point records with extra bytes. Previously, the LAS decoder - assumed the Point Record Length matched that of the LAS specifications (with the variable of the - optional intensity and user data). Some LAS files in the wild (particularly those created using - LASTools and of LAS version 1.2) have larger Point Record Lengths, which presumably carry extra - bytes of information. These extra byes are ignored, but they no longer throw off the decoding. -- Fixed a bug with writing Big-Ending GeoTIFF files. The 'MM' file header was not correct previously. -- Significantly reduced the memory requirements of the StochasticDepressionAnalysis tool. The tool - may be somewhat slower as a result, but it should be applicable to larger DEMs than was previously - possible. -- Fixed bugs with the Union and SplitWithLines tools. -- WhiteboxTools can now read and write Shapefiles of MultiPointZ, PolyLineZ, and PolygonZ ShapeTypes - missing the optional 'M' values (i.e. measures). -- SelectTilesByPolygon and LidarTileFootprint are now compatible with LAZ file inputs. Both of these - tools only rely on information in the input LiDAR file's header, which is the same for a LAZ file - as a LAS file. -- Fixed a bug with writing Saga GIS files (*.sdat) that inverted rasters. - -Version 0.15.0 (03-03-2019) -- The following tools were added to the project: - BoundaryShapeComplexity - NarrownessIndex - ShapeComplexityIndexRaster - -- Fixed a bug with the PanchromaticSharpening tool. -- Previously, if a LAS v1.4 file were input to a tool, the output LAS file, which is currently - always in LAS v1.3 format, would not correctly translate the 64-bit information (point - return, number of returns, classification) into 32-bit format. I have added the - get_32bit_from_64bit function to handle this translation more gracefully; albeit it is - still a lossy translation where returns greater than 5 are ignored and classification - values greater than 31 are lost. -- Added a maximum triangle edge length parameter to the LidarTinGridding tool to allow - for the exclusion of large-area triangles (i.e. low point density) from the gridding. -- The NormalizedDifferenceVegetationIndex tool has been renamed to NormalizedDifferenceIndex - to indicate the more general nature of this tool (i.e. NDVI, NDWI, OSAVI, etc.). -- Significant changes have been made to the BreachDepressions tool to make it more in-line - with the behaviour of the GoSpatial algorithm described in the original Lindsay (2016) - paper. These changes include: 1) the inclusion of an optional parameter to fill single-cell - pits prior to breaching, 2) the addition of a --flat_increment parameter, which overrides - the automatically derived value assigned to flat areas along breach channels (or filled - depressions), and 3) the tool now performs a fast post-breach filling operation, when - run in constrained-breaching mode (i.e. when the user specifies values for either - --max_depth or --max_length, placing constraints on the allowable breach channel size). - -Version 0.14.1 (10-02-2019) -- This release largely focuses on bug-fixes rather than feature additions. However, the - following tools were added to the library: - RasterArea - -- Fixed a bug with the MultiscaleTopographicPositionImage tool that prevented proper output - for files in GeoTIFF format. -- Several other tool-specific bug fixes. - -Version 0.14.0 (27-01-2019) -- The release largely focuses on bug-fixes rather than adding new features. The - following tools were added to the project: - CircularVarianceOfAspect - EdgeDensity - SurfaceAreaRatio - -- Fixed a bug that resulted in rasters with projected coordinate systems being - interpreted as geographic coordinates, thereby messing up the calculation of - inter-cell distances for tools like slope, aspect, curvature, etc. -- Fixed a bug with several of the math tools; output files took their data type - from the input file. In some cases, this does not work well because the input - is integer and the output must be floating point data. - - -Version 0.13.0 (08-01-2019) -- The release largely focusses on bug-fixes rather than adding new features. The - following tools were added to the project: - MosaicWithFeathering -- Support was added for GeoTIFF MODELTRANSFORMATIONTAG (Tag 33920). -- Support was added for reading GeoTIFFs that have coordinate transformations - defined by multiple tiepoints contained with the ModelTiepointTag (Tag 33922). - These rasters have their raster-to-model transform defined by a 2D polynomial - regression of the 3rd order. -- The initialize_using_file function in the abstract Raster model now transfers - information contained in an input GeoTIFF's ModelTiePoint, ModelPixelScale, - ModelTransform, GeoKeyDirectory, GeoDoubleParms, and GeoAsciiParams tags to - the output raster. This means that if a GeoTIFF file is input to a Whitebox - tool, and the output raster is specified to be of GeoTIFF format as well, - all of the coordinate information contain in the input raster will now be - contained in the output raster. -- The FeaturePreservingDenoise and DrainagePreservingSmoothing tools, both of - which are used for DEM generalization, now represent surface normal vectors - using 32-bit floats instead of the original double-precision values. This - does not alter the results of these tools significantly, but does reduce the - memory requirements and run-times of these tools substantially. -- The LidarKappa tool now outputs a raster displaying the spatial distribution - of the overall accuracy per grid cell (i.e. percent agreement). -- Fixed a bug with the RasterStreamsToVector tool that resulted in overlapping - traced streams. -- The D8FlowAccumulation tool has been modifed to use a fixed flow-width to - calculate specific contributing area, equal to the average grid cell resolution. - The tool previously used a variable flow-width for SCA calculations, however, - 1. this differs from the constant value used in Whitebox GAT, and 2. a - variable flow-width means that flow accumulation values do not increase - continuously in a downstream direction. This last issue was causing problems - with applications involving stream network extraction. This change does not - affect the 'cells' nor 'catchment area' outputs of the tool. -- Fixed a bug with the GeoTIFF NoData tag. -- Fixed a bug with the SetNodataValue tool. - - -Version 0.12.0 (22-11-2018) -- The following tools were added to the project: - BlockMaximumGridding - BlockMinimumGridding - Clip - Dissolve - Erase - JoinTables - Intersect - LasToShapefile - LidarClassifySubset - LinearityIndex - LineIntersections - LongestFlowpath - MergeTableWithCsv - MergeVectors - NearestNeighbourGridding - PatchOrientation - Polygonize - RasterToVectorLines - SplitWithLines - SymmetricalDifference - Union - VoronoiDiagram - -- Modified the algorithm used by the CostDistance tool from an iterative method of - finding the minimum cost surface to one that uses a priority-flood approach. This - is far more efficient. Also, there was a bug in the original code that was the - result of a mis-match between the neighbouring cell distances and the back-link - direction. In some cases this resulted in an infinite loop, which is now resolved. -- Improvements have been made to the WhiteboxTools GeoTIFF reader. A bug has been - fixed that prevented tile-oriented (in contrast to the more common strip-oriented) - TIFF files from being read properly. Support has been added for reading rasters - that have been compressed using the DEFLATE algorithm. Lastly, the WhiteboxTools - GeoTIFF reader now supports sparse rasters, as implemented by GDAL's GeoTIFF driver. -- An issue in the SAGA raster format reader has been fixed. - - -Version 0.11.0 (01-10-2018) -- This release is marked by the addition of several vector data processing capabilities. - Most notably, this includes support for TINing and TIN based gridding (vector and - LiDAR), as well as several vector patch shape indicies. The following tools were - added to the project: - AddPointCoordinatesToTable - CentroidVector - CompactnessRatio - ConstructVectorTIN - ElongationRatio - ExtendVectorLines - HoleProportion - LayerFootprint - LidarConstructVectorTIN - LidarTINGridding - LinesToPolygons - Medoid - MinimumBoundingCircle - MinimumBoundingEnvelope - MultiPartToSinglePart - PerimeterAreaRatio - PolygonArea - PolygonPerimeter - RasterStreamsToVector - RasterToVectorPoints - RelatedCircumscribingCircle - RemovePolygonHoles - ShapeComplexityIndex - SinglePartToMultiPart - SmoothVectors - SumOverlay - TINGridding - -- Added a minimum number of neighbours criteria in the neighbourhood search of the - LidarGroundPointFilter tool. In this way, if the fixed-radius search yields fewer - neighbours than this minimum neighbours threshold, a second kNN search is carried - out to identify the k nearest neighbours. This can be preferable for cases where - the point density varies significantly in the data set, e.g. in the case of - terrestrial LiDAR point clouds. -- The MinimumBoundingBox tool has been modified to take an optional minimization - criteria, including minimum box area, length, width, or perimeter. -- Fixed: Bug that resulted in a 0.5 m offset in the positioning of interpolated grids. -- Fixed: Viewshed tool now emits an intelligible error when the viewing station does - not overlap with the DEM. - - -Version 0.10.0 (16-09-2018) -- The following tools were added to the project: - CreateHexagonalVectorGrid - CreateRectangularVectorGrid - DrainagePreservingSmoothing - EliminateCoincidentPoints - ExtractNodes - HighPassMedianFilter - LasToMultipointShapefile - LidarHexBinning and VectorHexBinning - LidarTileFootprint - MaxDifferenceFromMean - MinimumBoundingBox - MinimumConvexHull - PolygonLongAxis and PolygonShortAxis - PolygonsToLines - ReinitializeAttributeTable - -- Refactoring of some data related to Point2D, and common algorithms (e.g. - point-in-poly, convex hull). -- Added unit tests to BoundingBox, point_in_poly, convex_hull, and elsewhere. -- Fixed a bug in LiDAR join related to tiles with fewer than two points. LAS files - now issue a warning upon saving when they contain less than two points. -- The default callback can now be modified in whitebox_tools.py, such that - a single custom callback can be used without having to specify it for each - tool function call. -- Added initial support for getting projection ESPG and WKT info from LAS files - and GeoTiff data. This is the start of a more fullsome approach to handling - spatial reference system information in the library. -- Fixed a bug in saving Shapefile m and z data. -- Fixed a bug that wouldn't allow the LidarIdwInterpolation and - LidarNearestNeighbourGridding tool to interpolate point classification data. -- LidarGroundPointFilter now has the ability to output a classified LAS file rather - than merely filtering non-ground points. Ground points are assigned classification - values of 2 while non-ground points are classified as 1. -- Updated the LidarKappaIndex tool to use a NN-search to find matching points between - the compared point clouds. -- Modified the FixedRadiusSearch structure to use 64-bit floats for storing coordinates. - This impacts performance efficiency but is needed for the fine precision of - positional information found in terrestrial LiDAR data. FixedRadiusSearch structures - have also had approximate kNN search methods added. - - -Version 0.9.0 (22-08-2018) -- Added the following tools: - ExtractRasterValuesAtPoints - FindLowestOrHighestPoints - LidarThinHighDensity - SelectTilesByPolygon - StandardDeviationOfSlope - -- Support has been added for writing Shapefile vector data. -- The SnapPourPoints and JensonSnapPourPoints tools have been modified to accept - vector inputs and to produce vector outputs. This is more consistent with - the Watershed tool, which requires vector pour point data inputs. - - -Version 0.8.0 (30-05-2018) -- Added the following tools: - CornerDetection - FastAlmostGaussianFilter - GaussianContrastStretch - IdwInterpolation - ImpoundmentIndex - LidarThin - StochasticDepressionAnalysis - UnsharpMasking - WeightedOverlay -- Modified some filters to take RGB inputs by operating on the intensity value. - These include AdaptiveFilter, BilateralFilter, ConservativeSmoothingFilter, - DiffOfGaussianFilter, EdgePreservingMeanFilter, EmbossFilter, GaussianFilter, - HighPassFilter, KNearestMeanFilter, LaplacianFilter, LaplacianOfGaussianFilter, - LeeFilter, MaximumFilter, MeanFilter, MedianFilter, MinimumFilter, OlympicFilter, - PrewittFilter, RangeFilter, RobertsCrossFilter, ScharrFilter, SobelFilter, and - UserDefinedWeightsFilter. -- Fixed a bug with reading/writing Whitebox Raster files containing RGB data. -- Modified the MajorityFilter tool to improve efficiency substantially. Also fixed - a bug in it and the DiversityFilter tools. - - -Version 0.7.0 (01-05-2018) -- Added the following tools: - AttributeCorrelation - ChangeVectorAnalysis - ClassifyOverlapPoints - ClipLidarToPolygon - ClipRasterToPolygon - CorrectVignetting - ErasePolygonFromLidar - ExportTableToCsv - RaiseWalls - TrendSurface - TrendSurfaceVectorPoints - UnnestBasins - UserDefinedWeightsFilter -- Updated TraceDownslopeFlowpaths to take vector seed point inputs. - -Version 0.6.0 (22-04-2018) -- Added the ability to read Shapefile attribute data (.dbf files). -- Added support to read LZW compressed GeoTIFFs, at least for simple - single-band files. The decoder can also handle the use of a horizontal - predictor (TIFF Tag 317). -- The following tools have been added in this release: - AttributeHistogram - AttributeScattergram - CountIf - ListUniqueValues - VectorLinesToRaster - VectorPointsToRaster - VectorPolygonsToRaster - -Version 0.5.1 (11-04-2018) -- This minor-point release fixes a far-reaching regression bug caused by a - change to the Raster class in the previous release. The change was - needed for the in-place operator tools added in the last update. This - modification however affected the proper running of several other tools - in the library, particularly those in the Math and Stats toolbox. The - issue has now been resolved. -- The VisibilityIndex tool has been added to the library. This is one - of the most computationally intensive tools in the library and should - really only be used in a high -- Modified tools with integer parameter inputs to parse strings - representations of floating point numbers. Previously, feeding - a tool 'filter_size=3.0' would cause a fatal error. -- Changed Raster so that when a filename with no extension is provided - as a parameter input to a tool, it defaults to a GeoTIFF. -- Added a new section to the User Manual titled, 'An Example WhiteboxTools - Python Project'. This addition provides a demonstration of how to - set-up a WhiteboxTools Python project, including the file structure - needed to import the library. - -Version 0.5.0 (04-04-2018) - -- The following tools have been added: - EdgePreservingMeanFilter - ElevationAboveStreamEuclidean - ErasePolygonFromRaster - FillBurn - FlattenLakes - ImageStackProfile - InPlaceAdd - InPlaceDivide - InPlaceMultiply - InPlaceSubtract - MaxAnisotropyDevSignature - PrincipalComponentAnalysis - RasterizeStreams - -- Updated tools so that the reporting of elapsed time respects verbose mode. -- Raster now allows for opening an existing raster in write mode ('w'), needed - for the in-place math operators (e.g. InPlaceAdd). -- Added update_display_min_max function to Raster. -- Output tables now highlight rows when the mouse hovers. - -Version 0.4.0 (04-03-2018) - -- This release has erognomic improvements for Python scripting with Whitebox. Tools can be called - in Python like this: - - wt = WhiteboxTools() - wt.slope(‘DEM.dep’, ‘slope.dep’) - -- There is a convenience method in whitebox_tools.py for each tool in the WhiteboxTools binary - executable. This makes it far easier to call tools from a Python script. See the User Manual - for details. -- Significant improvements and revisions have been made to the User Manual, and in particular - the section on Python based scripting with WhiteboxTools. -- The following tools have been added to the library: - LidarColourize - LidarPointStats - LidarRemoveDuplicates - LongProfile - LongProfileFromPoints - MaxElevDevSignature - MultiscaleRoughness - MultiscaleRoughnessSignature - PrintGeoTiffTags - Profile -- Updated Watershed and Viewshed tools to take vector point inputs. -- PennockLandformClass tool modified to have int8 output data type. Also fixed a bug in the input - parameters. - -Version 0.3.1 (15-02-2018) - -- No new tools have been added to this release. Instead the focus was on improving and enhancing - LAS file support and fixing a numbe of bugs. These include the following: -- Support has been added in the LAS file reader for handling Point Record Formats 4-11 in the - LAS 1.4 specificiations. This includes enhanced support for 64-bit LAS files. This change - resulted in cascading changes throughout the LiDAR infrastructure and LiDAR tools. Future - work will focus on writing LAS files in 1.4 format, instead of the current 1.3 format that is - saved. -- The LidarIdwInterpolation, LidarNearestNeighbourGridding, and LidarPointDensity tools have each - been modified to enhance the granularity of parallelism when operating in multi-file mode. This - has resulted in large improvements in performance when interpolating entire directories of - LAS files. -- The LasHeader object now has the ability to read a LAS header directly. This allows - interrogation of a LAS file without the need to create a full LAS object. This was useful - for identifying neighbouring tiles during interpolation, such that a buffer of points - from adjacent tiles can be used, thereby minimizing interpolation edge effects. -- There was a bug with the WhiteboxTools Runner that had issue with the use of a forward-slash (/) - in file paths on Windows. These have been fixed now. I also fixed every tool such that the use - of a forward slash for file paths on Windows won't result in an additional working directory - being appended to file names. This one resulted in many files being slightly modified. -- Added the ability to select the working directory in WhiteboxTools Runner. This is a useful - feature because some of the LiDAR tools now allow for no specified input/output files, in - which case they operate on all of the LAS files contained within the working directory. - -Version 0.3 (07-02-2018) - -- Added the following tools: - MaxAnisotropyDev - HysometricAnalysis - SlopeVsElevationPlot - LidarRemoveOutliers - -- Added initial support for reading Shapefile geometries. This is still a proof-of-concept - and no tools as of yet use Shapefile inputs. -- Added functionality to create beautiful and interactive line graph and scattergram - outputs for tools. -- LiDAR interpolation tools now have the option to interpolate all LAS files within the - working directory when an input file name is not specified. -- Added first draft of a pdf user manual for WhiteboxTools. - -Version 0.2 (12-01-2018) - -- Added the following tools: - KSTestForNormality - RadomSample - Mosaic - Resample - RadiusOfGyration - KMeansClustering - ModifiedKMeansClustering - D8MassFlux - DInfMassFlux - RasterHistogram - LidarHistogram - CrossTabulation - ImageAutocorrelation - ExtractRasterStatistics - AggregateRaster - Viewshed - -- Fixed several bugs including one affecting the reading of LAS files. - +WhiteboxTools + +The main tool library is contained in the whitebox_tools (or whitebox_tools.exe on +MS Windows) file. This is a command-line program that can be run from a terminal, i.e. +command prompt. For details on usage, change the working directory (cd) to this folder +and type the following at the command prompt: + +./whitebox_tools --help + +The following commands are recognized: +--cd, --wd Changes the working directory; used in conjunction with --run flag. +-h, --help Prints help information. +-l, --license Prints the whitebox-tools license. +--listtools Lists all available tools. Keywords may also be used, --listtools slope. +-r, --run Runs a tool; used in conjuction with --wd flag; -r="LidarInfo". +--toolbox Prints the toolbox associated with a tool; --toolbox=Slope. +--toolhelp Prints the help associated with a tool; --toolhelp="LidarInfo". +--toolparameters Prints the parameters (in json form) for a specific tool; --toolparameters="LidarInfo". +-v Verbose mode. Without this flag, tool outputs will not be printed. +--viewcode Opens the source code of a tool in a web browser; --viewcode="LidarInfo". +--version Prints the version information. + +Example Usage: +>> ./whitebox-tools -r=lidar_info --cd="/path/to/data/" -i=input.las --vlr --geokeys + + +The WhiteboxTools library may also be called from Python automation scripts. The +whitebox_tools.py script can be used as an easy way of interfacing with the various +commands. See the user manual for more deails. To use this script, simply use the +following import: + +from whitebox_tools import WhiteboxTools + +wbt = WhiteboxTools() +wbt.work_dir = "/path/to/data/" # Sets the Whitebox working directory + +wbt.d_inf_flow_accumulation("DEM.dep", "output.dep", log=True) + + +Additionally, included in this directory is the WhiteboxTools Runner, a simple Tkinter +user-interface that allows users to run the WhiteboxTools tools, with convenience for +specifying tool parameters. To run this interface, simply type: + +python3 wb_runner.py + +Or, if Python 3 is the default Python intepreter: + +python wb_runner.py + +At the command prompt (after cd'ing to this folder, which contains the script). + +WhiteboxTools is distributed under a permissive MIT open-source license. See LICENSE.txt +for more details. + +****************** +* Release Notes: * +****************** + +Version 1.3.1 (23-07-2020) +- Added the HypsometricallyTintedHillshade tool to create hypsometric tinted hillshades. +- Added the MultidirectionalHillshade tool. +- Added the ability to read/write in the Esri BIL raster format. +- Added the LidarRooftopAnalysis tool. +- The MultiPartToSinglePart tool now handles MultiPoint vectors. +- Fixed a bug with the VoronoiDiagram to better handle MultiPoint vectors. +- Fixed an issue with writing compressed RGB GeoTIFFs. +- Fixed an issue reading LZW compressed GeoTIFFs. + +Version 1.3.0 (07-06-2020) +- Tools will now output DEFLATE compressed GeoTIFFs when the --compress_rasters parameter is used. +- Added support for a newly developed compressed LiDAR data format, the ZLidar file. All tools + that accepted LAS file inputs and produced LAS outputs can now use '*.zlidar' files as well. I + have also added the LasToZlidar and ZlidarToLas tools to perform conversions. While the ZLidar + format does not yield compression rates quite as good as the popular LAZ file format, you can + expect ZLidar files to be between 20-30% of the size of the equivalent LAS file. A file + specification will be published in the near future to describe the open ZLidar data format. +- Added the AsciiToLas tool. +- Added the ContoursFromRaster tool for creating a vector contour coverage from a raster surface model (DEM). +- Added the ContoursFromPoints tool for creating a vector contour coverage from vector points. +- Added the UpdateNodataCells tool. +- Modified the Slope tool to optionally output in degrees, radians, or percent gradient. +- Modified the Mosaic tool, which now runs much faster with large numbers of input tiles. +- The vector-to-raster conversion tools now preserve input projections. +- Fixed a bug in the RasterToVectorPolygons tool. +- Fixed several bugs in the MergeTableWithCsv tool. +- Modified the FillMissingData tool to allow for the exclusion of edge-connected NoData cells from the operation. + This is better for irregular shaped DEMs that have large areas of NoData surrounding the valid data. +- The LidarConstructVectorTin tool has been depreciated. The tool was not creating the proper output. + Furthermore, since the number of points in the average LiDAR tile is usually many million, this tool + would usually produce Shapefiles that exceed the maximum allowable number of shape geometries. If + a vector TIN is required for a LiDAR point set, users should convert the file to a Shapefile and then + use the ConstructVectorTin tool instead. And of course, if you are interested in a raster TIN from a + LiDAR file, use the LidarTinGridding tool instead. +- FlattenLakes now handles multipart lake polygons. + +Version 1.2.0 (21-02-2020) +- Added the RasterToVectorPolygons tool, which now completes the raster-vector conversion tool set. +- Added the MultiscaleElevationPercentile tool. +- Added the AttributeCorrelationNeighbourhoodAnalysis tool. +- Added the RadialBasisFunctionInterpolation tool, which includes a thin-plate spline mode. +- Added the RasterPerimeter tool to measure the perimeter of raster polygons. +- Added the MDInfFlowAccumulation tool to perform the MD-infinity flow accumulation of Seibert + and McGlynn (2007). +- Added the InsertDams tool, which can be used to insert impoundment features at a set of points + of interest into a DEM. This tool can be used in combination with the ImpoundmentSizeIndex tool + to create artificial reservoirs/depressions. +- Added the HeightAboveGround tool, to normalize a LiDAR point cloud. Each point's z-value is + converted to the height above the nearest ground-classified point. +- Modified the LidarRbfInterpolation tool to improve efficiency. +- Fixed an issue with how floating point attributes were written in Shapefile attribute tables. +- Updated the LidarSegmentation tool, which now used RANSAC to fit planar models to points. +- Fixed an issue with the Reclass and ReclassFromFile tool that caused striping. +- The Relcass and ReclassFromFile tools now take 'min' and 'max' in the reclass string. +- The watershed tool now accepts either a set of vector points or a raster for the pour points + file. If a raster is specified, all non-zero, non-NoData valued cells will be considered + outlet cells and the watershed labels will be assigned based on these values. +- The D8 and D-infinity flow accumulation tools now take either an input DEM or a flow pointer raster + as inputs. + +Version 1.1.0 (09-12-2019) +- Added the BreachDepressionsLeastCost tool, which performs a modified form of the Lindsay + and Dhun (2015) impact minimizing breaching algorithm. This modified algorithm is very + efficient and can provide an excellent method for creating depressionless DEMs from large + DEMs, including those derived from LiDAR. It is particularly well suited to breaching + through road embankments, approximately the pathway of culverts. +- The FillDepressions tool algorithm has been completely re-developed. The new algorithm is + significantly faster than the previous method, which was based on the Wang and Lui method. + For legacy reasons, the previous tool has been retained and renamed FillDepressonsWangAndLui. + Notice that this new method also incorporates significantly improved flat area correction + that maintains general flowpaths of filled areas. +- The Sink and DepthInSink tools have been updated to use the new depression filling algorithm. +- Added the ClassifyBuildingsInLidar tool to reclassify LiDAR points within a LAS file + to the building class value (6) that are located within one or more building footprint + contained in an input polygon vector file. +- Added the NaturalNeighbourInterpolation tool for performing Sibson's (1981) interpolation + method on input point data. +- Added the UpslopeDepressionStorage tool to estimate the average upslope depression + storage capacity (DSC). +- Added the LidarRbfInterpolation tool for performing a radial basis function (RBF) interpolation + of LiDAR data sets. +- The WhiteboxTools Runner user interface has been significantly improved (many thanks to + Rachel Broders for these contributions). +- Fixed a bug in which the photometric interpretation was not being set by certain raster + decoders, including the SAGA encoder. This was causing an error when outputting GeoTIFF + files. +- Updated the ConstructVectorTIN and TINGridding tools to include a maximum triangle edge + length to help avoid the creation of spurious long and narrow triangles in convex regions + along the data boundaries. +- Added the ImageCorrelationNeighbourhoodAnalysis tool for performing correlation analysis + between two input rasters within roving search windows. The tool can be used to perform + Pearson's r, Spearman's Rho, or Kendall's Tau-b correlations. + +Version 1.0.2 (01-11-2019) +- Added the BurnStreamsAtRoads tool. +- Added a two-sample K-S test (TwoSampleKsTest) for comparing the distributions of two rasters. +- Added a Wilcoxon Signed-Rank test (WilcoxonSignedRankTest) for comparing two rasters. +- Added a paired-samples Student's t-test (PairedSampleTTest) for comparing two rasters. +- Added the inverse hyperbolic trig functions, i.e. the Arcosh, Arsinh, and Artanh tools. +- Renamed the LeeFilter to the LeeSigmaFilter. +- Renamed the RelativeStreamPowerIndex tool to StreamPowerIndex, to be more in-line with + other software. +- Fixed another bug related to the handling of Boolean tool parameters. + +Version 1.0.1 (20-10-2019) +- Boolean type tool parameters previously worked simply by the presence of the parameter flag. + This was causing problems with some WBT front-ends, particularly QGIS, where the parameters + were being provided to WBT as --flag=False. In this case, because the flag was present, it + was assumed to be True. All tools that have boolean parameters have been updated to handle + the case of --flag=False. This is a widespread modification that should fix the unexpected + behaviour of many tools in certain front-ends. +- Fixed a minor bug with the VectorPolygonToRaster tool. +- Fixed a bug in the DownstreamDistanceToStream tool. + +Version 1.0.0 (29-09-2019) +- Added support for reading and writing the BigTIFF format. This has resulted in numerous changes + throughout the codebase as a result of significant modification of ByteOrderReader and addition + of ByteOrderWriter. This change has touched almost every one of the raster format + encoders/decoders. +- Performance improvements have been made to the FlattenLakes (hydro-flattening) tool. +- Fixed a bug preventing the SplitColourComposite tool from reading the '--input' flag correctly. +- The ClipLidarToPolygon now issues a warning if the output LAS file does not contain any points + within the clipped region and does not output a file. Also, the LAS reader no longer panics + when it encounters a file with no points. Now it reads the header file, issues a warning, and + carries on, allowing the tools to handle the case of no points. +- ImageRegression can now optionally output a scatterplot. The scatterplot is based on a random + sample of a user-defined size. +- Added the CleanVector tool. +- ExtractRasterStatistics has been renamed ZonalStatistics to be more inline with other GIS, + including ArcGIS and QGIS. +- Added the median as a statistic that ZonalStatistics provides. +- Fixed a bug in the VectorPolygonsToRaster tool that sometimes mishandled polygon holes. +- Added the FilterLidarClasses tool to filter out points of user-specified classes. +- Added the LidarRansacPlanes tool to identify points belonging to planar surfaces. This tool + uses the RANSAC method, which is a robust modelling method that handles the presence of + numerous outlier points. +- The ClipLidarToPolygon tool has been parallelized. +- The LasToAscii and AsciiToLas tools have been updated to handle RGB colour data for points. +- Added the CsvPointsToVector tool to convert a CSV text table into a shapefile of vector points. + The table must contain x and y coordinate fields. +- The FeaturePreservingDenoise was renamed to FeaturePreservingSmoothing. The DrainagePreservingSmoothing + tool was removed. Use FeaturePreservingSmoothing instead. +- Added the ability to output the average number of point returns per pulse in the LidarPointStats tool. +- LidarTinGridding, LidarIdwIntarpolation, and LidarNearestNeighbourGridding now can interpolate the + return number, number of returns, and RGB colour data associated with points in a LAS file. +- Added the ModifyNoDataValue tool to change the NoData value in a raster. It updates the value in + the raster header and then modifies each grid cell in the raster containing the old NoData value + to the new value. This operation overwrites the existing raster. +- Fixed an issue with GeoTIFF NoData values that impacted many tools. NoData values were not interpreted + correctly when they were very large positive or negative values (near the min/max of an f32). + +Version 0.16.0 (24-05-2019) +- Added the MergeLineSegments and SphericalStdDevOfNormals tools. +- Fixed a bug with reading LAS files with point records with extra bytes. Previously, the LAS decoder + assumed the Point Record Length matched that of the LAS specifications (with the variable of the + optional intensity and user data). Some LAS files in the wild (particularly those created using + LASTools and of LAS version 1.2) have larger Point Record Lengths, which presumably carry extra + bytes of information. These extra byes are ignored, but they no longer throw off the decoding. +- Fixed a bug with writing Big-Ending GeoTIFF files. The 'MM' file header was not correct previously. +- Significantly reduced the memory requirements of the StochasticDepressionAnalysis tool. The tool + may be somewhat slower as a result, but it should be applicable to larger DEMs than was previously + possible. +- Fixed bugs with the Union and SplitWithLines tools. +- WhiteboxTools can now read and write Shapefiles of MultiPointZ, PolyLineZ, and PolygonZ ShapeTypes + missing the optional 'M' values (i.e. measures). +- SelectTilesByPolygon and LidarTileFootprint are now compatible with LAZ file inputs. Both of these + tools only rely on information in the input LiDAR file's header, which is the same for a LAZ file + as a LAS file. +- Fixed a bug with writing Saga GIS files (*.sdat) that inverted rasters. + +Version 0.15.0 (03-03-2019) +- The following tools were added to the project: + BoundaryShapeComplexity + NarrownessIndex + ShapeComplexityIndexRaster + +- Fixed a bug with the PanchromaticSharpening tool. +- Previously, if a LAS v1.4 file were input to a tool, the output LAS file, which is currently + always in LAS v1.3 format, would not correctly translate the 64-bit information (point + return, number of returns, classification) into 32-bit format. I have added the + get_32bit_from_64bit function to handle this translation more gracefully; albeit it is + still a lossy translation where returns greater than 5 are ignored and classification + values greater than 31 are lost. +- Added a maximum triangle edge length parameter to the LidarTinGridding tool to allow + for the exclusion of large-area triangles (i.e. low point density) from the gridding. +- The NormalizedDifferenceVegetationIndex tool has been renamed to NormalizedDifferenceIndex + to indicate the more general nature of this tool (i.e. NDVI, NDWI, OSAVI, etc.). +- Significant changes have been made to the BreachDepressions tool to make it more in-line + with the behaviour of the GoSpatial algorithm described in the original Lindsay (2016) + paper. These changes include: 1) the inclusion of an optional parameter to fill single-cell + pits prior to breaching, 2) the addition of a --flat_increment parameter, which overrides + the automatically derived value assigned to flat areas along breach channels (or filled + depressions), and 3) the tool now performs a fast post-breach filling operation, when + run in constrained-breaching mode (i.e. when the user specifies values for either + --max_depth or --max_length, placing constraints on the allowable breach channel size). + +Version 0.14.1 (10-02-2019) +- This release largely focuses on bug-fixes rather than feature additions. However, the + following tools were added to the library: + RasterArea + +- Fixed a bug with the MultiscaleTopographicPositionImage tool that prevented proper output + for files in GeoTIFF format. +- Several other tool-specific bug fixes. + +Version 0.14.0 (27-01-2019) +- The release largely focuses on bug-fixes rather than adding new features. The + following tools were added to the project: + CircularVarianceOfAspect + EdgeDensity + SurfaceAreaRatio + +- Fixed a bug that resulted in rasters with projected coordinate systems being + interpreted as geographic coordinates, thereby messing up the calculation of + inter-cell distances for tools like slope, aspect, curvature, etc. +- Fixed a bug with several of the math tools; output files took their data type + from the input file. In some cases, this does not work well because the input + is integer and the output must be floating point data. + + +Version 0.13.0 (08-01-2019) +- The release largely focusses on bug-fixes rather than adding new features. The + following tools were added to the project: + MosaicWithFeathering +- Support was added for GeoTIFF MODELTRANSFORMATIONTAG (Tag 33920). +- Support was added for reading GeoTIFFs that have coordinate transformations + defined by multiple tiepoints contained with the ModelTiepointTag (Tag 33922). + These rasters have their raster-to-model transform defined by a 2D polynomial + regression of the 3rd order. +- The initialize_using_file function in the abstract Raster model now transfers + information contained in an input GeoTIFF's ModelTiePoint, ModelPixelScale, + ModelTransform, GeoKeyDirectory, GeoDoubleParms, and GeoAsciiParams tags to + the output raster. This means that if a GeoTIFF file is input to a Whitebox + tool, and the output raster is specified to be of GeoTIFF format as well, + all of the coordinate information contain in the input raster will now be + contained in the output raster. +- The FeaturePreservingDenoise and DrainagePreservingSmoothing tools, both of + which are used for DEM generalization, now represent surface normal vectors + using 32-bit floats instead of the original double-precision values. This + does not alter the results of these tools significantly, but does reduce the + memory requirements and run-times of these tools substantially. +- The LidarKappa tool now outputs a raster displaying the spatial distribution + of the overall accuracy per grid cell (i.e. percent agreement). +- Fixed a bug with the RasterStreamsToVector tool that resulted in overlapping + traced streams. +- The D8FlowAccumulation tool has been modifed to use a fixed flow-width to + calculate specific contributing area, equal to the average grid cell resolution. + The tool previously used a variable flow-width for SCA calculations, however, + 1. this differs from the constant value used in Whitebox GAT, and 2. a + variable flow-width means that flow accumulation values do not increase + continuously in a downstream direction. This last issue was causing problems + with applications involving stream network extraction. This change does not + affect the 'cells' nor 'catchment area' outputs of the tool. +- Fixed a bug with the GeoTIFF NoData tag. +- Fixed a bug with the SetNodataValue tool. + + +Version 0.12.0 (22-11-2018) +- The following tools were added to the project: + BlockMaximumGridding + BlockMinimumGridding + Clip + Dissolve + Erase + JoinTables + Intersect + LasToShapefile + LidarClassifySubset + LinearityIndex + LineIntersections + LongestFlowpath + MergeTableWithCsv + MergeVectors + NearestNeighbourGridding + PatchOrientation + Polygonize + RasterToVectorLines + SplitWithLines + SymmetricalDifference + Union + VoronoiDiagram + +- Modified the algorithm used by the CostDistance tool from an iterative method of + finding the minimum cost surface to one that uses a priority-flood approach. This + is far more efficient. Also, there was a bug in the original code that was the + result of a mis-match between the neighbouring cell distances and the back-link + direction. In some cases this resulted in an infinite loop, which is now resolved. +- Improvements have been made to the WhiteboxTools GeoTIFF reader. A bug has been + fixed that prevented tile-oriented (in contrast to the more common strip-oriented) + TIFF files from being read properly. Support has been added for reading rasters + that have been compressed using the DEFLATE algorithm. Lastly, the WhiteboxTools + GeoTIFF reader now supports sparse rasters, as implemented by GDAL's GeoTIFF driver. +- An issue in the SAGA raster format reader has been fixed. + + +Version 0.11.0 (01-10-2018) +- This release is marked by the addition of several vector data processing capabilities. + Most notably, this includes support for TINing and TIN based gridding (vector and + LiDAR), as well as several vector patch shape indicies. The following tools were + added to the project: + AddPointCoordinatesToTable + CentroidVector + CompactnessRatio + ConstructVectorTIN + ElongationRatio + ExtendVectorLines + HoleProportion + LayerFootprint + LidarConstructVectorTIN + LidarTINGridding + LinesToPolygons + Medoid + MinimumBoundingCircle + MinimumBoundingEnvelope + MultiPartToSinglePart + PerimeterAreaRatio + PolygonArea + PolygonPerimeter + RasterStreamsToVector + RasterToVectorPoints + RelatedCircumscribingCircle + RemovePolygonHoles + ShapeComplexityIndex + SinglePartToMultiPart + SmoothVectors + SumOverlay + TINGridding + +- Added a minimum number of neighbours criteria in the neighbourhood search of the + LidarGroundPointFilter tool. In this way, if the fixed-radius search yields fewer + neighbours than this minimum neighbours threshold, a second kNN search is carried + out to identify the k nearest neighbours. This can be preferable for cases where + the point density varies significantly in the data set, e.g. in the case of + terrestrial LiDAR point clouds. +- The MinimumBoundingBox tool has been modified to take an optional minimization + criteria, including minimum box area, length, width, or perimeter. +- Fixed: Bug that resulted in a 0.5 m offset in the positioning of interpolated grids. +- Fixed: Viewshed tool now emits an intelligible error when the viewing station does + not overlap with the DEM. + + +Version 0.10.0 (16-09-2018) +- The following tools were added to the project: + CreateHexagonalVectorGrid + CreateRectangularVectorGrid + DrainagePreservingSmoothing + EliminateCoincidentPoints + ExtractNodes + HighPassMedianFilter + LasToMultipointShapefile + LidarHexBinning and VectorHexBinning + LidarTileFootprint + MaxDifferenceFromMean + MinimumBoundingBox + MinimumConvexHull + PolygonLongAxis and PolygonShortAxis + PolygonsToLines + ReinitializeAttributeTable + +- Refactoring of some data related to Point2D, and common algorithms (e.g. + point-in-poly, convex hull). +- Added unit tests to BoundingBox, point_in_poly, convex_hull, and elsewhere. +- Fixed a bug in LiDAR join related to tiles with fewer than two points. LAS files + now issue a warning upon saving when they contain less than two points. +- The default callback can now be modified in whitebox_tools.py, such that + a single custom callback can be used without having to specify it for each + tool function call. +- Added initial support for getting projection ESPG and WKT info from LAS files + and GeoTiff data. This is the start of a more fullsome approach to handling + spatial reference system information in the library. +- Fixed a bug in saving Shapefile m and z data. +- Fixed a bug that wouldn't allow the LidarIdwInterpolation and + LidarNearestNeighbourGridding tool to interpolate point classification data. +- LidarGroundPointFilter now has the ability to output a classified LAS file rather + than merely filtering non-ground points. Ground points are assigned classification + values of 2 while non-ground points are classified as 1. +- Updated the LidarKappaIndex tool to use a NN-search to find matching points between + the compared point clouds. +- Modified the FixedRadiusSearch structure to use 64-bit floats for storing coordinates. + This impacts performance efficiency but is needed for the fine precision of + positional information found in terrestrial LiDAR data. FixedRadiusSearch structures + have also had approximate kNN search methods added. + + +Version 0.9.0 (22-08-2018) +- Added the following tools: + ExtractRasterValuesAtPoints + FindLowestOrHighestPoints + LidarThinHighDensity + SelectTilesByPolygon + StandardDeviationOfSlope + +- Support has been added for writing Shapefile vector data. +- The SnapPourPoints and JensonSnapPourPoints tools have been modified to accept + vector inputs and to produce vector outputs. This is more consistent with + the Watershed tool, which requires vector pour point data inputs. + + +Version 0.8.0 (30-05-2018) +- Added the following tools: + CornerDetection + FastAlmostGaussianFilter + GaussianContrastStretch + IdwInterpolation + ImpoundmentIndex + LidarThin + StochasticDepressionAnalysis + UnsharpMasking + WeightedOverlay +- Modified some filters to take RGB inputs by operating on the intensity value. + These include AdaptiveFilter, BilateralFilter, ConservativeSmoothingFilter, + DiffOfGaussianFilter, EdgePreservingMeanFilter, EmbossFilter, GaussianFilter, + HighPassFilter, KNearestMeanFilter, LaplacianFilter, LaplacianOfGaussianFilter, + LeeFilter, MaximumFilter, MeanFilter, MedianFilter, MinimumFilter, OlympicFilter, + PrewittFilter, RangeFilter, RobertsCrossFilter, ScharrFilter, SobelFilter, and + UserDefinedWeightsFilter. +- Fixed a bug with reading/writing Whitebox Raster files containing RGB data. +- Modified the MajorityFilter tool to improve efficiency substantially. Also fixed + a bug in it and the DiversityFilter tools. + + +Version 0.7.0 (01-05-2018) +- Added the following tools: + AttributeCorrelation + ChangeVectorAnalysis + ClassifyOverlapPoints + ClipLidarToPolygon + ClipRasterToPolygon + CorrectVignetting + ErasePolygonFromLidar + ExportTableToCsv + RaiseWalls + TrendSurface + TrendSurfaceVectorPoints + UnnestBasins + UserDefinedWeightsFilter +- Updated TraceDownslopeFlowpaths to take vector seed point inputs. + +Version 0.6.0 (22-04-2018) +- Added the ability to read Shapefile attribute data (.dbf files). +- Added support to read LZW compressed GeoTIFFs, at least for simple + single-band files. The decoder can also handle the use of a horizontal + predictor (TIFF Tag 317). +- The following tools have been added in this release: + AttributeHistogram + AttributeScattergram + CountIf + ListUniqueValues + VectorLinesToRaster + VectorPointsToRaster + VectorPolygonsToRaster + +Version 0.5.1 (11-04-2018) +- This minor-point release fixes a far-reaching regression bug caused by a + change to the Raster class in the previous release. The change was + needed for the in-place operator tools added in the last update. This + modification however affected the proper running of several other tools + in the library, particularly those in the Math and Stats toolbox. The + issue has now been resolved. +- The VisibilityIndex tool has been added to the library. This is one + of the most computationally intensive tools in the library and should + really only be used in a high +- Modified tools with integer parameter inputs to parse strings + representations of floating point numbers. Previously, feeding + a tool 'filter_size=3.0' would cause a fatal error. +- Changed Raster so that when a filename with no extension is provided + as a parameter input to a tool, it defaults to a GeoTIFF. +- Added a new section to the User Manual titled, 'An Example WhiteboxTools + Python Project'. This addition provides a demonstration of how to + set-up a WhiteboxTools Python project, including the file structure + needed to import the library. + +Version 0.5.0 (04-04-2018) + +- The following tools have been added: + EdgePreservingMeanFilter + ElevationAboveStreamEuclidean + ErasePolygonFromRaster + FillBurn + FlattenLakes + ImageStackProfile + InPlaceAdd + InPlaceDivide + InPlaceMultiply + InPlaceSubtract + MaxAnisotropyDevSignature + PrincipalComponentAnalysis + RasterizeStreams + +- Updated tools so that the reporting of elapsed time respects verbose mode. +- Raster now allows for opening an existing raster in write mode ('w'), needed + for the in-place math operators (e.g. InPlaceAdd). +- Added update_display_min_max function to Raster. +- Output tables now highlight rows when the mouse hovers. + +Version 0.4.0 (04-03-2018) + +- This release has erognomic improvements for Python scripting with Whitebox. Tools can be called + in Python like this: + + wt = WhiteboxTools() + wt.slope(‘DEM.dep’, ‘slope.dep’) + +- There is a convenience method in whitebox_tools.py for each tool in the WhiteboxTools binary + executable. This makes it far easier to call tools from a Python script. See the User Manual + for details. +- Significant improvements and revisions have been made to the User Manual, and in particular + the section on Python based scripting with WhiteboxTools. +- The following tools have been added to the library: + LidarColourize + LidarPointStats + LidarRemoveDuplicates + LongProfile + LongProfileFromPoints + MaxElevDevSignature + MultiscaleRoughness + MultiscaleRoughnessSignature + PrintGeoTiffTags + Profile +- Updated Watershed and Viewshed tools to take vector point inputs. +- PennockLandformClass tool modified to have int8 output data type. Also fixed a bug in the input + parameters. + +Version 0.3.1 (15-02-2018) + +- No new tools have been added to this release. Instead the focus was on improving and enhancing + LAS file support and fixing a numbe of bugs. These include the following: +- Support has been added in the LAS file reader for handling Point Record Formats 4-11 in the + LAS 1.4 specificiations. This includes enhanced support for 64-bit LAS files. This change + resulted in cascading changes throughout the LiDAR infrastructure and LiDAR tools. Future + work will focus on writing LAS files in 1.4 format, instead of the current 1.3 format that is + saved. +- The LidarIdwInterpolation, LidarNearestNeighbourGridding, and LidarPointDensity tools have each + been modified to enhance the granularity of parallelism when operating in multi-file mode. This + has resulted in large improvements in performance when interpolating entire directories of + LAS files. +- The LasHeader object now has the ability to read a LAS header directly. This allows + interrogation of a LAS file without the need to create a full LAS object. This was useful + for identifying neighbouring tiles during interpolation, such that a buffer of points + from adjacent tiles can be used, thereby minimizing interpolation edge effects. +- There was a bug with the WhiteboxTools Runner that had issue with the use of a forward-slash (/) + in file paths on Windows. These have been fixed now. I also fixed every tool such that the use + of a forward slash for file paths on Windows won't result in an additional working directory + being appended to file names. This one resulted in many files being slightly modified. +- Added the ability to select the working directory in WhiteboxTools Runner. This is a useful + feature because some of the LiDAR tools now allow for no specified input/output files, in + which case they operate on all of the LAS files contained within the working directory. + +Version 0.3 (07-02-2018) + +- Added the following tools: + MaxAnisotropyDev + HysometricAnalysis + SlopeVsElevationPlot + LidarRemoveOutliers + +- Added initial support for reading Shapefile geometries. This is still a proof-of-concept + and no tools as of yet use Shapefile inputs. +- Added functionality to create beautiful and interactive line graph and scattergram + outputs for tools. +- LiDAR interpolation tools now have the option to interpolate all LAS files within the + working directory when an input file name is not specified. +- Added first draft of a pdf user manual for WhiteboxTools. + +Version 0.2 (12-01-2018) + +- Added the following tools: + KSTestForNormality + RadomSample + Mosaic + Resample + RadiusOfGyration + KMeansClustering + ModifiedKMeansClustering + D8MassFlux + DInfMassFlux + RasterHistogram + LidarHistogram + CrossTabulation + ImageAutocorrelation + ExtractRasterStatistics + AggregateRaster + Viewshed + +- Fixed several bugs including one affecting the reading of LAS files. + - Numerous enhancements \ No newline at end of file diff --git a/WBT/wb_runner.py b/WBT/wb_runner.py index a8e6a04..6b72376 100644 --- a/WBT/wb_runner.py +++ b/WBT/wb_runner.py @@ -1,1327 +1,1327 @@ -#!/usr/bin/env python3 - -# This script is part of the WhiteboxTools geospatial analysis library. -# Authors: Dr. John Lindsay, Rachel Broders -# Created: 28/11/2017 -# Last Modified: 05/11/2019 -# License: MIT - -import __future__ -import sys -# if sys.version_info[0] < 3: -# raise Exception("Must be using Python 3") -import json -import os -from os import path -# from __future__ import print_function -# from enum import Enum -import platform -import re #Added by Rachel for snake_to_camel function -from pathlib import Path -import glob -from sys import platform as _platform -import shlex -import tkinter as tk -from tkinter import ttk -from tkinter.scrolledtext import ScrolledText -from tkinter import filedialog -from tkinter import messagebox -from tkinter import PhotoImage -import webbrowser -from whitebox_tools import WhiteboxTools, to_camelcase - -wbt = WhiteboxTools() - - -class FileSelector(tk.Frame): - def __init__(self, json_str, runner, master=None): - # first make sure that the json data has the correct fields - j = json.loads(json_str) - self.name = j['name'] - self.description = j['description'] - self.flag = j['flags'][len(j['flags']) - 1] - self.parameter_type = j['parameter_type'] - self.file_type = "" - if "ExistingFile" in self.parameter_type: - self.file_type = j['parameter_type']['ExistingFile'] - elif "NewFile" in self.parameter_type: - self.file_type = j['parameter_type']['NewFile'] - self.optional = j['optional'] - default_value = j['default_value'] - - self.runner = runner - - ttk.Frame.__init__(self, master, padding='0.02i') - self.grid() - - self.label = ttk.Label(self, text=self.name, justify=tk.LEFT) - self.label.grid(row=0, column=0, sticky=tk.W) - self.label.columnconfigure(0, weight=1) - - if not self.optional: - self.label['text'] = self.label['text'] + "*" - - fs_frame = ttk.Frame(self, padding='0.0i') - self.value = tk.StringVar() - self.entry = ttk.Entry( - fs_frame, width=45, justify=tk.LEFT, textvariable=self.value) - self.entry.grid(row=0, column=0, sticky=tk.NSEW) - self.entry.columnconfigure(0, weight=1) - if default_value: - self.value.set(default_value) - - # dir_path = os.path.dirname(os.path.realpath(__file__)) - # print(dir_path) - # self.open_file_icon = tk.PhotoImage(file = dir_path + '//img//open.png') #Added by Rachel to replace file selector "..." button with open file icon - - # self.open_button = ttk.Button(fs_frame, width=4, image = self.open_file_icon, command=self.select_file, padding = '0.02i') - self.open_button = ttk.Button(fs_frame, width=4, text="...", command=self.select_file, padding = '0.02i') - self.open_button.grid(row=0, column=1, sticky=tk.E) - self.open_button.columnconfigure(0, weight=1) - fs_frame.grid(row=1, column=0, sticky=tk.NSEW) - fs_frame.columnconfigure(0, weight=10) - fs_frame.columnconfigure(1, weight=1) - # self.pack(fill=tk.BOTH, expand=1) - self.columnconfigure(0, weight=1) - self.rowconfigure(0, weight=1) - self.rowconfigure(1, weight=1) - - # Add the bindings - if _platform == "darwin": - self.entry.bind("", self.select_all) - else: - self.entry.bind("", self.select_all) - - def select_file(self): - try: - result = self.value.get() - if self.parameter_type == "Directory": - result = filedialog.askdirectory(initialdir=self.runner.working_dir, title="Select directory") - elif "ExistingFile" in self.parameter_type: - ftypes = [('All files', '*.*')] - if 'RasterAndVector' in self.file_type: - ftypes = [("Shapefiles", "*.shp"), ('Raster files', ('*.dep', '*.tif', - '*.tiff', '*.flt', - '*.sdat', '*.rdc', - '*.asc'))] - elif 'Raster' in self.file_type: - ftypes = [('Raster files', ('*.dep', '*.tif', - '*.tiff', '*.flt', - '*.sdat', '*.rdc', - '*.asc'))] - elif 'Lidar' in self.file_type: - ftypes = [("LiDAR files", ('*.las', '*.zlidar', '*.zip'))] - elif 'Vector' in self.file_type: - ftypes = [("Shapefiles", "*.shp")] - elif 'Text' in self.file_type: - ftypes = [("Text files", "*.txt"), ("all files", "*.*")] - elif 'Csv' in self.file_type: - ftypes = [("CSC files", "*.csv"), ("all files", "*.*")] - elif 'Html' in self.file_type: - ftypes = [("HTML files", "*.html")] - - result = filedialog.askopenfilename( - initialdir=self.runner.working_dir, title="Select file", filetypes=ftypes) - - elif "NewFile" in self.parameter_type: - result = filedialog.asksaveasfilename() - - self.value.set(result) - # update the working directory - self.runner.working_dir = os.path.dirname(result) - - except: - t = "file" - if self.parameter_type == "Directory": - t = "directory" - messagebox.showinfo("Warning", "Could not find {}".format(t)) - - def get_value(self): - if self.value.get(): - v = self.value.get() - # Do some quality assurance here. - # Is there a directory included? - if not path.dirname(v): - v = path.join(self.runner.working_dir, v) - - # What about a file extension? - ext = os.path.splitext(v)[-1].lower().strip() - if not ext: - ext = "" - if 'RasterAndVector' in self.file_type: - ext = '.tif' - elif 'Raster' in self.file_type: - ext = '.tif' - elif 'Lidar' in self.file_type: - ext = '.las' - elif 'Vector' in self.file_type: - ext = '.shp' - elif 'Text' in self.file_type: - ext = '.txt' - elif 'Csv' in self.file_type: - ext = '.csv' - elif 'Html' in self.file_type: - ext = '.html' - - v += ext - - v = path.normpath(v) - - return "{}='{}'".format(self.flag, v) - else: - t = "file" - if self.parameter_type == "Directory": - t = "directory" - if not self.optional: - messagebox.showinfo( - "Error", "Unspecified {} parameter {}.".format(t, self.flag)) - - return None - - def select_all(self, event): - self.entry.select_range(0, tk.END) - return 'break' - - -class FileOrFloat(tk.Frame): - def __init__(self, json_str, runner, master=None): - # first make sure that the json data has the correct fields - j = json.loads(json_str) - self.name = j['name'] - self.description = j['description'] - self.flag = j['flags'][len(j['flags']) - 1] - self.parameter_type = j['parameter_type'] - self.file_type = j['parameter_type']['ExistingFileOrFloat'] - self.optional = j['optional'] - default_value = j['default_value'] - - self.runner = runner - - ttk.Frame.__init__(self, master) - self.grid() - self['padding'] = '0.02i' - - self.label = ttk.Label(self, text=self.name, justify=tk.LEFT) - self.label.grid(row=0, column=0, sticky=tk.W) - self.label.columnconfigure(0, weight=1) - - if not self.optional: - self.label['text'] = self.label['text'] + "*" - - fs_frame = ttk.Frame(self, padding='0.0i') - self.value = tk.StringVar() - self.entry = ttk.Entry( - fs_frame, width=35, justify=tk.LEFT, textvariable=self.value) - self.entry.grid(row=0, column=0, sticky=tk.NSEW) - self.entry.columnconfigure(0, weight=1) - if default_value: - self.value.set(default_value) - - # self.img = tk.PhotoImage(file=script_dir + "/img/open.gif") - # self.open_button = ttk.Button(fs_frame, width=55, image=self.img, command=self.select_dir) - self.open_button = ttk.Button( - fs_frame, width=4, text="...", command=self.select_file) - self.open_button.grid(row=0, column=1, sticky=tk.E) - # self.open_button.columnconfigure(0, weight=1) - - self.label = ttk.Label(fs_frame, text='OR', justify=tk.LEFT) - self.label.grid(row=0, column=2, sticky=tk.W) - # self.label.columnconfigure(0, weight=1) - - self.value2 = tk.StringVar() - self.entry2 = ttk.Entry( - fs_frame, width=10, justify=tk.LEFT, textvariable=self.value2) - self.entry2.grid(row=0, column=3, sticky=tk.NSEW) - self.entry2.columnconfigure(0, weight=1) - self.entry2['justify'] = 'right' - - fs_frame.grid(row=1, column=0, sticky=tk.NSEW) - fs_frame.columnconfigure(0, weight=10) - fs_frame.columnconfigure(1, weight=1) - # self.pack(fill=tk.BOTH, expand=1) - self.columnconfigure(0, weight=1) - self.rowconfigure(0, weight=1) - self.rowconfigure(1, weight=1) - - # Add the bindings - if _platform == "darwin": - self.entry.bind("", self.select_all) - else: - self.entry.bind("", self.select_all) - - def select_file(self): - try: - result = self.value.get() - ftypes = [('All files', '*.*')] - if 'RasterAndVector' in self.file_type: - ftypes = [("Shapefiles", "*.shp"), ('Raster files', ('*.dep', '*.tif', - '*.tiff', '*.flt', - '*.sdat', '*.rdc', - '*.asc'))] - elif 'Raster' in self.file_type: - ftypes = [('Raster files', ('*.dep', '*.tif', - '*.tiff', '*.flt', - '*.sdat', '*.rdc', - '*.asc'))] - elif 'Lidar' in self.file_type: - ftypes = [("LiDAR files", ('*.las', '*.zlidar', '*.zip'))] - elif 'Vector' in self.file_type: - ftypes = [("Shapefiles", "*.shp")] - elif 'Text' in self.file_type: - ftypes = [("Text files", "*.txt"), ("all files", "*.*")] - elif 'Csv' in self.file_type: - ftypes = [("CSC files", "*.csv"), ("all files", "*.*")] - elif 'Html' in self.file_type: - ftypes = [("HTML files", "*.html")] - - result = filedialog.askopenfilename( - initialdir=self.runner.working_dir, title="Select file", filetypes=ftypes) - - self.value.set(result) - # update the working directory - self.runner.working_dir = os.path.dirname(result) - - except: - t = "file" - if self.parameter_type == "Directory": - t = "directory" - messagebox.showinfo("Warning", "Could not find {}".format(t)) - - def RepresentsFloat(self, s): - try: - float(s) - return True - except ValueError: - return False - - def get_value(self): - if self.value.get(): - v = self.value.get() - # Do some quality assurance here. - # Is there a directory included? - if not path.dirname(v): - v = path.join(self.runner.working_dir, v) - - # What about a file extension? - ext = os.path.splitext(v)[-1].lower() - if not ext: - ext = "" - if 'RasterAndVector' in self.file_type: - ext = '.tif' - elif 'Raster' in self.file_type: - ext = '.tif' - elif 'Lidar' in self.file_type: - ext = '.las' - elif 'Vector' in self.file_type: - ext = '.shp' - elif 'Text' in self.file_type: - ext = '.txt' - elif 'Csv' in self.file_type: - ext = '.csv' - elif 'Html' in self.file_type: - ext = '.html' - - v = v + ext - - v = path.normpath(v) - - return "{}='{}'".format(self.flag, v) - elif self.value2.get(): - v = self.value2.get() - if self.RepresentsFloat(v): - return "{}={}".format(self.flag, v) - else: - messagebox.showinfo( - "Error", "Error converting parameter {} to type Float.".format(self.flag)) - else: - if not self.optional: - messagebox.showinfo( - "Error", "Unspecified file/numeric parameter {}.".format(self.flag)) - - return None - - def select_all(self, event): - self.entry.select_range(0, tk.END) - return 'break' - - -class MultifileSelector(tk.Frame): - def __init__(self, json_str, runner, master=None): - # first make sure that the json data has the correct fields - j = json.loads(json_str) - self.name = j['name'] - self.description = j['description'] - self.flag = j['flags'][len(j['flags']) - 1] - self.parameter_type = j['parameter_type'] - self.file_type = "" - self.file_type = j['parameter_type']['FileList'] - self.optional = j['optional'] - default_value = j['default_value'] - - self.runner = runner - - ttk.Frame.__init__(self, master) - self.grid() - self['padding'] = '0.05i' - - self.label = ttk.Label(self, text=self.name, justify=tk.LEFT) - self.label.grid(row=0, column=0, sticky=tk.W) - self.label.columnconfigure(0, weight=1) - - if not self.optional: - self.label['text'] = self.label['text'] + "*" - - fs_frame = ttk.Frame(self, padding='0.0i') - # , variable=self.value) - self.opt = tk.Listbox(fs_frame, width=44, height=4) - self.opt.grid(row=0, column=0, sticky=tk.NSEW) - s = ttk.Scrollbar(fs_frame, orient=tk.VERTICAL, command=self.opt.yview) - s.grid(row=0, column=1, sticky=(tk.N, tk.S)) - self.opt['yscrollcommand'] = s.set - - btn_frame = ttk.Frame(fs_frame, padding='0.0i') - self.open_button = ttk.Button( - btn_frame, width=4, text="...", command=self.select_file) - self.open_button.grid(row=0, column=0, sticky=tk.NE) - self.open_button.columnconfigure(0, weight=1) - self.open_button.rowconfigure(0, weight=1) - - self.delete_button = ttk.Button( - btn_frame, width=4, text="del", command=self.delete_entry) - self.delete_button.grid(row=1, column=0, sticky=tk.NE) - self.delete_button.columnconfigure(0, weight=1) - self.delete_button.rowconfigure(1, weight=1) - - btn_frame.grid(row=0, column=2, sticky=tk.NE) - - fs_frame.grid(row=1, column=0, sticky=tk.NSEW) - fs_frame.columnconfigure(0, weight=10) - fs_frame.columnconfigure(1, weight=1) - fs_frame.columnconfigure(2, weight=1) - # self.pack(fill=tk.BOTH, expand=1) - self.columnconfigure(0, weight=1) - self.rowconfigure(0, weight=1) - self.rowconfigure(1, weight=1) - - def select_file(self): - try: - #result = self.value.get() - init_dir = self.runner.working_dir - ftypes = [('All files', '*.*')] - if 'RasterAndVector' in self.file_type: - ftypes = [("Shapefiles", "*.shp"), ('Raster files', ('*.dep', '*.tif', - '*.tiff', '*.flt', - '*.sdat', '*.rdc', - '*.asc'))] - elif 'Raster' in self.file_type: - ftypes = [('Raster files', ('*.dep', '*.tif', - '*.tiff', '*.flt', - '*.sdat', '*.rdc', - '*.asc'))] - elif 'Lidar' in self.file_type: - ftypes = [("LiDAR files", ('*.las', '*.zlidar', '*.zip'))] - elif 'Vector' in self.file_type: - ftypes = [("Shapefiles", "*.shp")] - elif 'Text' in self.file_type: - ftypes = [("Text files", "*.txt"), ("all files", "*.*")] - elif 'Csv' in self.file_type: - ftypes = [("CSC files", "*.csv"), ("all files", "*.*")] - elif 'Html' in self.file_type: - ftypes = [("HTML files", "*.html")] - - result = filedialog.askopenfilenames( - initialdir=init_dir, title="Select files", filetypes=ftypes) - if result: - for v in result: - self.opt.insert(tk.END, v) - - # update the working directory - self.runner.working_dir = os.path.dirname(result[0]) - - except: - messagebox.showinfo("Warning", "Could not find file") - - def delete_entry(self): - self.opt.delete(tk.ANCHOR) - - def get_value(self): - try: - l = self.opt.get(0, tk.END) - if l: - s = "" - for i in range(0, len(l)): - v = l[i] - if not path.dirname(v): - v = path.join(self.runner.working_dir, v) - v = path.normpath(v) - if i < len(l) - 1: - s += "{};".format(v) - else: - s += "{}".format(v) - - return "{}='{}'".format(self.flag, s) - else: - if not self.optional: - messagebox.showinfo( - "Error", "Unspecified non-optional parameter {}.".format(self.flag)) - - except: - messagebox.showinfo( - "Error", "Error formating files for parameter {}".format(self.flag)) - - return None - - -class BooleanInput(tk.Frame): - def __init__(self, json_str, master=None): - # first make sure that the json data has the correct fields - j = json.loads(json_str) - self.name = j['name'] - self.description = j['description'] - self.flag = j['flags'][len(j['flags']) - 1] - self.parameter_type = j['parameter_type'] - # just for quality control. BooleanInputs are always optional. - self.optional = True - default_value = j['default_value'] - - ttk.Frame.__init__(self, master) - self.grid() - self['padding'] = '0.05i' - - frame = ttk.Frame(self, padding='0.0i') - - self.value = tk.IntVar() - c = ttk.Checkbutton(frame, text=self.name, - width=55, variable=self.value) - c.grid(row=0, column=0, sticky=tk.W) - - # set the default value - if j['default_value'] != None and j['default_value'] != 'false': - self.value.set(1) - else: - self.value.set(0) - - frame.grid(row=1, column=0, sticky=tk.W) - frame.columnconfigure(0, weight=1) - - # self.pack(fill=tk.BOTH, expand=1) - self.columnconfigure(0, weight=1) - self.rowconfigure(0, weight=1) - - def get_value(self): - if self.value.get() == 1: - return self.flag - else: - return None - - -class OptionsInput(tk.Frame): - def __init__(self, json_str, master=None): - # first make sure that the json data has the correct fields - j = json.loads(json_str) - self.name = j['name'] - self.description = j['description'] - self.flag = j['flags'][len(j['flags']) - 1] - self.parameter_type = j['parameter_type'] - self.optional = j['optional'] - default_value = j['default_value'] - - ttk.Frame.__init__(self, master) - self.grid() - self['padding'] = '0.02i' - - frame = ttk.Frame(self, padding='0.0i') - - self.label = ttk.Label(self, text=self.name, justify=tk.LEFT) - self.label.grid(row=0, column=0, sticky=tk.W) - self.label.columnconfigure(0, weight=1) - - frame2 = ttk.Frame(frame, padding='0.0i') - opt = ttk.Combobox(frame2, width=40) - opt.grid(row=0, column=0, sticky=tk.NSEW) - - self.value = None # initialize in event of no default and no selection - i = 1 - default_index = -1 - list = j['parameter_type']['OptionList'] - values = () - for v in list: - values += (v,) - # opt.insert(tk.END, v) - if v == default_value: - default_index = i - 1 - i = i + 1 - - opt['values'] = values - - # opt.bind("<>", self.select) - opt.bind("<>", self.select) - if default_index >= 0: - opt.current(default_index) - opt.event_generate("<>") - # opt.see(default_index) - - frame2.grid(row=0, column=0, sticky=tk.W) - frame.grid(row=1, column=0, sticky=tk.W) - frame.columnconfigure(0, weight=1) - - # self.pack(fill=tk.BOTH, expand=1) - self.columnconfigure(0, weight=1) - self.rowconfigure(0, weight=1) - - # # first make sure that the json data has the correct fields - # j = json.loads(json_str) - # self.name = j['name'] - # self.description = j['description'] - # self.flag = j['flags'][len(j['flags']) - 1] - # self.parameter_type = j['parameter_type'] - # self.optional = j['optional'] - # default_value = j['default_value'] - - # ttk.Frame.__init__(self, master) - # self.grid() - # self['padding'] = '0.1i' - - # frame = ttk.Frame(self, padding='0.0i') - - # self.label = ttk.Label(self, text=self.name, justify=tk.LEFT) - # self.label.grid(row=0, column=0, sticky=tk.W) - # self.label.columnconfigure(0, weight=1) - - # frame2 = ttk.Frame(frame, padding='0.0i') - # opt = tk.Listbox(frame2, width=40) # , variable=self.value) - # opt.grid(row=0, column=0, sticky=tk.NSEW) - # s = ttk.Scrollbar(frame2, orient=tk.VERTICAL, command=opt.yview) - # s.grid(row=0, column=1, sticky=(tk.N, tk.S)) - # opt['yscrollcommand'] = s.set - - # self.value = None # initialize in event of no default and no selection - # i = 1 - # default_index = -1 - # list = j['parameter_type']['OptionList'] - # for v in list: - # #opt.insert(i, v) - # opt.insert(tk.END, v) - # if v == default_value: - # default_index = i - 1 - # i = i + 1 - - # if i - 1 < 4: - # opt['height'] = i - 1 - # else: - # opt['height'] = 3 - - # opt.bind("<>", self.select) - # if default_index >= 0: - # opt.select_set(default_index) - # opt.event_generate("<>") - # opt.see(default_index) - - # frame2.grid(row=0, column=0, sticky=tk.W) - # frame.grid(row=1, column=0, sticky=tk.W) - # frame.columnconfigure(0, weight=1) - - # # self.pack(fill=tk.BOTH, expand=1) - # self.columnconfigure(0, weight=1) - # self.rowconfigure(0, weight=1) - - def get_value(self): - if self.value: - return "{}='{}'".format(self.flag, self.value) - else: - if not self.optional: - messagebox.showinfo( - "Error", "Unspecified non-optional parameter {}.".format(self.flag)) - - return None - - def select(self, event): - widget = event.widget - # selection = widget.curselection() - self.value = widget.get() # selection[0]) - - -class DataInput(tk.Frame): - def __init__(self, json_str, master=None): - # first make sure that the json data has the correct fields - j = json.loads(json_str) - self.name = j['name'] - self.description = j['description'] - self.flag = j['flags'][len(j['flags']) - 1] - self.parameter_type = j['parameter_type'] - self.optional = j['optional'] - default_value = j['default_value'] - - ttk.Frame.__init__(self, master) - self.grid() - self['padding'] = '0.1i' - - self.label = ttk.Label(self, text=self.name, justify=tk.LEFT) - self.label.grid(row=0, column=0, sticky=tk.W) - self.label.columnconfigure(0, weight=1) - - self.value = tk.StringVar() - if default_value: - self.value.set(default_value) - else: - self.value.set("") - - self.entry = ttk.Entry(self, justify=tk.LEFT, textvariable=self.value) - self.entry.grid(row=0, column=1, sticky=tk.NSEW) - self.entry.columnconfigure(1, weight=10) - - if not self.optional: - self.label['text'] = self.label['text'] + "*" - - if ("Integer" in self.parameter_type or - "Float" in self.parameter_type or - "Double" in self.parameter_type): - self.entry['justify'] = 'right' - - # Add the bindings - if _platform == "darwin": - self.entry.bind("", self.select_all) - else: - self.entry.bind("", self.select_all) - - # self.pack(fill=tk.BOTH, expand=1) - self.columnconfigure(0, weight=1) - self.columnconfigure(1, weight=10) - self.rowconfigure(0, weight=1) - - def RepresentsInt(self, s): - try: - int(s) - return True - except ValueError: - return False - - def RepresentsFloat(self, s): - try: - float(s) - return True - except ValueError: - return False - - def get_value(self): - v = self.value.get() - if v: - if "Integer" in self.parameter_type: - if self.RepresentsInt(self.value.get()): - return "{}={}".format(self.flag, self.value.get()) - else: - messagebox.showinfo( - "Error", "Error converting parameter {} to type Integer.".format(self.flag)) - elif "Float" in self.parameter_type: - if self.RepresentsFloat(self.value.get()): - return "{}={}".format(self.flag, self.value.get()) - else: - messagebox.showinfo( - "Error", "Error converting parameter {} to type Float.".format(self.flag)) - elif "Double" in self.parameter_type: - if self.RepresentsFloat(self.value.get()): - return "{}={}".format(self.flag, self.value.get()) - else: - messagebox.showinfo( - "Error", "Error converting parameter {} to type Double.".format(self.flag)) - else: # String or StringOrNumber types - return "{}='{}'".format(self.flag, self.value.get()) - else: - if not self.optional: - messagebox.showinfo( - "Error", "Unspecified non-optional parameter {}.".format(self.flag)) - - return None - - def select_all(self, event): - self.entry.select_range(0, tk.END) - return 'break' - - -class WbRunner(tk.Frame): - def __init__(self, tool_name=None, master=None): - if platform.system() == 'Windows': - self.ext = '.exe' - else: - self.ext = '' - - exe_name = "whitebox_tools{}".format(self.ext) - - self.exe_path = path.dirname(path.abspath(__file__)) - os.chdir(self.exe_path) - for filename in glob.iglob('**/*', recursive=True): - if filename.endswith(exe_name): - self.exe_path = path.dirname(path.abspath(filename)) - break - - wbt.set_whitebox_dir(self.exe_path) - - ttk.Frame.__init__(self, master) - self.script_dir = os.path.dirname(os.path.realpath(__file__)) - self.grid() - self.tool_name = tool_name - self.master.title("WhiteboxTools Runner") - if _platform == "darwin": - os.system( - '''/usr/bin/osascript -e 'tell app "Finder" to set frontmost of process "Python" to true' ''') - self.create_widgets() - self.working_dir = str(Path.home()) - - def create_widgets(self): - - ######################################################### - # Overall/Top level Frame # - ######################################################### - #define left-side frame (toplevel_frame) and right-side frame (overall_frame) - toplevel_frame = ttk.Frame(self, padding='0.1i') - overall_frame = ttk.Frame(self, padding='0.1i') - #set-up layout - overall_frame.grid(row=0, column=1, sticky=tk.NSEW) - toplevel_frame.grid(row=0, column=0, sticky=tk.NSEW) - ######################################################### - # Calling basics # - ######################################################### - #Create all needed lists of tools and toolboxes - self.toolbox_list = self.get_toolboxes() - self.sort_toolboxes() - self.tools_and_toolboxes = wbt.toolbox('') - self.sort_tools_by_toolbox() - self.get_tools_list() - #Icons to be used in tool treeview - self.tool_icon = tk.PhotoImage(file = self.script_dir + '//img//tool.gif') - self.open_toolbox_icon = tk.PhotoImage(file = self.script_dir + '//img//open.gif') - self.closed_toolbox_icon = tk.PhotoImage(file = self.script_dir + '//img//closed.gif') - ######################################################### - # Toolboxes Frame # FIXME: change width or make horizontally scrollable - ######################################################### - #define tools_frame and tool_tree - self.tools_frame = ttk.LabelFrame(toplevel_frame, text="{} Available Tools".format(len(self.tools_list)), padding='0.1i') - self.tool_tree = ttk.Treeview(self.tools_frame, height = 21) - #Set up layout - self.tool_tree.grid(row=0, column=0, sticky=tk.NSEW) - self.tool_tree.column("#0", width = 280) #Set width so all tools are readable within the frame - self.tools_frame.grid(row=0, column=0, sticky=tk.NSEW) - self.tools_frame.columnconfigure(0, weight=10) - self.tools_frame.columnconfigure(1, weight=1) - self.tools_frame.rowconfigure(0, weight=10) - self.tools_frame.rowconfigure(1, weight=1) - #Add toolboxes and tools to treeview - index = 0 - for toolbox in self.lower_toolboxes: - if toolbox.find('/') != (-1): #toolboxes - self.tool_tree.insert(toolbox[:toolbox.find('/')], 0, text = " " + toolbox[toolbox.find('/') + 1:], iid = toolbox[toolbox.find('/') + 1:], tags = 'toolbox', image = self.closed_toolbox_icon) - for tool in self.sorted_tools[index]: #add tools within toolbox - self.tool_tree.insert(toolbox[toolbox.find('/') + 1:], 'end', text = " " + tool, tags = 'tool', iid = tool, image = self.tool_icon) - else: #subtoolboxes - self.tool_tree.insert('', 'end', text = " " + toolbox, iid = toolbox, tags = 'toolbox', image = self.closed_toolbox_icon) - for tool in self.sorted_tools[index]: #add tools within subtoolbox - self.tool_tree.insert(toolbox, 'end', text = " " + tool, iid = tool, tags = 'tool', image = self.tool_icon) - index = index + 1 - #bind tools in treeview to self.tree_update_tool_help function and toolboxes to self.update_toolbox_icon function - self.tool_tree.tag_bind('tool', "<>", self.tree_update_tool_help) - self.tool_tree.tag_bind('toolbox', "<>", self.update_toolbox_icon) - #Add vertical scrollbar to treeview frame - s = ttk.Scrollbar(self.tools_frame, orient=tk.VERTICAL,command=self.tool_tree.yview) - s.grid(row=0, column=1, sticky=(tk.N, tk.S)) - self.tool_tree['yscrollcommand'] = s.set - ######################################################### - # Search Bar # - ######################################################### - #create variables for search results and search input - self.search_list = [] - self.search_text = tk.StringVar() - #Create the elements of the search frame - self.search_frame = ttk.LabelFrame(toplevel_frame, padding='0.1i', text="{} Tools Found".format(len(self.search_list))) - self.search_label = ttk.Label(self.search_frame, text = "Search: ") - self.search_bar = ttk.Entry(self.search_frame, width = 30, textvariable = self.search_text) - self.search_results_listbox = tk.Listbox(self.search_frame, height=11) - self.search_scroll = ttk.Scrollbar(self.search_frame, orient=tk.VERTICAL, command=self.search_results_listbox.yview) - self.search_results_listbox['yscrollcommand'] = self.search_scroll.set - #Add bindings - self.search_results_listbox.bind("<>", self.search_update_tool_help) - self.search_bar.bind('', self.update_search) - #Define layout of the frame - self.search_frame.grid(row = 1, column = 0, sticky=tk.NSEW) - self.search_label.grid(row = 0, column = 0, sticky=tk.NW) - self.search_bar.grid(row = 0, column = 1, sticky=tk.NE) - self.search_results_listbox.grid(row = 1, column = 0, columnspan = 2, sticky=tk.NSEW, pady = 5) - self.search_scroll.grid(row=1, column=2, sticky=(tk.N, tk.S)) - #Configure rows and columns of the frame - self.search_frame.columnconfigure(0, weight=1) - self.search_frame.columnconfigure(1, weight=10) - self.search_frame.columnconfigure(1, weight=1) - self.search_frame.rowconfigure(0, weight=1) - self.search_frame.rowconfigure(1, weight = 10) - ######################################################### - # Current Tool Frame # - ######################################################### - #Create the elements of the current tool frame - self.current_tool_frame = ttk.Frame(overall_frame, padding='0.01i') - self.current_tool_lbl = ttk.Label(self.current_tool_frame, text="Current Tool: {}".format(self.tool_name), justify=tk.LEFT) # , font=("Helvetica", 12, "bold") - self.view_code_button = ttk.Button(self.current_tool_frame, text="View Code", width=12, command=self.view_code) - #Define layout of the frame - self.view_code_button.grid(row=0, column=1, sticky=tk.E) - self.current_tool_lbl.grid(row=0, column=0, sticky=tk.W) - self.current_tool_frame.grid(row=0, column=0, columnspan = 2, sticky=tk.NSEW) - #Configure rows and columns of the frame - self.current_tool_frame.columnconfigure(0, weight=1) - self.current_tool_frame.columnconfigure(1, weight=1) - ######################################################### - # Args Frame # - ######################################################### - # #Create the elements of the tool arguments frame - # self.arg_scroll = ttk.Scrollbar(overall_frame, orient='vertical') - # self.arg_canvas = tk.Canvas(overall_frame, bd=0, highlightthickness=0, yscrollcommand=self.arg_scroll.set) - # self.arg_scroll.config(command=self.arg_canvas.yview) #self.arg_scroll scrolls over self.arg_canvas - # self.arg_scroll_frame = ttk.Frame(self.arg_canvas) # create a frame inside the self.arg_canvas which will be scrolled with it - # self.arg_scroll_frame_id = self.arg_canvas.create_window(0, 0, window=self.arg_scroll_frame, anchor="nw") - # #Define layout of the frame - # self.arg_scroll.grid(row = 1, column = 1, sticky = (tk.NS, tk.E)) - # self.arg_canvas.grid(row = 1, column = 0, sticky = tk.NSEW) - # # reset the view - # self.arg_canvas.xview_moveto(0) - # self.arg_canvas.yview_moveto(0) - # #Add bindings - # self.arg_scroll_frame.bind('', self.configure_arg_scroll_frame) - # self.arg_canvas.bind('', self.configure_arg_canvas) - self.arg_scroll_frame = ttk.Frame(overall_frame, padding='0.0i') - self.arg_scroll_frame.grid(row=1, column=0, sticky=tk.NSEW) - self.arg_scroll_frame.columnconfigure(0, weight=1) - ######################################################### - # Buttons Frame # - ######################################################### - #Create the elements of the buttons frame - buttons_frame = ttk.Frame(overall_frame, padding='0.1i') - self.run_button = ttk.Button(buttons_frame, text="Run", width=8, command=self.run_tool) - self.quit_button = ttk.Button(buttons_frame, text="Cancel", width=8, command=self.cancel_operation) - self.help_button = ttk.Button(buttons_frame, text="Help", width=8, command=self.tool_help_button) - #Define layout of the frame - self.run_button.grid(row=0, column=0) - self.quit_button.grid(row=0, column=1) - self.help_button.grid(row = 0, column = 2) - buttons_frame.grid(row=2, column=0, columnspan = 2, sticky=tk.E) - ######################################################### - # Output Frame # - ######################################################### - #Create the elements of the output frame - output_frame = ttk.Frame(overall_frame) - outlabel = ttk.Label(output_frame, text="Output:", justify=tk.LEFT) - self.out_text = ScrolledText(output_frame, width=63, height=15, wrap=tk.NONE, padx=7, pady=7, exportselection = 0) - output_scrollbar = ttk.Scrollbar(output_frame, orient=tk.HORIZONTAL, command = self.out_text.xview) - self.out_text['xscrollcommand'] = output_scrollbar.set - #Retreive and insert the text for the current tool - k = wbt.tool_help(self.tool_name) - self.out_text.insert(tk.END, k) - #Define layout of the frame - outlabel.grid(row=0, column=0, sticky=tk.NW) - self.out_text.grid(row=1, column=0, sticky=tk.NSEW) - output_frame.grid(row=3, column=0, columnspan = 2, sticky=(tk.NS, tk.E)) - output_scrollbar.grid(row=2, column=0, sticky=(tk.W, tk.E)) - #Configure rows and columns of the frame - self.out_text.columnconfigure(0, weight=1) - output_frame.columnconfigure(0, weight=1) - # Add the binding - if _platform == "darwin": - self.out_text.bind("", self.select_all) - else: - self.out_text.bind("", self.select_all) - ######################################################### - # Progress Frame # - ######################################################### - #Create the elements of the progress frame - progress_frame = ttk.Frame(overall_frame, padding='0.1i') - self.progress_label = ttk.Label(progress_frame, text="Progress:", justify=tk.LEFT) - self.progress_var = tk.DoubleVar() - self.progress = ttk.Progressbar(progress_frame, orient="horizontal", variable=self.progress_var, length=200, maximum=100) - #Define layout of the frame - self.progress_label.grid(row=0, column=0, sticky=tk.E, padx=5) - self.progress.grid(row=0, column=1, sticky=tk.E) - progress_frame.grid(row=4, column=0, columnspan = 2, sticky=tk.SE) - ######################################################### - # Tool Selection # - ######################################################### - # Select the appropriate tool, if specified, otherwise the first tool - self.tool_tree.focus(self.tool_name) - self.tool_tree.selection_set(self.tool_name) - self.tool_tree.event_generate("<>") - ######################################################### - # Menus # - ######################################################### - menubar = tk.Menu(self) - - self.filemenu = tk.Menu(menubar, tearoff=0) - self.filemenu.add_command(label="Set Working Directory", command=self.set_directory) - self.filemenu.add_command(label="Locate WhiteboxTools exe", command=self.select_exe) - self.filemenu.add_command(label="Refresh Tools", command=self.refresh_tools) - wbt.set_compress_rasters(True) - self.filemenu.add_command(label="Do Not Compress Output TIFFs", command=self.update_compress) - self.filemenu.add_separator() - self.filemenu.add_command(label="Exit", command=self.quit) - menubar.add_cascade(label="File", menu=self.filemenu) - - editmenu = tk.Menu(menubar, tearoff=0) - editmenu.add_command(label="Cut", command=lambda: self.focus_get().event_generate("<>")) - editmenu.add_command(label="Copy", command=lambda: self.focus_get().event_generate("<>")) - editmenu.add_command(label="Paste", command=lambda: self.focus_get().event_generate("<>")) - menubar.add_cascade(label="Edit ", menu=editmenu) - - helpmenu = tk.Menu(menubar, tearoff=0) - helpmenu.add_command(label="About", command=self.help) - helpmenu.add_command(label="License", command=self.license) - menubar.add_cascade(label="Help ", menu=helpmenu) - - self.master.config(menu=menubar) - - def update_compress(self): - if wbt.get_compress_rasters(): - wbt.set_compress_rasters(False) - self.filemenu.entryconfig(3, label = "Compress Output TIFFs") - else: - wbt.set_compress_rasters(True) - self.filemenu.entryconfig(3, label = "Do Not Compress Output TIFFs") - - def get_toolboxes(self): - toolboxes = set() - for item in wbt.toolbox().splitlines(): # run wbt.toolbox with no tool specified--returns all - if item: - tb = item.split(":")[1].strip() - toolboxes.add(tb) - return sorted(toolboxes) - - def sort_toolboxes(self): - self.upper_toolboxes = [] - self.lower_toolboxes = [] - for toolbox in self.toolbox_list: - if toolbox.find('/') == (-1): #Does not contain a subtoolbox, i.e. does not contain '/' - self.upper_toolboxes.append(toolbox) #add to both upper toolbox list and lower toolbox list - self.lower_toolboxes.append(toolbox) - else: #Contains a subtoolbox - self.lower_toolboxes.append(toolbox) #add to only the lower toolbox list - self.upper_toolboxes = sorted(self.upper_toolboxes) #sort both lists alphabetically - self.lower_toolboxes = sorted(self.lower_toolboxes) - - def sort_tools_by_toolbox(self): - self.sorted_tools = [[] for i in range(len(self.lower_toolboxes))] #One list for each lower toolbox - count = 1 - for toolAndToolbox in self.tools_and_toolboxes.split('\n'): - if toolAndToolbox.strip(): - tool = toolAndToolbox.strip().split(':')[0].strip().replace("TIN", "Tin").replace("KS", "Ks").replace("FD", "Fd") #current tool - itemToolbox = toolAndToolbox.strip().split(':')[1].strip() #current toolbox - index = 0 - for toolbox in self.lower_toolboxes: #find which toolbox the current tool belongs to - if toolbox == itemToolbox: - self.sorted_tools[index].append(tool) #add current tool to list at appropriate index - break - index = index + 1 - count = count + 1 - - def get_tools_list(self): - self.tools_list = [] - selected_item = -1 - for item in wbt.list_tools().keys(): - if item: - value = to_camelcase(item).replace("TIN", "Tin").replace("KS", "Ks").replace("FD", "Fd") #format tool name - self.tools_list.append(value) #add tool to list - if item == self.tool_name: #update selected_item it tool found - selected_item = len(self.tools_list) - 1 - if selected_item == -1: #set self.tool_name as default tool - selected_item = 0 - self.tool_name = self.tools_list[0] - - def tree_update_tool_help(self, event): # read selection when tool selected from treeview then call self.update_tool_help - curItem = self.tool_tree.focus() - self.tool_name = self.tool_tree.item(curItem).get('text').replace(" ", "") - self.update_tool_help() - - def search_update_tool_help(self, event): # read selection when tool selected from search results then call self.update_tool_help - selection = self.search_results_listbox.curselection() - self.tool_name = self.search_results_listbox.get(selection[0]) - self.update_tool_help() - - def update_tool_help(self): - self.out_text.delete('1.0', tk.END) - for widget in self.arg_scroll_frame.winfo_children(): - widget.destroy() - - k = wbt.tool_help(self.tool_name) - self.print_to_output(k) - - j = json.loads(wbt.tool_parameters(self.tool_name)) - param_num = 0 - for p in j['parameters']: - json_str = json.dumps( - p, sort_keys=True, indent=2, separators=(',', ': ')) - pt = p['parameter_type'] - if 'ExistingFileOrFloat' in pt: - ff = FileOrFloat(json_str, self, self.arg_scroll_frame) - ff.grid(row=param_num, column=0, sticky=tk.NSEW) - param_num = param_num + 1 - elif ('ExistingFile' in pt or 'NewFile' in pt or 'Directory' in pt): - fs = FileSelector(json_str, self, self.arg_scroll_frame) - fs.grid(row=param_num, column=0, sticky=tk.NSEW) - param_num = param_num + 1 - elif 'FileList' in pt: - b = MultifileSelector(json_str, self, self.arg_scroll_frame) - b.grid(row=param_num, column=0, sticky=tk.W) - param_num = param_num + 1 - elif 'Boolean' in pt: - b = BooleanInput(json_str, self.arg_scroll_frame) - b.grid(row=param_num, column=0, sticky=tk.W) - param_num = param_num + 1 - elif 'OptionList' in pt: - b = OptionsInput(json_str, self.arg_scroll_frame) - b.grid(row=param_num, column=0, sticky=tk.W) - param_num = param_num + 1 - elif ('Float' in pt or 'Integer' in pt or - 'String' in pt or 'StringOrNumber' in pt or - 'StringList' in pt or 'VectorAttributeField' in pt): - b = DataInput(json_str, self.arg_scroll_frame) - b.grid(row=param_num, column=0, sticky=tk.NSEW) - param_num = param_num + 1 - else: - messagebox.showinfo( - "Error", "Unsupported parameter type: {}.".format(pt)) - self.update_args_box() - self.out_text.see("%d.%d" % (1, 0)) - - def update_toolbox_icon(self, event): - curItem = self.tool_tree.focus() - dict = self.tool_tree.item(curItem) #retreive the toolbox name - self.toolbox_name = dict.get('text'). replace(" ", "") #delete the space between the icon and text - self.toolbox_open = dict.get('open') #retreive whether the toolbox is open or not - if self.toolbox_open == True: #set image accordingly - self.tool_tree.item(self.toolbox_name, image = self.open_toolbox_icon) - else: - self.tool_tree.item(self.toolbox_name, image = self.closed_toolbox_icon) - - def update_search(self, event): - self.search_list = [] - self.search_string = self.search_text.get().lower() - self.search_results_listbox.delete(0, 'end') #empty the search results - num_results = 0 - for tool in self.tools_list: #search tool names - toolLower = tool.lower() - if toolLower.find(self.search_string) != (-1): #search string found within tool name - num_results = num_results + 1 - self.search_results_listbox.insert(num_results, tool) #tool added to listbox and to search results string - self.search_list.append(tool) - index = 0 - self.get_descriptions() - for description in self.descriptionList: #search tool descriptions - descriptionLower = description.lower() - if descriptionLower.find(self.search_string) != (-1): #search string found within tool description - found = 0 - for item in self.search_list: # check if this tool is already in the listbox - if self.tools_list[index] == item: - found = 1 - if found == 0: # add to listbox - num_results = num_results + 1 - self.search_results_listbox.insert(num_results, self.tools_list[index]) #tool added to listbox and to search results string - index = index + 1 - self.search_frame['text'] = "{} Tools Found".format(num_results) #update search label - - def get_descriptions(self): - self.descriptionList = [] - tools = wbt.list_tools() - toolsItems = tools.items() - for t in toolsItems: - self.descriptionList.append(t[1]) #second entry in tool dictionary is the description - - # def configure_arg_scroll_frame(self, event): - # # update the scrollbars to match the size of the inner frame - # size = (self.arg_scroll_frame.winfo_reqwidth(), self.arg_scroll_frame.winfo_reqheight()) - # self.arg_canvas.config(scrollregion="0 0 %s %s" % size) - # if self.arg_scroll_frame.winfo_reqwidth() != self.arg_canvas.winfo_width(): - # # update the canvas's width to fit the inner frame - # self.arg_canvas.config(width=self.arg_scroll_frame.winfo_reqwidth()) - - # def configure_arg_canvas(self, event): - # if self.arg_scroll_frame.winfo_reqwidth() != self.arg_canvas.winfo_width(): - # # update the inner frame's width to fill the canvas - # self.arg_canvas.itemconfigure(self.arg_scroll_frame_id, width=self.arg_canvas.winfo_width()) - - def tool_help_button(self): - index = 0 - found = False - #find toolbox corresponding to the current tool - for toolbox in self.lower_toolboxes: - for tool in self.sorted_tools[index]: - if tool == self.tool_name: - self.toolbox_name = toolbox - found = True - break - if found: - break - index = index + 1 - #change LiDAR to Lidar - if index == 10: - self.toolbox_name = to_camelcase(self.toolbox_name) - #format subtoolboxes as for URLs - self.toolbox_name = self.camel_to_snake(self.toolbox_name).replace('/', '').replace(' ', '') - #open the user manual section for the current tool - webbrowser.open_new_tab("https://jblindsay.github.io/wbt_book/available_tools/" + self.toolbox_name + ".html#" + self.tool_name) - - def camel_to_snake(self, s): # taken from tools_info.py - _underscorer1 = re.compile(r'(.)([A-Z][a-z]+)') - _underscorer2 = re.compile('([a-z0-9])([A-Z])') - subbed = _underscorer1.sub(r'\1_\2', s) - return _underscorer2.sub(r'\1_\2', subbed).lower() - - def refresh_tools(self): - #refresh lists - self.tools_and_toolboxes = wbt.toolbox('') - self.sort_tools_by_toolbox() - self.get_tools_list() - #clear self.tool_tree - self.tool_tree.delete(*self.tool_tree.get_children()) - #Add toolboxes and tools to treeview - index = 0 - for toolbox in self.lower_toolboxes: - if toolbox.find('/') != (-1): #toolboxes - self.tool_tree.insert(toolbox[:toolbox.find('/')], 0, text = " " + toolbox[toolbox.find('/') + 1:], iid = toolbox[toolbox.find('/') + 1:], tags = 'toolbox', image = self.closed_toolbox_icon) - for tool in self.sorted_tools[index]: #add tools within toolbox - self.tool_tree.insert(toolbox[toolbox.find('/') + 1:], 'end', text = " " + tool, tags = 'tool', iid = tool, image = self.tool_icon) - else: #subtoolboxes - self.tool_tree.insert('', 'end', text = " " + toolbox, iid = toolbox, tags = 'toolbox', image = self.closed_toolbox_icon) - for tool in self.sorted_tools[index]: #add tools within subtoolbox - self.tool_tree.insert(toolbox, 'end', text = " " + tool, iid = tool, tags = 'tool', image = self.tool_icon) - index = index + 1 - #Update label - self.tools_frame["text"] = "{} Available Tools".format(len(self.tools_list)) - - ######################################################### - # Functions (original) # - ######################################################### - def help(self): - self.print_to_output(wbt.version()) - - def license(self): - self.print_to_output(wbt.license()) - - def set_directory(self): - try: - self.working_dir =filedialog.askdirectory(initialdir=self.working_dir) - wbt.set_working_dir(self.working_dir) - except: - messagebox.showinfo( - "Warning", "Could not set the working directory.") - - def select_exe(self): - try: - filename = filedialog.askopenfilename(initialdir=self.exe_path) - self.exe_path = path.dirname(path.abspath(filename)) - wbt.set_whitebox_dir(self.exe_path) - self.refresh_tools() - except: - messagebox.showinfo( - "Warning", "Could not find WhiteboxTools executable file.") - - def run_tool(self): - # wd_str = self.wd.get_value() - wbt.set_working_dir(self.working_dir) - # args = shlex.split(self.args_value.get()) - - args = [] - for widget in self.arg_scroll_frame.winfo_children(): - v = widget.get_value() - if v: - args.append(v) - elif not widget.optional: - messagebox.showinfo( - "Error", "Non-optional tool parameter not specified.") - return - - self.print_line_to_output("") - # self.print_line_to_output("Tool arguments:{}".format(args)) - # self.print_line_to_output("") - # Run the tool and check the return value for an error - if wbt.run_tool(self.tool_name, args, self.custom_callback) == 1: - print("Error running {}".format(self.tool_name)) - - else: - self.run_button["text"] = "Run" - self.progress_var.set(0) - self.progress_label['text'] = "Progress:" - self.progress.update_idletasks() - - def print_to_output(self, value): - self.out_text.insert(tk.END, value) - self.out_text.see(tk.END) - - def print_line_to_output(self, value): - self.out_text.insert(tk.END, value + "\n") - self.out_text.see(tk.END) - - def cancel_operation(self): - wbt.cancel_op = True - self.print_line_to_output("Cancelling operation...") - self.progress.update_idletasks() - - def view_code(self): - webbrowser.open_new_tab(wbt.view_code(self.tool_name).strip()) - - def update_args_box(self): - s = "" - self.current_tool_lbl['text'] = "Current Tool: {}".format( - self.tool_name) - # self.spacer['width'] = width=(35-len(self.tool_name)) - for item in wbt.tool_help(self.tool_name).splitlines(): - if item.startswith("-"): - k = item.split(" ") - if "--" in k[1]: - value = k[1].replace(",", "") - else: - value = k[0].replace(",", "") - - if "flag" in item.lower(): - s = s + value + " " - else: - if "file" in item.lower(): - s = s + value + "='{}' " - else: - s = s + value + "={} " - - # self.args_value.set(s.strip()) - - def custom_callback(self, value): - ''' A custom callback for dealing with tool output. - ''' - if "%" in value: - try: - str_array = value.split(" ") - label = value.replace( - str_array[len(str_array) - 1], "").strip() - progress = float( - str_array[len(str_array) - 1].replace("%", "").strip()) - self.progress_var.set(int(progress)) - self.progress_label['text'] = label - except ValueError as e: - print("Problem converting parsed data into number: ", e) - except Exception as e: - print(e) - else: - self.print_line_to_output(value) - - self.update() # this is needed for cancelling and updating the progress bar - - def select_all(self, event): - self.out_text.tag_add(tk.SEL, "1.0", tk.END) - self.out_text.mark_set(tk.INSERT, "1.0") - self.out_text.see(tk.INSERT) - return 'break' - -class JsonPayload(object): - def __init__(self, j): - self.__dict__ = json.loads(j) - - -def main(): - tool_name = None - if len(sys.argv) > 1: - tool_name = str(sys.argv[1]) - wbr = WbRunner(tool_name) - wbr.mainloop() - - -if __name__ == '__main__': +#!/usr/bin/env python3 + +# This script is part of the WhiteboxTools geospatial analysis library. +# Authors: Dr. John Lindsay, Rachel Broders +# Created: 28/11/2017 +# Last Modified: 05/11/2019 +# License: MIT + +import __future__ +import sys +# if sys.version_info[0] < 3: +# raise Exception("Must be using Python 3") +import json +import os +from os import path +# from __future__ import print_function +# from enum import Enum +import platform +import re #Added by Rachel for snake_to_camel function +from pathlib import Path +import glob +from sys import platform as _platform +import shlex +import tkinter as tk +from tkinter import ttk +from tkinter.scrolledtext import ScrolledText +from tkinter import filedialog +from tkinter import messagebox +from tkinter import PhotoImage +import webbrowser +from whitebox_tools import WhiteboxTools, to_camelcase + +wbt = WhiteboxTools() + + +class FileSelector(tk.Frame): + def __init__(self, json_str, runner, master=None): + # first make sure that the json data has the correct fields + j = json.loads(json_str) + self.name = j['name'] + self.description = j['description'] + self.flag = j['flags'][len(j['flags']) - 1] + self.parameter_type = j['parameter_type'] + self.file_type = "" + if "ExistingFile" in self.parameter_type: + self.file_type = j['parameter_type']['ExistingFile'] + elif "NewFile" in self.parameter_type: + self.file_type = j['parameter_type']['NewFile'] + self.optional = j['optional'] + default_value = j['default_value'] + + self.runner = runner + + ttk.Frame.__init__(self, master, padding='0.02i') + self.grid() + + self.label = ttk.Label(self, text=self.name, justify=tk.LEFT) + self.label.grid(row=0, column=0, sticky=tk.W) + self.label.columnconfigure(0, weight=1) + + if not self.optional: + self.label['text'] = self.label['text'] + "*" + + fs_frame = ttk.Frame(self, padding='0.0i') + self.value = tk.StringVar() + self.entry = ttk.Entry( + fs_frame, width=45, justify=tk.LEFT, textvariable=self.value) + self.entry.grid(row=0, column=0, sticky=tk.NSEW) + self.entry.columnconfigure(0, weight=1) + if default_value: + self.value.set(default_value) + + # dir_path = os.path.dirname(os.path.realpath(__file__)) + # print(dir_path) + # self.open_file_icon = tk.PhotoImage(file = dir_path + '//img//open.png') #Added by Rachel to replace file selector "..." button with open file icon + + # self.open_button = ttk.Button(fs_frame, width=4, image = self.open_file_icon, command=self.select_file, padding = '0.02i') + self.open_button = ttk.Button(fs_frame, width=4, text="...", command=self.select_file, padding = '0.02i') + self.open_button.grid(row=0, column=1, sticky=tk.E) + self.open_button.columnconfigure(0, weight=1) + fs_frame.grid(row=1, column=0, sticky=tk.NSEW) + fs_frame.columnconfigure(0, weight=10) + fs_frame.columnconfigure(1, weight=1) + # self.pack(fill=tk.BOTH, expand=1) + self.columnconfigure(0, weight=1) + self.rowconfigure(0, weight=1) + self.rowconfigure(1, weight=1) + + # Add the bindings + if _platform == "darwin": + self.entry.bind("", self.select_all) + else: + self.entry.bind("", self.select_all) + + def select_file(self): + try: + result = self.value.get() + if self.parameter_type == "Directory": + result = filedialog.askdirectory(initialdir=self.runner.working_dir, title="Select directory") + elif "ExistingFile" in self.parameter_type: + ftypes = [('All files', '*.*')] + if 'RasterAndVector' in self.file_type: + ftypes = [("Shapefiles", "*.shp"), ('Raster files', ('*.dep', '*.tif', + '*.tiff', '*.bil', '*.flt', + '*.sdat', '*.rdc', + '*.asc'))] + elif 'Raster' in self.file_type: + ftypes = [('Raster files', ('*.dep', '*.tif', + '*.tiff', '*.bil', '*.flt', + '*.sdat', '*.rdc', + '*.asc'))] + elif 'Lidar' in self.file_type: + ftypes = [("LiDAR files", ('*.las', '*.zlidar', '*.zip'))] + elif 'Vector' in self.file_type: + ftypes = [("Shapefiles", "*.shp")] + elif 'Text' in self.file_type: + ftypes = [("Text files", "*.txt"), ("all files", "*.*")] + elif 'Csv' in self.file_type: + ftypes = [("CSC files", "*.csv"), ("all files", "*.*")] + elif 'Html' in self.file_type: + ftypes = [("HTML files", "*.html")] + + result = filedialog.askopenfilename( + initialdir=self.runner.working_dir, title="Select file", filetypes=ftypes) + + elif "NewFile" in self.parameter_type: + result = filedialog.asksaveasfilename() + + self.value.set(result) + # update the working directory + self.runner.working_dir = os.path.dirname(result) + + except: + t = "file" + if self.parameter_type == "Directory": + t = "directory" + messagebox.showinfo("Warning", "Could not find {}".format(t)) + + def get_value(self): + if self.value.get(): + v = self.value.get() + # Do some quality assurance here. + # Is there a directory included? + if not path.dirname(v): + v = path.join(self.runner.working_dir, v) + + # What about a file extension? + ext = os.path.splitext(v)[-1].lower().strip() + if not ext: + ext = "" + if 'RasterAndVector' in self.file_type: + ext = '.tif' + elif 'Raster' in self.file_type: + ext = '.tif' + elif 'Lidar' in self.file_type: + ext = '.las' + elif 'Vector' in self.file_type: + ext = '.shp' + elif 'Text' in self.file_type: + ext = '.txt' + elif 'Csv' in self.file_type: + ext = '.csv' + elif 'Html' in self.file_type: + ext = '.html' + + v += ext + + v = path.normpath(v) + + return "{}='{}'".format(self.flag, v) + else: + t = "file" + if self.parameter_type == "Directory": + t = "directory" + if not self.optional: + messagebox.showinfo( + "Error", "Unspecified {} parameter {}.".format(t, self.flag)) + + return None + + def select_all(self, event): + self.entry.select_range(0, tk.END) + return 'break' + + +class FileOrFloat(tk.Frame): + def __init__(self, json_str, runner, master=None): + # first make sure that the json data has the correct fields + j = json.loads(json_str) + self.name = j['name'] + self.description = j['description'] + self.flag = j['flags'][len(j['flags']) - 1] + self.parameter_type = j['parameter_type'] + self.file_type = j['parameter_type']['ExistingFileOrFloat'] + self.optional = j['optional'] + default_value = j['default_value'] + + self.runner = runner + + ttk.Frame.__init__(self, master) + self.grid() + self['padding'] = '0.02i' + + self.label = ttk.Label(self, text=self.name, justify=tk.LEFT) + self.label.grid(row=0, column=0, sticky=tk.W) + self.label.columnconfigure(0, weight=1) + + if not self.optional: + self.label['text'] = self.label['text'] + "*" + + fs_frame = ttk.Frame(self, padding='0.0i') + self.value = tk.StringVar() + self.entry = ttk.Entry( + fs_frame, width=35, justify=tk.LEFT, textvariable=self.value) + self.entry.grid(row=0, column=0, sticky=tk.NSEW) + self.entry.columnconfigure(0, weight=1) + if default_value: + self.value.set(default_value) + + # self.img = tk.PhotoImage(file=script_dir + "/img/open.gif") + # self.open_button = ttk.Button(fs_frame, width=55, image=self.img, command=self.select_dir) + self.open_button = ttk.Button( + fs_frame, width=4, text="...", command=self.select_file) + self.open_button.grid(row=0, column=1, sticky=tk.E) + # self.open_button.columnconfigure(0, weight=1) + + self.label = ttk.Label(fs_frame, text='OR', justify=tk.LEFT) + self.label.grid(row=0, column=2, sticky=tk.W) + # self.label.columnconfigure(0, weight=1) + + self.value2 = tk.StringVar() + self.entry2 = ttk.Entry( + fs_frame, width=10, justify=tk.LEFT, textvariable=self.value2) + self.entry2.grid(row=0, column=3, sticky=tk.NSEW) + self.entry2.columnconfigure(0, weight=1) + self.entry2['justify'] = 'right' + + fs_frame.grid(row=1, column=0, sticky=tk.NSEW) + fs_frame.columnconfigure(0, weight=10) + fs_frame.columnconfigure(1, weight=1) + # self.pack(fill=tk.BOTH, expand=1) + self.columnconfigure(0, weight=1) + self.rowconfigure(0, weight=1) + self.rowconfigure(1, weight=1) + + # Add the bindings + if _platform == "darwin": + self.entry.bind("", self.select_all) + else: + self.entry.bind("", self.select_all) + + def select_file(self): + try: + result = self.value.get() + ftypes = [('All files', '*.*')] + if 'RasterAndVector' in self.file_type: + ftypes = [("Shapefiles", "*.shp"), ('Raster files', ('*.dep', '*.tif', + '*.tiff', '*.bil', '*.flt', + '*.sdat', '*.rdc', + '*.asc'))] + elif 'Raster' in self.file_type: + ftypes = [('Raster files', ('*.dep', '*.tif', + '*.tiff', '*.bil', '*.flt', + '*.sdat', '*.rdc', + '*.asc'))] + elif 'Lidar' in self.file_type: + ftypes = [("LiDAR files", ('*.las', '*.zlidar', '*.zip'))] + elif 'Vector' in self.file_type: + ftypes = [("Shapefiles", "*.shp")] + elif 'Text' in self.file_type: + ftypes = [("Text files", "*.txt"), ("all files", "*.*")] + elif 'Csv' in self.file_type: + ftypes = [("CSC files", "*.csv"), ("all files", "*.*")] + elif 'Html' in self.file_type: + ftypes = [("HTML files", "*.html")] + + result = filedialog.askopenfilename( + initialdir=self.runner.working_dir, title="Select file", filetypes=ftypes) + + self.value.set(result) + # update the working directory + self.runner.working_dir = os.path.dirname(result) + + except: + t = "file" + if self.parameter_type == "Directory": + t = "directory" + messagebox.showinfo("Warning", "Could not find {}".format(t)) + + def RepresentsFloat(self, s): + try: + float(s) + return True + except ValueError: + return False + + def get_value(self): + if self.value.get(): + v = self.value.get() + # Do some quality assurance here. + # Is there a directory included? + if not path.dirname(v): + v = path.join(self.runner.working_dir, v) + + # What about a file extension? + ext = os.path.splitext(v)[-1].lower() + if not ext: + ext = "" + if 'RasterAndVector' in self.file_type: + ext = '.tif' + elif 'Raster' in self.file_type: + ext = '.tif' + elif 'Lidar' in self.file_type: + ext = '.las' + elif 'Vector' in self.file_type: + ext = '.shp' + elif 'Text' in self.file_type: + ext = '.txt' + elif 'Csv' in self.file_type: + ext = '.csv' + elif 'Html' in self.file_type: + ext = '.html' + + v = v + ext + + v = path.normpath(v) + + return "{}='{}'".format(self.flag, v) + elif self.value2.get(): + v = self.value2.get() + if self.RepresentsFloat(v): + return "{}={}".format(self.flag, v) + else: + messagebox.showinfo( + "Error", "Error converting parameter {} to type Float.".format(self.flag)) + else: + if not self.optional: + messagebox.showinfo( + "Error", "Unspecified file/numeric parameter {}.".format(self.flag)) + + return None + + def select_all(self, event): + self.entry.select_range(0, tk.END) + return 'break' + + +class MultifileSelector(tk.Frame): + def __init__(self, json_str, runner, master=None): + # first make sure that the json data has the correct fields + j = json.loads(json_str) + self.name = j['name'] + self.description = j['description'] + self.flag = j['flags'][len(j['flags']) - 1] + self.parameter_type = j['parameter_type'] + self.file_type = "" + self.file_type = j['parameter_type']['FileList'] + self.optional = j['optional'] + default_value = j['default_value'] + + self.runner = runner + + ttk.Frame.__init__(self, master) + self.grid() + self['padding'] = '0.05i' + + self.label = ttk.Label(self, text=self.name, justify=tk.LEFT) + self.label.grid(row=0, column=0, sticky=tk.W) + self.label.columnconfigure(0, weight=1) + + if not self.optional: + self.label['text'] = self.label['text'] + "*" + + fs_frame = ttk.Frame(self, padding='0.0i') + # , variable=self.value) + self.opt = tk.Listbox(fs_frame, width=44, height=4) + self.opt.grid(row=0, column=0, sticky=tk.NSEW) + s = ttk.Scrollbar(fs_frame, orient=tk.VERTICAL, command=self.opt.yview) + s.grid(row=0, column=1, sticky=(tk.N, tk.S)) + self.opt['yscrollcommand'] = s.set + + btn_frame = ttk.Frame(fs_frame, padding='0.0i') + self.open_button = ttk.Button( + btn_frame, width=4, text="...", command=self.select_file) + self.open_button.grid(row=0, column=0, sticky=tk.NE) + self.open_button.columnconfigure(0, weight=1) + self.open_button.rowconfigure(0, weight=1) + + self.delete_button = ttk.Button( + btn_frame, width=4, text="del", command=self.delete_entry) + self.delete_button.grid(row=1, column=0, sticky=tk.NE) + self.delete_button.columnconfigure(0, weight=1) + self.delete_button.rowconfigure(1, weight=1) + + btn_frame.grid(row=0, column=2, sticky=tk.NE) + + fs_frame.grid(row=1, column=0, sticky=tk.NSEW) + fs_frame.columnconfigure(0, weight=10) + fs_frame.columnconfigure(1, weight=1) + fs_frame.columnconfigure(2, weight=1) + # self.pack(fill=tk.BOTH, expand=1) + self.columnconfigure(0, weight=1) + self.rowconfigure(0, weight=1) + self.rowconfigure(1, weight=1) + + def select_file(self): + try: + #result = self.value.get() + init_dir = self.runner.working_dir + ftypes = [('All files', '*.*')] + if 'RasterAndVector' in self.file_type: + ftypes = [("Shapefiles", "*.shp"), ('Raster files', ('*.dep', '*.tif', + '*.tiff', '*.bil', '*.flt', + '*.sdat', '*.rdc', + '*.asc'))] + elif 'Raster' in self.file_type: + ftypes = [('Raster files', ('*.dep', '*.tif', + '*.tiff', '*.bil', '*.flt', + '*.sdat', '*.rdc', + '*.asc'))] + elif 'Lidar' in self.file_type: + ftypes = [("LiDAR files", ('*.las', '*.zlidar', '*.zip'))] + elif 'Vector' in self.file_type: + ftypes = [("Shapefiles", "*.shp")] + elif 'Text' in self.file_type: + ftypes = [("Text files", "*.txt"), ("all files", "*.*")] + elif 'Csv' in self.file_type: + ftypes = [("CSC files", "*.csv"), ("all files", "*.*")] + elif 'Html' in self.file_type: + ftypes = [("HTML files", "*.html")] + + result = filedialog.askopenfilenames( + initialdir=init_dir, title="Select files", filetypes=ftypes) + if result: + for v in result: + self.opt.insert(tk.END, v) + + # update the working directory + self.runner.working_dir = os.path.dirname(result[0]) + + except: + messagebox.showinfo("Warning", "Could not find file") + + def delete_entry(self): + self.opt.delete(tk.ANCHOR) + + def get_value(self): + try: + l = self.opt.get(0, tk.END) + if l: + s = "" + for i in range(0, len(l)): + v = l[i] + if not path.dirname(v): + v = path.join(self.runner.working_dir, v) + v = path.normpath(v) + if i < len(l) - 1: + s += "{};".format(v) + else: + s += "{}".format(v) + + return "{}='{}'".format(self.flag, s) + else: + if not self.optional: + messagebox.showinfo( + "Error", "Unspecified non-optional parameter {}.".format(self.flag)) + + except: + messagebox.showinfo( + "Error", "Error formating files for parameter {}".format(self.flag)) + + return None + + +class BooleanInput(tk.Frame): + def __init__(self, json_str, master=None): + # first make sure that the json data has the correct fields + j = json.loads(json_str) + self.name = j['name'] + self.description = j['description'] + self.flag = j['flags'][len(j['flags']) - 1] + self.parameter_type = j['parameter_type'] + # just for quality control. BooleanInputs are always optional. + self.optional = True + default_value = j['default_value'] + + ttk.Frame.__init__(self, master) + self.grid() + self['padding'] = '0.05i' + + frame = ttk.Frame(self, padding='0.0i') + + self.value = tk.IntVar() + c = ttk.Checkbutton(frame, text=self.name, + width=55, variable=self.value) + c.grid(row=0, column=0, sticky=tk.W) + + # set the default value + if j['default_value'] != None and j['default_value'] != 'false': + self.value.set(1) + else: + self.value.set(0) + + frame.grid(row=1, column=0, sticky=tk.W) + frame.columnconfigure(0, weight=1) + + # self.pack(fill=tk.BOTH, expand=1) + self.columnconfigure(0, weight=1) + self.rowconfigure(0, weight=1) + + def get_value(self): + if self.value.get() == 1: + return self.flag + else: + return None + + +class OptionsInput(tk.Frame): + def __init__(self, json_str, master=None): + # first make sure that the json data has the correct fields + j = json.loads(json_str) + self.name = j['name'] + self.description = j['description'] + self.flag = j['flags'][len(j['flags']) - 1] + self.parameter_type = j['parameter_type'] + self.optional = j['optional'] + default_value = j['default_value'] + + ttk.Frame.__init__(self, master) + self.grid() + self['padding'] = '0.02i' + + frame = ttk.Frame(self, padding='0.0i') + + self.label = ttk.Label(self, text=self.name, justify=tk.LEFT) + self.label.grid(row=0, column=0, sticky=tk.W) + self.label.columnconfigure(0, weight=1) + + frame2 = ttk.Frame(frame, padding='0.0i') + opt = ttk.Combobox(frame2, width=40) + opt.grid(row=0, column=0, sticky=tk.NSEW) + + self.value = None # initialize in event of no default and no selection + i = 1 + default_index = -1 + list = j['parameter_type']['OptionList'] + values = () + for v in list: + values += (v,) + # opt.insert(tk.END, v) + if v == default_value: + default_index = i - 1 + i = i + 1 + + opt['values'] = values + + # opt.bind("<>", self.select) + opt.bind("<>", self.select) + if default_index >= 0: + opt.current(default_index) + opt.event_generate("<>") + # opt.see(default_index) + + frame2.grid(row=0, column=0, sticky=tk.W) + frame.grid(row=1, column=0, sticky=tk.W) + frame.columnconfigure(0, weight=1) + + # self.pack(fill=tk.BOTH, expand=1) + self.columnconfigure(0, weight=1) + self.rowconfigure(0, weight=1) + + # # first make sure that the json data has the correct fields + # j = json.loads(json_str) + # self.name = j['name'] + # self.description = j['description'] + # self.flag = j['flags'][len(j['flags']) - 1] + # self.parameter_type = j['parameter_type'] + # self.optional = j['optional'] + # default_value = j['default_value'] + + # ttk.Frame.__init__(self, master) + # self.grid() + # self['padding'] = '0.1i' + + # frame = ttk.Frame(self, padding='0.0i') + + # self.label = ttk.Label(self, text=self.name, justify=tk.LEFT) + # self.label.grid(row=0, column=0, sticky=tk.W) + # self.label.columnconfigure(0, weight=1) + + # frame2 = ttk.Frame(frame, padding='0.0i') + # opt = tk.Listbox(frame2, width=40) # , variable=self.value) + # opt.grid(row=0, column=0, sticky=tk.NSEW) + # s = ttk.Scrollbar(frame2, orient=tk.VERTICAL, command=opt.yview) + # s.grid(row=0, column=1, sticky=(tk.N, tk.S)) + # opt['yscrollcommand'] = s.set + + # self.value = None # initialize in event of no default and no selection + # i = 1 + # default_index = -1 + # list = j['parameter_type']['OptionList'] + # for v in list: + # #opt.insert(i, v) + # opt.insert(tk.END, v) + # if v == default_value: + # default_index = i - 1 + # i = i + 1 + + # if i - 1 < 4: + # opt['height'] = i - 1 + # else: + # opt['height'] = 3 + + # opt.bind("<>", self.select) + # if default_index >= 0: + # opt.select_set(default_index) + # opt.event_generate("<>") + # opt.see(default_index) + + # frame2.grid(row=0, column=0, sticky=tk.W) + # frame.grid(row=1, column=0, sticky=tk.W) + # frame.columnconfigure(0, weight=1) + + # # self.pack(fill=tk.BOTH, expand=1) + # self.columnconfigure(0, weight=1) + # self.rowconfigure(0, weight=1) + + def get_value(self): + if self.value: + return "{}='{}'".format(self.flag, self.value) + else: + if not self.optional: + messagebox.showinfo( + "Error", "Unspecified non-optional parameter {}.".format(self.flag)) + + return None + + def select(self, event): + widget = event.widget + # selection = widget.curselection() + self.value = widget.get() # selection[0]) + + +class DataInput(tk.Frame): + def __init__(self, json_str, master=None): + # first make sure that the json data has the correct fields + j = json.loads(json_str) + self.name = j['name'] + self.description = j['description'] + self.flag = j['flags'][len(j['flags']) - 1] + self.parameter_type = j['parameter_type'] + self.optional = j['optional'] + default_value = j['default_value'] + + ttk.Frame.__init__(self, master) + self.grid() + self['padding'] = '0.1i' + + self.label = ttk.Label(self, text=self.name, justify=tk.LEFT) + self.label.grid(row=0, column=0, sticky=tk.W) + self.label.columnconfigure(0, weight=1) + + self.value = tk.StringVar() + if default_value: + self.value.set(default_value) + else: + self.value.set("") + + self.entry = ttk.Entry(self, justify=tk.LEFT, textvariable=self.value) + self.entry.grid(row=0, column=1, sticky=tk.NSEW) + self.entry.columnconfigure(1, weight=10) + + if not self.optional: + self.label['text'] = self.label['text'] + "*" + + if ("Integer" in self.parameter_type or + "Float" in self.parameter_type or + "Double" in self.parameter_type): + self.entry['justify'] = 'right' + + # Add the bindings + if _platform == "darwin": + self.entry.bind("", self.select_all) + else: + self.entry.bind("", self.select_all) + + # self.pack(fill=tk.BOTH, expand=1) + self.columnconfigure(0, weight=1) + self.columnconfigure(1, weight=10) + self.rowconfigure(0, weight=1) + + def RepresentsInt(self, s): + try: + int(s) + return True + except ValueError: + return False + + def RepresentsFloat(self, s): + try: + float(s) + return True + except ValueError: + return False + + def get_value(self): + v = self.value.get() + if v: + if "Integer" in self.parameter_type: + if self.RepresentsInt(self.value.get()): + return "{}={}".format(self.flag, self.value.get()) + else: + messagebox.showinfo( + "Error", "Error converting parameter {} to type Integer.".format(self.flag)) + elif "Float" in self.parameter_type: + if self.RepresentsFloat(self.value.get()): + return "{}={}".format(self.flag, self.value.get()) + else: + messagebox.showinfo( + "Error", "Error converting parameter {} to type Float.".format(self.flag)) + elif "Double" in self.parameter_type: + if self.RepresentsFloat(self.value.get()): + return "{}={}".format(self.flag, self.value.get()) + else: + messagebox.showinfo( + "Error", "Error converting parameter {} to type Double.".format(self.flag)) + else: # String or StringOrNumber types + return "{}='{}'".format(self.flag, self.value.get()) + else: + if not self.optional: + messagebox.showinfo( + "Error", "Unspecified non-optional parameter {}.".format(self.flag)) + + return None + + def select_all(self, event): + self.entry.select_range(0, tk.END) + return 'break' + + +class WbRunner(tk.Frame): + def __init__(self, tool_name=None, master=None): + if platform.system() == 'Windows': + self.ext = '.exe' + else: + self.ext = '' + + exe_name = "whitebox_tools{}".format(self.ext) + + self.exe_path = path.dirname(path.abspath(__file__)) + os.chdir(self.exe_path) + for filename in glob.iglob('**/*', recursive=True): + if filename.endswith(exe_name): + self.exe_path = path.dirname(path.abspath(filename)) + break + + wbt.set_whitebox_dir(self.exe_path) + + ttk.Frame.__init__(self, master) + self.script_dir = os.path.dirname(os.path.realpath(__file__)) + self.grid() + self.tool_name = tool_name + self.master.title("WhiteboxTools Runner") + if _platform == "darwin": + os.system( + '''/usr/bin/osascript -e 'tell app "Finder" to set frontmost of process "Python" to true' ''') + self.create_widgets() + self.working_dir = str(Path.home()) + + def create_widgets(self): + + ######################################################### + # Overall/Top level Frame # + ######################################################### + #define left-side frame (toplevel_frame) and right-side frame (overall_frame) + toplevel_frame = ttk.Frame(self, padding='0.1i') + overall_frame = ttk.Frame(self, padding='0.1i') + #set-up layout + overall_frame.grid(row=0, column=1, sticky=tk.NSEW) + toplevel_frame.grid(row=0, column=0, sticky=tk.NSEW) + ######################################################### + # Calling basics # + ######################################################### + #Create all needed lists of tools and toolboxes + self.toolbox_list = self.get_toolboxes() + self.sort_toolboxes() + self.tools_and_toolboxes = wbt.toolbox('') + self.sort_tools_by_toolbox() + self.get_tools_list() + #Icons to be used in tool treeview + self.tool_icon = tk.PhotoImage(file = self.script_dir + '//img//tool.gif') + self.open_toolbox_icon = tk.PhotoImage(file = self.script_dir + '//img//open.gif') + self.closed_toolbox_icon = tk.PhotoImage(file = self.script_dir + '//img//closed.gif') + ######################################################### + # Toolboxes Frame # FIXME: change width or make horizontally scrollable + ######################################################### + #define tools_frame and tool_tree + self.tools_frame = ttk.LabelFrame(toplevel_frame, text="{} Available Tools".format(len(self.tools_list)), padding='0.1i') + self.tool_tree = ttk.Treeview(self.tools_frame, height = 21) + #Set up layout + self.tool_tree.grid(row=0, column=0, sticky=tk.NSEW) + self.tool_tree.column("#0", width = 280) #Set width so all tools are readable within the frame + self.tools_frame.grid(row=0, column=0, sticky=tk.NSEW) + self.tools_frame.columnconfigure(0, weight=10) + self.tools_frame.columnconfigure(1, weight=1) + self.tools_frame.rowconfigure(0, weight=10) + self.tools_frame.rowconfigure(1, weight=1) + #Add toolboxes and tools to treeview + index = 0 + for toolbox in self.lower_toolboxes: + if toolbox.find('/') != (-1): #toolboxes + self.tool_tree.insert(toolbox[:toolbox.find('/')], 0, text = " " + toolbox[toolbox.find('/') + 1:], iid = toolbox[toolbox.find('/') + 1:], tags = 'toolbox', image = self.closed_toolbox_icon) + for tool in self.sorted_tools[index]: #add tools within toolbox + self.tool_tree.insert(toolbox[toolbox.find('/') + 1:], 'end', text = " " + tool, tags = 'tool', iid = tool, image = self.tool_icon) + else: #subtoolboxes + self.tool_tree.insert('', 'end', text = " " + toolbox, iid = toolbox, tags = 'toolbox', image = self.closed_toolbox_icon) + for tool in self.sorted_tools[index]: #add tools within subtoolbox + self.tool_tree.insert(toolbox, 'end', text = " " + tool, iid = tool, tags = 'tool', image = self.tool_icon) + index = index + 1 + #bind tools in treeview to self.tree_update_tool_help function and toolboxes to self.update_toolbox_icon function + self.tool_tree.tag_bind('tool', "<>", self.tree_update_tool_help) + self.tool_tree.tag_bind('toolbox', "<>", self.update_toolbox_icon) + #Add vertical scrollbar to treeview frame + s = ttk.Scrollbar(self.tools_frame, orient=tk.VERTICAL,command=self.tool_tree.yview) + s.grid(row=0, column=1, sticky=(tk.N, tk.S)) + self.tool_tree['yscrollcommand'] = s.set + ######################################################### + # Search Bar # + ######################################################### + #create variables for search results and search input + self.search_list = [] + self.search_text = tk.StringVar() + #Create the elements of the search frame + self.search_frame = ttk.LabelFrame(toplevel_frame, padding='0.1i', text="{} Tools Found".format(len(self.search_list))) + self.search_label = ttk.Label(self.search_frame, text = "Search: ") + self.search_bar = ttk.Entry(self.search_frame, width = 30, textvariable = self.search_text) + self.search_results_listbox = tk.Listbox(self.search_frame, height=11) + self.search_scroll = ttk.Scrollbar(self.search_frame, orient=tk.VERTICAL, command=self.search_results_listbox.yview) + self.search_results_listbox['yscrollcommand'] = self.search_scroll.set + #Add bindings + self.search_results_listbox.bind("<>", self.search_update_tool_help) + self.search_bar.bind('', self.update_search) + #Define layout of the frame + self.search_frame.grid(row = 1, column = 0, sticky=tk.NSEW) + self.search_label.grid(row = 0, column = 0, sticky=tk.NW) + self.search_bar.grid(row = 0, column = 1, sticky=tk.NE) + self.search_results_listbox.grid(row = 1, column = 0, columnspan = 2, sticky=tk.NSEW, pady = 5) + self.search_scroll.grid(row=1, column=2, sticky=(tk.N, tk.S)) + #Configure rows and columns of the frame + self.search_frame.columnconfigure(0, weight=1) + self.search_frame.columnconfigure(1, weight=10) + self.search_frame.columnconfigure(1, weight=1) + self.search_frame.rowconfigure(0, weight=1) + self.search_frame.rowconfigure(1, weight = 10) + ######################################################### + # Current Tool Frame # + ######################################################### + #Create the elements of the current tool frame + self.current_tool_frame = ttk.Frame(overall_frame, padding='0.01i') + self.current_tool_lbl = ttk.Label(self.current_tool_frame, text="Current Tool: {}".format(self.tool_name), justify=tk.LEFT) # , font=("Helvetica", 12, "bold") + self.view_code_button = ttk.Button(self.current_tool_frame, text="View Code", width=12, command=self.view_code) + #Define layout of the frame + self.view_code_button.grid(row=0, column=1, sticky=tk.E) + self.current_tool_lbl.grid(row=0, column=0, sticky=tk.W) + self.current_tool_frame.grid(row=0, column=0, columnspan = 2, sticky=tk.NSEW) + #Configure rows and columns of the frame + self.current_tool_frame.columnconfigure(0, weight=1) + self.current_tool_frame.columnconfigure(1, weight=1) + ######################################################### + # Args Frame # + ######################################################### + # #Create the elements of the tool arguments frame + # self.arg_scroll = ttk.Scrollbar(overall_frame, orient='vertical') + # self.arg_canvas = tk.Canvas(overall_frame, bd=0, highlightthickness=0, yscrollcommand=self.arg_scroll.set) + # self.arg_scroll.config(command=self.arg_canvas.yview) #self.arg_scroll scrolls over self.arg_canvas + # self.arg_scroll_frame = ttk.Frame(self.arg_canvas) # create a frame inside the self.arg_canvas which will be scrolled with it + # self.arg_scroll_frame_id = self.arg_canvas.create_window(0, 0, window=self.arg_scroll_frame, anchor="nw") + # #Define layout of the frame + # self.arg_scroll.grid(row = 1, column = 1, sticky = (tk.NS, tk.E)) + # self.arg_canvas.grid(row = 1, column = 0, sticky = tk.NSEW) + # # reset the view + # self.arg_canvas.xview_moveto(0) + # self.arg_canvas.yview_moveto(0) + # #Add bindings + # self.arg_scroll_frame.bind('', self.configure_arg_scroll_frame) + # self.arg_canvas.bind('', self.configure_arg_canvas) + self.arg_scroll_frame = ttk.Frame(overall_frame, padding='0.0i') + self.arg_scroll_frame.grid(row=1, column=0, sticky=tk.NSEW) + self.arg_scroll_frame.columnconfigure(0, weight=1) + ######################################################### + # Buttons Frame # + ######################################################### + #Create the elements of the buttons frame + buttons_frame = ttk.Frame(overall_frame, padding='0.1i') + self.run_button = ttk.Button(buttons_frame, text="Run", width=8, command=self.run_tool) + self.quit_button = ttk.Button(buttons_frame, text="Cancel", width=8, command=self.cancel_operation) + self.help_button = ttk.Button(buttons_frame, text="Help", width=8, command=self.tool_help_button) + #Define layout of the frame + self.run_button.grid(row=0, column=0) + self.quit_button.grid(row=0, column=1) + self.help_button.grid(row = 0, column = 2) + buttons_frame.grid(row=2, column=0, columnspan = 2, sticky=tk.E) + ######################################################### + # Output Frame # + ######################################################### + #Create the elements of the output frame + output_frame = ttk.Frame(overall_frame) + outlabel = ttk.Label(output_frame, text="Output:", justify=tk.LEFT) + self.out_text = ScrolledText(output_frame, width=63, height=15, wrap=tk.NONE, padx=7, pady=7, exportselection = 0) + output_scrollbar = ttk.Scrollbar(output_frame, orient=tk.HORIZONTAL, command = self.out_text.xview) + self.out_text['xscrollcommand'] = output_scrollbar.set + #Retreive and insert the text for the current tool + k = wbt.tool_help(self.tool_name) + self.out_text.insert(tk.END, k) + #Define layout of the frame + outlabel.grid(row=0, column=0, sticky=tk.NW) + self.out_text.grid(row=1, column=0, sticky=tk.NSEW) + output_frame.grid(row=3, column=0, columnspan = 2, sticky=(tk.NS, tk.E)) + output_scrollbar.grid(row=2, column=0, sticky=(tk.W, tk.E)) + #Configure rows and columns of the frame + self.out_text.columnconfigure(0, weight=1) + output_frame.columnconfigure(0, weight=1) + # Add the binding + if _platform == "darwin": + self.out_text.bind("", self.select_all) + else: + self.out_text.bind("", self.select_all) + ######################################################### + # Progress Frame # + ######################################################### + #Create the elements of the progress frame + progress_frame = ttk.Frame(overall_frame, padding='0.1i') + self.progress_label = ttk.Label(progress_frame, text="Progress:", justify=tk.LEFT) + self.progress_var = tk.DoubleVar() + self.progress = ttk.Progressbar(progress_frame, orient="horizontal", variable=self.progress_var, length=200, maximum=100) + #Define layout of the frame + self.progress_label.grid(row=0, column=0, sticky=tk.E, padx=5) + self.progress.grid(row=0, column=1, sticky=tk.E) + progress_frame.grid(row=4, column=0, columnspan = 2, sticky=tk.SE) + ######################################################### + # Tool Selection # + ######################################################### + # Select the appropriate tool, if specified, otherwise the first tool + self.tool_tree.focus(self.tool_name) + self.tool_tree.selection_set(self.tool_name) + self.tool_tree.event_generate("<>") + ######################################################### + # Menus # + ######################################################### + menubar = tk.Menu(self) + + self.filemenu = tk.Menu(menubar, tearoff=0) + self.filemenu.add_command(label="Set Working Directory", command=self.set_directory) + self.filemenu.add_command(label="Locate WhiteboxTools exe", command=self.select_exe) + self.filemenu.add_command(label="Refresh Tools", command=self.refresh_tools) + wbt.set_compress_rasters(True) + self.filemenu.add_command(label="Do Not Compress Output TIFFs", command=self.update_compress) + self.filemenu.add_separator() + self.filemenu.add_command(label="Exit", command=self.quit) + menubar.add_cascade(label="File", menu=self.filemenu) + + editmenu = tk.Menu(menubar, tearoff=0) + editmenu.add_command(label="Cut", command=lambda: self.focus_get().event_generate("<>")) + editmenu.add_command(label="Copy", command=lambda: self.focus_get().event_generate("<>")) + editmenu.add_command(label="Paste", command=lambda: self.focus_get().event_generate("<>")) + menubar.add_cascade(label="Edit ", menu=editmenu) + + helpmenu = tk.Menu(menubar, tearoff=0) + helpmenu.add_command(label="About", command=self.help) + helpmenu.add_command(label="License", command=self.license) + menubar.add_cascade(label="Help ", menu=helpmenu) + + self.master.config(menu=menubar) + + def update_compress(self): + if wbt.get_compress_rasters(): + wbt.set_compress_rasters(False) + self.filemenu.entryconfig(3, label = "Compress Output TIFFs") + else: + wbt.set_compress_rasters(True) + self.filemenu.entryconfig(3, label = "Do Not Compress Output TIFFs") + + def get_toolboxes(self): + toolboxes = set() + for item in wbt.toolbox().splitlines(): # run wbt.toolbox with no tool specified--returns all + if item: + tb = item.split(":")[1].strip() + toolboxes.add(tb) + return sorted(toolboxes) + + def sort_toolboxes(self): + self.upper_toolboxes = [] + self.lower_toolboxes = [] + for toolbox in self.toolbox_list: + if toolbox.find('/') == (-1): #Does not contain a subtoolbox, i.e. does not contain '/' + self.upper_toolboxes.append(toolbox) #add to both upper toolbox list and lower toolbox list + self.lower_toolboxes.append(toolbox) + else: #Contains a subtoolbox + self.lower_toolboxes.append(toolbox) #add to only the lower toolbox list + self.upper_toolboxes = sorted(self.upper_toolboxes) #sort both lists alphabetically + self.lower_toolboxes = sorted(self.lower_toolboxes) + + def sort_tools_by_toolbox(self): + self.sorted_tools = [[] for i in range(len(self.lower_toolboxes))] #One list for each lower toolbox + count = 1 + for toolAndToolbox in self.tools_and_toolboxes.split('\n'): + if toolAndToolbox.strip(): + tool = toolAndToolbox.strip().split(':')[0].strip().replace("TIN", "Tin").replace("KS", "Ks").replace("FD", "Fd") #current tool + itemToolbox = toolAndToolbox.strip().split(':')[1].strip() #current toolbox + index = 0 + for toolbox in self.lower_toolboxes: #find which toolbox the current tool belongs to + if toolbox == itemToolbox: + self.sorted_tools[index].append(tool) #add current tool to list at appropriate index + break + index = index + 1 + count = count + 1 + + def get_tools_list(self): + self.tools_list = [] + selected_item = -1 + for item in wbt.list_tools().keys(): + if item: + value = to_camelcase(item).replace("TIN", "Tin").replace("KS", "Ks").replace("FD", "Fd") #format tool name + self.tools_list.append(value) #add tool to list + if item == self.tool_name: #update selected_item it tool found + selected_item = len(self.tools_list) - 1 + if selected_item == -1: #set self.tool_name as default tool + selected_item = 0 + self.tool_name = self.tools_list[0] + + def tree_update_tool_help(self, event): # read selection when tool selected from treeview then call self.update_tool_help + curItem = self.tool_tree.focus() + self.tool_name = self.tool_tree.item(curItem).get('text').replace(" ", "") + self.update_tool_help() + + def search_update_tool_help(self, event): # read selection when tool selected from search results then call self.update_tool_help + selection = self.search_results_listbox.curselection() + self.tool_name = self.search_results_listbox.get(selection[0]) + self.update_tool_help() + + def update_tool_help(self): + self.out_text.delete('1.0', tk.END) + for widget in self.arg_scroll_frame.winfo_children(): + widget.destroy() + + k = wbt.tool_help(self.tool_name) + self.print_to_output(k) + + j = json.loads(wbt.tool_parameters(self.tool_name)) + param_num = 0 + for p in j['parameters']: + json_str = json.dumps( + p, sort_keys=True, indent=2, separators=(',', ': ')) + pt = p['parameter_type'] + if 'ExistingFileOrFloat' in pt: + ff = FileOrFloat(json_str, self, self.arg_scroll_frame) + ff.grid(row=param_num, column=0, sticky=tk.NSEW) + param_num = param_num + 1 + elif ('ExistingFile' in pt or 'NewFile' in pt or 'Directory' in pt): + fs = FileSelector(json_str, self, self.arg_scroll_frame) + fs.grid(row=param_num, column=0, sticky=tk.NSEW) + param_num = param_num + 1 + elif 'FileList' in pt: + b = MultifileSelector(json_str, self, self.arg_scroll_frame) + b.grid(row=param_num, column=0, sticky=tk.W) + param_num = param_num + 1 + elif 'Boolean' in pt: + b = BooleanInput(json_str, self.arg_scroll_frame) + b.grid(row=param_num, column=0, sticky=tk.W) + param_num = param_num + 1 + elif 'OptionList' in pt: + b = OptionsInput(json_str, self.arg_scroll_frame) + b.grid(row=param_num, column=0, sticky=tk.W) + param_num = param_num + 1 + elif ('Float' in pt or 'Integer' in pt or + 'String' in pt or 'StringOrNumber' in pt or + 'StringList' in pt or 'VectorAttributeField' in pt): + b = DataInput(json_str, self.arg_scroll_frame) + b.grid(row=param_num, column=0, sticky=tk.NSEW) + param_num = param_num + 1 + else: + messagebox.showinfo( + "Error", "Unsupported parameter type: {}.".format(pt)) + self.update_args_box() + self.out_text.see("%d.%d" % (1, 0)) + + def update_toolbox_icon(self, event): + curItem = self.tool_tree.focus() + dict = self.tool_tree.item(curItem) #retreive the toolbox name + self.toolbox_name = dict.get('text'). replace(" ", "") #delete the space between the icon and text + self.toolbox_open = dict.get('open') #retreive whether the toolbox is open or not + if self.toolbox_open == True: #set image accordingly + self.tool_tree.item(self.toolbox_name, image = self.open_toolbox_icon) + else: + self.tool_tree.item(self.toolbox_name, image = self.closed_toolbox_icon) + + def update_search(self, event): + self.search_list = [] + self.search_string = self.search_text.get().lower() + self.search_results_listbox.delete(0, 'end') #empty the search results + num_results = 0 + for tool in self.tools_list: #search tool names + toolLower = tool.lower() + if toolLower.find(self.search_string) != (-1): #search string found within tool name + num_results = num_results + 1 + self.search_results_listbox.insert(num_results, tool) #tool added to listbox and to search results string + self.search_list.append(tool) + index = 0 + self.get_descriptions() + for description in self.descriptionList: #search tool descriptions + descriptionLower = description.lower() + if descriptionLower.find(self.search_string) != (-1): #search string found within tool description + found = 0 + for item in self.search_list: # check if this tool is already in the listbox + if self.tools_list[index] == item: + found = 1 + if found == 0: # add to listbox + num_results = num_results + 1 + self.search_results_listbox.insert(num_results, self.tools_list[index]) #tool added to listbox and to search results string + index = index + 1 + self.search_frame['text'] = "{} Tools Found".format(num_results) #update search label + + def get_descriptions(self): + self.descriptionList = [] + tools = wbt.list_tools() + toolsItems = tools.items() + for t in toolsItems: + self.descriptionList.append(t[1]) #second entry in tool dictionary is the description + + # def configure_arg_scroll_frame(self, event): + # # update the scrollbars to match the size of the inner frame + # size = (self.arg_scroll_frame.winfo_reqwidth(), self.arg_scroll_frame.winfo_reqheight()) + # self.arg_canvas.config(scrollregion="0 0 %s %s" % size) + # if self.arg_scroll_frame.winfo_reqwidth() != self.arg_canvas.winfo_width(): + # # update the canvas's width to fit the inner frame + # self.arg_canvas.config(width=self.arg_scroll_frame.winfo_reqwidth()) + + # def configure_arg_canvas(self, event): + # if self.arg_scroll_frame.winfo_reqwidth() != self.arg_canvas.winfo_width(): + # # update the inner frame's width to fill the canvas + # self.arg_canvas.itemconfigure(self.arg_scroll_frame_id, width=self.arg_canvas.winfo_width()) + + def tool_help_button(self): + index = 0 + found = False + #find toolbox corresponding to the current tool + for toolbox in self.lower_toolboxes: + for tool in self.sorted_tools[index]: + if tool == self.tool_name: + self.toolbox_name = toolbox + found = True + break + if found: + break + index = index + 1 + #change LiDAR to Lidar + if index == 10: + self.toolbox_name = to_camelcase(self.toolbox_name) + #format subtoolboxes as for URLs + self.toolbox_name = self.camel_to_snake(self.toolbox_name).replace('/', '').replace(' ', '') + #open the user manual section for the current tool + webbrowser.open_new_tab("https://jblindsay.github.io/wbt_book/available_tools/" + self.toolbox_name + ".html#" + self.tool_name) + + def camel_to_snake(self, s): # taken from tools_info.py + _underscorer1 = re.compile(r'(.)([A-Z][a-z]+)') + _underscorer2 = re.compile('([a-z0-9])([A-Z])') + subbed = _underscorer1.sub(r'\1_\2', s) + return _underscorer2.sub(r'\1_\2', subbed).lower() + + def refresh_tools(self): + #refresh lists + self.tools_and_toolboxes = wbt.toolbox('') + self.sort_tools_by_toolbox() + self.get_tools_list() + #clear self.tool_tree + self.tool_tree.delete(*self.tool_tree.get_children()) + #Add toolboxes and tools to treeview + index = 0 + for toolbox in self.lower_toolboxes: + if toolbox.find('/') != (-1): #toolboxes + self.tool_tree.insert(toolbox[:toolbox.find('/')], 0, text = " " + toolbox[toolbox.find('/') + 1:], iid = toolbox[toolbox.find('/') + 1:], tags = 'toolbox', image = self.closed_toolbox_icon) + for tool in self.sorted_tools[index]: #add tools within toolbox + self.tool_tree.insert(toolbox[toolbox.find('/') + 1:], 'end', text = " " + tool, tags = 'tool', iid = tool, image = self.tool_icon) + else: #subtoolboxes + self.tool_tree.insert('', 'end', text = " " + toolbox, iid = toolbox, tags = 'toolbox', image = self.closed_toolbox_icon) + for tool in self.sorted_tools[index]: #add tools within subtoolbox + self.tool_tree.insert(toolbox, 'end', text = " " + tool, iid = tool, tags = 'tool', image = self.tool_icon) + index = index + 1 + #Update label + self.tools_frame["text"] = "{} Available Tools".format(len(self.tools_list)) + + ######################################################### + # Functions (original) # + ######################################################### + def help(self): + self.print_to_output(wbt.version()) + + def license(self): + self.print_to_output(wbt.license()) + + def set_directory(self): + try: + self.working_dir =filedialog.askdirectory(initialdir=self.working_dir) + wbt.set_working_dir(self.working_dir) + except: + messagebox.showinfo( + "Warning", "Could not set the working directory.") + + def select_exe(self): + try: + filename = filedialog.askopenfilename(initialdir=self.exe_path) + self.exe_path = path.dirname(path.abspath(filename)) + wbt.set_whitebox_dir(self.exe_path) + self.refresh_tools() + except: + messagebox.showinfo( + "Warning", "Could not find WhiteboxTools executable file.") + + def run_tool(self): + # wd_str = self.wd.get_value() + wbt.set_working_dir(self.working_dir) + # args = shlex.split(self.args_value.get()) + + args = [] + for widget in self.arg_scroll_frame.winfo_children(): + v = widget.get_value() + if v: + args.append(v) + elif not widget.optional: + messagebox.showinfo( + "Error", "Non-optional tool parameter not specified.") + return + + self.print_line_to_output("") + # self.print_line_to_output("Tool arguments:{}".format(args)) + # self.print_line_to_output("") + # Run the tool and check the return value for an error + if wbt.run_tool(self.tool_name, args, self.custom_callback) == 1: + print("Error running {}".format(self.tool_name)) + + else: + self.run_button["text"] = "Run" + self.progress_var.set(0) + self.progress_label['text'] = "Progress:" + self.progress.update_idletasks() + + def print_to_output(self, value): + self.out_text.insert(tk.END, value) + self.out_text.see(tk.END) + + def print_line_to_output(self, value): + self.out_text.insert(tk.END, value + "\n") + self.out_text.see(tk.END) + + def cancel_operation(self): + wbt.cancel_op = True + self.print_line_to_output("Cancelling operation...") + self.progress.update_idletasks() + + def view_code(self): + webbrowser.open_new_tab(wbt.view_code(self.tool_name).strip()) + + def update_args_box(self): + s = "" + self.current_tool_lbl['text'] = "Current Tool: {}".format( + self.tool_name) + # self.spacer['width'] = width=(35-len(self.tool_name)) + for item in wbt.tool_help(self.tool_name).splitlines(): + if item.startswith("-"): + k = item.split(" ") + if "--" in k[1]: + value = k[1].replace(",", "") + else: + value = k[0].replace(",", "") + + if "flag" in item.lower(): + s = s + value + " " + else: + if "file" in item.lower(): + s = s + value + "='{}' " + else: + s = s + value + "={} " + + # self.args_value.set(s.strip()) + + def custom_callback(self, value): + ''' A custom callback for dealing with tool output. + ''' + if "%" in value: + try: + str_array = value.split(" ") + label = value.replace( + str_array[len(str_array) - 1], "").strip() + progress = float( + str_array[len(str_array) - 1].replace("%", "").strip()) + self.progress_var.set(int(progress)) + self.progress_label['text'] = label + except ValueError as e: + print("Problem converting parsed data into number: ", e) + except Exception as e: + print(e) + else: + self.print_line_to_output(value) + + self.update() # this is needed for cancelling and updating the progress bar + + def select_all(self, event): + self.out_text.tag_add(tk.SEL, "1.0", tk.END) + self.out_text.mark_set(tk.INSERT, "1.0") + self.out_text.see(tk.INSERT) + return 'break' + +class JsonPayload(object): + def __init__(self, j): + self.__dict__ = json.loads(j) + + +def main(): + tool_name = None + if len(sys.argv) > 1: + tool_name = str(sys.argv[1]) + wbr = WbRunner(tool_name) + wbr.mainloop() + + +if __name__ == '__main__': main() \ No newline at end of file diff --git a/WBT/whitebox_tools.exe b/WBT/whitebox_tools.exe index 9e9d0e1..31641ea 100644 Binary files a/WBT/whitebox_tools.exe and b/WBT/whitebox_tools.exe differ diff --git a/WBT/whitebox_tools.py b/WBT/whitebox_tools.py index c33b24f..9623c8a 100644 --- a/WBT/whitebox_tools.py +++ b/WBT/whitebox_tools.py @@ -1,8145 +1,8230 @@ -#!/usr/bin/env python3 -''' This file is intended to be a helper for running whitebox-tools plugins from a Python script. -See whitebox_example.py for an example of how to use it. -''' - -# This script is part of the WhiteboxTools geospatial library. -# Authors: Dr. John Lindsay -# Created: 28/11/2017 -# Last Modified: 09/12/2019 -# License: MIT - -from __future__ import print_function -import os -from os import path -import sys -import platform -import re -# import shutil -from subprocess import CalledProcessError, Popen, PIPE, STDOUT - -running_windows = platform.system() == 'Windows' - -if running_windows: - from subprocess import STARTUPINFO, STARTF_USESHOWWINDOW - -def default_callback(value): - ''' - A simple default callback that outputs using the print function. When - tools are called without providing a custom callback, this function - will be used to print to standard output. - ''' - print(value) - - -def to_camelcase(name): - ''' - Convert snake_case name to CamelCase name - ''' - return ''.join(x.title() for x in name.split('_')) - - -def to_snakecase(name): - ''' - Convert CamelCase name to snake_case name - ''' - s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name) - return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower() - - -class WhiteboxTools(object): - ''' - An object for interfacing with the WhiteboxTools executable. - ''' - - def __init__(self): - if running_windows: - self.ext = '.exe' - else: - self.ext = '' - self.exe_name = "whitebox_tools{}".format(self.ext) - # self.exe_path = os.path.dirname(shutil.which( - # self.exe_name) or path.dirname(path.abspath(__file__))) - # self.exe_path = os.path.dirname(os.path.join(os.path.realpath(__file__))) - self.exe_path = path.dirname(path.abspath(__file__)) - self.work_dir = "" - self.verbose = True - self.cancel_op = False - self.default_callback = default_callback - self.start_minimized = False - self.__compress_rasters = False - - def set_whitebox_dir(self, path_str): - ''' - Sets the directory to the WhiteboxTools executable file. - ''' - self.exe_path = path_str - - def set_working_dir(self, path_str): - ''' - Sets the working directory, i.e. the directory in which - the data files are located. By setting the working - directory, tool input parameters that are files need only - specify the file name rather than the complete file path. - ''' - self.work_dir = path.normpath(path_str) - - def set_verbose_mode(self, val=True): - ''' - Sets verbose mode. If verbose mode is False, tools will not - print output messages. Tools will frequently provide substantial - feedback while they are operating, e.g. updating progress for - various sub-routines. When the user has scripted a workflow - that ties many tools in sequence, this level of tool output - can be problematic. By setting verbose mode to False, these - messages are suppressed and tools run as background processes. - ''' - self.verbose = val - - def set_default_callback(self, callback_func): - ''' - Sets the default callback used for handling tool text outputs. - ''' - self.default_callback = callback_func - - def set_compress_rasters(self, compress_rasters): - ''' - Sets the flag used by WhiteboxTools to determine whether to use compression for output rasters. - ''' - self.__compress_rasters = compress_rasters - - def get_compress_rasters(self): - return self.__compress_rasters - - def run_tool(self, tool_name, args, callback=None): - ''' - Runs a tool and specifies tool arguments. - Returns 0 if completes without error. - Returns 1 if error encountered (details are sent to callback). - Returns 2 if process is cancelled by user. - ''' - try: - if callback is None: - callback = self.default_callback - - os.chdir(self.exe_path) - args2 = [] - args2.append("." + path.sep + self.exe_name) - args2.append("--run=\"{}\"".format(to_camelcase(tool_name))) - - if self.work_dir.strip() != "": - args2.append("--wd=\"{}\"".format(self.work_dir)) - - for arg in args: - args2.append(arg) - - # args_str = args_str[:-1] - # a.append("--args=\"{}\"".format(args_str)) - - if self.verbose: - args2.append("-v") - - if self.__compress_rasters: - args2.append("--compress_rasters") - - if self.verbose: - cl = "" - for v in args2: - cl += v + " " - callback(cl.strip() + "\n") - - proc = None - - if running_windows and self.start_minimized == True: - si = STARTUPINFO() - si.dwFlags = STARTF_USESHOWWINDOW - si.wShowWindow = 6 #Set window minimized - proc = Popen(args2, shell=False, stdout=PIPE, - stderr=STDOUT, bufsize=1, universal_newlines=True, - startupinfo=si) - else: - proc = Popen(args2, shell=False, stdout=PIPE, - stderr=STDOUT, bufsize=1, universal_newlines=True) - - while proc is not None: - line = proc.stdout.readline() - sys.stdout.flush() - if line != '': - if not self.cancel_op: - callback(line.strip()) - else: - self.cancel_op = False - proc.terminate() - return 2 - - else: - break - - return 0 - except (OSError, ValueError, CalledProcessError) as err: - callback(str(err)) - return 1 - - def help(self): - ''' - Retrieves the help description for WhiteboxTools. - ''' - try: - os.chdir(self.exe_path) - args = [] - args.append("." + os.path.sep + self.exe_name) - args.append("-h") - - proc = Popen(args, shell=False, stdout=PIPE, - stderr=STDOUT, bufsize=1, universal_newlines=True) - ret = "" - while True: - line = proc.stdout.readline() - if line != '': - ret += line - else: - break - - return ret - except (OSError, ValueError, CalledProcessError) as err: - return err - - def license(self): - ''' - Retrieves the license information for WhiteboxTools. - ''' - try: - os.chdir(self.exe_path) - args = [] - args.append("." + os.path.sep + self.exe_name) - args.append("--license") - - proc = Popen(args, shell=False, stdout=PIPE, - stderr=STDOUT, bufsize=1, universal_newlines=True) - ret = "" - while True: - line = proc.stdout.readline() - if line != '': - ret += line - else: - break - - return ret - except (OSError, ValueError, CalledProcessError) as err: - return err - - def version(self): - ''' - Retrieves the version information for WhiteboxTools. - ''' - try: - os.chdir(self.exe_path) - args = [] - args.append("." + os.path.sep + self.exe_name) - args.append("--version") - - proc = Popen(args, shell=False, stdout=PIPE, - stderr=STDOUT, bufsize=1, universal_newlines=True) - ret = "" - while True: - line = proc.stdout.readline() - if line != '': - ret += line - else: - break - - return ret - except (OSError, ValueError, CalledProcessError) as err: - return err - - def tool_help(self, tool_name=''): - ''' - Retrieves the help description for a specific tool. - ''' - try: - os.chdir(self.exe_path) - args = [] - args.append("." + os.path.sep + self.exe_name) - args.append("--toolhelp={}".format(to_camelcase(tool_name))) - - proc = Popen(args, shell=False, stdout=PIPE, - stderr=STDOUT, bufsize=1, universal_newlines=True) - ret = "" - while True: - line = proc.stdout.readline() - if line != '': - ret += line - else: - break - - return ret - except (OSError, ValueError, CalledProcessError) as err: - return err - - def tool_parameters(self, tool_name): - ''' - Retrieves the tool parameter descriptions for a specific tool. - ''' - try: - os.chdir(self.exe_path) - args = [] - args.append("." + os.path.sep + self.exe_name) - args.append("--toolparameters={}".format(to_camelcase(tool_name))) - - proc = Popen(args, shell=False, stdout=PIPE, - stderr=STDOUT, bufsize=1, universal_newlines=True) - ret = "" - while True: - line = proc.stdout.readline() - if line != '': - ret += line - else: - break - - return ret - except (OSError, ValueError, CalledProcessError) as err: - return err - - def toolbox(self, tool_name=''): - ''' - Retrieve the toolbox for a specific tool. - ''' - try: - os.chdir(self.exe_path) - args = [] - args.append("." + os.path.sep + self.exe_name) - args.append("--toolbox={}".format(to_camelcase(tool_name))) - - proc = Popen(args, shell=False, stdout=PIPE, - stderr=STDOUT, bufsize=1, universal_newlines=True) - ret = "" - while True: - line = proc.stdout.readline() - if line != '': - ret += line - else: - break - - return ret - except (OSError, ValueError, CalledProcessError) as err: - return err - - def view_code(self, tool_name): - ''' - Opens a web browser to view the source code for a specific tool - on the projects source code repository. - ''' - try: - os.chdir(self.exe_path) - args = [] - args.append("." + os.path.sep + self.exe_name) - args.append("--viewcode={}".format(to_camelcase(tool_name))) - - proc = Popen(args, shell=False, stdout=PIPE, - stderr=STDOUT, bufsize=1, universal_newlines=True) - ret = "" - while True: - line = proc.stdout.readline() - if line != '': - ret += line - else: - break - - return ret - except (OSError, ValueError, CalledProcessError) as err: - return err - - def list_tools(self, keywords=[]): - ''' - Lists all available tools in WhiteboxTools. - ''' - try: - os.chdir(self.exe_path) - args = [] - args.append("." + os.path.sep + self.exe_name) - args.append("--listtools") - if len(keywords) > 0: - for kw in keywords: - args.append(kw) - - proc = Popen(args, shell=False, stdout=PIPE, - stderr=STDOUT, bufsize=1, universal_newlines=True) - ret = {} - line = proc.stdout.readline() # skip number of available tools header - while True: - line = proc.stdout.readline() - if line != '': - if line.strip() != '': - name, descr = line.split(':') - ret[to_snakecase(name.strip())] = descr.strip() - else: - break - - return ret - except (OSError, ValueError, CalledProcessError) as err: - return err - - ######################################################################## - # The following methods are convenience methods for each available tool. - # This needs updating whenever new tools are added to the WhiteboxTools - # library. They can be generated automatically using the - # whitebox_plugin_generator.py script. It would also be possible to - # discover plugins at runtime and monkey-patch their methods using - # MethodType. However, this would not be as useful since it would - # restrict the ability for text editors and IDEs to use autocomplete. - ######################################################################## - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ############## - # Data Tools # - ############## - - def add_point_coordinates_to_table(self, i, callback=None): - """Modifies the attribute table of a point vector by adding fields containing each point's X and Y coordinates. - - Keyword arguments: - - i -- Input vector Points file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - return self.run_tool('add_point_coordinates_to_table', args, callback) # returns 1 if error - - def clean_vector(self, i, output, callback=None): - """Removes null features and lines/polygons with fewer than the required number of vertices. - - Keyword arguments: - - i -- Input vector file. - output -- Output vector file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('clean_vector', args, callback) # returns 1 if error - - def convert_nodata_to_zero(self, i, output, callback=None): - """Converts nodata values in a raster to zero. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('convert_nodata_to_zero', args, callback) # returns 1 if error - - def convert_raster_format(self, i, output, callback=None): - """Converts raster data from one format to another. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('convert_raster_format', args, callback) # returns 1 if error - - def csv_points_to_vector(self, i, output, xfield=0, yfield=1, epsg=None, callback=None): - """Converts a CSV text file to vector points. - - Keyword arguments: - - i -- Input CSV file (i.e. source of data to be imported). - output -- Output vector file. - xfield -- X field number (e.g. 0 for first field). - yfield -- Y field number (e.g. 1 for second field). - epsg -- EPSG projection (e.g. 2958). - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--xfield={}".format(xfield)) - args.append("--yfield={}".format(yfield)) - if epsg is not None: args.append("--epsg='{}'".format(epsg)) - return self.run_tool('csv_points_to_vector', args, callback) # returns 1 if error - - def export_table_to_csv(self, i, output, headers=True, callback=None): - """Exports an attribute table to a CSV text file. - - Keyword arguments: - - i -- Input vector file. - output -- Output raster file. - headers -- Export field names as file header?. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - if headers: args.append("--headers") - return self.run_tool('export_table_to_csv', args, callback) # returns 1 if error - - def join_tables(self, input1, pkey, input2, fkey, import_field, callback=None): - """Merge a vector's attribute table with another table based on a common field. - - Keyword arguments: - - input1 -- Input primary vector file (i.e. the table to be modified). - pkey -- Primary key field. - input2 -- Input foreign vector file (i.e. source of data to be imported). - fkey -- Foreign key field. - import_field -- Imported field (all fields will be imported if not specified). - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input1='{}'".format(input1)) - args.append("--pkey='{}'".format(pkey)) - args.append("--input2='{}'".format(input2)) - args.append("--fkey='{}'".format(fkey)) - args.append("--import_field='{}'".format(import_field)) - return self.run_tool('join_tables', args, callback) # returns 1 if error - - def lines_to_polygons(self, i, output, callback=None): - """Converts vector polylines to polygons. - - Keyword arguments: - - i -- Input vector line file. - output -- Output vector polygon file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('lines_to_polygons', args, callback) # returns 1 if error - - def merge_table_with_csv(self, i, pkey, csv, fkey, import_field=None, callback=None): - """Merge a vector's attribute table with a table contained within a CSV text file. - - Keyword arguments: - - i -- Input primary vector file (i.e. the table to be modified). - pkey -- Primary key field. - csv -- Input CSV file (i.e. source of data to be imported). - fkey -- Foreign key field. - import_field -- Imported field (all fields will be imported if not specified). - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--pkey='{}'".format(pkey)) - args.append("--csv='{}'".format(csv)) - args.append("--fkey='{}'".format(fkey)) - if import_field is not None: args.append("--import_field='{}'".format(import_field)) - return self.run_tool('merge_table_with_csv', args, callback) # returns 1 if error - - def merge_vectors(self, inputs, output, callback=None): - """Combines two or more input vectors of the same ShapeType creating a single, new output vector. - - Keyword arguments: - - inputs -- Input vector files. - output -- Output vector file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--inputs='{}'".format(inputs)) - args.append("--output='{}'".format(output)) - return self.run_tool('merge_vectors', args, callback) # returns 1 if error - - def modify_no_data_value(self, i, new_value="-32768.0", callback=None): - """Converts nodata values in a raster to zero. - - Keyword arguments: - - i -- Input raster file. - new_value -- New NoData value. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--new_value={}".format(new_value)) - return self.run_tool('modify_no_data_value', args, callback) # returns 1 if error - - def multi_part_to_single_part(self, i, output, exclude_holes=True, callback=None): - """Converts a vector file containing multi-part features into a vector containing only single-part features. - - Keyword arguments: - - i -- Input vector line or polygon file. - output -- Output vector line or polygon file. - exclude_holes -- Exclude hole parts from the feature splitting? (holes will continue to belong to their features in output.). - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - if exclude_holes: args.append("--exclude_holes") - return self.run_tool('multi_part_to_single_part', args, callback) # returns 1 if error - - def new_raster_from_base(self, base, output, value="nodata", data_type="float", callback=None): - """Creates a new raster using a base image. - - Keyword arguments: - - base -- Input base raster file. - output -- Output raster file. - value -- Constant value to fill raster with; either 'nodata' or numeric value. - data_type -- Output raster data type; options include 'double' (64-bit), 'float' (32-bit), and 'integer' (signed 16-bit) (default is 'float'). - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--base='{}'".format(base)) - args.append("--output='{}'".format(output)) - args.append("--value={}".format(value)) - args.append("--data_type={}".format(data_type)) - return self.run_tool('new_raster_from_base', args, callback) # returns 1 if error - - def polygons_to_lines(self, i, output, callback=None): - """Converts vector polygons to polylines. - - Keyword arguments: - - i -- Input vector polygon file. - output -- Output vector lines file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('polygons_to_lines', args, callback) # returns 1 if error - - def print_geo_tiff_tags(self, i, callback=None): - """Prints the tags within a GeoTIFF. - - Keyword arguments: - - i -- Input GeoTIFF file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - return self.run_tool('print_geo_tiff_tags', args, callback) # returns 1 if error - - def raster_to_vector_lines(self, i, output, callback=None): - """Converts a raster lines features into a vector of the POLYLINE shapetype. - - Keyword arguments: - - i -- Input raster lines file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('raster_to_vector_lines', args, callback) # returns 1 if error - - def raster_to_vector_points(self, i, output, callback=None): - """Converts a raster dataset to a vector of the POINT shapetype. - - Keyword arguments: - - i -- Input raster file. - output -- Output vector points file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('raster_to_vector_points', args, callback) # returns 1 if error - - def raster_to_vector_polygons(self, i, output, callback=None): - """Converts a raster dataset to a vector of the POLYGON shapetype. - - Keyword arguments: - - i -- Input raster file. - output -- Output vector polygons file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('raster_to_vector_polygons', args, callback) # returns 1 if error - - def reinitialize_attribute_table(self, i, callback=None): - """Reinitializes a vector's attribute table deleting all fields but the feature ID (FID). - - Keyword arguments: - - i -- Input vector file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - return self.run_tool('reinitialize_attribute_table', args, callback) # returns 1 if error - - def remove_polygon_holes(self, i, output, callback=None): - """Removes holes within the features of a vector polygon file. - - Keyword arguments: - - i -- Input vector polygon file. - output -- Output vector polygon file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('remove_polygon_holes', args, callback) # returns 1 if error - - def set_nodata_value(self, i, output, back_value=0.0, callback=None): - """Assign a specified value in an input image to the NoData value. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - back_value -- Background value to set to nodata. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--back_value={}".format(back_value)) - return self.run_tool('set_nodata_value', args, callback) # returns 1 if error - - def single_part_to_multi_part(self, i, output, field=None, callback=None): - """Converts a vector file containing multi-part features into a vector containing only single-part features. - - Keyword arguments: - - i -- Input vector line or polygon file. - field -- Grouping ID field name in attribute table. - output -- Output vector line or polygon file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - if field is not None: args.append("--field='{}'".format(field)) - args.append("--output='{}'".format(output)) - return self.run_tool('single_part_to_multi_part', args, callback) # returns 1 if error - - def vector_lines_to_raster(self, i, output, field="FID", nodata=True, cell_size=None, base=None, callback=None): - """Converts a vector containing polylines into a raster. - - Keyword arguments: - - i -- Input vector lines file. - field -- Input field name in attribute table. - output -- Output raster file. - nodata -- Background value to set to NoData. Without this flag, it will be set to 0.0. - cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. - base -- Optionally specified input base raster file. Not used when a cell size is specified. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--field={}".format(field)) - args.append("--output='{}'".format(output)) - if nodata: args.append("--nodata") - if cell_size is not None: args.append("--cell_size='{}'".format(cell_size)) - if base is not None: args.append("--base='{}'".format(base)) - return self.run_tool('vector_lines_to_raster', args, callback) # returns 1 if error - - def vector_points_to_raster(self, i, output, field="FID", assign="last", nodata=True, cell_size=None, base=None, callback=None): - """Converts a vector containing points into a raster. - - Keyword arguments: - - i -- Input vector Points file. - field -- Input field name in attribute table. - output -- Output raster file. - assign -- Assignment operation, where multiple points are in the same grid cell; options include 'first', 'last' (default), 'min', 'max', 'sum'. - nodata -- Background value to set to NoData. Without this flag, it will be set to 0.0. - cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. - base -- Optionally specified input base raster file. Not used when a cell size is specified. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--field={}".format(field)) - args.append("--output='{}'".format(output)) - args.append("--assign={}".format(assign)) - if nodata: args.append("--nodata") - if cell_size is not None: args.append("--cell_size='{}'".format(cell_size)) - if base is not None: args.append("--base='{}'".format(base)) - return self.run_tool('vector_points_to_raster', args, callback) # returns 1 if error - - def vector_polygons_to_raster(self, i, output, field="FID", nodata=True, cell_size=None, base=None, callback=None): - """Converts a vector containing polygons into a raster. - - Keyword arguments: - - i -- Input vector polygons file. - field -- Input field name in attribute table. - output -- Output raster file. - nodata -- Background value to set to NoData. Without this flag, it will be set to 0.0. - cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. - base -- Optionally specified input base raster file. Not used when a cell size is specified. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--field={}".format(field)) - args.append("--output='{}'".format(output)) - if nodata: args.append("--nodata") - if cell_size is not None: args.append("--cell_size='{}'".format(cell_size)) - if base is not None: args.append("--base='{}'".format(base)) - return self.run_tool('vector_polygons_to_raster', args, callback) # returns 1 if error - - ################ - # GIS Analysis # - ################ - - def aggregate_raster(self, i, output, agg_factor=2, type="mean", callback=None): - """Aggregates a raster to a lower resolution. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - agg_factor -- Aggregation factor, in pixels. - type -- Statistic used to fill output pixels. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--agg_factor={}".format(agg_factor)) - args.append("--type={}".format(type)) - return self.run_tool('aggregate_raster', args, callback) # returns 1 if error - - def block_maximum_gridding(self, i, field, output, use_z=False, cell_size=None, base=None, callback=None): - """Creates a raster grid based on a set of vector points and assigns grid values using a block maximum scheme. - - Keyword arguments: - - i -- Input vector Points file. - field -- Input field name in attribute table. - use_z -- Use z-coordinate instead of field?. - output -- Output raster file. - cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. - base -- Optionally specified input base raster file. Not used when a cell size is specified. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--field='{}'".format(field)) - if use_z: args.append("--use_z") - args.append("--output='{}'".format(output)) - if cell_size is not None: args.append("--cell_size='{}'".format(cell_size)) - if base is not None: args.append("--base='{}'".format(base)) - return self.run_tool('block_maximum_gridding', args, callback) # returns 1 if error - - def block_minimum_gridding(self, i, field, output, use_z=False, cell_size=None, base=None, callback=None): - """Creates a raster grid based on a set of vector points and assigns grid values using a block minimum scheme. - - Keyword arguments: - - i -- Input vector Points file. - field -- Input field name in attribute table. - use_z -- Use z-coordinate instead of field?. - output -- Output raster file. - cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. - base -- Optionally specified input base raster file. Not used when a cell size is specified. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--field='{}'".format(field)) - if use_z: args.append("--use_z") - args.append("--output='{}'".format(output)) - if cell_size is not None: args.append("--cell_size='{}'".format(cell_size)) - if base is not None: args.append("--base='{}'".format(base)) - return self.run_tool('block_minimum_gridding', args, callback) # returns 1 if error - - def centroid(self, i, output, text_output=False, callback=None): - """Calculates the centroid, or average location, of raster polygon objects. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - text_output -- Optional text output. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - if text_output: args.append("--text_output") - return self.run_tool('centroid', args, callback) # returns 1 if error - - def centroid_vector(self, i, output, callback=None): - """Identifes the centroid point of a vector polyline or polygon feature or a group of vector points. - - Keyword arguments: - - i -- Input vector file. - output -- Output vector file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('centroid_vector', args, callback) # returns 1 if error - - def clump(self, i, output, diag=True, zero_back=False, callback=None): - """Groups cells that form discrete areas, assigning them unique identifiers. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - diag -- Flag indicating whether diagonal connections should be considered. - zero_back -- Flag indicating whether zero values should be treated as a background. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - if diag: args.append("--diag") - if zero_back: args.append("--zero_back") - return self.run_tool('clump', args, callback) # returns 1 if error - - def construct_vector_tin(self, i, output, field=None, use_z=False, max_triangle_edge_length=None, callback=None): - """Creates a vector triangular irregular network (TIN) for a set of vector points. - - Keyword arguments: - - i -- Input vector points file. - field -- Input field name in attribute table. - use_z -- Use the 'z' dimension of the Shapefile's geometry instead of an attribute field?. - output -- Output vector polygon file. - max_triangle_edge_length -- Optional maximum triangle edge length; triangles larger than this size will not be gridded. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - if field is not None: args.append("--field='{}'".format(field)) - if use_z: args.append("--use_z") - args.append("--output='{}'".format(output)) - if max_triangle_edge_length is not None: args.append("--max_triangle_edge_length='{}'".format(max_triangle_edge_length)) - return self.run_tool('construct_vector_tin', args, callback) # returns 1 if error - - def create_hexagonal_vector_grid(self, i, output, width, orientation="horizontal", callback=None): - """Creates a hexagonal vector grid. - - Keyword arguments: - - i -- Input base file. - output -- Output vector polygon file. - width -- The grid cell width. - orientation -- Grid Orientation, 'horizontal' or 'vertical'. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--width='{}'".format(width)) - args.append("--orientation={}".format(orientation)) - return self.run_tool('create_hexagonal_vector_grid', args, callback) # returns 1 if error - - def create_plane(self, base, output, gradient=15.0, aspect=90.0, constant=0.0, callback=None): - """Creates a raster image based on the equation for a simple plane. - - Keyword arguments: - - base -- Input base raster file. - output -- Output raster file. - gradient -- Slope gradient in degrees (-85.0 to 85.0). - aspect -- Aspect (direction) in degrees clockwise from north (0.0-360.0). - constant -- Constant value. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--base='{}'".format(base)) - args.append("--output='{}'".format(output)) - args.append("--gradient={}".format(gradient)) - args.append("--aspect={}".format(aspect)) - args.append("--constant={}".format(constant)) - return self.run_tool('create_plane', args, callback) # returns 1 if error - - def create_rectangular_vector_grid(self, i, output, width, height, xorig=0, yorig=0, callback=None): - """Creates a rectangular vector grid. - - Keyword arguments: - - i -- Input base file. - output -- Output vector polygon file. - width -- The grid cell width. - height -- The grid cell height. - xorig -- The grid origin x-coordinate. - yorig -- The grid origin y-coordinate. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--width='{}'".format(width)) - args.append("--height='{}'".format(height)) - args.append("--xorig={}".format(xorig)) - args.append("--yorig={}".format(yorig)) - return self.run_tool('create_rectangular_vector_grid', args, callback) # returns 1 if error - - def dissolve(self, i, output, field=None, snap=0.0, callback=None): - """Removes the interior, or shared, boundaries within a vector polygon coverage. - - Keyword arguments: - - i -- Input vector file. - field -- Dissolve field attribute (optional). - output -- Output vector file. - snap -- Snap tolerance. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - if field is not None: args.append("--field='{}'".format(field)) - args.append("--output='{}'".format(output)) - args.append("--snap={}".format(snap)) - return self.run_tool('dissolve', args, callback) # returns 1 if error - - def eliminate_coincident_points(self, i, output, tolerance, callback=None): - """Removes any coincident, or nearly coincident, points from a vector points file. - - Keyword arguments: - - i -- Input vector file. - output -- Output vector polygon file. - tolerance -- The distance tolerance for points. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--tolerance='{}'".format(tolerance)) - return self.run_tool('eliminate_coincident_points', args, callback) # returns 1 if error - - def extend_vector_lines(self, i, output, dist, extend="both ends", callback=None): - """Extends vector lines by a specified distance. - - Keyword arguments: - - i -- Input vector polyline file. - output -- Output vector polyline file. - dist -- The distance to extend. - extend -- Extend direction, 'both ends' (default), 'line start', 'line end'. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--dist='{}'".format(dist)) - args.append("--extend={}".format(extend)) - return self.run_tool('extend_vector_lines', args, callback) # returns 1 if error - - def extract_nodes(self, i, output, callback=None): - """Converts vector lines or polygons into vertex points. - - Keyword arguments: - - i -- Input vector lines or polygon file. - output -- Output vector points file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('extract_nodes', args, callback) # returns 1 if error - - def extract_raster_values_at_points(self, inputs, points, out_text=False, callback=None): - """Extracts the values of raster(s) at vector point locations. - - Keyword arguments: - - inputs -- Input raster files. - points -- Input vector points file. - out_text -- Output point values as text? Otherwise, the only output is to to the points file's attribute table. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--inputs='{}'".format(inputs)) - args.append("--points='{}'".format(points)) - if out_text: args.append("--out_text") - return self.run_tool('extract_raster_values_at_points', args, callback) # returns 1 if error - - def find_lowest_or_highest_points(self, i, output, out_type="lowest", callback=None): - """Locates the lowest and/or highest valued cells in a raster. - - Keyword arguments: - - i -- Input raster file. - output -- Output vector points file. - out_type -- Output type; one of 'area' (default) and 'volume'. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--out_type={}".format(out_type)) - return self.run_tool('find_lowest_or_highest_points', args, callback) # returns 1 if error - - def idw_interpolation(self, i, field, output, use_z=False, weight=2.0, radius=None, min_points=None, cell_size=None, base=None, callback=None): - """Interpolates vector points into a raster surface using an inverse-distance weighted scheme. - - Keyword arguments: - - i -- Input vector Points file. - field -- Input field name in attribute table. - use_z -- Use z-coordinate instead of field?. - output -- Output raster file. - weight -- IDW weight value. - radius -- Search Radius in map units. - min_points -- Minimum number of points. - cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. - base -- Optionally specified input base raster file. Not used when a cell size is specified. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--field='{}'".format(field)) - if use_z: args.append("--use_z") - args.append("--output='{}'".format(output)) - args.append("--weight={}".format(weight)) - if radius is not None: args.append("--radius='{}'".format(radius)) - if min_points is not None: args.append("--min_points='{}'".format(min_points)) - if cell_size is not None: args.append("--cell_size='{}'".format(cell_size)) - if base is not None: args.append("--base='{}'".format(base)) - return self.run_tool('idw_interpolation', args, callback) # returns 1 if error - - def layer_footprint(self, i, output, callback=None): - """Creates a vector polygon footprint of the area covered by a raster grid or vector layer. - - Keyword arguments: - - i -- Input raster or vector file. - output -- Output vector polygon file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('layer_footprint', args, callback) # returns 1 if error - - def medoid(self, i, output, callback=None): - """Calculates the medoid for a series of vector features contained in a shapefile. - - Keyword arguments: - - i -- Input vector file. - output -- Output vector file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('medoid', args, callback) # returns 1 if error - - def minimum_bounding_box(self, i, output, criterion="area", features=True, callback=None): - """Creates a vector minimum bounding rectangle around vector features. - - Keyword arguments: - - i -- Input vector file. - output -- Output vector polygon file. - criterion -- Minimization criterion; options include 'area' (default), 'length', 'width', and 'perimeter'. - features -- Find the minimum bounding rectangles around each individual vector feature. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--criterion={}".format(criterion)) - if features: args.append("--features") - return self.run_tool('minimum_bounding_box', args, callback) # returns 1 if error - - def minimum_bounding_circle(self, i, output, features=True, callback=None): - """Delineates the minimum bounding circle (i.e. smallest enclosing circle) for a group of vectors. - - Keyword arguments: - - i -- Input vector file. - output -- Output vector polygon file. - features -- Find the minimum bounding circle around each individual vector feature. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - if features: args.append("--features") - return self.run_tool('minimum_bounding_circle', args, callback) # returns 1 if error - - def minimum_bounding_envelope(self, i, output, features=True, callback=None): - """Creates a vector axis-aligned minimum bounding rectangle (envelope) around vector features. - - Keyword arguments: - - i -- Input vector file. - output -- Output vector polygon file. - features -- Find the minimum bounding envelop around each individual vector feature. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - if features: args.append("--features") - return self.run_tool('minimum_bounding_envelope', args, callback) # returns 1 if error - - def minimum_convex_hull(self, i, output, features=True, callback=None): - """Creates a vector convex polygon around vector features. - - Keyword arguments: - - i -- Input vector file. - output -- Output vector polygon file. - features -- Find the hulls around each vector feature. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - if features: args.append("--features") - return self.run_tool('minimum_convex_hull', args, callback) # returns 1 if error - - def natural_neighbour_interpolation(self, i, output, field=None, use_z=False, cell_size=None, base=None, clip=True, callback=None): - """Creates a raster grid based on Sibson's natural neighbour method. - - Keyword arguments: - - i -- Input vector points file. - field -- Input field name in attribute table. - use_z -- Use the 'z' dimension of the Shapefile's geometry instead of an attribute field?. - output -- Output raster file. - cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. - base -- Optionally specified input base raster file. Not used when a cell size is specified. - clip -- Clip the data to the convex hull of the points?. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - if field is not None: args.append("--field='{}'".format(field)) - if use_z: args.append("--use_z") - args.append("--output='{}'".format(output)) - if cell_size is not None: args.append("--cell_size='{}'".format(cell_size)) - if base is not None: args.append("--base='{}'".format(base)) - if clip: args.append("--clip") - return self.run_tool('natural_neighbour_interpolation', args, callback) # returns 1 if error - - def nearest_neighbour_gridding(self, i, field, output, use_z=False, cell_size=None, base=None, max_dist=None, callback=None): - """Creates a raster grid based on a set of vector points and assigns grid values using the nearest neighbour. - - Keyword arguments: - - i -- Input vector Points file. - field -- Input field name in attribute table. - use_z -- Use z-coordinate instead of field?. - output -- Output raster file. - cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. - base -- Optionally specified input base raster file. Not used when a cell size is specified. - max_dist -- Maximum search distance (optional). - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--field='{}'".format(field)) - if use_z: args.append("--use_z") - args.append("--output='{}'".format(output)) - if cell_size is not None: args.append("--cell_size='{}'".format(cell_size)) - if base is not None: args.append("--base='{}'".format(base)) - if max_dist is not None: args.append("--max_dist='{}'".format(max_dist)) - return self.run_tool('nearest_neighbour_gridding', args, callback) # returns 1 if error - - def polygon_area(self, i, callback=None): - """Calculates the area of vector polygons. - - Keyword arguments: - - i -- Input vector polygon file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - return self.run_tool('polygon_area', args, callback) # returns 1 if error - - def polygon_long_axis(self, i, output, callback=None): - """This tool can be used to map the long axis of polygon features. - - Keyword arguments: - - i -- Input vector polygons file. - output -- Output vector polyline file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('polygon_long_axis', args, callback) # returns 1 if error - - def polygon_perimeter(self, i, callback=None): - """Calculates the perimeter of vector polygons. - - Keyword arguments: - - i -- Input vector polygon file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - return self.run_tool('polygon_perimeter', args, callback) # returns 1 if error - - def polygon_short_axis(self, i, output, callback=None): - """This tool can be used to map the short axis of polygon features. - - Keyword arguments: - - i -- Input vector polygons file. - output -- Output vector polyline file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('polygon_short_axis', args, callback) # returns 1 if error - - def radial_basis_function_interpolation(self, i, field, output, use_z=False, radius=None, min_points=None, func_type="ThinPlateSpline", poly_order="none", weight=0.1, cell_size=None, base=None, callback=None): - """Interpolates vector points into a raster surface using a radial basis function scheme. - - Keyword arguments: - - i -- Input vector points file. - field -- Input field name in attribute table. - use_z -- Use z-coordinate instead of field?. - output -- Output raster file. - radius -- Search Radius (in map units). - min_points -- Minimum number of points. - func_type -- Radial basis function type; options are 'ThinPlateSpline' (default), 'PolyHarmonic', 'Gaussian', 'MultiQuadric', 'InverseMultiQuadric'. - poly_order -- Polynomial order; options are 'none' (default), 'constant', 'affine'. - weight -- Weight parameter used in basis function. - cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. - base -- Optionally specified input base raster file. Not used when a cell size is specified. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--field='{}'".format(field)) - if use_z: args.append("--use_z") - args.append("--output='{}'".format(output)) - if radius is not None: args.append("--radius='{}'".format(radius)) - if min_points is not None: args.append("--min_points='{}'".format(min_points)) - args.append("--func_type={}".format(func_type)) - args.append("--poly_order={}".format(poly_order)) - args.append("--weight={}".format(weight)) - if cell_size is not None: args.append("--cell_size='{}'".format(cell_size)) - if base is not None: args.append("--base='{}'".format(base)) - return self.run_tool('radial_basis_function_interpolation', args, callback) # returns 1 if error - - def raster_area(self, i, output=None, out_text=False, units="grid cells", zero_back=False, callback=None): - """Calculates the area of polygons or classes within a raster image. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - out_text -- Would you like to output polygon areas to text?. - units -- Area units; options include 'grid cells' and 'map units'. - zero_back -- Flag indicating whether zero values should be treated as a background. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - if output is not None: args.append("--output='{}'".format(output)) - if out_text: args.append("--out_text") - args.append("--units={}".format(units)) - if zero_back: args.append("--zero_back") - return self.run_tool('raster_area', args, callback) # returns 1 if error - - def raster_cell_assignment(self, i, output, assign="column", callback=None): - """Assign row or column number to cells. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - assign -- Which variable would you like to assign to grid cells? Options include 'column', 'row', 'x', and 'y'. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--assign={}".format(assign)) - return self.run_tool('raster_cell_assignment', args, callback) # returns 1 if error - - def raster_perimeter(self, i, output=None, out_text=False, units="grid cells", zero_back=False, callback=None): - """Calculates the perimeters of polygons or classes within a raster image. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - out_text -- Would you like to output polygon areas to text?. - units -- Area units; options include 'grid cells' and 'map units'. - zero_back -- Flag indicating whether zero values should be treated as a background. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - if output is not None: args.append("--output='{}'".format(output)) - if out_text: args.append("--out_text") - args.append("--units={}".format(units)) - if zero_back: args.append("--zero_back") - return self.run_tool('raster_perimeter', args, callback) # returns 1 if error - - def reclass(self, i, output, reclass_vals, assign_mode=False, callback=None): - """Reclassifies the values in a raster image. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - reclass_vals -- Reclassification triplet values (new value; from value; to less than), e.g. '0.0;0.0;1.0;1.0;1.0;2.0'. - assign_mode -- Optional Boolean flag indicating whether to operate in assign mode, reclass_vals values are interpreted as new value; old value pairs. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--reclass_vals='{}'".format(reclass_vals)) - if assign_mode: args.append("--assign_mode") - return self.run_tool('reclass', args, callback) # returns 1 if error - - def reclass_equal_interval(self, i, output, interval=10.0, start_val=None, end_val=None, callback=None): - """Reclassifies the values in a raster image based on equal-ranges. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - interval -- Class interval size. - start_val -- Optional starting value (default is input minimum value). - end_val -- Optional ending value (default is input maximum value). - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--interval={}".format(interval)) - if start_val is not None: args.append("--start_val='{}'".format(start_val)) - if end_val is not None: args.append("--end_val='{}'".format(end_val)) - return self.run_tool('reclass_equal_interval', args, callback) # returns 1 if error - - def reclass_from_file(self, i, reclass_file, output, callback=None): - """Reclassifies the values in a raster image using reclass ranges in a text file. - - Keyword arguments: - - i -- Input raster file. - reclass_file -- Input text file containing reclass ranges. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--reclass_file='{}'".format(reclass_file)) - args.append("--output='{}'".format(output)) - return self.run_tool('reclass_from_file', args, callback) # returns 1 if error - - def smooth_vectors(self, i, output, filter=3, callback=None): - """Smooths a vector coverage of either a POLYLINE or POLYGON base ShapeType. - - Keyword arguments: - - i -- Input vector POLYLINE or POLYGON file. - output -- Output vector file. - filter -- The filter size, any odd integer greater than or equal to 3; default is 3. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--filter={}".format(filter)) - return self.run_tool('smooth_vectors', args, callback) # returns 1 if error - - def tin_gridding(self, i, output, field=None, use_z=False, resolution=None, base=None, max_triangle_edge_length=None, callback=None): - """Creates a raster grid based on a triangular irregular network (TIN) fitted to vector points. - - Keyword arguments: - - i -- Input vector points file. - field -- Input field name in attribute table. - use_z -- Use the 'z' dimension of the Shapefile's geometry instead of an attribute field?. - output -- Output raster file. - resolution -- Output raster's grid resolution. - base -- Optionally specified input base raster file. Not used when a cell size is specified. - max_triangle_edge_length -- Optional maximum triangle edge length; triangles larger than this size will not be gridded. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - if field is not None: args.append("--field='{}'".format(field)) - if use_z: args.append("--use_z") - args.append("--output='{}'".format(output)) - if resolution is not None: args.append("--resolution='{}'".format(resolution)) - if base is not None: args.append("--base='{}'".format(base)) - if max_triangle_edge_length is not None: args.append("--max_triangle_edge_length='{}'".format(max_triangle_edge_length)) - return self.run_tool('tin_gridding', args, callback) # returns 1 if error - - def vector_hex_binning(self, i, output, width, orientation="horizontal", callback=None): - """Hex-bins a set of vector points. - - Keyword arguments: - - i -- Input base file. - output -- Output vector polygon file. - width -- The grid cell width. - orientation -- Grid Orientation, 'horizontal' or 'vertical'. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--width='{}'".format(width)) - args.append("--orientation={}".format(orientation)) - return self.run_tool('vector_hex_binning', args, callback) # returns 1 if error - - def voronoi_diagram(self, i, output, callback=None): - """Creates a vector Voronoi diagram for a set of vector points. - - Keyword arguments: - - i -- Input vector points file. - output -- Output vector polygon file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('voronoi_diagram', args, callback) # returns 1 if error - - ############################### - # GIS Analysis/Distance Tools # - ############################### - - def buffer_raster(self, i, output, size, gridcells=False, callback=None): - """Maps a distance-based buffer around each non-background (non-zero/non-nodata) grid cell in an input image. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - size -- Buffer size. - gridcells -- Optional flag to indicate that the 'size' threshold should be measured in grid cells instead of the default map units. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--size='{}'".format(size)) - if gridcells: args.append("--gridcells") - return self.run_tool('buffer_raster', args, callback) # returns 1 if error - - def cost_allocation(self, source, backlink, output, callback=None): - """Identifies the source cell to which each grid cell is connected by a least-cost pathway in a cost-distance analysis. - - Keyword arguments: - - source -- Input source raster file. - backlink -- Input backlink raster file generated by the cost-distance tool. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--source='{}'".format(source)) - args.append("--backlink='{}'".format(backlink)) - args.append("--output='{}'".format(output)) - return self.run_tool('cost_allocation', args, callback) # returns 1 if error - - def cost_distance(self, source, cost, out_accum, out_backlink, callback=None): - """Performs cost-distance accumulation on a cost surface and a group of source cells. - - Keyword arguments: - - source -- Input source raster file. - cost -- Input cost (friction) raster file. - out_accum -- Output cost accumulation raster file. - out_backlink -- Output backlink raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--source='{}'".format(source)) - args.append("--cost='{}'".format(cost)) - args.append("--out_accum='{}'".format(out_accum)) - args.append("--out_backlink='{}'".format(out_backlink)) - return self.run_tool('cost_distance', args, callback) # returns 1 if error - - def cost_pathway(self, destination, backlink, output, zero_background=False, callback=None): - """Performs cost-distance pathway analysis using a series of destination grid cells. - - Keyword arguments: - - destination -- Input destination raster file. - backlink -- Input backlink raster file generated by the cost-distance tool. - output -- Output cost pathway raster file. - zero_background -- Flag indicating whether zero values should be treated as a background. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--destination='{}'".format(destination)) - args.append("--backlink='{}'".format(backlink)) - args.append("--output='{}'".format(output)) - if zero_background: args.append("--zero_background") - return self.run_tool('cost_pathway', args, callback) # returns 1 if error - - def euclidean_allocation(self, i, output, callback=None): - """Assigns grid cells in the output raster the value of the nearest target cell in the input image, measured by the Shih and Wu (2004) Euclidean distance transform. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('euclidean_allocation', args, callback) # returns 1 if error - - def euclidean_distance(self, i, output, callback=None): - """Calculates the Shih and Wu (2004) Euclidean distance transform. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('euclidean_distance', args, callback) # returns 1 if error - - ############################## - # GIS Analysis/Overlay Tools # - ############################## - - def average_overlay(self, inputs, output, callback=None): - """Calculates the average for each grid cell from a group of raster images. - - Keyword arguments: - - inputs -- Input raster files. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--inputs='{}'".format(inputs)) - args.append("--output='{}'".format(output)) - return self.run_tool('average_overlay', args, callback) # returns 1 if error - - def clip(self, i, clip, output, callback=None): - """Extract all the features, or parts of features, that overlap with the features of the clip vector. - - Keyword arguments: - - i -- Input vector file. - clip -- Input clip polygon vector file. - output -- Output vector file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--clip='{}'".format(clip)) - args.append("--output='{}'".format(output)) - return self.run_tool('clip', args, callback) # returns 1 if error - - def clip_raster_to_polygon(self, i, polygons, output, maintain_dimensions=False, callback=None): - """Clips a raster to a vector polygon. - - Keyword arguments: - - i -- Input raster file. - polygons -- Input vector polygons file. - output -- Output raster file. - maintain_dimensions -- Maintain input raster dimensions?. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--polygons='{}'".format(polygons)) - args.append("--output='{}'".format(output)) - if maintain_dimensions: args.append("--maintain_dimensions") - return self.run_tool('clip_raster_to_polygon', args, callback) # returns 1 if error - - def count_if(self, inputs, output, value, callback=None): - """Counts the number of occurrences of a specified value in a cell-stack of rasters. - - Keyword arguments: - - inputs -- Input raster files. - output -- Output raster file. - value -- Search value (e.g. countif value = 5.0). - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--inputs='{}'".format(inputs)) - args.append("--output='{}'".format(output)) - args.append("--value='{}'".format(value)) - return self.run_tool('count_if', args, callback) # returns 1 if error - - def difference(self, i, overlay, output, callback=None): - """Outputs the features that occur in one of the two vector inputs but not both, i.e. no overlapping features. - - Keyword arguments: - - i -- Input vector file. - overlay -- Input overlay vector file. - output -- Output vector file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--overlay='{}'".format(overlay)) - args.append("--output='{}'".format(output)) - return self.run_tool('difference', args, callback) # returns 1 if error - - def erase(self, i, erase, output, callback=None): - """Removes all the features, or parts of features, that overlap with the features of the erase vector polygon. - - Keyword arguments: - - i -- Input vector file. - erase -- Input erase polygon vector file. - output -- Output vector file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--erase='{}'".format(erase)) - args.append("--output='{}'".format(output)) - return self.run_tool('erase', args, callback) # returns 1 if error - - def erase_polygon_from_raster(self, i, polygons, output, callback=None): - """Erases (cuts out) a vector polygon from a raster. - - Keyword arguments: - - i -- Input raster file. - polygons -- Input vector polygons file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--polygons='{}'".format(polygons)) - args.append("--output='{}'".format(output)) - return self.run_tool('erase_polygon_from_raster', args, callback) # returns 1 if error - - def highest_position(self, inputs, output, callback=None): - """Identifies the stack position of the maximum value within a raster stack on a cell-by-cell basis. - - Keyword arguments: - - inputs -- Input raster files. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--inputs='{}'".format(inputs)) - args.append("--output='{}'".format(output)) - return self.run_tool('highest_position', args, callback) # returns 1 if error - - def intersect(self, i, overlay, output, snap=0.0, callback=None): - """Identifies the parts of features in common between two input vector layers. - - Keyword arguments: - - i -- Input vector file. - overlay -- Input overlay vector file. - output -- Output vector file. - snap -- Snap tolerance. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--overlay='{}'".format(overlay)) - args.append("--output='{}'".format(output)) - args.append("--snap={}".format(snap)) - return self.run_tool('intersect', args, callback) # returns 1 if error - - def line_intersections(self, input1, input2, output, callback=None): - """Identifies points where the features of two vector line layers intersect. - - Keyword arguments: - - input1 -- Input vector polyline file. - input2 -- Input vector polyline file. - output -- Output vector point file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input1='{}'".format(input1)) - args.append("--input2='{}'".format(input2)) - args.append("--output='{}'".format(output)) - return self.run_tool('line_intersections', args, callback) # returns 1 if error - - def lowest_position(self, inputs, output, callback=None): - """Identifies the stack position of the minimum value within a raster stack on a cell-by-cell basis. - - Keyword arguments: - - inputs -- Input raster files. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--inputs='{}'".format(inputs)) - args.append("--output='{}'".format(output)) - return self.run_tool('lowest_position', args, callback) # returns 1 if error - - def max_absolute_overlay(self, inputs, output, callback=None): - """Evaluates the maximum absolute value for each grid cell from a stack of input rasters. - - Keyword arguments: - - inputs -- Input raster files. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--inputs='{}'".format(inputs)) - args.append("--output='{}'".format(output)) - return self.run_tool('max_absolute_overlay', args, callback) # returns 1 if error - - def max_overlay(self, inputs, output, callback=None): - """Evaluates the maximum value for each grid cell from a stack of input rasters. - - Keyword arguments: - - inputs -- Input raster files. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--inputs='{}'".format(inputs)) - args.append("--output='{}'".format(output)) - return self.run_tool('max_overlay', args, callback) # returns 1 if error - - def merge_line_segments(self, i, output, snap=0.0, callback=None): - """Merges vector line segments into larger features. - - Keyword arguments: - - i -- Input vector file. - output -- Output vector file. - snap -- Snap tolerance. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--snap={}".format(snap)) - return self.run_tool('merge_line_segments', args, callback) # returns 1 if error - - def min_absolute_overlay(self, inputs, output, callback=None): - """Evaluates the minimum absolute value for each grid cell from a stack of input rasters. - - Keyword arguments: - - inputs -- Input raster files. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--inputs='{}'".format(inputs)) - args.append("--output='{}'".format(output)) - return self.run_tool('min_absolute_overlay', args, callback) # returns 1 if error - - def min_overlay(self, inputs, output, callback=None): - """Evaluates the minimum value for each grid cell from a stack of input rasters. - - Keyword arguments: - - inputs -- Input raster files. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--inputs='{}'".format(inputs)) - args.append("--output='{}'".format(output)) - return self.run_tool('min_overlay', args, callback) # returns 1 if error - - def percent_equal_to(self, inputs, comparison, output, callback=None): - """Calculates the percentage of a raster stack that have cell values equal to an input on a cell-by-cell basis. - - Keyword arguments: - - inputs -- Input raster files. - comparison -- Input comparison raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--inputs='{}'".format(inputs)) - args.append("--comparison='{}'".format(comparison)) - args.append("--output='{}'".format(output)) - return self.run_tool('percent_equal_to', args, callback) # returns 1 if error - - def percent_greater_than(self, inputs, comparison, output, callback=None): - """Calculates the percentage of a raster stack that have cell values greather than an input on a cell-by-cell basis. - - Keyword arguments: - - inputs -- Input raster files. - comparison -- Input comparison raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--inputs='{}'".format(inputs)) - args.append("--comparison='{}'".format(comparison)) - args.append("--output='{}'".format(output)) - return self.run_tool('percent_greater_than', args, callback) # returns 1 if error - - def percent_less_than(self, inputs, comparison, output, callback=None): - """Calculates the percentage of a raster stack that have cell values less than an input on a cell-by-cell basis. - - Keyword arguments: - - inputs -- Input raster files. - comparison -- Input comparison raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--inputs='{}'".format(inputs)) - args.append("--comparison='{}'".format(comparison)) - args.append("--output='{}'".format(output)) - return self.run_tool('percent_less_than', args, callback) # returns 1 if error - - def pick_from_list(self, inputs, pos_input, output, callback=None): - """Outputs the value from a raster stack specified by a position raster. - - Keyword arguments: - - inputs -- Input raster files. - pos_input -- Input position raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--inputs='{}'".format(inputs)) - args.append("--pos_input='{}'".format(pos_input)) - args.append("--output='{}'".format(output)) - return self.run_tool('pick_from_list', args, callback) # returns 1 if error - - def polygonize(self, inputs, output, callback=None): - """Creates a polygon layer from two or more intersecting line features contained in one or more input vector line files. - - Keyword arguments: - - inputs -- Input vector polyline file. - output -- Output vector polygon file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--inputs='{}'".format(inputs)) - args.append("--output='{}'".format(output)) - return self.run_tool('polygonize', args, callback) # returns 1 if error - - def split_with_lines(self, i, split, output, callback=None): - """Splits the lines or polygons in one layer using the lines in another layer. - - Keyword arguments: - - i -- Input vector line or polygon file. - split -- Input vector polyline file. - output -- Output vector file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--split='{}'".format(split)) - args.append("--output='{}'".format(output)) - return self.run_tool('split_with_lines', args, callback) # returns 1 if error - - def sum_overlay(self, inputs, output, callback=None): - """Calculates the sum for each grid cell from a group of raster images. - - Keyword arguments: - - inputs -- Input raster files. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--inputs='{}'".format(inputs)) - args.append("--output='{}'".format(output)) - return self.run_tool('sum_overlay', args, callback) # returns 1 if error - - def symmetrical_difference(self, i, overlay, output, snap=0.0, callback=None): - """Outputs the features that occur in one of the two vector inputs but not both, i.e. no overlapping features. - - Keyword arguments: - - i -- Input vector file. - overlay -- Input overlay vector file. - output -- Output vector file. - snap -- Snap tolerance. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--overlay='{}'".format(overlay)) - args.append("--output='{}'".format(output)) - args.append("--snap={}".format(snap)) - return self.run_tool('symmetrical_difference', args, callback) # returns 1 if error - - def union(self, i, overlay, output, snap=0.0, callback=None): - """Splits vector layers at their overlaps, creating a layer containing all the portions from both input and overlay layers. - - Keyword arguments: - - i -- Input vector file. - overlay -- Input overlay vector file. - output -- Output vector file. - snap -- Snap tolerance. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--overlay='{}'".format(overlay)) - args.append("--output='{}'".format(output)) - args.append("--snap={}".format(snap)) - return self.run_tool('union', args, callback) # returns 1 if error - - def update_nodata_cells(self, input1, input2, output, callback=None): - """Replaces the NoData values in an input raster with the corresponding values contained in a second update layer. - - Keyword arguments: - - input1 -- Input raster file 1. - input2 -- Input raster file 2; update layer. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input1='{}'".format(input1)) - args.append("--input2='{}'".format(input2)) - args.append("--output='{}'".format(output)) - return self.run_tool('update_nodata_cells', args, callback) # returns 1 if error - - def weighted_overlay(self, factors, weights, output, cost=None, constraints=None, scale_max=1.0, callback=None): - """Performs a weighted sum on multiple input rasters after converting each image to a common scale. The tool performs a multi-criteria evaluation (MCE). - - Keyword arguments: - - factors -- Input factor raster files. - weights -- Weight values, contained in quotes and separated by commas or semicolons. Must have the same number as factors. - cost -- Weight values, contained in quotes and separated by commas or semicolons. Must have the same number as factors. - constraints -- Input constraints raster files. - output -- Output raster file. - scale_max -- Suitability scale maximum value (common values are 1.0, 100.0, and 255.0). - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--factors='{}'".format(factors)) - args.append("--weights='{}'".format(weights)) - if cost is not None: args.append("--cost='{}'".format(cost)) - if constraints is not None: args.append("--constraints='{}'".format(constraints)) - args.append("--output='{}'".format(output)) - args.append("--scale_max={}".format(scale_max)) - return self.run_tool('weighted_overlay', args, callback) # returns 1 if error - - def weighted_sum(self, inputs, weights, output, callback=None): - """Performs a weighted-sum overlay on multiple input raster images. - - Keyword arguments: - - inputs -- Input raster files. - weights -- Weight values, contained in quotes and separated by commas or semicolons. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--inputs='{}'".format(inputs)) - args.append("--weights='{}'".format(weights)) - args.append("--output='{}'".format(output)) - return self.run_tool('weighted_sum', args, callback) # returns 1 if error - - ################################## - # GIS Analysis/Patch Shape Tools # - ################################## - - def boundary_shape_complexity(self, i, output, callback=None): - """Calculates the complexity of the boundaries of raster polygons. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('boundary_shape_complexity', args, callback) # returns 1 if error - - def compactness_ratio(self, i, callback=None): - """Calculates the compactness ratio (A/P), a measure of shape complexity, for vector polygons. - - Keyword arguments: - - i -- Input vector polygon file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - return self.run_tool('compactness_ratio', args, callback) # returns 1 if error - - def edge_proportion(self, i, output, output_text=False, callback=None): - """Calculate the proportion of cells in a raster polygon that are edge cells. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - output_text -- flag indicating whether a text report should also be output. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - if output_text: args.append("--output_text") - return self.run_tool('edge_proportion', args, callback) # returns 1 if error - - def elongation_ratio(self, i, callback=None): - """Calculates the elongation ratio for vector polygons. - - Keyword arguments: - - i -- Input vector polygon file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - return self.run_tool('elongation_ratio', args, callback) # returns 1 if error - - def find_patch_or_class_edge_cells(self, i, output, callback=None): - """Finds all cells located on the edge of patch or class features. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('find_patch_or_class_edge_cells', args, callback) # returns 1 if error - - def hole_proportion(self, i, callback=None): - """Calculates the proportion of the total area of a polygon's holes relative to the area of the polygon's hull. - - Keyword arguments: - - i -- Input vector polygon file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - return self.run_tool('hole_proportion', args, callback) # returns 1 if error - - def linearity_index(self, i, callback=None): - """Calculates the linearity index for vector polygons. - - Keyword arguments: - - i -- Input vector polygon file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - return self.run_tool('linearity_index', args, callback) # returns 1 if error - - def narrowness_index(self, i, output, callback=None): - """Calculates the narrowness of raster polygons. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('narrowness_index', args, callback) # returns 1 if error - - def patch_orientation(self, i, callback=None): - """Calculates the orientation of vector polygons. - - Keyword arguments: - - i -- Input vector polygon file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - return self.run_tool('patch_orientation', args, callback) # returns 1 if error - - def perimeter_area_ratio(self, i, callback=None): - """Calculates the perimeter-area ratio of vector polygons. - - Keyword arguments: - - i -- Input vector polygon file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - return self.run_tool('perimeter_area_ratio', args, callback) # returns 1 if error - - def radius_of_gyration(self, i, output, text_output=False, callback=None): - """Calculates the distance of cells from their polygon's centroid. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - text_output -- Optional text output. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - if text_output: args.append("--text_output") - return self.run_tool('radius_of_gyration', args, callback) # returns 1 if error - - def related_circumscribing_circle(self, i, callback=None): - """Calculates the related circumscribing circle of vector polygons. - - Keyword arguments: - - i -- Input vector polygon file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - return self.run_tool('related_circumscribing_circle', args, callback) # returns 1 if error - - def shape_complexity_index(self, i, callback=None): - """Calculates overall polygon shape complexity or irregularity. - - Keyword arguments: - - i -- Input vector polygon file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - return self.run_tool('shape_complexity_index', args, callback) # returns 1 if error - - def shape_complexity_index_raster(self, i, output, callback=None): - """Calculates the complexity of raster polygons or classes. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('shape_complexity_index_raster', args, callback) # returns 1 if error - - ############################ - # Geomorphometric Analysis # - ############################ - - def aspect(self, dem, output, zfactor=1.0, callback=None): - """Calculates an aspect raster from an input DEM. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - args.append("--zfactor={}".format(zfactor)) - return self.run_tool('aspect', args, callback) # returns 1 if error - - def average_normal_vector_angular_deviation(self, dem, output, filter=11, callback=None): - """Calculates the circular variance of aspect at a scale for a DEM. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - filter -- Size of the filter kernel. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - args.append("--filter={}".format(filter)) - return self.run_tool('average_normal_vector_angular_deviation', args, callback) # returns 1 if error - - def circular_variance_of_aspect(self, dem, output, filter=11, callback=None): - """Calculates the circular variance of aspect at a scale for a DEM. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - filter -- Size of the filter kernel. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - args.append("--filter={}".format(filter)) - return self.run_tool('circular_variance_of_aspect', args, callback) # returns 1 if error - - def contours_from_points(self, i, output, field=None, use_z=False, max_triangle_edge_length=None, interval=10.0, base=0.0, smooth=5, callback=None): - """Creates a contour coverage from a set of input points. - - Keyword arguments: - - i -- Input vector points file. - field -- Input field name in attribute table. - use_z -- Use the 'z' dimension of the Shapefile's geometry instead of an attribute field?. - output -- Output vector lines file. - max_triangle_edge_length -- Optional maximum triangle edge length; triangles larger than this size will not be gridded. - interval -- Contour interval. - base -- Base contour height. - smooth -- Smoothing filter size (in num. points), e.g. 3, 5, 7, 9, 11. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - if field is not None: args.append("--field='{}'".format(field)) - if use_z: args.append("--use_z") - args.append("--output='{}'".format(output)) - if max_triangle_edge_length is not None: args.append("--max_triangle_edge_length='{}'".format(max_triangle_edge_length)) - args.append("--interval={}".format(interval)) - args.append("--base={}".format(base)) - args.append("--smooth={}".format(smooth)) - return self.run_tool('contours_from_points', args, callback) # returns 1 if error - - def contours_from_raster(self, i, output, interval=10.0, base=0.0, smooth=9, tolerance=10.0, callback=None): - """Derives a vector contour coverage from a raster surface. - - Keyword arguments: - - i -- Input surface raster file. - output -- Output vector contour file. - interval -- Contour interval. - base -- Base contour height. - smooth -- Smoothing filter size (in num. points), e.g. 3, 5, 7, 9, 11. - tolerance -- Tolerance factor, in degrees (0-45); determines generalization level. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--interval={}".format(interval)) - args.append("--base={}".format(base)) - args.append("--smooth={}".format(smooth)) - args.append("--tolerance={}".format(tolerance)) - return self.run_tool('contours_from_raster', args, callback) # returns 1 if error - - def dev_from_mean_elev(self, dem, output, filterx=11, filtery=11, callback=None): - """Calculates deviation from mean elevation. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - filterx -- Size of the filter kernel in the x-direction. - filtery -- Size of the filter kernel in the y-direction. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - args.append("--filterx={}".format(filterx)) - args.append("--filtery={}".format(filtery)) - return self.run_tool('dev_from_mean_elev', args, callback) # returns 1 if error - - def diff_from_mean_elev(self, dem, output, filterx=11, filtery=11, callback=None): - """Calculates difference from mean elevation (equivalent to a high-pass filter). - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - filterx -- Size of the filter kernel in the x-direction. - filtery -- Size of the filter kernel in the y-direction. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - args.append("--filterx={}".format(filterx)) - args.append("--filtery={}".format(filtery)) - return self.run_tool('diff_from_mean_elev', args, callback) # returns 1 if error - - def directional_relief(self, dem, output, azimuth=0.0, max_dist=None, callback=None): - """Calculates relief for cells in an input DEM for a specified direction. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - azimuth -- Wind azimuth in degrees. - max_dist -- Optional maximum search distance (unspecified if none; in xy units). - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - args.append("--azimuth={}".format(azimuth)) - if max_dist is not None: args.append("--max_dist='{}'".format(max_dist)) - return self.run_tool('directional_relief', args, callback) # returns 1 if error - - def downslope_index(self, dem, output, drop=2.0, out_type="tangent", callback=None): - """Calculates the Hjerdt et al. (2004) downslope index. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - drop -- Vertical drop value (default is 2.0). - out_type -- Output type, options include 'tangent', 'degrees', 'radians', 'distance' (default is 'tangent'). - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - args.append("--drop={}".format(drop)) - args.append("--out_type={}".format(out_type)) - return self.run_tool('downslope_index', args, callback) # returns 1 if error - - def edge_density(self, dem, output, filter=11, norm_diff=5.0, zfactor=1.0, callback=None): - """Calculates the density of edges, or breaks-in-slope within DEMs. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - filter -- Size of the filter kernel. - norm_diff -- Maximum difference in normal vectors, in degrees. - zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - args.append("--filter={}".format(filter)) - args.append("--norm_diff={}".format(norm_diff)) - args.append("--zfactor={}".format(zfactor)) - return self.run_tool('edge_density', args, callback) # returns 1 if error - - def elev_above_pit(self, dem, output, callback=None): - """Calculate the elevation of each grid cell above the nearest downstream pit cell or grid edge cell. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - return self.run_tool('elev_above_pit', args, callback) # returns 1 if error - - def elev_percentile(self, dem, output, filterx=11, filtery=11, sig_digits=2, callback=None): - """Calculates the elevation percentile raster from a DEM. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - filterx -- Size of the filter kernel in the x-direction. - filtery -- Size of the filter kernel in the y-direction. - sig_digits -- Number of significant digits. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - args.append("--filterx={}".format(filterx)) - args.append("--filtery={}".format(filtery)) - args.append("--sig_digits={}".format(sig_digits)) - return self.run_tool('elev_percentile', args, callback) # returns 1 if error - - def elev_relative_to_min_max(self, dem, output, callback=None): - """Calculates the elevation of a location relative to the minimum and maximum elevations in a DEM. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - return self.run_tool('elev_relative_to_min_max', args, callback) # returns 1 if error - - def elev_relative_to_watershed_min_max(self, dem, watersheds, output, callback=None): - """Calculates the elevation of a location relative to the minimum and maximum elevations in a watershed. - - Keyword arguments: - - dem -- Input raster DEM file. - watersheds -- Input raster watersheds file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--watersheds='{}'".format(watersheds)) - args.append("--output='{}'".format(output)) - return self.run_tool('elev_relative_to_watershed_min_max', args, callback) # returns 1 if error - - def feature_preserving_smoothing(self, dem, output, filter=11, norm_diff=15.0, num_iter=3, max_diff=0.5, zfactor=1.0, callback=None): - """Reduces short-scale variation in an input DEM using a modified Sun et al. (2007) algorithm. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - filter -- Size of the filter kernel. - norm_diff -- Maximum difference in normal vectors, in degrees. - num_iter -- Number of iterations. - max_diff -- Maximum allowable absolute elevation change (optional). - zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - args.append("--filter={}".format(filter)) - args.append("--norm_diff={}".format(norm_diff)) - args.append("--num_iter={}".format(num_iter)) - args.append("--max_diff={}".format(max_diff)) - args.append("--zfactor={}".format(zfactor)) - return self.run_tool('feature_preserving_smoothing', args, callback) # returns 1 if error - - def fetch_analysis(self, dem, output, azimuth=0.0, hgt_inc=0.05, callback=None): - """Performs an analysis of fetch or upwind distance to an obstacle. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - azimuth -- Wind azimuth in degrees in degrees. - hgt_inc -- Height increment value. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - args.append("--azimuth={}".format(azimuth)) - args.append("--hgt_inc={}".format(hgt_inc)) - return self.run_tool('fetch_analysis', args, callback) # returns 1 if error - - def fill_missing_data(self, i, output, filter=11, weight=2.0, no_edges=True, callback=None): - """Fills NoData holes in a DEM. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - filter -- Filter size (cells). - weight -- IDW weight value. - no_edges -- Optional flag indicating whether to exclude NoData cells in edge regions. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--filter={}".format(filter)) - args.append("--weight={}".format(weight)) - if no_edges: args.append("--no_edges") - return self.run_tool('fill_missing_data', args, callback) # returns 1 if error - - def find_ridges(self, dem, output, line_thin=True, callback=None): - """Identifies potential ridge and peak grid cells. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - line_thin -- Optional flag indicating whether post-processing line-thinning should be performed. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - if line_thin: args.append("--line_thin") - return self.run_tool('find_ridges', args, callback) # returns 1 if error - - def hillshade(self, dem, output, azimuth=315.0, altitude=30.0, zfactor=1.0, callback=None): - """Calculates a hillshade raster from an input DEM. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - azimuth -- Illumination source azimuth in degrees. - altitude -- Illumination source altitude in degrees. - zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - args.append("--azimuth={}".format(azimuth)) - args.append("--altitude={}".format(altitude)) - args.append("--zfactor={}".format(zfactor)) - return self.run_tool('hillshade', args, callback) # returns 1 if error - - def horizon_angle(self, dem, output, azimuth=0.0, max_dist=None, callback=None): - """Calculates horizon angle (maximum upwind slope) for each grid cell in an input DEM. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - azimuth -- Wind azimuth in degrees. - max_dist -- Optional maximum search distance (unspecified if none; in xy units). - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - args.append("--azimuth={}".format(azimuth)) - if max_dist is not None: args.append("--max_dist='{}'".format(max_dist)) - return self.run_tool('horizon_angle', args, callback) # returns 1 if error - - def hypsometric_analysis(self, inputs, output, watershed=None, callback=None): - """Calculates a hypsometric curve for one or more DEMs. - - Keyword arguments: - - inputs -- Input DEM files. - watershed -- Input watershed files (optional). - output -- Output HTML file (default name will be based on input file if unspecified). - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--inputs='{}'".format(inputs)) - if watershed is not None: args.append("--watershed='{}'".format(watershed)) - args.append("--output='{}'".format(output)) - return self.run_tool('hypsometric_analysis', args, callback) # returns 1 if error - - def max_anisotropy_dev(self, dem, out_mag, out_scale, max_scale, min_scale=3, step=2, callback=None): - """Calculates the maximum anisotropy (directionality) in elevation deviation over a range of spatial scales. - - Keyword arguments: - - dem -- Input raster DEM file. - out_mag -- Output raster DEVmax magnitude file. - out_scale -- Output raster DEVmax scale file. - min_scale -- Minimum search neighbourhood radius in grid cells. - max_scale -- Maximum search neighbourhood radius in grid cells. - step -- Step size as any positive non-zero integer. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--out_mag='{}'".format(out_mag)) - args.append("--out_scale='{}'".format(out_scale)) - args.append("--min_scale={}".format(min_scale)) - args.append("--max_scale='{}'".format(max_scale)) - args.append("--step={}".format(step)) - return self.run_tool('max_anisotropy_dev', args, callback) # returns 1 if error - - def max_anisotropy_dev_signature(self, dem, points, output, max_scale, min_scale=1, step=1, callback=None): - """Calculates the anisotropy in deviation from mean for points over a range of spatial scales. - - Keyword arguments: - - dem -- Input raster DEM file. - points -- Input vector points file. - output -- Output HTML file. - min_scale -- Minimum search neighbourhood radius in grid cells. - max_scale -- Maximum search neighbourhood radius in grid cells. - step -- Step size as any positive non-zero integer. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--points='{}'".format(points)) - args.append("--output='{}'".format(output)) - args.append("--min_scale={}".format(min_scale)) - args.append("--max_scale='{}'".format(max_scale)) - args.append("--step={}".format(step)) - return self.run_tool('max_anisotropy_dev_signature', args, callback) # returns 1 if error - - def max_branch_length(self, dem, output, log=False, callback=None): - """Lindsay and Seibert's (2013) branch length index is used to map drainage divides or ridge lines. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - log -- Optional flag to request the output be log-transformed. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - if log: args.append("--log") - return self.run_tool('max_branch_length', args, callback) # returns 1 if error - - def max_difference_from_mean(self, dem, out_mag, out_scale, min_scale, max_scale, step=1, callback=None): - """Calculates the maximum difference from mean elevation over a range of spatial scales. - - Keyword arguments: - - dem -- Input raster DEM file. - out_mag -- Output raster DIFFmax magnitude file. - out_scale -- Output raster DIFFmax scale file. - min_scale -- Minimum search neighbourhood radius in grid cells. - max_scale -- Maximum search neighbourhood radius in grid cells. - step -- Step size as any positive non-zero integer. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--out_mag='{}'".format(out_mag)) - args.append("--out_scale='{}'".format(out_scale)) - args.append("--min_scale='{}'".format(min_scale)) - args.append("--max_scale='{}'".format(max_scale)) - args.append("--step={}".format(step)) - return self.run_tool('max_difference_from_mean', args, callback) # returns 1 if error - - def max_downslope_elev_change(self, dem, output, callback=None): - """Calculates the maximum downslope change in elevation between a grid cell and its eight downslope neighbors. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - return self.run_tool('max_downslope_elev_change', args, callback) # returns 1 if error - - def max_elev_dev_signature(self, dem, points, output, min_scale, max_scale, step=10, callback=None): - """Calculates the maximum elevation deviation over a range of spatial scales and for a set of points. - - Keyword arguments: - - dem -- Input raster DEM file. - points -- Input vector points file. - output -- Output HTML file. - min_scale -- Minimum search neighbourhood radius in grid cells. - max_scale -- Maximum search neighbourhood radius in grid cells. - step -- Step size as any positive non-zero integer. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--points='{}'".format(points)) - args.append("--output='{}'".format(output)) - args.append("--min_scale='{}'".format(min_scale)) - args.append("--max_scale='{}'".format(max_scale)) - args.append("--step={}".format(step)) - return self.run_tool('max_elev_dev_signature', args, callback) # returns 1 if error - - def max_elevation_deviation(self, dem, out_mag, out_scale, min_scale, max_scale, step=1, callback=None): - """Calculates the maximum elevation deviation over a range of spatial scales. - - Keyword arguments: - - dem -- Input raster DEM file. - out_mag -- Output raster DEVmax magnitude file. - out_scale -- Output raster DEVmax scale file. - min_scale -- Minimum search neighbourhood radius in grid cells. - max_scale -- Maximum search neighbourhood radius in grid cells. - step -- Step size as any positive non-zero integer. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--out_mag='{}'".format(out_mag)) - args.append("--out_scale='{}'".format(out_scale)) - args.append("--min_scale='{}'".format(min_scale)) - args.append("--max_scale='{}'".format(max_scale)) - args.append("--step={}".format(step)) - return self.run_tool('max_elevation_deviation', args, callback) # returns 1 if error - - def min_downslope_elev_change(self, dem, output, callback=None): - """Calculates the minimum downslope change in elevation between a grid cell and its eight downslope neighbors. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - return self.run_tool('min_downslope_elev_change', args, callback) # returns 1 if error - - def multiscale_elevation_percentile(self, dem, out_mag, out_scale, sig_digits=3, min_scale=4, step=1, num_steps=10, step_nonlinearity=1.0, callback=None): - """Calculates surface roughness over a range of spatial scales. - - Keyword arguments: - - dem -- Input raster DEM file. - out_mag -- Output raster roughness magnitude file. - out_scale -- Output raster roughness scale file. - sig_digits -- Number of significant digits. - min_scale -- Minimum search neighbourhood radius in grid cells. - step -- Step size as any positive non-zero integer. - num_steps -- Number of steps. - step_nonlinearity -- Step nonlinearity factor (1.0-2.0 is typical). - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--out_mag='{}'".format(out_mag)) - args.append("--out_scale='{}'".format(out_scale)) - args.append("--sig_digits={}".format(sig_digits)) - args.append("--min_scale={}".format(min_scale)) - args.append("--step={}".format(step)) - args.append("--num_steps={}".format(num_steps)) - args.append("--step_nonlinearity={}".format(step_nonlinearity)) - return self.run_tool('multiscale_elevation_percentile', args, callback) # returns 1 if error - - def multiscale_roughness(self, dem, out_mag, out_scale, max_scale, min_scale=1, step=1, callback=None): - """Calculates surface roughness over a range of spatial scales. - - Keyword arguments: - - dem -- Input raster DEM file. - out_mag -- Output raster roughness magnitude file. - out_scale -- Output raster roughness scale file. - min_scale -- Minimum search neighbourhood radius in grid cells. - max_scale -- Maximum search neighbourhood radius in grid cells. - step -- Step size as any positive non-zero integer. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--out_mag='{}'".format(out_mag)) - args.append("--out_scale='{}'".format(out_scale)) - args.append("--min_scale={}".format(min_scale)) - args.append("--max_scale='{}'".format(max_scale)) - args.append("--step={}".format(step)) - return self.run_tool('multiscale_roughness', args, callback) # returns 1 if error - - def multiscale_roughness_signature(self, dem, points, output, max_scale, min_scale=1, step=1, callback=None): - """Calculates the surface roughness for points over a range of spatial scales. - - Keyword arguments: - - dem -- Input raster DEM file. - points -- Input vector points file. - output -- Output HTML file. - min_scale -- Minimum search neighbourhood radius in grid cells. - max_scale -- Maximum search neighbourhood radius in grid cells. - step -- Step size as any positive non-zero integer. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--points='{}'".format(points)) - args.append("--output='{}'".format(output)) - args.append("--min_scale={}".format(min_scale)) - args.append("--max_scale='{}'".format(max_scale)) - args.append("--step={}".format(step)) - return self.run_tool('multiscale_roughness_signature', args, callback) # returns 1 if error - - def multiscale_std_dev_normals(self, dem, out_mag, out_scale, min_scale=1, step=1, num_steps=10, step_nonlinearity=1.0, callback=None): - """Calculates surface roughness over a range of spatial scales. - - Keyword arguments: - - dem -- Input raster DEM file. - out_mag -- Output raster roughness magnitude file. - out_scale -- Output raster roughness scale file. - min_scale -- Minimum search neighbourhood radius in grid cells. - step -- Step size as any positive non-zero integer. - num_steps -- Number of steps. - step_nonlinearity -- Step nonlinearity factor (1.0-2.0 is typical). - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--out_mag='{}'".format(out_mag)) - args.append("--out_scale='{}'".format(out_scale)) - args.append("--min_scale={}".format(min_scale)) - args.append("--step={}".format(step)) - args.append("--num_steps={}".format(num_steps)) - args.append("--step_nonlinearity={}".format(step_nonlinearity)) - return self.run_tool('multiscale_std_dev_normals', args, callback) # returns 1 if error - - def multiscale_std_dev_normals_signature(self, dem, points, output, min_scale=1, step=1, num_steps=10, step_nonlinearity=1.0, callback=None): - """Calculates the surface roughness for points over a range of spatial scales. - - Keyword arguments: - - dem -- Input raster DEM file. - points -- Input vector points file. - output -- Output HTML file. - min_scale -- Minimum search neighbourhood radius in grid cells. - step -- Step size as any positive non-zero integer. - num_steps -- Number of steps. - step_nonlinearity -- Step nonlinearity factor (1.0-2.0 is typical). - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--points='{}'".format(points)) - args.append("--output='{}'".format(output)) - args.append("--min_scale={}".format(min_scale)) - args.append("--step={}".format(step)) - args.append("--num_steps={}".format(num_steps)) - args.append("--step_nonlinearity={}".format(step_nonlinearity)) - return self.run_tool('multiscale_std_dev_normals_signature', args, callback) # returns 1 if error - - def multiscale_topographic_position_image(self, local, meso, broad, output, lightness=1.2, callback=None): - """Creates a multiscale topographic position image from three DEVmax rasters of differing spatial scale ranges. - - Keyword arguments: - - local -- Input local-scale topographic position (DEVmax) raster file. - meso -- Input meso-scale topographic position (DEVmax) raster file. - broad -- Input broad-scale topographic position (DEVmax) raster file. - output -- Output raster file. - lightness -- Image lightness value (default is 1.2). - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--local='{}'".format(local)) - args.append("--meso='{}'".format(meso)) - args.append("--broad='{}'".format(broad)) - args.append("--output='{}'".format(output)) - args.append("--lightness={}".format(lightness)) - return self.run_tool('multiscale_topographic_position_image', args, callback) # returns 1 if error - - def num_downslope_neighbours(self, dem, output, callback=None): - """Calculates the number of downslope neighbours to each grid cell in a DEM. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - return self.run_tool('num_downslope_neighbours', args, callback) # returns 1 if error - - def num_upslope_neighbours(self, dem, output, callback=None): - """Calculates the number of upslope neighbours to each grid cell in a DEM. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - return self.run_tool('num_upslope_neighbours', args, callback) # returns 1 if error - - def pennock_landform_class(self, dem, output, slope=3.0, prof=0.1, plan=0.0, zfactor=1.0, callback=None): - """Classifies hillslope zones based on slope, profile curvature, and plan curvature. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - slope -- Slope threshold value, in degrees (default is 3.0). - prof -- Profile curvature threshold value (default is 0.1). - plan -- Plan curvature threshold value (default is 0.0). - zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - args.append("--slope={}".format(slope)) - args.append("--prof={}".format(prof)) - args.append("--plan={}".format(plan)) - args.append("--zfactor={}".format(zfactor)) - return self.run_tool('pennock_landform_class', args, callback) # returns 1 if error - - def percent_elev_range(self, dem, output, filterx=3, filtery=3, callback=None): - """Calculates percent of elevation range from a DEM. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - filterx -- Size of the filter kernel in the x-direction. - filtery -- Size of the filter kernel in the y-direction. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - args.append("--filterx={}".format(filterx)) - args.append("--filtery={}".format(filtery)) - return self.run_tool('percent_elev_range', args, callback) # returns 1 if error - - def plan_curvature(self, dem, output, zfactor=1.0, callback=None): - """Calculates a plan (contour) curvature raster from an input DEM. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - args.append("--zfactor={}".format(zfactor)) - return self.run_tool('plan_curvature', args, callback) # returns 1 if error - - def profile(self, lines, surface, output, callback=None): - """Plots profiles from digital surface models. - - Keyword arguments: - - lines -- Input vector line file. - surface -- Input raster surface file. - output -- Output HTML file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--lines='{}'".format(lines)) - args.append("--surface='{}'".format(surface)) - args.append("--output='{}'".format(output)) - return self.run_tool('profile', args, callback) # returns 1 if error - - def profile_curvature(self, dem, output, zfactor=1.0, callback=None): - """Calculates a profile curvature raster from an input DEM. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - args.append("--zfactor={}".format(zfactor)) - return self.run_tool('profile_curvature', args, callback) # returns 1 if error - - def relative_aspect(self, dem, output, azimuth=0.0, zfactor=1.0, callback=None): - """Calculates relative aspect (relative to a user-specified direction) from an input DEM. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - azimuth -- Illumination source azimuth. - zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - args.append("--azimuth={}".format(azimuth)) - args.append("--zfactor={}".format(zfactor)) - return self.run_tool('relative_aspect', args, callback) # returns 1 if error - - def relative_topographic_position(self, dem, output, filterx=11, filtery=11, callback=None): - """Calculates the relative topographic position index from a DEM. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - filterx -- Size of the filter kernel in the x-direction. - filtery -- Size of the filter kernel in the y-direction. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - args.append("--filterx={}".format(filterx)) - args.append("--filtery={}".format(filtery)) - return self.run_tool('relative_topographic_position', args, callback) # returns 1 if error - - def remove_off_terrain_objects(self, dem, output, filter=11, slope=15.0, callback=None): - """Removes off-terrain objects from a raster digital elevation model (DEM). - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - filter -- Filter size (cells). - slope -- Slope threshold value. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - args.append("--filter={}".format(filter)) - args.append("--slope={}".format(slope)) - return self.run_tool('remove_off_terrain_objects', args, callback) # returns 1 if error - - def ruggedness_index(self, dem, output, zfactor=1.0, callback=None): - """Calculates the Riley et al.'s (1999) terrain ruggedness index from an input DEM. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - args.append("--zfactor={}".format(zfactor)) - return self.run_tool('ruggedness_index', args, callback) # returns 1 if error - - def sediment_transport_index(self, sca, slope, output, sca_exponent=0.4, slope_exponent=1.3, callback=None): - """Calculates the sediment transport index. - - Keyword arguments: - - sca -- Input raster specific contributing area (SCA) file. - slope -- Input raster slope file. - output -- Output raster file. - sca_exponent -- SCA exponent value. - slope_exponent -- Slope exponent value. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--sca='{}'".format(sca)) - args.append("--slope='{}'".format(slope)) - args.append("--output='{}'".format(output)) - args.append("--sca_exponent={}".format(sca_exponent)) - args.append("--slope_exponent={}".format(slope_exponent)) - return self.run_tool('sediment_transport_index', args, callback) # returns 1 if error - - def slope(self, dem, output, zfactor=1.0, units="degrees", callback=None): - """Calculates a slope raster from an input DEM. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. - units -- Units of output raster; options include 'degrees', 'radians', 'percent'. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - args.append("--zfactor={}".format(zfactor)) - args.append("--units={}".format(units)) - return self.run_tool('slope', args, callback) # returns 1 if error - - def slope_vs_elevation_plot(self, inputs, output, watershed=None, callback=None): - """Creates a slope vs. elevation plot for one or more DEMs. - - Keyword arguments: - - inputs -- Input DEM files. - watershed -- Input watershed files (optional). - output -- Output HTML file (default name will be based on input file if unspecified). - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--inputs='{}'".format(inputs)) - if watershed is not None: args.append("--watershed='{}'".format(watershed)) - args.append("--output='{}'".format(output)) - return self.run_tool('slope_vs_elevation_plot', args, callback) # returns 1 if error - - def spherical_std_dev_of_normals(self, dem, output, filter=11, callback=None): - """Calculates the spherical standard deviation of surface normals for a DEM. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - filter -- Size of the filter kernel. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - args.append("--filter={}".format(filter)) - return self.run_tool('spherical_std_dev_of_normals', args, callback) # returns 1 if error - - def standard_deviation_of_slope(self, i, output, zfactor=1.0, filterx=11, filtery=11, callback=None): - """Calculates the standard deviation of slope from an input DEM. - - Keyword arguments: - - i -- Input raster DEM file. - output -- Output raster DEM file. - zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. - filterx -- Size of the filter kernel in the x-direction. - filtery -- Size of the filter kernel in the y-direction. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--zfactor={}".format(zfactor)) - args.append("--filterx={}".format(filterx)) - args.append("--filtery={}".format(filtery)) - return self.run_tool('standard_deviation_of_slope', args, callback) # returns 1 if error - - def stream_power_index(self, sca, slope, output, exponent=1.0, callback=None): - """Calculates the relative stream power index. - - Keyword arguments: - - sca -- Input raster specific contributing area (SCA) file. - slope -- Input raster slope file. - output -- Output raster file. - exponent -- SCA exponent value. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--sca='{}'".format(sca)) - args.append("--slope='{}'".format(slope)) - args.append("--output='{}'".format(output)) - args.append("--exponent={}".format(exponent)) - return self.run_tool('stream_power_index', args, callback) # returns 1 if error - - def surface_area_ratio(self, dem, output, callback=None): - """Calculates a the surface area ratio of each grid cell in an input DEM. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - return self.run_tool('surface_area_ratio', args, callback) # returns 1 if error - - def tangential_curvature(self, dem, output, zfactor=1.0, callback=None): - """Calculates a tangential curvature raster from an input DEM. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - args.append("--zfactor={}".format(zfactor)) - return self.run_tool('tangential_curvature', args, callback) # returns 1 if error - - def total_curvature(self, dem, output, zfactor=1.0, callback=None): - """Calculates a total curvature raster from an input DEM. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - args.append("--zfactor={}".format(zfactor)) - return self.run_tool('total_curvature', args, callback) # returns 1 if error - - def viewshed(self, dem, stations, output, height=2.0, callback=None): - """Identifies the viewshed for a point or set of points. - - Keyword arguments: - - dem -- Input raster DEM file. - stations -- Input viewing station vector file. - output -- Output raster file. - height -- Viewing station height, in z units. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--stations='{}'".format(stations)) - args.append("--output='{}'".format(output)) - args.append("--height={}".format(height)) - return self.run_tool('viewshed', args, callback) # returns 1 if error - - def visibility_index(self, dem, output, height=2.0, res_factor=2, callback=None): - """Estimates the relative visibility of sites in a DEM. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - height -- Viewing station height, in z units. - res_factor -- The resolution factor determines the density of measured viewsheds. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - args.append("--height={}".format(height)) - args.append("--res_factor={}".format(res_factor)) - return self.run_tool('visibility_index', args, callback) # returns 1 if error - - def wetness_index(self, sca, slope, output, callback=None): - """Calculates the topographic wetness index, Ln(A / tan(slope)). - - Keyword arguments: - - sca -- Input raster specific contributing area (SCA) file. - slope -- Input raster slope file (in degrees). - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--sca='{}'".format(sca)) - args.append("--slope='{}'".format(slope)) - args.append("--output='{}'".format(output)) - return self.run_tool('wetness_index', args, callback) # returns 1 if error - - ######################### - # Hydrological Analysis # - ######################### - - def average_flowpath_slope(self, dem, output, callback=None): - """Measures the average slope gradient from each grid cell to all upslope divide cells. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - return self.run_tool('average_flowpath_slope', args, callback) # returns 1 if error - - def average_upslope_flowpath_length(self, dem, output, callback=None): - """Measures the average length of all upslope flowpaths draining each grid cell. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - return self.run_tool('average_upslope_flowpath_length', args, callback) # returns 1 if error - - def basins(self, d8_pntr, output, esri_pntr=False, callback=None): - """Identifies drainage basins that drain to the DEM edge. - - Keyword arguments: - - d8_pntr -- Input raster D8 pointer file. - output -- Output raster file. - esri_pntr -- D8 pointer uses the ESRI style scheme. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--d8_pntr='{}'".format(d8_pntr)) - args.append("--output='{}'".format(output)) - if esri_pntr: args.append("--esri_pntr") - return self.run_tool('basins', args, callback) # returns 1 if error - - def breach_depressions(self, dem, output, max_depth=None, max_length=None, flat_increment=None, fill_pits=False, callback=None): - """Breaches all of the depressions in a DEM using Lindsay's (2016) algorithm. This should be preferred over depression filling in most cases. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - max_depth -- Optional maximum breach depth (default is Inf). - max_length -- Optional maximum breach channel length (in grid cells; default is Inf). - flat_increment -- Optional elevation increment applied to flat areas. - fill_pits -- Optional flag indicating whether to fill single-cell pits. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - if max_depth is not None: args.append("--max_depth='{}'".format(max_depth)) - if max_length is not None: args.append("--max_length='{}'".format(max_length)) - if flat_increment is not None: args.append("--flat_increment='{}'".format(flat_increment)) - if fill_pits: args.append("--fill_pits") - return self.run_tool('breach_depressions', args, callback) # returns 1 if error - - def breach_depressions_least_cost(self, dem, output, dist, max_cost=None, min_dist=True, flat_increment=None, fill=True, callback=None): - """Breaches the depressions in a DEM using a least-cost pathway method. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - dist -- Maximum search distance for breach paths in cells. - max_cost -- Optional maximum breach cost (default is Inf). - min_dist -- Optional flag indicating whether to minimize breach distances. - flat_increment -- Optional elevation increment applied to flat areas. - fill -- Optional flag indicating whether to fill any remaining unbreached depressions. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - args.append("--dist='{}'".format(dist)) - if max_cost is not None: args.append("--max_cost='{}'".format(max_cost)) - if min_dist: args.append("--min_dist") - if flat_increment is not None: args.append("--flat_increment='{}'".format(flat_increment)) - if fill: args.append("--fill") - return self.run_tool('breach_depressions_least_cost', args, callback) # returns 1 if error - - def breach_single_cell_pits(self, dem, output, callback=None): - """Removes single-cell pits from an input DEM by breaching. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - return self.run_tool('breach_single_cell_pits', args, callback) # returns 1 if error - - def burn_streams_at_roads(self, dem, streams, roads, output, width=None, callback=None): - """Burns-in streams at the sites of road embankments. - - Keyword arguments: - - dem -- Input raster digital elevation model (DEM) file. - streams -- Input vector streams file. - roads -- Input vector roads file. - output -- Output raster file. - width -- Maximum road embankment width, in map units. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--streams='{}'".format(streams)) - args.append("--roads='{}'".format(roads)) - args.append("--output='{}'".format(output)) - if width is not None: args.append("--width='{}'".format(width)) - return self.run_tool('burn_streams_at_roads', args, callback) # returns 1 if error - - def d8_flow_accumulation(self, i, output, out_type="cells", log=False, clip=False, pntr=False, esri_pntr=False, callback=None): - """Calculates a D8 flow accumulation raster from an input DEM or flow pointer. - - Keyword arguments: - - i -- Input raster DEM or D8 pointer file. - output -- Output raster file. - out_type -- Output type; one of 'cells' (default), 'catchment area', and 'specific contributing area'. - log -- Optional flag to request the output be log-transformed. - clip -- Optional flag to request clipping the display max by 1%. - pntr -- Is the input raster a D8 flow pointer rather than a DEM?. - esri_pntr -- Input D8 pointer uses the ESRI style scheme. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--out_type={}".format(out_type)) - if log: args.append("--log") - if clip: args.append("--clip") - if pntr: args.append("--pntr") - if esri_pntr: args.append("--esri_pntr") - return self.run_tool('d8_flow_accumulation', args, callback) # returns 1 if error - - def d8_mass_flux(self, dem, loading, efficiency, absorption, output, callback=None): - """Performs a D8 mass flux calculation. - - Keyword arguments: - - dem -- Input raster DEM file. - loading -- Input loading raster file. - efficiency -- Input efficiency raster file. - absorption -- Input absorption raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--loading='{}'".format(loading)) - args.append("--efficiency='{}'".format(efficiency)) - args.append("--absorption='{}'".format(absorption)) - args.append("--output='{}'".format(output)) - return self.run_tool('d8_mass_flux', args, callback) # returns 1 if error - - def d8_pointer(self, dem, output, esri_pntr=False, callback=None): - """Calculates a D8 flow pointer raster from an input DEM. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - esri_pntr -- D8 pointer uses the ESRI style scheme. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - if esri_pntr: args.append("--esri_pntr") - return self.run_tool('d8_pointer', args, callback) # returns 1 if error - - def d_inf_flow_accumulation(self, i, output, out_type="Specific Contributing Area", threshold=None, log=False, clip=False, pntr=False, callback=None): - """Calculates a D-infinity flow accumulation raster from an input DEM. - - Keyword arguments: - - i -- Input raster DEM or D-infinity pointer file. - output -- Output raster file. - out_type -- Output type; one of 'cells', 'sca' (default), and 'ca'. - threshold -- Optional convergence threshold parameter, in grid cells; default is inifinity. - log -- Optional flag to request the output be log-transformed. - clip -- Optional flag to request clipping the display max by 1%. - pntr -- Is the input raster a D-infinity flow pointer rather than a DEM?. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--out_type={}".format(out_type)) - if threshold is not None: args.append("--threshold='{}'".format(threshold)) - if log: args.append("--log") - if clip: args.append("--clip") - if pntr: args.append("--pntr") - return self.run_tool('d_inf_flow_accumulation', args, callback) # returns 1 if error - - def d_inf_mass_flux(self, dem, loading, efficiency, absorption, output, callback=None): - """Performs a D-infinity mass flux calculation. - - Keyword arguments: - - dem -- Input raster DEM file. - loading -- Input loading raster file. - efficiency -- Input efficiency raster file. - absorption -- Input absorption raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--loading='{}'".format(loading)) - args.append("--efficiency='{}'".format(efficiency)) - args.append("--absorption='{}'".format(absorption)) - args.append("--output='{}'".format(output)) - return self.run_tool('d_inf_mass_flux', args, callback) # returns 1 if error - - def d_inf_pointer(self, dem, output, callback=None): - """Calculates a D-infinity flow pointer (flow direction) raster from an input DEM. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - return self.run_tool('d_inf_pointer', args, callback) # returns 1 if error - - def depth_in_sink(self, dem, output, zero_background=False, callback=None): - """Measures the depth of sinks (depressions) in a DEM. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - zero_background -- Flag indicating whether the background value of zero should be used. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - if zero_background: args.append("--zero_background") - return self.run_tool('depth_in_sink', args, callback) # returns 1 if error - - def downslope_distance_to_stream(self, dem, streams, output, callback=None): - """Measures distance to the nearest downslope stream cell. - - Keyword arguments: - - dem -- Input raster DEM file. - streams -- Input raster streams file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--streams='{}'".format(streams)) - args.append("--output='{}'".format(output)) - return self.run_tool('downslope_distance_to_stream', args, callback) # returns 1 if error - - def downslope_flowpath_length(self, d8_pntr, output, watersheds=None, weights=None, esri_pntr=False, callback=None): - """Calculates the downslope flowpath length from each cell to basin outlet. - - Keyword arguments: - - d8_pntr -- Input D8 pointer raster file. - watersheds -- Optional input watershed raster file. - weights -- Optional input weights raster file. - output -- Output raster file. - esri_pntr -- D8 pointer uses the ESRI style scheme. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--d8_pntr='{}'".format(d8_pntr)) - if watersheds is not None: args.append("--watersheds='{}'".format(watersheds)) - if weights is not None: args.append("--weights='{}'".format(weights)) - args.append("--output='{}'".format(output)) - if esri_pntr: args.append("--esri_pntr") - return self.run_tool('downslope_flowpath_length', args, callback) # returns 1 if error - - def elevation_above_stream(self, dem, streams, output, callback=None): - """Calculates the elevation of cells above the nearest downslope stream cell. - - Keyword arguments: - - dem -- Input raster DEM file. - streams -- Input raster streams file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--streams='{}'".format(streams)) - args.append("--output='{}'".format(output)) - return self.run_tool('elevation_above_stream', args, callback) # returns 1 if error - - def elevation_above_stream_euclidean(self, dem, streams, output, callback=None): - """Calculates the elevation of cells above the nearest (Euclidean distance) stream cell. - - Keyword arguments: - - dem -- Input raster DEM file. - streams -- Input raster streams file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--streams='{}'".format(streams)) - args.append("--output='{}'".format(output)) - return self.run_tool('elevation_above_stream_euclidean', args, callback) # returns 1 if error - - def fd8_flow_accumulation(self, dem, output, out_type="specific contributing area", exponent=1.1, threshold=None, log=False, clip=False, callback=None): - """Calculates an FD8 flow accumulation raster from an input DEM. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - out_type -- Output type; one of 'cells', 'specific contributing area' (default), and 'catchment area'. - exponent -- Optional exponent parameter; default is 1.1. - threshold -- Optional convergence threshold parameter, in grid cells; default is inifinity. - log -- Optional flag to request the output be log-transformed. - clip -- Optional flag to request clipping the display max by 1%. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - args.append("--out_type={}".format(out_type)) - args.append("--exponent={}".format(exponent)) - if threshold is not None: args.append("--threshold='{}'".format(threshold)) - if log: args.append("--log") - if clip: args.append("--clip") - return self.run_tool('fd8_flow_accumulation', args, callback) # returns 1 if error - - def fd8_pointer(self, dem, output, callback=None): - """Calculates an FD8 flow pointer raster from an input DEM. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - return self.run_tool('fd8_pointer', args, callback) # returns 1 if error - - def fill_burn(self, dem, streams, output, callback=None): - """Burns streams into a DEM using the FillBurn (Saunders, 1999) method. - - Keyword arguments: - - dem -- Input raster DEM file. - streams -- Input vector streams file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--streams='{}'".format(streams)) - args.append("--output='{}'".format(output)) - return self.run_tool('fill_burn', args, callback) # returns 1 if error - - def fill_depressions(self, dem, output, fix_flats=True, flat_increment=None, max_depth=None, callback=None): - """Fills all of the depressions in a DEM. Depression breaching should be preferred in most cases. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - fix_flats -- Optional flag indicating whether flat areas should have a small gradient applied. - flat_increment -- Optional elevation increment applied to flat areas. - max_depth -- Optional maximum depression depth to fill. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - if fix_flats: args.append("--fix_flats") - if flat_increment is not None: args.append("--flat_increment='{}'".format(flat_increment)) - if max_depth is not None: args.append("--max_depth='{}'".format(max_depth)) - return self.run_tool('fill_depressions', args, callback) # returns 1 if error - - def fill_depressions_planchon_and_darboux(self, dem, output, fix_flats=True, flat_increment=None, callback=None): - """Fills all of the depressions in a DEM using the Planchon and Darboux (2002) method. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - fix_flats -- Optional flag indicating whether flat areas should have a small gradient applied. - flat_increment -- Optional elevation increment applied to flat areas. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - if fix_flats: args.append("--fix_flats") - if flat_increment is not None: args.append("--flat_increment='{}'".format(flat_increment)) - return self.run_tool('fill_depressions_planchon_and_darboux', args, callback) # returns 1 if error - - def fill_depressions_wang_and_liu(self, dem, output, fix_flats=True, flat_increment=None, callback=None): - """Fills all of the depressions in a DEM using the Wang and Liu (2006) method. Depression breaching should be preferred in most cases. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - fix_flats -- Optional flag indicating whether flat areas should have a small gradient applied. - flat_increment -- Optional elevation increment applied to flat areas. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - if fix_flats: args.append("--fix_flats") - if flat_increment is not None: args.append("--flat_increment='{}'".format(flat_increment)) - return self.run_tool('fill_depressions_wang_and_liu', args, callback) # returns 1 if error - - def fill_single_cell_pits(self, dem, output, callback=None): - """Raises pit cells to the elevation of their lowest neighbour. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - return self.run_tool('fill_single_cell_pits', args, callback) # returns 1 if error - - def find_no_flow_cells(self, dem, output, callback=None): - """Finds grid cells with no downslope neighbours. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - return self.run_tool('find_no_flow_cells', args, callback) # returns 1 if error - - def find_parallel_flow(self, d8_pntr, streams, output, callback=None): - """Finds areas of parallel flow in D8 flow direction rasters. - - Keyword arguments: - - d8_pntr -- Input D8 pointer raster file. - streams -- Input raster streams file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--d8_pntr='{}'".format(d8_pntr)) - args.append("--streams='{}'".format(streams)) - args.append("--output='{}'".format(output)) - return self.run_tool('find_parallel_flow', args, callback) # returns 1 if error - - def flatten_lakes(self, dem, lakes, output, callback=None): - """Flattens lake polygons in a raster DEM. - - Keyword arguments: - - dem -- Input raster DEM file. - lakes -- Input lakes vector polygons file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--lakes='{}'".format(lakes)) - args.append("--output='{}'".format(output)) - return self.run_tool('flatten_lakes', args, callback) # returns 1 if error - - def flood_order(self, dem, output, callback=None): - """Assigns each DEM grid cell its order in the sequence of inundations that are encountered during a search starting from the edges, moving inward at increasing elevations. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - return self.run_tool('flood_order', args, callback) # returns 1 if error - - def flow_accumulation_full_workflow(self, dem, out_dem, out_pntr, out_accum, out_type="Specific Contributing Area", log=False, clip=False, esri_pntr=False, callback=None): - """Resolves all of the depressions in a DEM, outputting a breached DEM, an aspect-aligned non-divergent flow pointer, and a flow accumulation raster. - - Keyword arguments: - - dem -- Input raster DEM file. - out_dem -- Output raster DEM file. - out_pntr -- Output raster flow pointer file. - out_accum -- Output raster flow accumulation file. - out_type -- Output type; one of 'cells', 'sca' (default), and 'ca'. - log -- Optional flag to request the output be log-transformed. - clip -- Optional flag to request clipping the display max by 1%. - esri_pntr -- D8 pointer uses the ESRI style scheme. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--out_dem='{}'".format(out_dem)) - args.append("--out_pntr='{}'".format(out_pntr)) - args.append("--out_accum='{}'".format(out_accum)) - args.append("--out_type={}".format(out_type)) - if log: args.append("--log") - if clip: args.append("--clip") - if esri_pntr: args.append("--esri_pntr") - return self.run_tool('flow_accumulation_full_workflow', args, callback) # returns 1 if error - - def flow_length_diff(self, d8_pntr, output, esri_pntr=False, callback=None): - """Calculates the local maximum absolute difference in downslope flowpath length, useful in mapping drainage divides and ridges. - - Keyword arguments: - - d8_pntr -- Input D8 pointer raster file. - output -- Output raster file. - esri_pntr -- D8 pointer uses the ESRI style scheme. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--d8_pntr='{}'".format(d8_pntr)) - args.append("--output='{}'".format(output)) - if esri_pntr: args.append("--esri_pntr") - return self.run_tool('flow_length_diff', args, callback) # returns 1 if error - - def hillslopes(self, d8_pntr, streams, output, esri_pntr=False, callback=None): - """Identifies the individual hillslopes draining to each link in a stream network. - - Keyword arguments: - - d8_pntr -- Input raster D8 pointer file. - streams -- Input raster streams file. - output -- Output raster file. - esri_pntr -- D8 pointer uses the ESRI style scheme. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--d8_pntr='{}'".format(d8_pntr)) - args.append("--streams='{}'".format(streams)) - args.append("--output='{}'".format(output)) - if esri_pntr: args.append("--esri_pntr") - return self.run_tool('hillslopes', args, callback) # returns 1 if error - - def impoundment_size_index(self, dem, output, damlength, out_type="mean depth", callback=None): - """Calculates the impoundment size resulting from damming a DEM. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output file. - out_type -- Output type; one of 'mean depth' (default), 'volume', 'area', 'max depth'. - damlength -- Maximum length of the dam. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - args.append("--out_type={}".format(out_type)) - args.append("--damlength='{}'".format(damlength)) - return self.run_tool('impoundment_size_index', args, callback) # returns 1 if error - - def insert_dams(self, dem, dam_pts, output, damlength, callback=None): - """Calculates the impoundment size resulting from damming a DEM. - - Keyword arguments: - - dem -- Input raster DEM file. - dam_pts -- Input vector dam points file. - output -- Output file. - damlength -- Maximum length of the dam. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--dam_pts='{}'".format(dam_pts)) - args.append("--output='{}'".format(output)) - args.append("--damlength='{}'".format(damlength)) - return self.run_tool('insert_dams', args, callback) # returns 1 if error - - def isobasins(self, dem, output, size, callback=None): - """Divides a landscape into nearly equal sized drainage basins (i.e. watersheds). - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - size -- Target basin size, in grid cells. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - args.append("--size='{}'".format(size)) - return self.run_tool('isobasins', args, callback) # returns 1 if error - - def jenson_snap_pour_points(self, pour_pts, streams, output, snap_dist, callback=None): - """Moves outlet points used to specify points of interest in a watershedding operation to the nearest stream cell. - - Keyword arguments: - - pour_pts -- Input vector pour points (outlet) file. - streams -- Input raster streams file. - output -- Output vector file. - snap_dist -- Maximum snap distance in map units. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--pour_pts='{}'".format(pour_pts)) - args.append("--streams='{}'".format(streams)) - args.append("--output='{}'".format(output)) - args.append("--snap_dist='{}'".format(snap_dist)) - return self.run_tool('jenson_snap_pour_points', args, callback) # returns 1 if error - - def longest_flowpath(self, dem, basins, output, callback=None): - """Delineates the longest flowpaths for a group of subbasins or watersheds. - - Keyword arguments: - - dem -- Input raster DEM file. - basins -- Input raster basins file. - output -- Output vector file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--basins='{}'".format(basins)) - args.append("--output='{}'".format(output)) - return self.run_tool('longest_flowpath', args, callback) # returns 1 if error - - def max_upslope_flowpath_length(self, dem, output, callback=None): - """Measures the maximum length of all upslope flowpaths draining each grid cell. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - return self.run_tool('max_upslope_flowpath_length', args, callback) # returns 1 if error - - def md_inf_flow_accumulation(self, dem, output, out_type="specific contributing area", exponent=1.1, threshold=None, log=False, clip=False, callback=None): - """Calculates an FD8 flow accumulation raster from an input DEM. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - out_type -- Output type; one of 'cells', 'specific contributing area' (default), and 'catchment area'. - exponent -- Optional exponent parameter; default is 1.1. - threshold -- Optional convergence threshold parameter, in grid cells; default is inifinity. - log -- Optional flag to request the output be log-transformed. - clip -- Optional flag to request clipping the display max by 1%. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - args.append("--out_type={}".format(out_type)) - args.append("--exponent={}".format(exponent)) - if threshold is not None: args.append("--threshold='{}'".format(threshold)) - if log: args.append("--log") - if clip: args.append("--clip") - return self.run_tool('md_inf_flow_accumulation', args, callback) # returns 1 if error - - def num_inflowing_neighbours(self, dem, output, callback=None): - """Computes the number of inflowing neighbours to each cell in an input DEM based on the D8 algorithm. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - return self.run_tool('num_inflowing_neighbours', args, callback) # returns 1 if error - - def raise_walls(self, i, dem, output, breach=None, height=100.0, callback=None): - """Raises walls in a DEM along a line or around a polygon, e.g. a watershed. - - Keyword arguments: - - i -- Input vector lines or polygons file. - breach -- Optional input vector breach lines. - dem -- Input raster DEM file. - output -- Output raster file. - height -- Wall height. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - if breach is not None: args.append("--breach='{}'".format(breach)) - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - args.append("--height={}".format(height)) - return self.run_tool('raise_walls', args, callback) # returns 1 if error - - def rho8_pointer(self, dem, output, esri_pntr=False, callback=None): - """Calculates a stochastic Rho8 flow pointer raster from an input DEM. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - esri_pntr -- D8 pointer uses the ESRI style scheme. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - if esri_pntr: args.append("--esri_pntr") - return self.run_tool('rho8_pointer', args, callback) # returns 1 if error - - def sink(self, i, output, zero_background=False, callback=None): - """Identifies the depressions in a DEM, giving each feature a unique identifier. - - Keyword arguments: - - i -- Input raster DEM file. - output -- Output raster file. - zero_background -- Flag indicating whether a background value of zero should be used. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - if zero_background: args.append("--zero_background") - return self.run_tool('sink', args, callback) # returns 1 if error - - def snap_pour_points(self, pour_pts, flow_accum, output, snap_dist, callback=None): - """Moves outlet points used to specify points of interest in a watershedding operation to the cell with the highest flow accumulation in its neighbourhood. - - Keyword arguments: - - pour_pts -- Input vector pour points (outlet) file. - flow_accum -- Input raster D8 flow accumulation file. - output -- Output vector file. - snap_dist -- Maximum snap distance in map units. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--pour_pts='{}'".format(pour_pts)) - args.append("--flow_accum='{}'".format(flow_accum)) - args.append("--output='{}'".format(output)) - args.append("--snap_dist='{}'".format(snap_dist)) - return self.run_tool('snap_pour_points', args, callback) # returns 1 if error - - def stochastic_depression_analysis(self, dem, output, rmse, range, iterations=100, callback=None): - """Preforms a stochastic analysis of depressions within a DEM. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output file. - rmse -- The DEM's root-mean-square-error (RMSE), in z units. This determines error magnitude. - range -- The error field's correlation length, in xy-units. - iterations -- The number of iterations. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - args.append("--rmse='{}'".format(rmse)) - args.append("--range='{}'".format(range)) - args.append("--iterations={}".format(iterations)) - return self.run_tool('stochastic_depression_analysis', args, callback) # returns 1 if error - - def strahler_order_basins(self, d8_pntr, streams, output, esri_pntr=False, callback=None): - """Identifies Strahler-order basins from an input stream network. - - Keyword arguments: - - d8_pntr -- Input raster D8 pointer file. - streams -- Input raster streams file. - output -- Output raster file. - esri_pntr -- D8 pointer uses the ESRI style scheme. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--d8_pntr='{}'".format(d8_pntr)) - args.append("--streams='{}'".format(streams)) - args.append("--output='{}'".format(output)) - if esri_pntr: args.append("--esri_pntr") - return self.run_tool('strahler_order_basins', args, callback) # returns 1 if error - - def subbasins(self, d8_pntr, streams, output, esri_pntr=False, callback=None): - """Identifies the catchments, or sub-basin, draining to each link in a stream network. - - Keyword arguments: - - d8_pntr -- Input D8 pointer raster file. - streams -- Input raster streams file. - output -- Output raster file. - esri_pntr -- D8 pointer uses the ESRI style scheme. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--d8_pntr='{}'".format(d8_pntr)) - args.append("--streams='{}'".format(streams)) - args.append("--output='{}'".format(output)) - if esri_pntr: args.append("--esri_pntr") - return self.run_tool('subbasins', args, callback) # returns 1 if error - - def trace_downslope_flowpaths(self, seed_pts, d8_pntr, output, esri_pntr=False, zero_background=False, callback=None): - """Traces downslope flowpaths from one or more target sites (i.e. seed points). - - Keyword arguments: - - seed_pts -- Input vector seed points file. - d8_pntr -- Input D8 pointer raster file. - output -- Output raster file. - esri_pntr -- D8 pointer uses the ESRI style scheme. - zero_background -- Flag indicating whether a background value of zero should be used. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--seed_pts='{}'".format(seed_pts)) - args.append("--d8_pntr='{}'".format(d8_pntr)) - args.append("--output='{}'".format(output)) - if esri_pntr: args.append("--esri_pntr") - if zero_background: args.append("--zero_background") - return self.run_tool('trace_downslope_flowpaths', args, callback) # returns 1 if error - - def unnest_basins(self, d8_pntr, pour_pts, output, esri_pntr=False, callback=None): - """Extract whole watersheds for a set of outlet points. - - Keyword arguments: - - d8_pntr -- Input D8 pointer raster file. - pour_pts -- Input vector pour points (outlet) file. - output -- Output raster file. - esri_pntr -- D8 pointer uses the ESRI style scheme. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--d8_pntr='{}'".format(d8_pntr)) - args.append("--pour_pts='{}'".format(pour_pts)) - args.append("--output='{}'".format(output)) - if esri_pntr: args.append("--esri_pntr") - return self.run_tool('unnest_basins', args, callback) # returns 1 if error - - def upslope_depression_storage(self, dem, output, callback=None): - """Estimates the average upslope depression storage depth. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - return self.run_tool('upslope_depression_storage', args, callback) # returns 1 if error - - def watershed(self, d8_pntr, pour_pts, output, esri_pntr=False, callback=None): - """Identifies the watershed, or drainage basin, draining to a set of target cells. - - Keyword arguments: - - d8_pntr -- Input D8 pointer raster file. - pour_pts -- Input pour points (outlet) file. - output -- Output raster file. - esri_pntr -- D8 pointer uses the ESRI style scheme. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--d8_pntr='{}'".format(d8_pntr)) - args.append("--pour_pts='{}'".format(pour_pts)) - args.append("--output='{}'".format(output)) - if esri_pntr: args.append("--esri_pntr") - return self.run_tool('watershed', args, callback) # returns 1 if error - - ########################## - # Image Processing Tools # - ########################## - - def change_vector_analysis(self, date1, date2, magnitude, direction, callback=None): - """Performs a change vector analysis on a two-date multi-spectral dataset. - - Keyword arguments: - - date1 -- Input raster files for the earlier date. - date2 -- Input raster files for the later date. - magnitude -- Output vector magnitude raster file. - direction -- Output vector Direction raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--date1='{}'".format(date1)) - args.append("--date2='{}'".format(date2)) - args.append("--magnitude='{}'".format(magnitude)) - args.append("--direction='{}'".format(direction)) - return self.run_tool('change_vector_analysis', args, callback) # returns 1 if error - - def closing(self, i, output, filterx=11, filtery=11, callback=None): - """A closing is a mathematical morphology operation involving an erosion (min filter) of a dilation (max filter) set. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - filterx -- Size of the filter kernel in the x-direction. - filtery -- Size of the filter kernel in the y-direction. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--filterx={}".format(filterx)) - args.append("--filtery={}".format(filtery)) - return self.run_tool('closing', args, callback) # returns 1 if error - - def create_colour_composite(self, red, green, blue, output, opacity=None, enhance=True, zeros=False, callback=None): - """Creates a colour-composite image from three bands of multispectral imagery. - - Keyword arguments: - - red -- Input red band image file. - green -- Input green band image file. - blue -- Input blue band image file. - opacity -- Input opacity band image file (optional). - output -- Output colour composite file. - enhance -- Optional flag indicating whether a balance contrast enhancement is performed. - zeros -- Optional flag to indicate if zeros are nodata values. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--red='{}'".format(red)) - args.append("--green='{}'".format(green)) - args.append("--blue='{}'".format(blue)) - if opacity is not None: args.append("--opacity='{}'".format(opacity)) - args.append("--output='{}'".format(output)) - if enhance: args.append("--enhance") - if zeros: args.append("--zeros") - return self.run_tool('create_colour_composite', args, callback) # returns 1 if error - - def flip_image(self, i, output, direction="vertical", callback=None): - """Reflects an image in the vertical or horizontal axis. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - direction -- Direction of reflection; options include 'v' (vertical), 'h' (horizontal), and 'b' (both). - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--direction={}".format(direction)) - return self.run_tool('flip_image', args, callback) # returns 1 if error - - def ihs_to_rgb(self, intensity, hue, saturation, red=None, green=None, blue=None, output=None, callback=None): - """Converts intensity, hue, and saturation (IHS) images into red, green, and blue (RGB) images. - - Keyword arguments: - - intensity -- Input intensity file. - hue -- Input hue file. - saturation -- Input saturation file. - red -- Output red band file. Optionally specified if colour-composite not specified. - green -- Output green band file. Optionally specified if colour-composite not specified. - blue -- Output blue band file. Optionally specified if colour-composite not specified. - output -- Output colour-composite file. Only used if individual bands are not specified. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--intensity='{}'".format(intensity)) - args.append("--hue='{}'".format(hue)) - args.append("--saturation='{}'".format(saturation)) - if red is not None: args.append("--red='{}'".format(red)) - if green is not None: args.append("--green='{}'".format(green)) - if blue is not None: args.append("--blue='{}'".format(blue)) - if output is not None: args.append("--output='{}'".format(output)) - return self.run_tool('ihs_to_rgb', args, callback) # returns 1 if error - - def image_stack_profile(self, inputs, points, output, callback=None): - """Plots an image stack profile (i.e. signature) for a set of points and multispectral images. - - Keyword arguments: - - inputs -- Input multispectral image files. - points -- Input vector points file. - output -- Output HTML file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--inputs='{}'".format(inputs)) - args.append("--points='{}'".format(points)) - args.append("--output='{}'".format(output)) - return self.run_tool('image_stack_profile', args, callback) # returns 1 if error - - def integral_image(self, i, output, callback=None): - """Transforms an input image (summed area table) into its integral image equivalent. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('integral_image', args, callback) # returns 1 if error - - def k_means_clustering(self, inputs, output, classes, out_html=None, max_iterations=10, class_change=2.0, initialize="diagonal", min_class_size=10, callback=None): - """Performs a k-means clustering operation on a multi-spectral dataset. - - Keyword arguments: - - inputs -- Input raster files. - output -- Output raster file. - out_html -- Output HTML report file. - classes -- Number of classes. - max_iterations -- Maximum number of iterations. - class_change -- Minimum percent of cells changed between iterations before completion. - initialize -- How to initialize cluster centres?. - min_class_size -- Minimum class size, in pixels. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--inputs='{}'".format(inputs)) - args.append("--output='{}'".format(output)) - if out_html is not None: args.append("--out_html='{}'".format(out_html)) - args.append("--classes='{}'".format(classes)) - args.append("--max_iterations={}".format(max_iterations)) - args.append("--class_change={}".format(class_change)) - args.append("--initialize={}".format(initialize)) - args.append("--min_class_size={}".format(min_class_size)) - return self.run_tool('k_means_clustering', args, callback) # returns 1 if error - - def line_thinning(self, i, output, callback=None): - """Performs line thinning a on Boolean raster image; intended to be used with the RemoveSpurs tool. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('line_thinning', args, callback) # returns 1 if error - - def modified_k_means_clustering(self, inputs, output, out_html=None, start_clusters=1000, merge_dist=None, max_iterations=10, class_change=2.0, callback=None): - """Performs a modified k-means clustering operation on a multi-spectral dataset. - - Keyword arguments: - - inputs -- Input raster files. - output -- Output raster file. - out_html -- Output HTML report file. - start_clusters -- Initial number of clusters. - merge_dist -- Cluster merger distance. - max_iterations -- Maximum number of iterations. - class_change -- Minimum percent of cells changed between iterations before completion. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--inputs='{}'".format(inputs)) - args.append("--output='{}'".format(output)) - if out_html is not None: args.append("--out_html='{}'".format(out_html)) - args.append("--start_clusters={}".format(start_clusters)) - if merge_dist is not None: args.append("--merge_dist='{}'".format(merge_dist)) - args.append("--max_iterations={}".format(max_iterations)) - args.append("--class_change={}".format(class_change)) - return self.run_tool('modified_k_means_clustering', args, callback) # returns 1 if error - - def mosaic(self, output, inputs=None, method="nn", callback=None): - """Mosaics two or more images together. - - Keyword arguments: - - inputs -- Input raster files. - output -- Output raster file. - method -- Resampling method; options include 'nn' (nearest neighbour), 'bilinear', and 'cc' (cubic convolution). - callback -- Custom function for handling tool text outputs. - """ - args = [] - if inputs is not None: args.append("--inputs='{}'".format(inputs)) - args.append("--output='{}'".format(output)) - args.append("--method={}".format(method)) - return self.run_tool('mosaic', args, callback) # returns 1 if error - - def mosaic_with_feathering(self, input1, input2, output, method="cc", weight=4.0, callback=None): - """Mosaics two images together using a feathering technique in overlapping areas to reduce edge-effects. - - Keyword arguments: - - input1 -- Input raster file to modify. - input2 -- Input reference raster file. - output -- Output raster file. - method -- Resampling method; options include 'nn' (nearest neighbour), 'bilinear', and 'cc' (cubic convolution). - weight -- . - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input1='{}'".format(input1)) - args.append("--input2='{}'".format(input2)) - args.append("--output='{}'".format(output)) - args.append("--method={}".format(method)) - args.append("--weight={}".format(weight)) - return self.run_tool('mosaic_with_feathering', args, callback) # returns 1 if error - - def normalized_difference_index(self, input1, input2, output, clip=0.0, correction=0.0, callback=None): - """Calculate a normalized-difference index (NDI) from two bands of multispectral image data. - - Keyword arguments: - - input1 -- Input image 1 (e.g. near-infrared band). - input2 -- Input image 2 (e.g. red band). - output -- Output raster file. - clip -- Optional amount to clip the distribution tails by, in percent. - correction -- Optional adjustment value (e.g. 1, or 0.16 for the optimal soil adjusted vegetation index, OSAVI). - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input1='{}'".format(input1)) - args.append("--input2='{}'".format(input2)) - args.append("--output='{}'".format(output)) - args.append("--clip={}".format(clip)) - args.append("--correction={}".format(correction)) - return self.run_tool('normalized_difference_index', args, callback) # returns 1 if error - - def opening(self, i, output, filterx=11, filtery=11, callback=None): - """An opening is a mathematical morphology operation involving a dilation (max filter) of an erosion (min filter) set. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - filterx -- Size of the filter kernel in the x-direction. - filtery -- Size of the filter kernel in the y-direction. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--filterx={}".format(filterx)) - args.append("--filtery={}".format(filtery)) - return self.run_tool('opening', args, callback) # returns 1 if error - - def remove_spurs(self, i, output, iterations=10, callback=None): - """Removes the spurs (pruning operation) from a Boolean line image; intended to be used on the output of the LineThinning tool. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - iterations -- Maximum number of iterations. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--iterations={}".format(iterations)) - return self.run_tool('remove_spurs', args, callback) # returns 1 if error - - def resample(self, inputs, destination, method="cc", callback=None): - """Resamples one or more input images into a destination image. - - Keyword arguments: - - inputs -- Input raster files. - destination -- Destination raster file. - method -- Resampling method; options include 'nn' (nearest neighbour), 'bilinear', and 'cc' (cubic convolution). - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--inputs='{}'".format(inputs)) - args.append("--destination='{}'".format(destination)) - args.append("--method={}".format(method)) - return self.run_tool('resample', args, callback) # returns 1 if error - - def rgb_to_ihs(self, intensity, hue, saturation, red=None, green=None, blue=None, composite=None, callback=None): - """Converts red, green, and blue (RGB) images into intensity, hue, and saturation (IHS) images. - - Keyword arguments: - - red -- Input red band image file. Optionally specified if colour-composite not specified. - green -- Input green band image file. Optionally specified if colour-composite not specified. - blue -- Input blue band image file. Optionally specified if colour-composite not specified. - composite -- Input colour-composite image file. Only used if individual bands are not specified. - intensity -- Output intensity raster file. - hue -- Output hue raster file. - saturation -- Output saturation raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - if red is not None: args.append("--red='{}'".format(red)) - if green is not None: args.append("--green='{}'".format(green)) - if blue is not None: args.append("--blue='{}'".format(blue)) - if composite is not None: args.append("--composite='{}'".format(composite)) - args.append("--intensity='{}'".format(intensity)) - args.append("--hue='{}'".format(hue)) - args.append("--saturation='{}'".format(saturation)) - return self.run_tool('rgb_to_ihs', args, callback) # returns 1 if error - - def split_colour_composite(self, i, red=None, green=None, blue=None, callback=None): - """This tool splits an RGB colour composite image into seperate multispectral images. - - Keyword arguments: - - i -- Input colour composite image file. - red -- Output red band file. - green -- Output green band file. - blue -- Output blue band file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - if red is not None: args.append("--red='{}'".format(red)) - if green is not None: args.append("--green='{}'".format(green)) - if blue is not None: args.append("--blue='{}'".format(blue)) - return self.run_tool('split_colour_composite', args, callback) # returns 1 if error - - def thicken_raster_line(self, i, output, callback=None): - """Thickens single-cell wide lines within a raster image. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('thicken_raster_line', args, callback) # returns 1 if error - - def tophat_transform(self, i, output, filterx=11, filtery=11, variant="white", callback=None): - """Performs either a white or black top-hat transform on an input image. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - filterx -- Size of the filter kernel in the x-direction. - filtery -- Size of the filter kernel in the y-direction. - variant -- Optional variant value. Options include 'white' and 'black'. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--filterx={}".format(filterx)) - args.append("--filtery={}".format(filtery)) - args.append("--variant={}".format(variant)) - return self.run_tool('tophat_transform', args, callback) # returns 1 if error - - def write_function_memory_insertion(self, input1, input2, output, input3=None, callback=None): - """Performs a write function memory insertion for single-band multi-date change detection. - - Keyword arguments: - - input1 -- Input raster file associated with the first date. - input2 -- Input raster file associated with the second date. - input3 -- Optional input raster file associated with the third date. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input1='{}'".format(input1)) - args.append("--input2='{}'".format(input2)) - if input3 is not None: args.append("--input3='{}'".format(input3)) - args.append("--output='{}'".format(output)) - return self.run_tool('write_function_memory_insertion', args, callback) # returns 1 if error - - ################################## - # Image Processing Tools/Filters # - ################################## - - def adaptive_filter(self, i, output, filterx=11, filtery=11, threshold=2.0, callback=None): - """Performs an adaptive filter on an image. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - filterx -- Size of the filter kernel in the x-direction. - filtery -- Size of the filter kernel in the y-direction. - threshold -- Difference from mean threshold, in standard deviations. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--filterx={}".format(filterx)) - args.append("--filtery={}".format(filtery)) - args.append("--threshold={}".format(threshold)) - return self.run_tool('adaptive_filter', args, callback) # returns 1 if error - - def bilateral_filter(self, i, output, sigma_dist=0.75, sigma_int=1.0, callback=None): - """A bilateral filter is an edge-preserving smoothing filter introduced by Tomasi and Manduchi (1998). - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - sigma_dist -- Standard deviation in distance in pixels. - sigma_int -- Standard deviation in intensity in pixels. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--sigma_dist={}".format(sigma_dist)) - args.append("--sigma_int={}".format(sigma_int)) - return self.run_tool('bilateral_filter', args, callback) # returns 1 if error - - def conservative_smoothing_filter(self, i, output, filterx=3, filtery=3, callback=None): - """Performs a conservative-smoothing filter on an image. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - filterx -- Size of the filter kernel in the x-direction. - filtery -- Size of the filter kernel in the y-direction. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--filterx={}".format(filterx)) - args.append("--filtery={}".format(filtery)) - return self.run_tool('conservative_smoothing_filter', args, callback) # returns 1 if error - - def corner_detection(self, i, output, callback=None): - """Identifies corner patterns in boolean images using hit-and-miss pattern matching. - - Keyword arguments: - - i -- Input boolean image. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('corner_detection', args, callback) # returns 1 if error - - def diff_of_gaussian_filter(self, i, output, sigma1=2.0, sigma2=4.0, callback=None): - """Performs a Difference of Gaussian (DoG) filter on an image. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - sigma1 -- Standard deviation distance in pixels. - sigma2 -- Standard deviation distance in pixels. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--sigma1={}".format(sigma1)) - args.append("--sigma2={}".format(sigma2)) - return self.run_tool('diff_of_gaussian_filter', args, callback) # returns 1 if error - - def diversity_filter(self, i, output, filterx=11, filtery=11, callback=None): - """Assigns each cell in the output grid the number of different values in a moving window centred on each grid cell in the input raster. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - filterx -- Size of the filter kernel in the x-direction. - filtery -- Size of the filter kernel in the y-direction. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--filterx={}".format(filterx)) - args.append("--filtery={}".format(filtery)) - return self.run_tool('diversity_filter', args, callback) # returns 1 if error - - def edge_preserving_mean_filter(self, i, output, threshold, filter=11, callback=None): - """Performs a simple edge-preserving mean filter on an input image. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - filter -- Size of the filter kernel. - threshold -- Maximum difference in values. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--filter={}".format(filter)) - args.append("--threshold='{}'".format(threshold)) - return self.run_tool('edge_preserving_mean_filter', args, callback) # returns 1 if error - - def emboss_filter(self, i, output, direction="n", clip=0.0, callback=None): - """Performs an emboss filter on an image, similar to a hillshade operation. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - direction -- Direction of reflection; options include 'n', 's', 'e', 'w', 'ne', 'se', 'nw', 'sw'. - clip -- Optional amount to clip the distribution tails by, in percent. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--direction={}".format(direction)) - args.append("--clip={}".format(clip)) - return self.run_tool('emboss_filter', args, callback) # returns 1 if error - - def fast_almost_gaussian_filter(self, i, output, sigma=1.8, callback=None): - """Performs a fast approximate Gaussian filter on an image. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - sigma -- Standard deviation distance in pixels. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--sigma={}".format(sigma)) - return self.run_tool('fast_almost_gaussian_filter', args, callback) # returns 1 if error - - def gaussian_filter(self, i, output, sigma=0.75, callback=None): - """Performs a Gaussian filter on an image. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - sigma -- Standard deviation distance in pixels. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--sigma={}".format(sigma)) - return self.run_tool('gaussian_filter', args, callback) # returns 1 if error - - def high_pass_filter(self, i, output, filterx=11, filtery=11, callback=None): - """Performs a high-pass filter on an input image. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - filterx -- Size of the filter kernel in the x-direction. - filtery -- Size of the filter kernel in the y-direction. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--filterx={}".format(filterx)) - args.append("--filtery={}".format(filtery)) - return self.run_tool('high_pass_filter', args, callback) # returns 1 if error - - def high_pass_median_filter(self, i, output, filterx=11, filtery=11, sig_digits=2, callback=None): - """Performs a high pass median filter on an input image. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - filterx -- Size of the filter kernel in the x-direction. - filtery -- Size of the filter kernel in the y-direction. - sig_digits -- Number of significant digits. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--filterx={}".format(filterx)) - args.append("--filtery={}".format(filtery)) - args.append("--sig_digits={}".format(sig_digits)) - return self.run_tool('high_pass_median_filter', args, callback) # returns 1 if error - - def k_nearest_mean_filter(self, i, output, filterx=11, filtery=11, k=5, callback=None): - """A k-nearest mean filter is a type of edge-preserving smoothing filter. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - filterx -- Size of the filter kernel in the x-direction. - filtery -- Size of the filter kernel in the y-direction. - k -- k-value in pixels; this is the number of nearest-valued neighbours to use. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--filterx={}".format(filterx)) - args.append("--filtery={}".format(filtery)) - args.append("-k={}".format(k)) - return self.run_tool('k_nearest_mean_filter', args, callback) # returns 1 if error - - def laplacian_filter(self, i, output, variant="3x3(1)", clip=0.0, callback=None): - """Performs a Laplacian filter on an image. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - variant -- Optional variant value. Options include 3x3(1), 3x3(2), 3x3(3), 3x3(4), 5x5(1), and 5x5(2) (default is 3x3(1)). - clip -- Optional amount to clip the distribution tails by, in percent. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--variant={}".format(variant)) - args.append("--clip={}".format(clip)) - return self.run_tool('laplacian_filter', args, callback) # returns 1 if error - - def laplacian_of_gaussian_filter(self, i, output, sigma=0.75, callback=None): - """Performs a Laplacian-of-Gaussian (LoG) filter on an image. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - sigma -- Standard deviation in pixels. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--sigma={}".format(sigma)) - return self.run_tool('laplacian_of_gaussian_filter', args, callback) # returns 1 if error - - def lee_sigma_filter(self, i, output, filterx=11, filtery=11, sigma=10.0, m=5.0, callback=None): - """Performs a Lee (Sigma) smoothing filter on an image. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - filterx -- Size of the filter kernel in the x-direction. - filtery -- Size of the filter kernel in the y-direction. - sigma -- Sigma value should be related to the standarad deviation of the distribution of image speckle noise. - m -- M-threshold value the minimum allowable number of pixels within the intensity range. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--filterx={}".format(filterx)) - args.append("--filtery={}".format(filtery)) - args.append("--sigma={}".format(sigma)) - args.append("-m={}".format(m)) - return self.run_tool('lee_sigma_filter', args, callback) # returns 1 if error - - def line_detection_filter(self, i, output, variant="vertical", absvals=False, clip=0.0, callback=None): - """Performs a line-detection filter on an image. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - variant -- Optional variant value. Options include 'v' (vertical), 'h' (horizontal), '45', and '135' (default is 'v'). - absvals -- Optional flag indicating whether outputs should be absolute values. - clip -- Optional amount to clip the distribution tails by, in percent. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--variant={}".format(variant)) - if absvals: args.append("--absvals") - args.append("--clip={}".format(clip)) - return self.run_tool('line_detection_filter', args, callback) # returns 1 if error - - def majority_filter(self, i, output, filterx=11, filtery=11, callback=None): - """Assigns each cell in the output grid the most frequently occurring value (mode) in a moving window centred on each grid cell in the input raster. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - filterx -- Size of the filter kernel in the x-direction. - filtery -- Size of the filter kernel in the y-direction. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--filterx={}".format(filterx)) - args.append("--filtery={}".format(filtery)) - return self.run_tool('majority_filter', args, callback) # returns 1 if error - - def maximum_filter(self, i, output, filterx=11, filtery=11, callback=None): - """Assigns each cell in the output grid the maximum value in a moving window centred on each grid cell in the input raster. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - filterx -- Size of the filter kernel in the x-direction. - filtery -- Size of the filter kernel in the y-direction. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--filterx={}".format(filterx)) - args.append("--filtery={}".format(filtery)) - return self.run_tool('maximum_filter', args, callback) # returns 1 if error - - def mean_filter(self, i, output, filterx=3, filtery=3, callback=None): - """Performs a mean filter (low-pass filter) on an input image. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - filterx -- Size of the filter kernel in the x-direction. - filtery -- Size of the filter kernel in the y-direction. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--filterx={}".format(filterx)) - args.append("--filtery={}".format(filtery)) - return self.run_tool('mean_filter', args, callback) # returns 1 if error - - def median_filter(self, i, output, filterx=11, filtery=11, sig_digits=2, callback=None): - """Performs a median filter on an input image. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - filterx -- Size of the filter kernel in the x-direction. - filtery -- Size of the filter kernel in the y-direction. - sig_digits -- Number of significant digits. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--filterx={}".format(filterx)) - args.append("--filtery={}".format(filtery)) - args.append("--sig_digits={}".format(sig_digits)) - return self.run_tool('median_filter', args, callback) # returns 1 if error - - def minimum_filter(self, i, output, filterx=11, filtery=11, callback=None): - """Assigns each cell in the output grid the minimum value in a moving window centred on each grid cell in the input raster. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - filterx -- Size of the filter kernel in the x-direction. - filtery -- Size of the filter kernel in the y-direction. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--filterx={}".format(filterx)) - args.append("--filtery={}".format(filtery)) - return self.run_tool('minimum_filter', args, callback) # returns 1 if error - - def olympic_filter(self, i, output, filterx=11, filtery=11, callback=None): - """Performs an olympic smoothing filter on an image. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - filterx -- Size of the filter kernel in the x-direction. - filtery -- Size of the filter kernel in the y-direction. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--filterx={}".format(filterx)) - args.append("--filtery={}".format(filtery)) - return self.run_tool('olympic_filter', args, callback) # returns 1 if error - - def percentile_filter(self, i, output, filterx=11, filtery=11, sig_digits=2, callback=None): - """Performs a percentile filter on an input image. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - filterx -- Size of the filter kernel in the x-direction. - filtery -- Size of the filter kernel in the y-direction. - sig_digits -- Number of significant digits. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--filterx={}".format(filterx)) - args.append("--filtery={}".format(filtery)) - args.append("--sig_digits={}".format(sig_digits)) - return self.run_tool('percentile_filter', args, callback) # returns 1 if error - - def prewitt_filter(self, i, output, clip=0.0, callback=None): - """Performs a Prewitt edge-detection filter on an image. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - clip -- Optional amount to clip the distribution tails by, in percent. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--clip={}".format(clip)) - return self.run_tool('prewitt_filter', args, callback) # returns 1 if error - - def range_filter(self, i, output, filterx=11, filtery=11, callback=None): - """Assigns each cell in the output grid the range of values in a moving window centred on each grid cell in the input raster. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - filterx -- Size of the filter kernel in the x-direction. - filtery -- Size of the filter kernel in the y-direction. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--filterx={}".format(filterx)) - args.append("--filtery={}".format(filtery)) - return self.run_tool('range_filter', args, callback) # returns 1 if error - - def roberts_cross_filter(self, i, output, clip=0.0, callback=None): - """Performs a Robert's cross edge-detection filter on an image. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - clip -- Optional amount to clip the distribution tails by, in percent. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--clip={}".format(clip)) - return self.run_tool('roberts_cross_filter', args, callback) # returns 1 if error - - def scharr_filter(self, i, output, clip=0.0, callback=None): - """Performs a Scharr edge-detection filter on an image. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - clip -- Optional amount to clip the distribution tails by, in percent. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--clip={}".format(clip)) - return self.run_tool('scharr_filter', args, callback) # returns 1 if error - - def sobel_filter(self, i, output, variant="3x3", clip=0.0, callback=None): - """Performs a Sobel edge-detection filter on an image. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - variant -- Optional variant value. Options include 3x3 and 5x5 (default is 3x3). - clip -- Optional amount to clip the distribution tails by, in percent (default is 0.0). - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--variant={}".format(variant)) - args.append("--clip={}".format(clip)) - return self.run_tool('sobel_filter', args, callback) # returns 1 if error - - def standard_deviation_filter(self, i, output, filterx=11, filtery=11, callback=None): - """Assigns each cell in the output grid the standard deviation of values in a moving window centred on each grid cell in the input raster. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - filterx -- Size of the filter kernel in the x-direction. - filtery -- Size of the filter kernel in the y-direction. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--filterx={}".format(filterx)) - args.append("--filtery={}".format(filtery)) - return self.run_tool('standard_deviation_filter', args, callback) # returns 1 if error - - def total_filter(self, i, output, filterx=11, filtery=11, callback=None): - """Performs a total filter on an input image. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - filterx -- Size of the filter kernel in the x-direction. - filtery -- Size of the filter kernel in the y-direction. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--filterx={}".format(filterx)) - args.append("--filtery={}".format(filtery)) - return self.run_tool('total_filter', args, callback) # returns 1 if error - - def unsharp_masking(self, i, output, sigma=0.75, amount=100.0, threshold=0.0, callback=None): - """An image sharpening technique that enhances edges. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - sigma -- Standard deviation distance in pixels. - amount -- A percentage and controls the magnitude of each overshoot. - threshold -- Controls the minimal brightness change that will be sharpened. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--sigma={}".format(sigma)) - args.append("--amount={}".format(amount)) - args.append("--threshold={}".format(threshold)) - return self.run_tool('unsharp_masking', args, callback) # returns 1 if error - - def user_defined_weights_filter(self, i, weights, output, center="center", normalize=False, callback=None): - """Performs a user-defined weights filter on an image. - - Keyword arguments: - - i -- Input raster file. - weights -- Input weights file. - output -- Output raster file. - center -- Kernel center cell; options include 'center', 'upper-left', 'upper-right', 'lower-left', 'lower-right'. - normalize -- Normalize kernel weights? This can reduce edge effects and lessen the impact of data gaps (nodata) but is not suited when the kernel weights sum to zero. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--weights='{}'".format(weights)) - args.append("--output='{}'".format(output)) - args.append("--center={}".format(center)) - if normalize: args.append("--normalize") - return self.run_tool('user_defined_weights_filter', args, callback) # returns 1 if error - - ############################################ - # Image Processing Tools/Image Enhancement # - ############################################ - - def balance_contrast_enhancement(self, i, output, band_mean=100.0, callback=None): - """Performs a balance contrast enhancement on a colour-composite image of multispectral data. - - Keyword arguments: - - i -- Input colour composite image file. - output -- Output raster file. - band_mean -- Band mean value. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--band_mean={}".format(band_mean)) - return self.run_tool('balance_contrast_enhancement', args, callback) # returns 1 if error - - def correct_vignetting(self, i, pp, output, focal_length=304.8, image_width=228.6, n=4.0, callback=None): - """Corrects the darkening of images towards corners. - - Keyword arguments: - - i -- Input raster file. - pp -- Input principal point file. - output -- Output raster file. - focal_length -- Camera focal length, in millimeters. - image_width -- Distance between photograph edges, in millimeters. - n -- The 'n' parameter. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--pp='{}'".format(pp)) - args.append("--output='{}'".format(output)) - args.append("--focal_length={}".format(focal_length)) - args.append("--image_width={}".format(image_width)) - args.append("-n={}".format(n)) - return self.run_tool('correct_vignetting', args, callback) # returns 1 if error - - def direct_decorrelation_stretch(self, i, output, k=0.5, clip=1.0, callback=None): - """Performs a direct decorrelation stretch enhancement on a colour-composite image of multispectral data. - - Keyword arguments: - - i -- Input colour composite image file. - output -- Output raster file. - k -- Achromatic factor (k) ranges between 0 (no effect) and 1 (full saturation stretch), although typical values range from 0.3 to 0.7. - clip -- Optional percent to clip the upper tail by during the stretch. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("-k={}".format(k)) - args.append("--clip={}".format(clip)) - return self.run_tool('direct_decorrelation_stretch', args, callback) # returns 1 if error - - def gamma_correction(self, i, output, gamma=0.5, callback=None): - """Performs a gamma correction on an input images. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - gamma -- Gamma value. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--gamma={}".format(gamma)) - return self.run_tool('gamma_correction', args, callback) # returns 1 if error - - def gaussian_contrast_stretch(self, i, output, num_tones=256, callback=None): - """Performs a Gaussian contrast stretch on input images. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - num_tones -- Number of tones in the output image. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--num_tones={}".format(num_tones)) - return self.run_tool('gaussian_contrast_stretch', args, callback) # returns 1 if error - - def histogram_equalization(self, i, output, num_tones=256, callback=None): - """Performs a histogram equalization contrast enhancment on an image. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - num_tones -- Number of tones in the output image. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--num_tones={}".format(num_tones)) - return self.run_tool('histogram_equalization', args, callback) # returns 1 if error - - def histogram_matching(self, i, histo_file, output, callback=None): - """Alters the statistical distribution of a raster image matching it to a specified PDF. - - Keyword arguments: - - i -- Input raster file. - histo_file -- Input reference probability distribution function (pdf) text file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--histo_file='{}'".format(histo_file)) - args.append("--output='{}'".format(output)) - return self.run_tool('histogram_matching', args, callback) # returns 1 if error - - def histogram_matching_two_images(self, input1, input2, output, callback=None): - """This tool alters the cumulative distribution function of a raster image to that of another image. - - Keyword arguments: - - input1 -- Input raster file to modify. - input2 -- Input reference raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input1='{}'".format(input1)) - args.append("--input2='{}'".format(input2)) - args.append("--output='{}'".format(output)) - return self.run_tool('histogram_matching_two_images', args, callback) # returns 1 if error - - def min_max_contrast_stretch(self, i, output, min_val, max_val, num_tones=256, callback=None): - """Performs a min-max contrast stretch on an input greytone image. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - min_val -- Lower tail clip value. - max_val -- Upper tail clip value. - num_tones -- Number of tones in the output image. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--min_val='{}'".format(min_val)) - args.append("--max_val='{}'".format(max_val)) - args.append("--num_tones={}".format(num_tones)) - return self.run_tool('min_max_contrast_stretch', args, callback) # returns 1 if error - - def panchromatic_sharpening(self, pan, output, red=None, green=None, blue=None, composite=None, method="brovey", callback=None): - """Increases the spatial resolution of image data by combining multispectral bands with panchromatic data. - - Keyword arguments: - - red -- Input red band image file. Optionally specified if colour-composite not specified. - green -- Input green band image file. Optionally specified if colour-composite not specified. - blue -- Input blue band image file. Optionally specified if colour-composite not specified. - composite -- Input colour-composite image file. Only used if individual bands are not specified. - pan -- Input panchromatic band file. - output -- Output colour composite file. - method -- Options include 'brovey' (default) and 'ihs'. - callback -- Custom function for handling tool text outputs. - """ - args = [] - if red is not None: args.append("--red='{}'".format(red)) - if green is not None: args.append("--green='{}'".format(green)) - if blue is not None: args.append("--blue='{}'".format(blue)) - if composite is not None: args.append("--composite='{}'".format(composite)) - args.append("--pan='{}'".format(pan)) - args.append("--output='{}'".format(output)) - args.append("--method={}".format(method)) - return self.run_tool('panchromatic_sharpening', args, callback) # returns 1 if error - - def percentage_contrast_stretch(self, i, output, clip=1.0, tail="both", num_tones=256, callback=None): - """Performs a percentage linear contrast stretch on input images. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - clip -- Optional amount to clip the distribution tails by, in percent. - tail -- Specified which tails to clip; options include 'upper', 'lower', and 'both' (default is 'both'). - num_tones -- Number of tones in the output image. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--clip={}".format(clip)) - args.append("--tail={}".format(tail)) - args.append("--num_tones={}".format(num_tones)) - return self.run_tool('percentage_contrast_stretch', args, callback) # returns 1 if error - - def sigmoidal_contrast_stretch(self, i, output, cutoff=0.0, gain=1.0, num_tones=256, callback=None): - """Performs a sigmoidal contrast stretch on input images. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - cutoff -- Cutoff value between 0.0 and 0.95. - gain -- Gain value. - num_tones -- Number of tones in the output image. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--cutoff={}".format(cutoff)) - args.append("--gain={}".format(gain)) - args.append("--num_tones={}".format(num_tones)) - return self.run_tool('sigmoidal_contrast_stretch', args, callback) # returns 1 if error - - def standard_deviation_contrast_stretch(self, i, output, stdev=2.0, num_tones=256, callback=None): - """Performs a standard-deviation contrast stretch on input images. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - stdev -- Standard deviation clip value. - num_tones -- Number of tones in the output image. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--stdev={}".format(stdev)) - args.append("--num_tones={}".format(num_tones)) - return self.run_tool('standard_deviation_contrast_stretch', args, callback) # returns 1 if error - - ############### - # LiDAR Tools # - ############### - - def ascii_to_las(self, inputs, pattern, proj=None, callback=None): - """Converts one or more ASCII files containing LiDAR points into LAS files. - - Keyword arguments: - - inputs -- Input LiDAR ASCII files (.csv). - pattern -- Input field pattern. - proj -- Well-known-text string or EPSG code describing projection. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--inputs='{}'".format(inputs)) - args.append("--pattern='{}'".format(pattern)) - if proj is not None: args.append("--proj='{}'".format(proj)) - return self.run_tool('ascii_to_las', args, callback) # returns 1 if error - - def classify_buildings_in_lidar(self, i, buildings, output, callback=None): - """Reclassifies a LiDAR points that lie within vector building footprints. - - Keyword arguments: - - i -- Input LiDAR file. - buildings -- Input vector polygons file. - output -- Output LiDAR file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--buildings='{}'".format(buildings)) - args.append("--output='{}'".format(output)) - return self.run_tool('classify_buildings_in_lidar', args, callback) # returns 1 if error - - def classify_overlap_points(self, i, output, resolution=2.0, filter=False, callback=None): - """Classifies or filters LAS points in regions of overlapping flight lines. - - Keyword arguments: - - i -- Input LiDAR file. - output -- Output LiDAR file. - resolution -- The size of the square area used to evaluate nearby points in the LiDAR data. - filter -- Filter out points from overlapping flightlines? If false, overlaps will simply be classified. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--resolution={}".format(resolution)) - if filter: args.append("--filter") - return self.run_tool('classify_overlap_points', args, callback) # returns 1 if error - - def clip_lidar_to_polygon(self, i, polygons, output, callback=None): - """Clips a LiDAR point cloud to a vector polygon or polygons. - - Keyword arguments: - - i -- Input LiDAR file. - polygons -- Input vector polygons file. - output -- Output LiDAR file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--polygons='{}'".format(polygons)) - args.append("--output='{}'".format(output)) - return self.run_tool('clip_lidar_to_polygon', args, callback) # returns 1 if error - - def erase_polygon_from_lidar(self, i, polygons, output, callback=None): - """Erases (cuts out) a vector polygon or polygons from a LiDAR point cloud. - - Keyword arguments: - - i -- Input LiDAR file. - polygons -- Input vector polygons file. - output -- Output LiDAR file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--polygons='{}'".format(polygons)) - args.append("--output='{}'".format(output)) - return self.run_tool('erase_polygon_from_lidar', args, callback) # returns 1 if error - - def filter_lidar_classes(self, i, output, exclude_cls=None, callback=None): - """Removes points in a LAS file with certain specified class values. - - Keyword arguments: - - i -- Input LiDAR file. - output -- Output LiDAR file. - exclude_cls -- Optional exclude classes from interpolation; Valid class values range from 0 to 18, based on LAS specifications. Example, --exclude_cls='3,4,5,6,7,18'. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - if exclude_cls is not None: args.append("--exclude_cls='{}'".format(exclude_cls)) - return self.run_tool('filter_lidar_classes', args, callback) # returns 1 if error - - def filter_lidar_scan_angles(self, i, output, threshold, callback=None): - """Removes points in a LAS file with scan angles greater than a threshold. - - Keyword arguments: - - i -- Input LiDAR file. - output -- Output LiDAR file. - threshold -- Scan angle threshold. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--threshold='{}'".format(threshold)) - return self.run_tool('filter_lidar_scan_angles', args, callback) # returns 1 if error - - def find_flightline_edge_points(self, i, output, callback=None): - """Identifies points along a flightline's edge in a LAS file. - - Keyword arguments: - - i -- Input LiDAR file. - output -- Output file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('find_flightline_edge_points', args, callback) # returns 1 if error - - def flightline_overlap(self, i=None, output=None, resolution=1.0, callback=None): - """Reads a LiDAR (LAS) point file and outputs a raster containing the number of overlapping flight lines in each grid cell. - - Keyword arguments: - - i -- Input LiDAR file. - output -- Output file. - resolution -- Output raster's grid resolution. - callback -- Custom function for handling tool text outputs. - """ - args = [] - if i is not None: args.append("--input='{}'".format(i)) - if output is not None: args.append("--output='{}'".format(output)) - args.append("--resolution={}".format(resolution)) - return self.run_tool('flightline_overlap', args, callback) # returns 1 if error - - def height_above_ground(self, i=None, output=None, callback=None): - """Normalizes a LiDAR point cloud, providing the height above the nearest ground-classified point. - - Keyword arguments: - - i -- Input LiDAR file (including extension). - output -- Output raster file (including extension). - callback -- Custom function for handling tool text outputs. - """ - args = [] - if i is not None: args.append("--input='{}'".format(i)) - if output is not None: args.append("--output='{}'".format(output)) - return self.run_tool('height_above_ground', args, callback) # returns 1 if error - - def las_to_ascii(self, inputs, callback=None): - """Converts one or more LAS files into ASCII text files. - - Keyword arguments: - - inputs -- Input LiDAR files. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--inputs='{}'".format(inputs)) - return self.run_tool('las_to_ascii', args, callback) # returns 1 if error - - def las_to_multipoint_shapefile(self, i=None, callback=None): - """Converts one or more LAS files into MultipointZ vector Shapefiles. When the input parameter is not specified, the tool grids all LAS files contained within the working directory. - - Keyword arguments: - - i -- Input LiDAR file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - if i is not None: args.append("--input='{}'".format(i)) - return self.run_tool('las_to_multipoint_shapefile', args, callback) # returns 1 if error - - def las_to_shapefile(self, i=None, callback=None): - """Converts one or more LAS files into a vector Shapefile of POINT ShapeType. - - Keyword arguments: - - i -- Input LiDAR file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - if i is not None: args.append("--input='{}'".format(i)) - return self.run_tool('las_to_shapefile', args, callback) # returns 1 if error - - def las_to_zlidar(self, inputs=None, outdir=None, callback=None): - """Converts one or more LAS files into the zlidar compressed LiDAR data format. - - Keyword arguments: - - inputs -- Input LAS files. - outdir -- Output directory into which zlidar files are created. If unspecified, it is assumed to be the same as the inputs. - callback -- Custom function for handling tool text outputs. - """ - args = [] - if inputs is not None: args.append("--inputs='{}'".format(inputs)) - if outdir is not None: args.append("--outdir='{}'".format(outdir)) - return self.run_tool('las_to_zlidar', args, callback) # returns 1 if error - - def lidar_block_maximum(self, i=None, output=None, resolution=1.0, callback=None): - """Creates a block-maximum raster from an input LAS file. When the input/output parameters are not specified, the tool grids all LAS files contained within the working directory. - - Keyword arguments: - - i -- Input LiDAR file. - output -- Output file. - resolution -- Output raster's grid resolution. - callback -- Custom function for handling tool text outputs. - """ - args = [] - if i is not None: args.append("--input='{}'".format(i)) - if output is not None: args.append("--output='{}'".format(output)) - args.append("--resolution={}".format(resolution)) - return self.run_tool('lidar_block_maximum', args, callback) # returns 1 if error - - def lidar_block_minimum(self, i=None, output=None, resolution=1.0, callback=None): - """Creates a block-minimum raster from an input LAS file. When the input/output parameters are not specified, the tool grids all LAS files contained within the working directory. - - Keyword arguments: - - i -- Input LiDAR file. - output -- Output file. - resolution -- Output raster's grid resolution. - callback -- Custom function for handling tool text outputs. - """ - args = [] - if i is not None: args.append("--input='{}'".format(i)) - if output is not None: args.append("--output='{}'".format(output)) - args.append("--resolution={}".format(resolution)) - return self.run_tool('lidar_block_minimum', args, callback) # returns 1 if error - - def lidar_classify_subset(self, base, subset, output, subset_class, nonsubset_class=None, callback=None): - """Classifies the values in one LiDAR point cloud that correpond with points in a subset cloud. - - Keyword arguments: - - base -- Input base LiDAR file. - subset -- Input subset LiDAR file. - output -- Output LiDAR file. - subset_class -- Subset point class value (must be 0-18; see LAS specifications). - nonsubset_class -- Non-subset point class value (must be 0-18; see LAS specifications). - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--base='{}'".format(base)) - args.append("--subset='{}'".format(subset)) - args.append("--output='{}'".format(output)) - args.append("--subset_class='{}'".format(subset_class)) - if nonsubset_class is not None: args.append("--nonsubset_class='{}'".format(nonsubset_class)) - return self.run_tool('lidar_classify_subset', args, callback) # returns 1 if error - - def lidar_colourize(self, in_lidar, in_image, output, callback=None): - """Adds the red-green-blue colour fields of a LiDAR (LAS) file based on an input image. - - Keyword arguments: - - in_lidar -- Input LiDAR file. - in_image -- Input colour image file. - output -- Output LiDAR file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--in_lidar='{}'".format(in_lidar)) - args.append("--in_image='{}'".format(in_image)) - args.append("--output='{}'".format(output)) - return self.run_tool('lidar_colourize', args, callback) # returns 1 if error - - def lidar_elevation_slice(self, i, output, minz=None, maxz=None, cls=False, inclassval=2, outclassval=1, callback=None): - """Outputs all of the points within a LiDAR (LAS) point file that lie between a specified elevation range. - - Keyword arguments: - - i -- Input LiDAR file. - output -- Output LiDAR file. - minz -- Minimum elevation value (optional). - maxz -- Maximum elevation value (optional). - cls -- Optional boolean flag indicating whether points outside the range should be retained in output but reclassified. - inclassval -- Optional parameter specifying the class value assigned to points within the slice. - outclassval -- Optional parameter specifying the class value assigned to points within the slice. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - if minz is not None: args.append("--minz='{}'".format(minz)) - if maxz is not None: args.append("--maxz='{}'".format(maxz)) - if cls: args.append("--class") - args.append("--inclassval={}".format(inclassval)) - args.append("--outclassval={}".format(outclassval)) - return self.run_tool('lidar_elevation_slice', args, callback) # returns 1 if error - - def lidar_ground_point_filter(self, i, output, radius=2.0, min_neighbours=0, slope_threshold=45.0, height_threshold=1.0, classify=True, slope_norm=True, height_above_ground=False, callback=None): - """Identifies ground points within LiDAR dataset using a slope-based method. - - Keyword arguments: - - i -- Input LiDAR file. - output -- Output LiDAR file. - radius -- Search Radius. - min_neighbours -- The minimum number of neighbouring points within search areas. If fewer points than this threshold are idenfied during the fixed-radius search, a subsequent kNN search is performed to identify the k number of neighbours. - slope_threshold -- Maximum inter-point slope to be considered an off-terrain point. - height_threshold -- Inter-point height difference to be considered an off-terrain point. - classify -- Classify points as ground (2) or off-ground (1). - slope_norm -- Perform initial ground slope normalization?. - height_above_ground -- Transform output to height above average ground elevation?. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--radius={}".format(radius)) - args.append("--min_neighbours={}".format(min_neighbours)) - args.append("--slope_threshold={}".format(slope_threshold)) - args.append("--height_threshold={}".format(height_threshold)) - if classify: args.append("--classify") - if slope_norm: args.append("--slope_norm") - if height_above_ground: args.append("--height_above_ground") - return self.run_tool('lidar_ground_point_filter', args, callback) # returns 1 if error - - def lidar_hex_binning(self, i, output, width, orientation="horizontal", callback=None): - """Hex-bins a set of LiDAR points. - - Keyword arguments: - - i -- Input base file. - output -- Output vector polygon file. - width -- The grid cell width. - orientation -- Grid Orientation, 'horizontal' or 'vertical'. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--width='{}'".format(width)) - args.append("--orientation={}".format(orientation)) - return self.run_tool('lidar_hex_binning', args, callback) # returns 1 if error - - def lidar_hillshade(self, i, output, azimuth=315.0, altitude=30.0, radius=1.0, callback=None): - """Calculates a hillshade value for points within a LAS file and stores these data in the RGB field. - - Keyword arguments: - - i -- Input LiDAR file. - output -- Output file. - azimuth -- Illumination source azimuth in degrees. - altitude -- Illumination source altitude in degrees. - radius -- Search Radius. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--azimuth={}".format(azimuth)) - args.append("--altitude={}".format(altitude)) - args.append("--radius={}".format(radius)) - return self.run_tool('lidar_hillshade', args, callback) # returns 1 if error - - def lidar_histogram(self, i, output, parameter="elevation", clip=1.0, callback=None): - """Creates a histogram of LiDAR data. - - Keyword arguments: - - i -- Input LiDAR file. - output -- Output HTML file (default name will be based on input file if unspecified). - parameter -- Parameter; options are 'elevation' (default), 'intensity', 'scan angle', 'class'. - clip -- Amount to clip distribution tails (in percent). - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--parameter={}".format(parameter)) - args.append("--clip={}".format(clip)) - return self.run_tool('lidar_histogram', args, callback) # returns 1 if error - - def lidar_idw_interpolation(self, i=None, output=None, parameter="elevation", returns="all", resolution=1.0, weight=1.0, radius=2.5, exclude_cls=None, minz=None, maxz=None, callback=None): - """Interpolates LAS files using an inverse-distance weighted (IDW) scheme. When the input/output parameters are not specified, the tool interpolates all LAS files contained within the working directory. - - Keyword arguments: - - i -- Input LiDAR file (including extension). - output -- Output raster file (including extension). - parameter -- Interpolation parameter; options are 'elevation' (default), 'intensity', 'class', 'return_number', 'number_of_returns', 'scan angle', 'rgb', 'user data'. - returns -- Point return types to include; options are 'all' (default), 'last', 'first'. - resolution -- Output raster's grid resolution. - weight -- IDW weight value. - radius -- Search Radius. - exclude_cls -- Optional exclude classes from interpolation; Valid class values range from 0 to 18, based on LAS specifications. Example, --exclude_cls='3,4,5,6,7,18'. - minz -- Optional minimum elevation for inclusion in interpolation. - maxz -- Optional maximum elevation for inclusion in interpolation. - callback -- Custom function for handling tool text outputs. - """ - args = [] - if i is not None: args.append("--input='{}'".format(i)) - if output is not None: args.append("--output='{}'".format(output)) - args.append("--parameter={}".format(parameter)) - args.append("--returns={}".format(returns)) - args.append("--resolution={}".format(resolution)) - args.append("--weight={}".format(weight)) - args.append("--radius={}".format(radius)) - if exclude_cls is not None: args.append("--exclude_cls='{}'".format(exclude_cls)) - if minz is not None: args.append("--minz='{}'".format(minz)) - if maxz is not None: args.append("--maxz='{}'".format(maxz)) - return self.run_tool('lidar_idw_interpolation', args, callback) # returns 1 if error - - def lidar_info(self, i, output=None, vlr=True, geokeys=True, callback=None): - """Prints information about a LiDAR (LAS) dataset, including header, point return frequency, and classification data and information about the variable length records (VLRs) and geokeys. - - Keyword arguments: - - i -- Input LiDAR file. - output -- Output HTML file for summary report. - vlr -- Flag indicating whether or not to print the variable length records (VLRs). - geokeys -- Flag indicating whether or not to print the geokeys. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - if output is not None: args.append("--output='{}'".format(output)) - if vlr: args.append("--vlr") - if geokeys: args.append("--geokeys") - return self.run_tool('lidar_info', args, callback) # returns 1 if error - - def lidar_join(self, inputs, output, callback=None): - """Joins multiple LiDAR (LAS) files into a single LAS file. - - Keyword arguments: - - inputs -- Input LiDAR files. - output -- Output LiDAR file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--inputs='{}'".format(inputs)) - args.append("--output='{}'".format(output)) - return self.run_tool('lidar_join', args, callback) # returns 1 if error - - def lidar_kappa_index(self, input1, input2, output, class_accuracy, resolution=1.0, callback=None): - """Performs a kappa index of agreement (KIA) analysis on the classifications of two LAS files. - - Keyword arguments: - - input1 -- Input LiDAR classification file. - input2 -- Input LiDAR reference file. - output -- Output HTML file. - class_accuracy -- Output classification accuracy raster file. - resolution -- Output raster's grid resolution. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input1='{}'".format(input1)) - args.append("--input2='{}'".format(input2)) - args.append("--output='{}'".format(output)) - args.append("--class_accuracy='{}'".format(class_accuracy)) - args.append("--resolution={}".format(resolution)) - return self.run_tool('lidar_kappa_index', args, callback) # returns 1 if error - - def lidar_nearest_neighbour_gridding(self, i=None, output=None, parameter="elevation", returns="all", resolution=1.0, radius=2.5, exclude_cls=None, minz=None, maxz=None, callback=None): - """Grids LAS files using nearest-neighbour scheme. When the input/output parameters are not specified, the tool grids all LAS files contained within the working directory. - - Keyword arguments: - - i -- Input LiDAR file (including extension). - output -- Output raster file (including extension). - parameter -- Interpolation parameter; options are 'elevation' (default), 'intensity', 'class', 'return_number', 'number_of_returns', 'scan angle', 'rgb', 'user data'. - returns -- Point return types to include; options are 'all' (default), 'last', 'first'. - resolution -- Output raster's grid resolution. - radius -- Search Radius. - exclude_cls -- Optional exclude classes from interpolation; Valid class values range from 0 to 18, based on LAS specifications. Example, --exclude_cls='3,4,5,6,7,18'. - minz -- Optional minimum elevation for inclusion in interpolation. - maxz -- Optional maximum elevation for inclusion in interpolation. - callback -- Custom function for handling tool text outputs. - """ - args = [] - if i is not None: args.append("--input='{}'".format(i)) - if output is not None: args.append("--output='{}'".format(output)) - args.append("--parameter={}".format(parameter)) - args.append("--returns={}".format(returns)) - args.append("--resolution={}".format(resolution)) - args.append("--radius={}".format(radius)) - if exclude_cls is not None: args.append("--exclude_cls='{}'".format(exclude_cls)) - if minz is not None: args.append("--minz='{}'".format(minz)) - if maxz is not None: args.append("--maxz='{}'".format(maxz)) - return self.run_tool('lidar_nearest_neighbour_gridding', args, callback) # returns 1 if error - - def lidar_point_density(self, i=None, output=None, returns="all", resolution=1.0, radius=2.5, exclude_cls=None, minz=None, maxz=None, callback=None): - """Calculates the spatial pattern of point density for a LiDAR data set. When the input/output parameters are not specified, the tool grids all LAS files contained within the working directory. - - Keyword arguments: - - i -- Input LiDAR file (including extension). - output -- Output raster file (including extension). - returns -- Point return types to include; options are 'all' (default), 'last', 'first'. - resolution -- Output raster's grid resolution. - radius -- Search radius. - exclude_cls -- Optional exclude classes from interpolation; Valid class values range from 0 to 18, based on LAS specifications. Example, --exclude_cls='3,4,5,6,7,18'. - minz -- Optional minimum elevation for inclusion in interpolation. - maxz -- Optional maximum elevation for inclusion in interpolation. - callback -- Custom function for handling tool text outputs. - """ - args = [] - if i is not None: args.append("--input='{}'".format(i)) - if output is not None: args.append("--output='{}'".format(output)) - args.append("--returns={}".format(returns)) - args.append("--resolution={}".format(resolution)) - args.append("--radius={}".format(radius)) - if exclude_cls is not None: args.append("--exclude_cls='{}'".format(exclude_cls)) - if minz is not None: args.append("--minz='{}'".format(minz)) - if maxz is not None: args.append("--maxz='{}'".format(maxz)) - return self.run_tool('lidar_point_density', args, callback) # returns 1 if error - - def lidar_point_stats(self, i=None, resolution=1.0, num_points=True, num_pulses=False, avg_points_per_pulse=True, z_range=False, intensity_range=False, predom_class=False, callback=None): - """Creates several rasters summarizing the distribution of LAS point data. When the input/output parameters are not specified, the tool works on all LAS files contained within the working directory. - - Keyword arguments: - - i -- Input LiDAR file. - resolution -- Output raster's grid resolution. - num_points -- Flag indicating whether or not to output the number of points (returns) raster. - num_pulses -- Flag indicating whether or not to output the number of pulses raster. - avg_points_per_pulse -- Flag indicating whether or not to output the average number of points (returns) per pulse raster. - z_range -- Flag indicating whether or not to output the elevation range raster. - intensity_range -- Flag indicating whether or not to output the intensity range raster. - predom_class -- Flag indicating whether or not to output the predominant classification raster. - callback -- Custom function for handling tool text outputs. - """ - args = [] - if i is not None: args.append("--input='{}'".format(i)) - args.append("--resolution={}".format(resolution)) - if num_points: args.append("--num_points") - if num_pulses: args.append("--num_pulses") - if avg_points_per_pulse: args.append("--avg_points_per_pulse") - if z_range: args.append("--z_range") - if intensity_range: args.append("--intensity_range") - if predom_class: args.append("--predom_class") - return self.run_tool('lidar_point_stats', args, callback) # returns 1 if error - - def lidar_ransac_planes(self, i, output, radius=2.0, num_iter=50, num_samples=5, threshold=0.35, model_size=8, max_slope=80.0, classify=False, callback=None): - """Performs a RANSAC analysis to identify points within a LiDAR point cloud that belong to linear planes. - - Keyword arguments: - - i -- Input LiDAR file. - output -- Output LiDAR file. - radius -- Search Radius. - num_iter -- Number of iterations. - num_samples -- Number of sample points on which to build the model. - threshold -- Threshold used to determine inlier points. - model_size -- Acceptable model size. - max_slope -- Maximum planar slope. - classify -- Classify points as ground (2) or off-ground (1). - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--radius={}".format(radius)) - args.append("--num_iter={}".format(num_iter)) - args.append("--num_samples={}".format(num_samples)) - args.append("--threshold={}".format(threshold)) - args.append("--model_size={}".format(model_size)) - args.append("--max_slope={}".format(max_slope)) - if classify: args.append("--classify") - return self.run_tool('lidar_ransac_planes', args, callback) # returns 1 if error - - def lidar_rbf_interpolation(self, i=None, output=None, parameter="elevation", returns="all", resolution=1.0, num_points=20, exclude_cls=None, minz=None, maxz=None, func_type="ThinPlateSpline", poly_order="none", weight=5, callback=None): - """Interpolates LAS files using a radial basis function (RBF) scheme. When the input/output parameters are not specified, the tool interpolates all LAS files contained within the working directory. - - Keyword arguments: - - i -- Input LiDAR file (including extension). - output -- Output raster file (including extension). - parameter -- Interpolation parameter; options are 'elevation' (default), 'intensity', 'class', 'return_number', 'number_of_returns', 'scan angle', 'rgb', 'user data'. - returns -- Point return types to include; options are 'all' (default), 'last', 'first'. - resolution -- Output raster's grid resolution. - num_points -- Number of points. - exclude_cls -- Optional exclude classes from interpolation; Valid class values range from 0 to 18, based on LAS specifications. Example, --exclude_cls='3,4,5,6,7,18'. - minz -- Optional minimum elevation for inclusion in interpolation. - maxz -- Optional maximum elevation for inclusion in interpolation. - func_type -- Radial basis function type; options are 'ThinPlateSpline' (default), 'PolyHarmonic', 'Gaussian', 'MultiQuadric', 'InverseMultiQuadric'. - poly_order -- Polynomial order; options are 'none' (default), 'constant', 'affine'. - weight -- Weight parameter used in basis function. - callback -- Custom function for handling tool text outputs. - """ - args = [] - if i is not None: args.append("--input='{}'".format(i)) - if output is not None: args.append("--output='{}'".format(output)) - args.append("--parameter={}".format(parameter)) - args.append("--returns={}".format(returns)) - args.append("--resolution={}".format(resolution)) - args.append("--num_points={}".format(num_points)) - if exclude_cls is not None: args.append("--exclude_cls='{}'".format(exclude_cls)) - if minz is not None: args.append("--minz='{}'".format(minz)) - if maxz is not None: args.append("--maxz='{}'".format(maxz)) - args.append("--func_type={}".format(func_type)) - args.append("--poly_order={}".format(poly_order)) - args.append("--weight={}".format(weight)) - return self.run_tool('lidar_rbf_interpolation', args, callback) # returns 1 if error - - def lidar_remove_duplicates(self, i, output, include_z=False, callback=None): - """Removes duplicate points from a LiDAR data set. - - Keyword arguments: - - i -- Input LiDAR file. - output -- Output LiDAR file. - include_z -- Include z-values in point comparison?. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - if include_z: args.append("--include_z") - return self.run_tool('lidar_remove_duplicates', args, callback) # returns 1 if error - - def lidar_remove_outliers(self, i, output, radius=2.0, elev_diff=50.0, use_median=False, classify=True, callback=None): - """Removes outliers (high and low points) in a LiDAR point cloud. - - Keyword arguments: - - i -- Input LiDAR file. - output -- Output LiDAR file. - radius -- Search Radius. - elev_diff -- Max. elevation difference. - use_median -- Optional flag indicating whether to use the difference from median elevation rather than mean. - classify -- Classify points as ground (2) or off-ground (1). - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--radius={}".format(radius)) - args.append("--elev_diff={}".format(elev_diff)) - if use_median: args.append("--use_median") - if classify: args.append("--classify") - return self.run_tool('lidar_remove_outliers', args, callback) # returns 1 if error - - def lidar_segmentation(self, i, output, radius=2.0, num_iter=50, num_samples=10, threshold=0.15, model_size=15, max_slope=80.0, norm_diff=10.0, maxzdiff=1.0, classes=False, ground=False, callback=None): - """Segments a LiDAR point cloud based on differences in the orientation of fitted planar surfaces and point proximity. - - Keyword arguments: - - i -- Input LiDAR file. - output -- Output LiDAR file. - radius -- Search Radius. - num_iter -- Number of iterations. - num_samples -- Number of sample points on which to build the model. - threshold -- Threshold used to determine inlier points. - model_size -- Acceptable model size. - max_slope -- Maximum planar slope. - norm_diff -- Maximum difference in normal vectors, in degrees. - maxzdiff -- Maximum difference in elevation (z units) between neighbouring points of the same segment. - classes -- Segments don't cross class boundaries. - ground -- Classify the largest segment as ground points?. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--radius={}".format(radius)) - args.append("--num_iter={}".format(num_iter)) - args.append("--num_samples={}".format(num_samples)) - args.append("--threshold={}".format(threshold)) - args.append("--model_size={}".format(model_size)) - args.append("--max_slope={}".format(max_slope)) - args.append("--norm_diff={}".format(norm_diff)) - args.append("--maxzdiff={}".format(maxzdiff)) - if classes: args.append("--classes") - if ground: args.append("--ground") - return self.run_tool('lidar_segmentation', args, callback) # returns 1 if error - - def lidar_segmentation_based_filter(self, i, output, radius=5.0, norm_diff=2.0, maxzdiff=1.0, classify=False, callback=None): - """Identifies ground points within LiDAR point clouds using a segmentation based approach. - - Keyword arguments: - - i -- Input LiDAR file. - output -- Output file. - radius -- Search Radius. - norm_diff -- Maximum difference in normal vectors, in degrees. - maxzdiff -- Maximum difference in elevation (z units) between neighbouring points of the same segment. - classify -- Classify points as ground (2) or off-ground (1). - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--radius={}".format(radius)) - args.append("--norm_diff={}".format(norm_diff)) - args.append("--maxzdiff={}".format(maxzdiff)) - if classify: args.append("--classify") - return self.run_tool('lidar_segmentation_based_filter', args, callback) # returns 1 if error - - def lidar_thin(self, i, output, resolution=2.0, method="lowest", save_filtered=False, callback=None): - """Thins a LiDAR point cloud, reducing point density. - - Keyword arguments: - - i -- Input LiDAR file. - output -- Output LiDAR file. - resolution -- The size of the square area used to evaluate nearby points in the LiDAR data. - method -- Point selection method; options are 'first', 'last', 'lowest' (default), 'highest', 'nearest'. - save_filtered -- Save filtered points to seperate file?. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--resolution={}".format(resolution)) - args.append("--method={}".format(method)) - if save_filtered: args.append("--save_filtered") - return self.run_tool('lidar_thin', args, callback) # returns 1 if error - - def lidar_thin_high_density(self, i, output, density, resolution=1.0, save_filtered=False, callback=None): - """Thins points from high density areas within a LiDAR point cloud. - - Keyword arguments: - - i -- Input LiDAR file. - output -- Output LiDAR file. - resolution -- Output raster's grid resolution. - density -- Max. point density (points / m^3). - save_filtered -- Save filtered points to seperate file?. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--resolution={}".format(resolution)) - args.append("--density='{}'".format(density)) - if save_filtered: args.append("--save_filtered") - return self.run_tool('lidar_thin_high_density', args, callback) # returns 1 if error - - def lidar_tile(self, i, width=1000.0, height=1000.0, origin_x=0.0, origin_y=0.0, min_points=2, callback=None): - """Tiles a LiDAR LAS file into multiple LAS files. - - Keyword arguments: - - i -- Input LiDAR file. - width -- Width of tiles in the X dimension; default 1000.0. - height -- Height of tiles in the Y dimension. - origin_x -- Origin point X coordinate for tile grid. - origin_y -- Origin point Y coordinate for tile grid. - min_points -- Minimum number of points contained in a tile for it to be saved. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--width={}".format(width)) - args.append("--height={}".format(height)) - args.append("--origin_x={}".format(origin_x)) - args.append("--origin_y={}".format(origin_y)) - args.append("--min_points={}".format(min_points)) - return self.run_tool('lidar_tile', args, callback) # returns 1 if error - - def lidar_tile_footprint(self, output, i=None, hull=False, callback=None): - """Creates a vector polygon of the convex hull of a LiDAR point cloud. When the input/output parameters are not specified, the tool works with all LAS files contained within the working directory. - - Keyword arguments: - - i -- Input LiDAR file. - output -- Output vector polygon file. - hull -- Identify the convex hull around points. - callback -- Custom function for handling tool text outputs. - """ - args = [] - if i is not None: args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - if hull: args.append("--hull") - return self.run_tool('lidar_tile_footprint', args, callback) # returns 1 if error - - def lidar_tin_gridding(self, i=None, output=None, parameter="elevation", returns="all", resolution=1.0, exclude_cls=None, minz=None, maxz=None, max_triangle_edge_length=None, callback=None): - """Creates a raster grid based on a Delaunay triangular irregular network (TIN) fitted to LiDAR points. - - Keyword arguments: - - i -- Input LiDAR file (including extension). - output -- Output raster file (including extension). - parameter -- Interpolation parameter; options are 'elevation' (default), 'intensity', 'class', 'return_number', 'number_of_returns', 'scan angle', 'rgb', 'user data'. - returns -- Point return types to include; options are 'all' (default), 'last', 'first'. - resolution -- Output raster's grid resolution. - exclude_cls -- Optional exclude classes from interpolation; Valid class values range from 0 to 18, based on LAS specifications. Example, --exclude_cls='3,4,5,6,7,18'. - minz -- Optional minimum elevation for inclusion in interpolation. - maxz -- Optional maximum elevation for inclusion in interpolation. - max_triangle_edge_length -- Optional maximum triangle edge length; triangles larger than this size will not be gridded. - callback -- Custom function for handling tool text outputs. - """ - args = [] - if i is not None: args.append("--input='{}'".format(i)) - if output is not None: args.append("--output='{}'".format(output)) - args.append("--parameter={}".format(parameter)) - args.append("--returns={}".format(returns)) - args.append("--resolution={}".format(resolution)) - if exclude_cls is not None: args.append("--exclude_cls='{}'".format(exclude_cls)) - if minz is not None: args.append("--minz='{}'".format(minz)) - if maxz is not None: args.append("--maxz='{}'".format(maxz)) - if max_triangle_edge_length is not None: args.append("--max_triangle_edge_length='{}'".format(max_triangle_edge_length)) - return self.run_tool('lidar_tin_gridding', args, callback) # returns 1 if error - - def lidar_tophat_transform(self, i, output, radius=1.0, callback=None): - """Performs a white top-hat transform on a Lidar dataset; as an estimate of height above ground, this is useful for modelling the vegetation canopy. - - Keyword arguments: - - i -- Input LiDAR file. - output -- Output LiDAR file. - radius -- Search Radius. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--radius={}".format(radius)) - return self.run_tool('lidar_tophat_transform', args, callback) # returns 1 if error - - def normal_vectors(self, i, output, radius=1.0, callback=None): - """Calculates normal vectors for points within a LAS file and stores these data (XYZ vector components) in the RGB field. - - Keyword arguments: - - i -- Input LiDAR file. - output -- Output LiDAR file. - radius -- Search Radius. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--radius={}".format(radius)) - return self.run_tool('normal_vectors', args, callback) # returns 1 if error - - def select_tiles_by_polygon(self, indir, outdir, polygons, callback=None): - """Copies LiDAR tiles overlapping with a polygon into an output directory. - - Keyword arguments: - - indir -- Input LAS file source directory. - outdir -- Output directory into which LAS files within the polygon are copied. - polygons -- Input vector polygons file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--indir='{}'".format(indir)) - args.append("--outdir='{}'".format(outdir)) - args.append("--polygons='{}'".format(polygons)) - return self.run_tool('select_tiles_by_polygon', args, callback) # returns 1 if error - - def zlidar_to_las(self, inputs=None, outdir=None, callback=None): - """Converts one or more zlidar files into the LAS data format. - - Keyword arguments: - - inputs -- Input ZLidar files. - outdir -- Output directory into which zlidar files are created. If unspecified, it is assumed to be the same as the inputs. - callback -- Custom function for handling tool text outputs. - """ - args = [] - if inputs is not None: args.append("--inputs='{}'".format(inputs)) - if outdir is not None: args.append("--outdir='{}'".format(outdir)) - return self.run_tool('zlidar_to_las', args, callback) # returns 1 if error - - ######################## - # Math and Stats Tools # - ######################## - - def And(self, input1, input2, output, callback=None): - """Performs a logical AND operator on two Boolean raster images. - - Keyword arguments: - - input1 -- Input raster file. - input2 -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input1='{}'".format(input1)) - args.append("--input2='{}'".format(input2)) - args.append("--output='{}'".format(output)) - return self.run_tool('and', args, callback) # returns 1 if error - - def Not(self, input1, input2, output, callback=None): - """Performs a logical NOT operator on two Boolean raster images. - - Keyword arguments: - - input1 -- Input raster file. - input2 -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input1='{}'".format(input1)) - args.append("--input2='{}'".format(input2)) - args.append("--output='{}'".format(output)) - return self.run_tool('not', args, callback) # returns 1 if error - - def Or(self, input1, input2, output, callback=None): - """Performs a logical OR operator on two Boolean raster images. - - Keyword arguments: - - input1 -- Input raster file. - input2 -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input1='{}'".format(input1)) - args.append("--input2='{}'".format(input2)) - args.append("--output='{}'".format(output)) - return self.run_tool('or', args, callback) # returns 1 if error - - def absolute_value(self, i, output, callback=None): - """Calculates the absolute value of every cell in a raster. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('absolute_value', args, callback) # returns 1 if error - - def add(self, input1, input2, output, callback=None): - """Performs an addition operation on two rasters or a raster and a constant value. - - Keyword arguments: - - input1 -- Input raster file or constant value. - input2 -- Input raster file or constant value. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input1='{}'".format(input1)) - args.append("--input2='{}'".format(input2)) - args.append("--output='{}'".format(output)) - return self.run_tool('add', args, callback) # returns 1 if error - - def anova(self, i, features, output, callback=None): - """Performs an analysis of variance (ANOVA) test on a raster dataset. - - Keyword arguments: - - i -- Input raster file. - features -- Feature definition (or class) raster. - output -- Output HTML file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--features='{}'".format(features)) - args.append("--output='{}'".format(output)) - return self.run_tool('anova', args, callback) # returns 1 if error - - def arc_cos(self, i, output, callback=None): - """Returns the inverse cosine (arccos) of each values in a raster. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('arc_cos', args, callback) # returns 1 if error - - def arc_sin(self, i, output, callback=None): - """Returns the inverse sine (arcsin) of each values in a raster. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('arc_sin', args, callback) # returns 1 if error - - def arc_tan(self, i, output, callback=None): - """Returns the inverse tangent (arctan) of each values in a raster. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('arc_tan', args, callback) # returns 1 if error - - def arcosh(self, i, output, callback=None): - """Returns the inverse hyperbolic cosine (arcosh) of each values in a raster. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('arcosh', args, callback) # returns 1 if error - - def arsinh(self, i, output, callback=None): - """Returns the inverse hyperbolic sine (arsinh) of each values in a raster. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('arsinh', args, callback) # returns 1 if error - - def artanh(self, i, output, callback=None): - """Returns the inverse hyperbolic tangent (arctanh) of each values in a raster. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('artanh', args, callback) # returns 1 if error - - def atan2(self, input_y, input_x, output, callback=None): - """Returns the 2-argument inverse tangent (atan2). - - Keyword arguments: - - input_y -- Input y raster file or constant value (rise). - input_x -- Input x raster file or constant value (run). - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input_y='{}'".format(input_y)) - args.append("--input_x='{}'".format(input_x)) - args.append("--output='{}'".format(output)) - return self.run_tool('atan2', args, callback) # returns 1 if error - - def attribute_correlation(self, i, output=None, callback=None): - """Performs a correlation analysis on attribute fields from a vector database. - - Keyword arguments: - - i -- Input vector file. - output -- Output HTML file (default name will be based on input file if unspecified). - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - if output is not None: args.append("--output='{}'".format(output)) - return self.run_tool('attribute_correlation', args, callback) # returns 1 if error - - def attribute_correlation_neighbourhood_analysis(self, i, field1, field2, radius=None, min_points=None, stat="pearson", callback=None): - """Performs a correlation on two input vector attributes within a neighbourhood search windows. - - Keyword arguments: - - i -- Input vector file. - field1 -- First input field name (dependent variable) in attribute table. - field2 -- Second input field name (independent variable) in attribute table. - radius -- Search Radius (in map units). - min_points -- Minimum number of points. - stat -- Correlation type; one of 'pearson' (default) and 'spearman'. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--field1='{}'".format(field1)) - args.append("--field2='{}'".format(field2)) - if radius is not None: args.append("--radius='{}'".format(radius)) - if min_points is not None: args.append("--min_points='{}'".format(min_points)) - args.append("--stat={}".format(stat)) - return self.run_tool('attribute_correlation_neighbourhood_analysis', args, callback) # returns 1 if error - - def attribute_histogram(self, i, field, output, callback=None): - """Creates a histogram for the field values of a vector's attribute table. - - Keyword arguments: - - i -- Input raster file. - field -- Input field name in attribute table. - output -- Output HTML file (default name will be based on input file if unspecified). - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--field='{}'".format(field)) - args.append("--output='{}'".format(output)) - return self.run_tool('attribute_histogram', args, callback) # returns 1 if error - - def attribute_scattergram(self, i, fieldx, fieldy, output, trendline=False, callback=None): - """Creates a scattergram for two field values of a vector's attribute table. - - Keyword arguments: - - i -- Input raster file. - fieldx -- Input field name in attribute table for the x-axis. - fieldy -- Input field name in attribute table for the y-axis. - output -- Output HTML file (default name will be based on input file if unspecified). - trendline -- Draw the trendline. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--fieldx='{}'".format(fieldx)) - args.append("--fieldy='{}'".format(fieldy)) - args.append("--output='{}'".format(output)) - if trendline: args.append("--trendline") - return self.run_tool('attribute_scattergram', args, callback) # returns 1 if error - - def ceil(self, i, output, callback=None): - """Returns the smallest (closest to negative infinity) value that is greater than or equal to the values in a raster. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('ceil', args, callback) # returns 1 if error - - def cos(self, i, output, callback=None): - """Returns the cosine (cos) of each values in a raster. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('cos', args, callback) # returns 1 if error - - def cosh(self, i, output, callback=None): - """Returns the hyperbolic cosine (cosh) of each values in a raster. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('cosh', args, callback) # returns 1 if error - - def crispness_index(self, i, output=None, callback=None): - """Calculates the Crispness Index, which is used to quantify how crisp (or conversely how fuzzy) a probability image is. - - Keyword arguments: - - i -- Input raster file. - output -- Optional output html file (default name will be based on input file if unspecified). - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - if output is not None: args.append("--output='{}'".format(output)) - return self.run_tool('crispness_index', args, callback) # returns 1 if error - - def cross_tabulation(self, input1, input2, output, callback=None): - """Performs a cross-tabulation on two categorical images. - - Keyword arguments: - - input1 -- Input raster file 1. - input2 -- Input raster file 1. - output -- Output HTML file (default name will be based on input file if unspecified). - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input1='{}'".format(input1)) - args.append("--input2='{}'".format(input2)) - args.append("--output='{}'".format(output)) - return self.run_tool('cross_tabulation', args, callback) # returns 1 if error - - def cumulative_distribution(self, i, output, callback=None): - """Converts a raster image to its cumulative distribution function. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('cumulative_distribution', args, callback) # returns 1 if error - - def decrement(self, i, output, callback=None): - """Decreases the values of each grid cell in an input raster by 1.0 (see also InPlaceSubtract). - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('decrement', args, callback) # returns 1 if error - - def divide(self, input1, input2, output, callback=None): - """Performs a division operation on two rasters or a raster and a constant value. - - Keyword arguments: - - input1 -- Input raster file or constant value. - input2 -- Input raster file or constant value. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input1='{}'".format(input1)) - args.append("--input2='{}'".format(input2)) - args.append("--output='{}'".format(output)) - return self.run_tool('divide', args, callback) # returns 1 if error - - def equal_to(self, input1, input2, output, callback=None): - """Performs a equal-to comparison operation on two rasters or a raster and a constant value. - - Keyword arguments: - - input1 -- Input raster file or constant value. - input2 -- Input raster file or constant value. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input1='{}'".format(input1)) - args.append("--input2='{}'".format(input2)) - args.append("--output='{}'".format(output)) - return self.run_tool('equal_to', args, callback) # returns 1 if error - - def exp(self, i, output, callback=None): - """Returns the exponential (base e) of values in a raster. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('exp', args, callback) # returns 1 if error - - def exp2(self, i, output, callback=None): - """Returns the exponential (base 2) of values in a raster. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('exp2', args, callback) # returns 1 if error - - def floor(self, i, output, callback=None): - """Returns the largest (closest to positive infinity) value that is less than or equal to the values in a raster. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('floor', args, callback) # returns 1 if error - - def greater_than(self, input1, input2, output, incl_equals=False, callback=None): - """Performs a greater-than comparison operation on two rasters or a raster and a constant value. - - Keyword arguments: - - input1 -- Input raster file or constant value. - input2 -- Input raster file or constant value. - output -- Output raster file. - incl_equals -- Perform a greater-than-or-equal-to operation. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input1='{}'".format(input1)) - args.append("--input2='{}'".format(input2)) - args.append("--output='{}'".format(output)) - if incl_equals: args.append("--incl_equals") - return self.run_tool('greater_than', args, callback) # returns 1 if error - - def image_autocorrelation(self, inputs, output, contiguity="Rook", callback=None): - """Performs Moran's I analysis on two or more input images. - - Keyword arguments: - - inputs -- Input raster files. - contiguity -- Contiguity type. - output -- Output HTML file (default name will be based on input file if unspecified). - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--inputs='{}'".format(inputs)) - args.append("--contiguity={}".format(contiguity)) - args.append("--output='{}'".format(output)) - return self.run_tool('image_autocorrelation', args, callback) # returns 1 if error - - def image_correlation(self, inputs, output=None, callback=None): - """Performs image correlation on two or more input images. - - Keyword arguments: - - inputs -- Input raster files. - output -- Output HTML file (default name will be based on input file if unspecified). - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--inputs='{}'".format(inputs)) - if output is not None: args.append("--output='{}'".format(output)) - return self.run_tool('image_correlation', args, callback) # returns 1 if error - - def image_correlation_neighbourhood_analysis(self, input1, input2, output1, output2, filter=11, stat="pearson", callback=None): - """Performs image correlation on two input images neighbourhood search windows. - - Keyword arguments: - - input1 -- Input raster file. - input2 -- Input raster file. - output1 -- Output correlation (r-value or rho) raster file. - output2 -- Output significance (p-value) raster file. - filter -- Size of the filter kernel. - stat -- Correlation type; one of 'pearson' (default) and 'spearman'. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input1='{}'".format(input1)) - args.append("--input2='{}'".format(input2)) - args.append("--output1='{}'".format(output1)) - args.append("--output2='{}'".format(output2)) - args.append("--filter={}".format(filter)) - args.append("--stat={}".format(stat)) - return self.run_tool('image_correlation_neighbourhood_analysis', args, callback) # returns 1 if error - - def image_regression(self, input1, input2, output, out_residuals=None, standardize=False, scattergram=False, num_samples=1000, callback=None): - """Performs image regression analysis on two input images. - - Keyword arguments: - - input1 -- Input raster file (independent variable, X). - input2 -- Input raster file (dependent variable, Y). - output -- Output HTML file for regression summary report. - out_residuals -- Output raster regression resdidual file. - standardize -- Optional flag indicating whether to standardize the residuals map. - scattergram -- Optional flag indicating whether to output a scattergram. - num_samples -- Number of samples used to create scattergram. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input1='{}'".format(input1)) - args.append("--input2='{}'".format(input2)) - args.append("--output='{}'".format(output)) - if out_residuals is not None: args.append("--out_residuals='{}'".format(out_residuals)) - if standardize: args.append("--standardize") - if scattergram: args.append("--scattergram") - args.append("--num_samples={}".format(num_samples)) - return self.run_tool('image_regression', args, callback) # returns 1 if error - - def in_place_add(self, input1, input2, callback=None): - """Performs an in-place addition operation (input1 += input2). - - Keyword arguments: - - input1 -- Input raster file. - input2 -- Input raster file or constant value. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input1='{}'".format(input1)) - args.append("--input2='{}'".format(input2)) - return self.run_tool('in_place_add', args, callback) # returns 1 if error - - def in_place_divide(self, input1, input2, callback=None): - """Performs an in-place division operation (input1 /= input2). - - Keyword arguments: - - input1 -- Input raster file. - input2 -- Input raster file or constant value. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input1='{}'".format(input1)) - args.append("--input2='{}'".format(input2)) - return self.run_tool('in_place_divide', args, callback) # returns 1 if error - - def in_place_multiply(self, input1, input2, callback=None): - """Performs an in-place multiplication operation (input1 *= input2). - - Keyword arguments: - - input1 -- Input raster file. - input2 -- Input raster file or constant value. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input1='{}'".format(input1)) - args.append("--input2='{}'".format(input2)) - return self.run_tool('in_place_multiply', args, callback) # returns 1 if error - - def in_place_subtract(self, input1, input2, callback=None): - """Performs an in-place subtraction operation (input1 -= input2). - - Keyword arguments: - - input1 -- Input raster file. - input2 -- Input raster file or constant value. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input1='{}'".format(input1)) - args.append("--input2='{}'".format(input2)) - return self.run_tool('in_place_subtract', args, callback) # returns 1 if error - - def increment(self, i, output, callback=None): - """Increases the values of each grid cell in an input raster by 1.0. (see also InPlaceAdd). - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('increment', args, callback) # returns 1 if error - - def integer_division(self, input1, input2, output, callback=None): - """Performs an integer division operation on two rasters or a raster and a constant value. - - Keyword arguments: - - input1 -- Input raster file or constant value. - input2 -- Input raster file or constant value. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input1='{}'".format(input1)) - args.append("--input2='{}'".format(input2)) - args.append("--output='{}'".format(output)) - return self.run_tool('integer_division', args, callback) # returns 1 if error - - def is_no_data(self, i, output, callback=None): - """Identifies NoData valued pixels in an image. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('is_no_data', args, callback) # returns 1 if error - - def kappa_index(self, input1, input2, output, callback=None): - """Performs a kappa index of agreement (KIA) analysis on two categorical raster files. - - Keyword arguments: - - input1 -- Input classification raster file. - input2 -- Input reference raster file. - output -- Output HTML file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input1='{}'".format(input1)) - args.append("--input2='{}'".format(input2)) - args.append("--output='{}'".format(output)) - return self.run_tool('kappa_index', args, callback) # returns 1 if error - - def ks_test_for_normality(self, i, output, num_samples=None, callback=None): - """Evaluates whether the values in a raster are normally distributed. - - Keyword arguments: - - i -- Input raster file. - output -- Output HTML file. - num_samples -- Number of samples. Leave blank to use whole image. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - if num_samples is not None: args.append("--num_samples='{}'".format(num_samples)) - return self.run_tool('ks_test_for_normality', args, callback) # returns 1 if error - - def less_than(self, input1, input2, output, incl_equals=False, callback=None): - """Performs a less-than comparison operation on two rasters or a raster and a constant value. - - Keyword arguments: - - input1 -- Input raster file or constant value. - input2 -- Input raster file or constant value. - output -- Output raster file. - incl_equals -- Perform a less-than-or-equal-to operation. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input1='{}'".format(input1)) - args.append("--input2='{}'".format(input2)) - args.append("--output='{}'".format(output)) - if incl_equals: args.append("--incl_equals") - return self.run_tool('less_than', args, callback) # returns 1 if error - - def list_unique_values(self, i, field, output, callback=None): - """Lists the unique values contained in a field witin a vector's attribute table. - - Keyword arguments: - - i -- Input raster file. - field -- Input field name in attribute table. - output -- Output HTML file (default name will be based on input file if unspecified). - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--field='{}'".format(field)) - args.append("--output='{}'".format(output)) - return self.run_tool('list_unique_values', args, callback) # returns 1 if error - - def ln(self, i, output, callback=None): - """Returns the natural logarithm of values in a raster. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('ln', args, callback) # returns 1 if error - - def log10(self, i, output, callback=None): - """Returns the base-10 logarithm of values in a raster. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('log10', args, callback) # returns 1 if error - - def log2(self, i, output, callback=None): - """Returns the base-2 logarithm of values in a raster. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('log2', args, callback) # returns 1 if error - - def max(self, input1, input2, output, callback=None): - """Performs a MAX operation on two rasters or a raster and a constant value. - - Keyword arguments: - - input1 -- Input raster file or constant value. - input2 -- Input raster file or constant value. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input1='{}'".format(input1)) - args.append("--input2='{}'".format(input2)) - args.append("--output='{}'".format(output)) - return self.run_tool('max', args, callback) # returns 1 if error - - def min(self, input1, input2, output, callback=None): - """Performs a MIN operation on two rasters or a raster and a constant value. - - Keyword arguments: - - input1 -- Input raster file or constant value. - input2 -- Input raster file or constant value. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input1='{}'".format(input1)) - args.append("--input2='{}'".format(input2)) - args.append("--output='{}'".format(output)) - return self.run_tool('min', args, callback) # returns 1 if error - - def modulo(self, input1, input2, output, callback=None): - """Performs a modulo operation on two rasters or a raster and a constant value. - - Keyword arguments: - - input1 -- Input raster file or constant value. - input2 -- Input raster file or constant value. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input1='{}'".format(input1)) - args.append("--input2='{}'".format(input2)) - args.append("--output='{}'".format(output)) - return self.run_tool('modulo', args, callback) # returns 1 if error - - def multiply(self, input1, input2, output, callback=None): - """Performs a multiplication operation on two rasters or a raster and a constant value. - - Keyword arguments: - - input1 -- Input raster file or constant value. - input2 -- Input raster file or constant value. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input1='{}'".format(input1)) - args.append("--input2='{}'".format(input2)) - args.append("--output='{}'".format(output)) - return self.run_tool('multiply', args, callback) # returns 1 if error - - def negate(self, i, output, callback=None): - """Changes the sign of values in a raster or the 0-1 values of a Boolean raster. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('negate', args, callback) # returns 1 if error - - def not_equal_to(self, input1, input2, output, callback=None): - """Performs a not-equal-to comparison operation on two rasters or a raster and a constant value. - - Keyword arguments: - - input1 -- Input raster file or constant value. - input2 -- Input raster file or constant value. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input1='{}'".format(input1)) - args.append("--input2='{}'".format(input2)) - args.append("--output='{}'".format(output)) - return self.run_tool('not_equal_to', args, callback) # returns 1 if error - - def paired_sample_t_test(self, input1, input2, output, num_samples=None, callback=None): - """Performs a 2-sample K-S test for significant differences on two input rasters. - - Keyword arguments: - - input1 -- First input raster file. - input2 -- Second input raster file. - output -- Output HTML file. - num_samples -- Number of samples. Leave blank to use whole image. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input1='{}'".format(input1)) - args.append("--input2='{}'".format(input2)) - args.append("--output='{}'".format(output)) - if num_samples is not None: args.append("--num_samples='{}'".format(num_samples)) - return self.run_tool('paired_sample_t_test', args, callback) # returns 1 if error - - def power(self, input1, input2, output, callback=None): - """Raises the values in grid cells of one rasters, or a constant value, by values in another raster or constant value. - - Keyword arguments: - - input1 -- Input raster file or constant value. - input2 -- Input raster file or constant value. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input1='{}'".format(input1)) - args.append("--input2='{}'".format(input2)) - args.append("--output='{}'".format(output)) - return self.run_tool('power', args, callback) # returns 1 if error - - def principal_component_analysis(self, inputs, output, num_comp=None, standardized=False, callback=None): - """Performs a principal component analysis (PCA) on a multi-spectral dataset. - - Keyword arguments: - - inputs -- Input raster files. - output -- Output HTML report file. - num_comp -- Number of component images to output; <= to num. input images. - standardized -- Perform standardized PCA?. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--inputs='{}'".format(inputs)) - args.append("--output='{}'".format(output)) - if num_comp is not None: args.append("--num_comp='{}'".format(num_comp)) - if standardized: args.append("--standardized") - return self.run_tool('principal_component_analysis', args, callback) # returns 1 if error - - def quantiles(self, i, output, num_quantiles=5, callback=None): - """Transforms raster values into quantiles. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - num_quantiles -- Number of quantiles. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--num_quantiles={}".format(num_quantiles)) - return self.run_tool('quantiles', args, callback) # returns 1 if error - - def random_field(self, base, output, callback=None): - """Creates an image containing random values. - - Keyword arguments: - - base -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--base='{}'".format(base)) - args.append("--output='{}'".format(output)) - return self.run_tool('random_field', args, callback) # returns 1 if error - - def random_sample(self, base, output, num_samples=1000, callback=None): - """Creates an image containing randomly located sample grid cells with unique IDs. - - Keyword arguments: - - base -- Input raster file. - output -- Output raster file. - num_samples -- Number of samples. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--base='{}'".format(base)) - args.append("--output='{}'".format(output)) - args.append("--num_samples={}".format(num_samples)) - return self.run_tool('random_sample', args, callback) # returns 1 if error - - def raster_histogram(self, i, output, callback=None): - """Creates a histogram from raster values. - - Keyword arguments: - - i -- Input raster file. - output -- Output HTML file (default name will be based on input file if unspecified). - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('raster_histogram', args, callback) # returns 1 if error - - def raster_summary_stats(self, i, callback=None): - """Measures a rasters min, max, average, standard deviation, num. non-nodata cells, and total. - - Keyword arguments: - - i -- Input raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - return self.run_tool('raster_summary_stats', args, callback) # returns 1 if error - - def reciprocal(self, i, output, callback=None): - """Returns the reciprocal (i.e. 1 / z) of values in a raster. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('reciprocal', args, callback) # returns 1 if error - - def rescale_value_range(self, i, output, out_min_val, out_max_val, clip_min=None, clip_max=None, callback=None): - """Performs a min-max contrast stretch on an input greytone image. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - out_min_val -- New minimum value in output image. - out_max_val -- New maximum value in output image. - clip_min -- Optional lower tail clip value. - clip_max -- Optional upper tail clip value. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--out_min_val='{}'".format(out_min_val)) - args.append("--out_max_val='{}'".format(out_max_val)) - if clip_min is not None: args.append("--clip_min='{}'".format(clip_min)) - if clip_max is not None: args.append("--clip_max='{}'".format(clip_max)) - return self.run_tool('rescale_value_range', args, callback) # returns 1 if error - - def root_mean_square_error(self, i, base, callback=None): - """Calculates the RMSE and other accuracy statistics. - - Keyword arguments: - - i -- Input raster file. - base -- Input base raster file used for comparison. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--base='{}'".format(base)) - return self.run_tool('root_mean_square_error', args, callback) # returns 1 if error - - def round(self, i, output, callback=None): - """Rounds the values in an input raster to the nearest integer value. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('round', args, callback) # returns 1 if error - - def sin(self, i, output, callback=None): - """Returns the sine (sin) of each values in a raster. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('sin', args, callback) # returns 1 if error - - def sinh(self, i, output, callback=None): - """Returns the hyperbolic sine (sinh) of each values in a raster. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('sinh', args, callback) # returns 1 if error - - def square(self, i, output, callback=None): - """Squares the values in a raster. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('square', args, callback) # returns 1 if error - - def square_root(self, i, output, callback=None): - """Returns the square root of the values in a raster. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('square_root', args, callback) # returns 1 if error - - def subtract(self, input1, input2, output, callback=None): - """Performs a differencing operation on two rasters or a raster and a constant value. - - Keyword arguments: - - input1 -- Input raster file or constant value. - input2 -- Input raster file or constant value. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input1='{}'".format(input1)) - args.append("--input2='{}'".format(input2)) - args.append("--output='{}'".format(output)) - return self.run_tool('subtract', args, callback) # returns 1 if error - - def tan(self, i, output, callback=None): - """Returns the tangent (tan) of each values in a raster. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('tan', args, callback) # returns 1 if error - - def tanh(self, i, output, callback=None): - """Returns the hyperbolic tangent (tanh) of each values in a raster. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('tanh', args, callback) # returns 1 if error - - def to_degrees(self, i, output, callback=None): - """Converts a raster from radians to degrees. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('to_degrees', args, callback) # returns 1 if error - - def to_radians(self, i, output, callback=None): - """Converts a raster from degrees to radians. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('to_radians', args, callback) # returns 1 if error - - def trend_surface(self, i, output, order=1, callback=None): - """Estimates the trend surface of an input raster file. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - order -- Polynomial order (1 to 10). - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - args.append("--order={}".format(order)) - return self.run_tool('trend_surface', args, callback) # returns 1 if error - - def trend_surface_vector_points(self, i, field, output, cell_size, order=1, callback=None): - """Estimates a trend surface from vector points. - - Keyword arguments: - - i -- Input vector Points file. - field -- Input field name in attribute table. - output -- Output raster file. - order -- Polynomial order (1 to 10). - cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--field='{}'".format(field)) - args.append("--output='{}'".format(output)) - args.append("--order={}".format(order)) - args.append("--cell_size='{}'".format(cell_size)) - return self.run_tool('trend_surface_vector_points', args, callback) # returns 1 if error - - def truncate(self, i, output, num_decimals=None, callback=None): - """Truncates the values in a raster to the desired number of decimal places. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - num_decimals -- Number of decimals left after truncation (default is zero). - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - if num_decimals is not None: args.append("--num_decimals='{}'".format(num_decimals)) - return self.run_tool('truncate', args, callback) # returns 1 if error - - def turning_bands_simulation(self, base, output, range, iterations=1000, callback=None): - """Creates an image containing random values based on a turning-bands simulation. - - Keyword arguments: - - base -- Input base raster file. - output -- Output file. - range -- The field's range, in xy-units, related to the extent of spatial autocorrelation. - iterations -- The number of iterations. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--base='{}'".format(base)) - args.append("--output='{}'".format(output)) - args.append("--range='{}'".format(range)) - args.append("--iterations={}".format(iterations)) - return self.run_tool('turning_bands_simulation', args, callback) # returns 1 if error - - def two_sample_ks_test(self, input1, input2, output, num_samples=None, callback=None): - """Performs a 2-sample K-S test for significant differences on two input rasters. - - Keyword arguments: - - input1 -- First input raster file. - input2 -- Second input raster file. - output -- Output HTML file. - num_samples -- Number of samples. Leave blank to use whole image. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input1='{}'".format(input1)) - args.append("--input2='{}'".format(input2)) - args.append("--output='{}'".format(output)) - if num_samples is not None: args.append("--num_samples='{}'".format(num_samples)) - return self.run_tool('two_sample_ks_test', args, callback) # returns 1 if error - - def wilcoxon_signed_rank_test(self, input1, input2, output, num_samples=None, callback=None): - """Performs a 2-sample K-S test for significant differences on two input rasters. - - Keyword arguments: - - input1 -- First input raster file. - input2 -- Second input raster file. - output -- Output HTML file. - num_samples -- Number of samples. Leave blank to use whole image. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input1='{}'".format(input1)) - args.append("--input2='{}'".format(input2)) - args.append("--output='{}'".format(output)) - if num_samples is not None: args.append("--num_samples='{}'".format(num_samples)) - return self.run_tool('wilcoxon_signed_rank_test', args, callback) # returns 1 if error - - def xor(self, input1, input2, output, callback=None): - """Performs a logical XOR operator on two Boolean raster images. - - Keyword arguments: - - input1 -- Input raster file. - input2 -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input1='{}'".format(input1)) - args.append("--input2='{}'".format(input2)) - args.append("--output='{}'".format(output)) - return self.run_tool('xor', args, callback) # returns 1 if error - - def z_scores(self, i, output, callback=None): - """Standardizes the values in an input raster by converting to z-scores. - - Keyword arguments: - - i -- Input raster file. - output -- Output raster file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--output='{}'".format(output)) - return self.run_tool('z_scores', args, callback) # returns 1 if error - - def zonal_statistics(self, i, features, output=None, stat="mean", out_table=None, callback=None): - """Extracts descriptive statistics for a group of patches in a raster. - - Keyword arguments: - - i -- Input data raster file. - features -- Input feature definition raster file. - output -- Output raster file. - stat -- Statistic to extract, including 'mean', 'median', 'minimum', 'maximum', 'range', 'standard deviation', and 'total'. - out_table -- Output HTML Table file. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--input='{}'".format(i)) - args.append("--features='{}'".format(features)) - if output is not None: args.append("--output='{}'".format(output)) - args.append("--stat={}".format(stat)) - if out_table is not None: args.append("--out_table='{}'".format(out_table)) - return self.run_tool('zonal_statistics', args, callback) # returns 1 if error - - ########################### - # Stream Network Analysis # - ########################### - - def distance_to_outlet(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None): - """Calculates the distance of stream grid cells to the channel network outlet cell. - - Keyword arguments: - - d8_pntr -- Input raster D8 pointer file. - streams -- Input raster streams file. - output -- Output raster file. - esri_pntr -- D8 pointer uses the ESRI style scheme. - zero_background -- Flag indicating whether a background value of zero should be used. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--d8_pntr='{}'".format(d8_pntr)) - args.append("--streams='{}'".format(streams)) - args.append("--output='{}'".format(output)) - if esri_pntr: args.append("--esri_pntr") - if zero_background: args.append("--zero_background") - return self.run_tool('distance_to_outlet', args, callback) # returns 1 if error - - def extract_streams(self, flow_accum, output, threshold, zero_background=False, callback=None): - """Extracts stream grid cells from a flow accumulation raster. - - Keyword arguments: - - flow_accum -- Input raster D8 flow accumulation file. - output -- Output raster file. - threshold -- Threshold in flow accumulation values for channelization. - zero_background -- Flag indicating whether a background value of zero should be used. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--flow_accum='{}'".format(flow_accum)) - args.append("--output='{}'".format(output)) - args.append("--threshold='{}'".format(threshold)) - if zero_background: args.append("--zero_background") - return self.run_tool('extract_streams', args, callback) # returns 1 if error - - def extract_valleys(self, dem, output, variant="LQ", line_thin=True, filter=5, callback=None): - """Identifies potential valley bottom grid cells based on local topolography alone. - - Keyword arguments: - - dem -- Input raster DEM file. - output -- Output raster file. - variant -- Options include 'LQ' (lower quartile), 'JandR' (Johnston and Rosenfeld), and 'PandD' (Peucker and Douglas); default is 'LQ'. - line_thin -- Optional flag indicating whether post-processing line-thinning should be performed. - filter -- Optional argument (only used when variant='lq') providing the filter size, in grid cells, used for lq-filtering (default is 5). - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - args.append("--variant={}".format(variant)) - if line_thin: args.append("--line_thin") - args.append("--filter={}".format(filter)) - return self.run_tool('extract_valleys', args, callback) # returns 1 if error - - def farthest_channel_head(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None): - """Calculates the distance to the furthest upstream channel head for each stream cell. - - Keyword arguments: - - d8_pntr -- Input raster D8 pointer file. - streams -- Input raster streams file. - output -- Output raster file. - esri_pntr -- D8 pointer uses the ESRI style scheme. - zero_background -- Flag indicating whether a background value of zero should be used. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--d8_pntr='{}'".format(d8_pntr)) - args.append("--streams='{}'".format(streams)) - args.append("--output='{}'".format(output)) - if esri_pntr: args.append("--esri_pntr") - if zero_background: args.append("--zero_background") - return self.run_tool('farthest_channel_head', args, callback) # returns 1 if error - - def find_main_stem(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None): - """Finds the main stem, based on stream lengths, of each stream network. - - Keyword arguments: - - d8_pntr -- Input raster D8 pointer file. - streams -- Input raster streams file. - output -- Output raster file. - esri_pntr -- D8 pointer uses the ESRI style scheme. - zero_background -- Flag indicating whether a background value of zero should be used. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--d8_pntr='{}'".format(d8_pntr)) - args.append("--streams='{}'".format(streams)) - args.append("--output='{}'".format(output)) - if esri_pntr: args.append("--esri_pntr") - if zero_background: args.append("--zero_background") - return self.run_tool('find_main_stem', args, callback) # returns 1 if error - - def hack_stream_order(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None): - """Assigns the Hack stream order to each tributary in a stream network. - - Keyword arguments: - - d8_pntr -- Input raster D8 pointer file. - streams -- Input raster streams file. - output -- Output raster file. - esri_pntr -- D8 pointer uses the ESRI style scheme. - zero_background -- Flag indicating whether a background value of zero should be used. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--d8_pntr='{}'".format(d8_pntr)) - args.append("--streams='{}'".format(streams)) - args.append("--output='{}'".format(output)) - if esri_pntr: args.append("--esri_pntr") - if zero_background: args.append("--zero_background") - return self.run_tool('hack_stream_order', args, callback) # returns 1 if error - - def horton_stream_order(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None): - """Assigns the Horton stream order to each tributary in a stream network. - - Keyword arguments: - - d8_pntr -- Input raster D8 pointer file. - streams -- Input raster streams file. - output -- Output raster file. - esri_pntr -- D8 pointer uses the ESRI style scheme. - zero_background -- Flag indicating whether a background value of zero should be used. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--d8_pntr='{}'".format(d8_pntr)) - args.append("--streams='{}'".format(streams)) - args.append("--output='{}'".format(output)) - if esri_pntr: args.append("--esri_pntr") - if zero_background: args.append("--zero_background") - return self.run_tool('horton_stream_order', args, callback) # returns 1 if error - - def length_of_upstream_channels(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None): - """Calculates the total length of channels upstream. - - Keyword arguments: - - d8_pntr -- Input raster D8 pointer file. - streams -- Input raster streams file. - output -- Output raster file. - esri_pntr -- D8 pointer uses the ESRI style scheme. - zero_background -- Flag indicating whether a background value of zero should be used. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--d8_pntr='{}'".format(d8_pntr)) - args.append("--streams='{}'".format(streams)) - args.append("--output='{}'".format(output)) - if esri_pntr: args.append("--esri_pntr") - if zero_background: args.append("--zero_background") - return self.run_tool('length_of_upstream_channels', args, callback) # returns 1 if error - - def long_profile(self, d8_pntr, streams, dem, output, esri_pntr=False, callback=None): - """Plots the stream longitudinal profiles for one or more rivers. - - Keyword arguments: - - d8_pntr -- Input raster D8 pointer file. - streams -- Input raster streams file. - dem -- Input raster DEM file. - output -- Output HTML file. - esri_pntr -- D8 pointer uses the ESRI style scheme. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--d8_pntr='{}'".format(d8_pntr)) - args.append("--streams='{}'".format(streams)) - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - if esri_pntr: args.append("--esri_pntr") - return self.run_tool('long_profile', args, callback) # returns 1 if error - - def long_profile_from_points(self, d8_pntr, points, dem, output, esri_pntr=False, callback=None): - """Plots the longitudinal profiles from flow-paths initiating from a set of vector points. - - Keyword arguments: - - d8_pntr -- Input raster D8 pointer file. - points -- Input vector points file. - dem -- Input raster DEM file. - output -- Output HTML file. - esri_pntr -- D8 pointer uses the ESRI style scheme. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--d8_pntr='{}'".format(d8_pntr)) - args.append("--points='{}'".format(points)) - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - if esri_pntr: args.append("--esri_pntr") - return self.run_tool('long_profile_from_points', args, callback) # returns 1 if error - - def raster_streams_to_vector(self, streams, d8_pntr, output, esri_pntr=False, callback=None): - """Converts a raster stream file into a vector file. - - Keyword arguments: - - streams -- Input raster streams file. - d8_pntr -- Input raster D8 pointer file. - output -- Output vector file. - esri_pntr -- D8 pointer uses the ESRI style scheme. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--streams='{}'".format(streams)) - args.append("--d8_pntr='{}'".format(d8_pntr)) - args.append("--output='{}'".format(output)) - if esri_pntr: args.append("--esri_pntr") - return self.run_tool('raster_streams_to_vector', args, callback) # returns 1 if error - - def rasterize_streams(self, streams, base, output, nodata=True, feature_id=False, callback=None): - """Rasterizes vector streams based on Lindsay (2016) method. - - Keyword arguments: - - streams -- Input vector streams file. - base -- Input base raster file. - output -- Output raster file. - nodata -- Use NoData value for background?. - feature_id -- Use feature number as output value?. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--streams='{}'".format(streams)) - args.append("--base='{}'".format(base)) - args.append("--output='{}'".format(output)) - if nodata: args.append("--nodata") - if feature_id: args.append("--feature_id") - return self.run_tool('rasterize_streams', args, callback) # returns 1 if error - - def remove_short_streams(self, d8_pntr, streams, output, min_length, esri_pntr=False, callback=None): - """Removes short first-order streams from a stream network. - - Keyword arguments: - - d8_pntr -- Input raster D8 pointer file. - streams -- Input raster streams file. - output -- Output raster file. - min_length -- Minimum tributary length (in map units) used for network prunning. - esri_pntr -- D8 pointer uses the ESRI style scheme. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--d8_pntr='{}'".format(d8_pntr)) - args.append("--streams='{}'".format(streams)) - args.append("--output='{}'".format(output)) - args.append("--min_length='{}'".format(min_length)) - if esri_pntr: args.append("--esri_pntr") - return self.run_tool('remove_short_streams', args, callback) # returns 1 if error - - def shreve_stream_magnitude(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None): - """Assigns the Shreve stream magnitude to each link in a stream network. - - Keyword arguments: - - d8_pntr -- Input raster D8 pointer file. - streams -- Input raster streams file. - output -- Output raster file. - esri_pntr -- D8 pointer uses the ESRI style scheme. - zero_background -- Flag indicating whether a background value of zero should be used. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--d8_pntr='{}'".format(d8_pntr)) - args.append("--streams='{}'".format(streams)) - args.append("--output='{}'".format(output)) - if esri_pntr: args.append("--esri_pntr") - if zero_background: args.append("--zero_background") - return self.run_tool('shreve_stream_magnitude', args, callback) # returns 1 if error - - def strahler_stream_order(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None): - """Assigns the Strahler stream order to each link in a stream network. - - Keyword arguments: - - d8_pntr -- Input raster D8 pointer file. - streams -- Input raster streams file. - output -- Output raster file. - esri_pntr -- D8 pointer uses the ESRI style scheme. - zero_background -- Flag indicating whether a background value of zero should be used. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--d8_pntr='{}'".format(d8_pntr)) - args.append("--streams='{}'".format(streams)) - args.append("--output='{}'".format(output)) - if esri_pntr: args.append("--esri_pntr") - if zero_background: args.append("--zero_background") - return self.run_tool('strahler_stream_order', args, callback) # returns 1 if error - - def stream_link_class(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None): - """Identifies the exterior/interior links and nodes in a stream network. - - Keyword arguments: - - d8_pntr -- Input raster D8 pointer file. - streams -- Input raster streams file. - output -- Output raster file. - esri_pntr -- D8 pointer uses the ESRI style scheme. - zero_background -- Flag indicating whether a background value of zero should be used. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--d8_pntr='{}'".format(d8_pntr)) - args.append("--streams='{}'".format(streams)) - args.append("--output='{}'".format(output)) - if esri_pntr: args.append("--esri_pntr") - if zero_background: args.append("--zero_background") - return self.run_tool('stream_link_class', args, callback) # returns 1 if error - - def stream_link_identifier(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None): - """Assigns a unique identifier to each link in a stream network. - - Keyword arguments: - - d8_pntr -- Input raster D8 pointer file. - streams -- Input raster streams file. - output -- Output raster file. - esri_pntr -- D8 pointer uses the ESRI style scheme. - zero_background -- Flag indicating whether a background value of zero should be used. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--d8_pntr='{}'".format(d8_pntr)) - args.append("--streams='{}'".format(streams)) - args.append("--output='{}'".format(output)) - if esri_pntr: args.append("--esri_pntr") - if zero_background: args.append("--zero_background") - return self.run_tool('stream_link_identifier', args, callback) # returns 1 if error - - def stream_link_length(self, d8_pntr, linkid, output, esri_pntr=False, zero_background=False, callback=None): - """Estimates the length of each link (or tributary) in a stream network. - - Keyword arguments: - - d8_pntr -- Input raster D8 pointer file. - linkid -- Input raster streams link ID (or tributary ID) file. - output -- Output raster file. - esri_pntr -- D8 pointer uses the ESRI style scheme. - zero_background -- Flag indicating whether a background value of zero should be used. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--d8_pntr='{}'".format(d8_pntr)) - args.append("--linkid='{}'".format(linkid)) - args.append("--output='{}'".format(output)) - if esri_pntr: args.append("--esri_pntr") - if zero_background: args.append("--zero_background") - return self.run_tool('stream_link_length', args, callback) # returns 1 if error - - def stream_link_slope(self, d8_pntr, linkid, dem, output, esri_pntr=False, zero_background=False, callback=None): - """Estimates the average slope of each link (or tributary) in a stream network. - - Keyword arguments: - - d8_pntr -- Input raster D8 pointer file. - linkid -- Input raster streams link ID (or tributary ID) file. - dem -- Input raster DEM file. - output -- Output raster file. - esri_pntr -- D8 pointer uses the ESRI style scheme. - zero_background -- Flag indicating whether a background value of zero should be used. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--d8_pntr='{}'".format(d8_pntr)) - args.append("--linkid='{}'".format(linkid)) - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - if esri_pntr: args.append("--esri_pntr") - if zero_background: args.append("--zero_background") - return self.run_tool('stream_link_slope', args, callback) # returns 1 if error - - def stream_slope_continuous(self, d8_pntr, streams, dem, output, esri_pntr=False, zero_background=False, callback=None): - """Estimates the slope of each grid cell in a stream network. - - Keyword arguments: - - d8_pntr -- Input raster D8 pointer file. - streams -- Input raster streams file. - dem -- Input raster DEM file. - output -- Output raster file. - esri_pntr -- D8 pointer uses the ESRI style scheme. - zero_background -- Flag indicating whether a background value of zero should be used. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--d8_pntr='{}'".format(d8_pntr)) - args.append("--streams='{}'".format(streams)) - args.append("--dem='{}'".format(dem)) - args.append("--output='{}'".format(output)) - if esri_pntr: args.append("--esri_pntr") - if zero_background: args.append("--zero_background") - return self.run_tool('stream_slope_continuous', args, callback) # returns 1 if error - - def topological_stream_order(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None): - """Assigns each link in a stream network its topological order. - - Keyword arguments: - - d8_pntr -- Input raster D8 pointer file. - streams -- Input raster streams file. - output -- Output raster file. - esri_pntr -- D8 pointer uses the ESRI style scheme. - zero_background -- Flag indicating whether a background value of zero should be used. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--d8_pntr='{}'".format(d8_pntr)) - args.append("--streams='{}'".format(streams)) - args.append("--output='{}'".format(output)) - if esri_pntr: args.append("--esri_pntr") - if zero_background: args.append("--zero_background") - return self.run_tool('topological_stream_order', args, callback) # returns 1 if error - - def tributary_identifier(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None): - """Assigns a unique identifier to each tributary in a stream network. - - Keyword arguments: - - d8_pntr -- Input raster D8 pointer file. - streams -- Input raster streams file. - output -- Output raster file. - esri_pntr -- D8 pointer uses the ESRI style scheme. - zero_background -- Flag indicating whether a background value of zero should be used. - callback -- Custom function for handling tool text outputs. - """ - args = [] - args.append("--d8_pntr='{}'".format(d8_pntr)) - args.append("--streams='{}'".format(streams)) - args.append("--output='{}'".format(output)) - if esri_pntr: args.append("--esri_pntr") - if zero_background: args.append("--zero_background") - return self.run_tool('tributary_identifier', args, callback) # returns 1 if error +#!/usr/bin/env python3 +''' This file is intended to be a helper for running whitebox-tools plugins from a Python script. +See whitebox_example.py for an example of how to use it. +''' + +# This script is part of the WhiteboxTools geospatial library. +# Authors: Dr. John Lindsay +# Created: 28/11/2017 +# Last Modified: 09/12/2019 +# License: MIT + +from __future__ import print_function +import os +from os import path +import sys +import platform +import re +# import shutil +from subprocess import CalledProcessError, Popen, PIPE, STDOUT + +running_windows = platform.system() == 'Windows' + +if running_windows: + from subprocess import STARTUPINFO, STARTF_USESHOWWINDOW + +def default_callback(value): + ''' + A simple default callback that outputs using the print function. When + tools are called without providing a custom callback, this function + will be used to print to standard output. + ''' + print(value) + + +def to_camelcase(name): + ''' + Convert snake_case name to CamelCase name + ''' + return ''.join(x.title() for x in name.split('_')) + + +def to_snakecase(name): + ''' + Convert CamelCase name to snake_case name + ''' + s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name) + return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower() + + +class WhiteboxTools(object): + ''' + An object for interfacing with the WhiteboxTools executable. + ''' + + def __init__(self): + if running_windows: + self.ext = '.exe' + else: + self.ext = '' + self.exe_name = "whitebox_tools{}".format(self.ext) + # self.exe_path = os.path.dirname(shutil.which( + # self.exe_name) or path.dirname(path.abspath(__file__))) + # self.exe_path = os.path.dirname(os.path.join(os.path.realpath(__file__))) + self.exe_path = path.dirname(path.abspath(__file__)) + self.work_dir = "" + self.verbose = True + self.cancel_op = False + self.default_callback = default_callback + self.start_minimized = False + self.__compress_rasters = False + + def set_whitebox_dir(self, path_str): + ''' + Sets the directory to the WhiteboxTools executable file. + ''' + self.exe_path = path_str + + def set_working_dir(self, path_str): + ''' + Sets the working directory, i.e. the directory in which + the data files are located. By setting the working + directory, tool input parameters that are files need only + specify the file name rather than the complete file path. + ''' + self.work_dir = path.normpath(path_str) + + def set_verbose_mode(self, val=True): + ''' + Sets verbose mode. If verbose mode is False, tools will not + print output messages. Tools will frequently provide substantial + feedback while they are operating, e.g. updating progress for + various sub-routines. When the user has scripted a workflow + that ties many tools in sequence, this level of tool output + can be problematic. By setting verbose mode to False, these + messages are suppressed and tools run as background processes. + ''' + self.verbose = val + + def set_default_callback(self, callback_func): + ''' + Sets the default callback used for handling tool text outputs. + ''' + self.default_callback = callback_func + + def set_compress_rasters(self, compress_rasters): + ''' + Sets the flag used by WhiteboxTools to determine whether to use compression for output rasters. + ''' + self.__compress_rasters = compress_rasters + + def get_compress_rasters(self): + return self.__compress_rasters + + def run_tool(self, tool_name, args, callback=None): + ''' + Runs a tool and specifies tool arguments. + Returns 0 if completes without error. + Returns 1 if error encountered (details are sent to callback). + Returns 2 if process is cancelled by user. + ''' + try: + if callback is None: + callback = self.default_callback + + os.chdir(self.exe_path) + args2 = [] + args2.append("." + path.sep + self.exe_name) + args2.append("--run=\"{}\"".format(to_camelcase(tool_name))) + + if self.work_dir.strip() != "": + args2.append("--wd=\"{}\"".format(self.work_dir)) + + for arg in args: + args2.append(arg) + + # args_str = args_str[:-1] + # a.append("--args=\"{}\"".format(args_str)) + + if self.verbose: + args2.append("-v") + + if self.__compress_rasters: + args2.append("--compress_rasters") + + if self.verbose: + cl = "" + for v in args2: + cl += v + " " + callback(cl.strip() + "\n") + + proc = None + + if running_windows and self.start_minimized == True: + si = STARTUPINFO() + si.dwFlags = STARTF_USESHOWWINDOW + si.wShowWindow = 6 #Set window minimized + proc = Popen(args2, shell=False, stdout=PIPE, + stderr=STDOUT, bufsize=1, universal_newlines=True, + startupinfo=si) + else: + proc = Popen(args2, shell=False, stdout=PIPE, + stderr=STDOUT, bufsize=1, universal_newlines=True) + + while proc is not None: + line = proc.stdout.readline() + sys.stdout.flush() + if line != '': + if not self.cancel_op: + callback(line.strip()) + else: + self.cancel_op = False + proc.terminate() + return 2 + + else: + break + + return 0 + except (OSError, ValueError, CalledProcessError) as err: + callback(str(err)) + return 1 + + def help(self): + ''' + Retrieves the help description for WhiteboxTools. + ''' + try: + os.chdir(self.exe_path) + args = [] + args.append("." + os.path.sep + self.exe_name) + args.append("-h") + + proc = Popen(args, shell=False, stdout=PIPE, + stderr=STDOUT, bufsize=1, universal_newlines=True) + ret = "" + while True: + line = proc.stdout.readline() + if line != '': + ret += line + else: + break + + return ret + except (OSError, ValueError, CalledProcessError) as err: + return err + + def license(self): + ''' + Retrieves the license information for WhiteboxTools. + ''' + try: + os.chdir(self.exe_path) + args = [] + args.append("." + os.path.sep + self.exe_name) + args.append("--license") + + proc = Popen(args, shell=False, stdout=PIPE, + stderr=STDOUT, bufsize=1, universal_newlines=True) + ret = "" + while True: + line = proc.stdout.readline() + if line != '': + ret += line + else: + break + + return ret + except (OSError, ValueError, CalledProcessError) as err: + return err + + def version(self): + ''' + Retrieves the version information for WhiteboxTools. + ''' + try: + os.chdir(self.exe_path) + args = [] + args.append("." + os.path.sep + self.exe_name) + args.append("--version") + + proc = Popen(args, shell=False, stdout=PIPE, + stderr=STDOUT, bufsize=1, universal_newlines=True) + ret = "" + while True: + line = proc.stdout.readline() + if line != '': + ret += line + else: + break + + return ret + except (OSError, ValueError, CalledProcessError) as err: + return err + + def tool_help(self, tool_name=''): + ''' + Retrieves the help description for a specific tool. + ''' + try: + os.chdir(self.exe_path) + args = [] + args.append("." + os.path.sep + self.exe_name) + args.append("--toolhelp={}".format(to_camelcase(tool_name))) + + proc = Popen(args, shell=False, stdout=PIPE, + stderr=STDOUT, bufsize=1, universal_newlines=True) + ret = "" + while True: + line = proc.stdout.readline() + if line != '': + ret += line + else: + break + + return ret + except (OSError, ValueError, CalledProcessError) as err: + return err + + def tool_parameters(self, tool_name): + ''' + Retrieves the tool parameter descriptions for a specific tool. + ''' + try: + os.chdir(self.exe_path) + args = [] + args.append("." + os.path.sep + self.exe_name) + args.append("--toolparameters={}".format(to_camelcase(tool_name))) + + proc = Popen(args, shell=False, stdout=PIPE, + stderr=STDOUT, bufsize=1, universal_newlines=True) + ret = "" + while True: + line = proc.stdout.readline() + if line != '': + ret += line + else: + break + + return ret + except (OSError, ValueError, CalledProcessError) as err: + return err + + def toolbox(self, tool_name=''): + ''' + Retrieve the toolbox for a specific tool. + ''' + try: + os.chdir(self.exe_path) + args = [] + args.append("." + os.path.sep + self.exe_name) + args.append("--toolbox={}".format(to_camelcase(tool_name))) + + proc = Popen(args, shell=False, stdout=PIPE, + stderr=STDOUT, bufsize=1, universal_newlines=True) + ret = "" + while True: + line = proc.stdout.readline() + if line != '': + ret += line + else: + break + + return ret + except (OSError, ValueError, CalledProcessError) as err: + return err + + def view_code(self, tool_name): + ''' + Opens a web browser to view the source code for a specific tool + on the projects source code repository. + ''' + try: + os.chdir(self.exe_path) + args = [] + args.append("." + os.path.sep + self.exe_name) + args.append("--viewcode={}".format(to_camelcase(tool_name))) + + proc = Popen(args, shell=False, stdout=PIPE, + stderr=STDOUT, bufsize=1, universal_newlines=True) + ret = "" + while True: + line = proc.stdout.readline() + if line != '': + ret += line + else: + break + + return ret + except (OSError, ValueError, CalledProcessError) as err: + return err + + def list_tools(self, keywords=[]): + ''' + Lists all available tools in WhiteboxTools. + ''' + try: + os.chdir(self.exe_path) + args = [] + args.append("." + os.path.sep + self.exe_name) + args.append("--listtools") + if len(keywords) > 0: + for kw in keywords: + args.append(kw) + + proc = Popen(args, shell=False, stdout=PIPE, + stderr=STDOUT, bufsize=1, universal_newlines=True) + ret = {} + line = proc.stdout.readline() # skip number of available tools header + while True: + line = proc.stdout.readline() + if line != '': + if line.strip() != '': + name, descr = line.split(':') + ret[to_snakecase(name.strip())] = descr.strip() + else: + break + + return ret + except (OSError, ValueError, CalledProcessError) as err: + return err + + ######################################################################## + # The following methods are convenience methods for each available tool. + # This needs updating whenever new tools are added to the WhiteboxTools + # library. They can be generated automatically using the + # whitebox_plugin_generator.py script. It would also be possible to + # discover plugins at runtime and monkey-patch their methods using + # MethodType. However, this would not be as useful since it would + # restrict the ability for text editors and IDEs to use autocomplete. + ######################################################################## + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ############## + # Data Tools # + ############## + + def add_point_coordinates_to_table(self, i, callback=None): + """Modifies the attribute table of a point vector by adding fields containing each point's X and Y coordinates. + + Keyword arguments: + + i -- Input vector Points file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + return self.run_tool('add_point_coordinates_to_table', args, callback) # returns 1 if error + + def clean_vector(self, i, output, callback=None): + """Removes null features and lines/polygons with fewer than the required number of vertices. + + Keyword arguments: + + i -- Input vector file. + output -- Output vector file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('clean_vector', args, callback) # returns 1 if error + + def convert_nodata_to_zero(self, i, output, callback=None): + """Converts nodata values in a raster to zero. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('convert_nodata_to_zero', args, callback) # returns 1 if error + + def convert_raster_format(self, i, output, callback=None): + """Converts raster data from one format to another. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('convert_raster_format', args, callback) # returns 1 if error + + def csv_points_to_vector(self, i, output, xfield=0, yfield=1, epsg=None, callback=None): + """Converts a CSV text file to vector points. + + Keyword arguments: + + i -- Input CSV file (i.e. source of data to be imported). + output -- Output vector file. + xfield -- X field number (e.g. 0 for first field). + yfield -- Y field number (e.g. 1 for second field). + epsg -- EPSG projection (e.g. 2958). + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--xfield={}".format(xfield)) + args.append("--yfield={}".format(yfield)) + if epsg is not None: args.append("--epsg='{}'".format(epsg)) + return self.run_tool('csv_points_to_vector', args, callback) # returns 1 if error + + def export_table_to_csv(self, i, output, headers=True, callback=None): + """Exports an attribute table to a CSV text file. + + Keyword arguments: + + i -- Input vector file. + output -- Output raster file. + headers -- Export field names as file header?. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + if headers: args.append("--headers") + return self.run_tool('export_table_to_csv', args, callback) # returns 1 if error + + def join_tables(self, input1, pkey, input2, fkey, import_field, callback=None): + """Merge a vector's attribute table with another table based on a common field. + + Keyword arguments: + + input1 -- Input primary vector file (i.e. the table to be modified). + pkey -- Primary key field. + input2 -- Input foreign vector file (i.e. source of data to be imported). + fkey -- Foreign key field. + import_field -- Imported field (all fields will be imported if not specified). + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input1='{}'".format(input1)) + args.append("--pkey='{}'".format(pkey)) + args.append("--input2='{}'".format(input2)) + args.append("--fkey='{}'".format(fkey)) + args.append("--import_field='{}'".format(import_field)) + return self.run_tool('join_tables', args, callback) # returns 1 if error + + def lines_to_polygons(self, i, output, callback=None): + """Converts vector polylines to polygons. + + Keyword arguments: + + i -- Input vector line file. + output -- Output vector polygon file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('lines_to_polygons', args, callback) # returns 1 if error + + def merge_table_with_csv(self, i, pkey, csv, fkey, import_field=None, callback=None): + """Merge a vector's attribute table with a table contained within a CSV text file. + + Keyword arguments: + + i -- Input primary vector file (i.e. the table to be modified). + pkey -- Primary key field. + csv -- Input CSV file (i.e. source of data to be imported). + fkey -- Foreign key field. + import_field -- Imported field (all fields will be imported if not specified). + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--pkey='{}'".format(pkey)) + args.append("--csv='{}'".format(csv)) + args.append("--fkey='{}'".format(fkey)) + if import_field is not None: args.append("--import_field='{}'".format(import_field)) + return self.run_tool('merge_table_with_csv', args, callback) # returns 1 if error + + def merge_vectors(self, inputs, output, callback=None): + """Combines two or more input vectors of the same ShapeType creating a single, new output vector. + + Keyword arguments: + + inputs -- Input vector files. + output -- Output vector file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--inputs='{}'".format(inputs)) + args.append("--output='{}'".format(output)) + return self.run_tool('merge_vectors', args, callback) # returns 1 if error + + def modify_no_data_value(self, i, new_value="-32768.0", callback=None): + """Converts nodata values in a raster to zero. + + Keyword arguments: + + i -- Input raster file. + new_value -- New NoData value. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--new_value={}".format(new_value)) + return self.run_tool('modify_no_data_value', args, callback) # returns 1 if error + + def multi_part_to_single_part(self, i, output, exclude_holes=True, callback=None): + """Converts a vector file containing multi-part features into a vector containing only single-part features. + + Keyword arguments: + + i -- Input vector line or polygon file. + output -- Output vector line or polygon file. + exclude_holes -- Exclude hole parts from the feature splitting? (holes will continue to belong to their features in output.). + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + if exclude_holes: args.append("--exclude_holes") + return self.run_tool('multi_part_to_single_part', args, callback) # returns 1 if error + + def new_raster_from_base(self, base, output, value="nodata", data_type="float", callback=None): + """Creates a new raster using a base image. + + Keyword arguments: + + base -- Input base raster file. + output -- Output raster file. + value -- Constant value to fill raster with; either 'nodata' or numeric value. + data_type -- Output raster data type; options include 'double' (64-bit), 'float' (32-bit), and 'integer' (signed 16-bit) (default is 'float'). + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--base='{}'".format(base)) + args.append("--output='{}'".format(output)) + args.append("--value={}".format(value)) + args.append("--data_type={}".format(data_type)) + return self.run_tool('new_raster_from_base', args, callback) # returns 1 if error + + def polygons_to_lines(self, i, output, callback=None): + """Converts vector polygons to polylines. + + Keyword arguments: + + i -- Input vector polygon file. + output -- Output vector lines file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('polygons_to_lines', args, callback) # returns 1 if error + + def print_geo_tiff_tags(self, i, callback=None): + """Prints the tags within a GeoTIFF. + + Keyword arguments: + + i -- Input GeoTIFF file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + return self.run_tool('print_geo_tiff_tags', args, callback) # returns 1 if error + + def raster_to_vector_lines(self, i, output, callback=None): + """Converts a raster lines features into a vector of the POLYLINE shapetype. + + Keyword arguments: + + i -- Input raster lines file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('raster_to_vector_lines', args, callback) # returns 1 if error + + def raster_to_vector_points(self, i, output, callback=None): + """Converts a raster dataset to a vector of the POINT shapetype. + + Keyword arguments: + + i -- Input raster file. + output -- Output vector points file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('raster_to_vector_points', args, callback) # returns 1 if error + + def raster_to_vector_polygons(self, i, output, callback=None): + """Converts a raster dataset to a vector of the POLYGON shapetype. + + Keyword arguments: + + i -- Input raster file. + output -- Output vector polygons file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('raster_to_vector_polygons', args, callback) # returns 1 if error + + def reinitialize_attribute_table(self, i, callback=None): + """Reinitializes a vector's attribute table deleting all fields but the feature ID (FID). + + Keyword arguments: + + i -- Input vector file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + return self.run_tool('reinitialize_attribute_table', args, callback) # returns 1 if error + + def remove_polygon_holes(self, i, output, callback=None): + """Removes holes within the features of a vector polygon file. + + Keyword arguments: + + i -- Input vector polygon file. + output -- Output vector polygon file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('remove_polygon_holes', args, callback) # returns 1 if error + + def set_nodata_value(self, i, output, back_value=0.0, callback=None): + """Assign a specified value in an input image to the NoData value. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + back_value -- Background value to set to nodata. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--back_value={}".format(back_value)) + return self.run_tool('set_nodata_value', args, callback) # returns 1 if error + + def single_part_to_multi_part(self, i, output, field=None, callback=None): + """Converts a vector file containing multi-part features into a vector containing only single-part features. + + Keyword arguments: + + i -- Input vector line or polygon file. + field -- Grouping ID field name in attribute table. + output -- Output vector line or polygon file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + if field is not None: args.append("--field='{}'".format(field)) + args.append("--output='{}'".format(output)) + return self.run_tool('single_part_to_multi_part', args, callback) # returns 1 if error + + def vector_lines_to_raster(self, i, output, field="FID", nodata=True, cell_size=None, base=None, callback=None): + """Converts a vector containing polylines into a raster. + + Keyword arguments: + + i -- Input vector lines file. + field -- Input field name in attribute table. + output -- Output raster file. + nodata -- Background value to set to NoData. Without this flag, it will be set to 0.0. + cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. + base -- Optionally specified input base raster file. Not used when a cell size is specified. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--field={}".format(field)) + args.append("--output='{}'".format(output)) + if nodata: args.append("--nodata") + if cell_size is not None: args.append("--cell_size='{}'".format(cell_size)) + if base is not None: args.append("--base='{}'".format(base)) + return self.run_tool('vector_lines_to_raster', args, callback) # returns 1 if error + + def vector_points_to_raster(self, i, output, field="FID", assign="last", nodata=True, cell_size=None, base=None, callback=None): + """Converts a vector containing points into a raster. + + Keyword arguments: + + i -- Input vector Points file. + field -- Input field name in attribute table. + output -- Output raster file. + assign -- Assignment operation, where multiple points are in the same grid cell; options include 'first', 'last' (default), 'min', 'max', 'sum'. + nodata -- Background value to set to NoData. Without this flag, it will be set to 0.0. + cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. + base -- Optionally specified input base raster file. Not used when a cell size is specified. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--field={}".format(field)) + args.append("--output='{}'".format(output)) + args.append("--assign={}".format(assign)) + if nodata: args.append("--nodata") + if cell_size is not None: args.append("--cell_size='{}'".format(cell_size)) + if base is not None: args.append("--base='{}'".format(base)) + return self.run_tool('vector_points_to_raster', args, callback) # returns 1 if error + + def vector_polygons_to_raster(self, i, output, field="FID", nodata=True, cell_size=None, base=None, callback=None): + """Converts a vector containing polygons into a raster. + + Keyword arguments: + + i -- Input vector polygons file. + field -- Input field name in attribute table. + output -- Output raster file. + nodata -- Background value to set to NoData. Without this flag, it will be set to 0.0. + cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. + base -- Optionally specified input base raster file. Not used when a cell size is specified. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--field={}".format(field)) + args.append("--output='{}'".format(output)) + if nodata: args.append("--nodata") + if cell_size is not None: args.append("--cell_size='{}'".format(cell_size)) + if base is not None: args.append("--base='{}'".format(base)) + return self.run_tool('vector_polygons_to_raster', args, callback) # returns 1 if error + + ################ + # GIS Analysis # + ################ + + def aggregate_raster(self, i, output, agg_factor=2, type="mean", callback=None): + """Aggregates a raster to a lower resolution. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + agg_factor -- Aggregation factor, in pixels. + type -- Statistic used to fill output pixels. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--agg_factor={}".format(agg_factor)) + args.append("--type={}".format(type)) + return self.run_tool('aggregate_raster', args, callback) # returns 1 if error + + def block_maximum_gridding(self, i, field, output, use_z=False, cell_size=None, base=None, callback=None): + """Creates a raster grid based on a set of vector points and assigns grid values using a block maximum scheme. + + Keyword arguments: + + i -- Input vector Points file. + field -- Input field name in attribute table. + use_z -- Use z-coordinate instead of field?. + output -- Output raster file. + cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. + base -- Optionally specified input base raster file. Not used when a cell size is specified. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--field='{}'".format(field)) + if use_z: args.append("--use_z") + args.append("--output='{}'".format(output)) + if cell_size is not None: args.append("--cell_size='{}'".format(cell_size)) + if base is not None: args.append("--base='{}'".format(base)) + return self.run_tool('block_maximum_gridding', args, callback) # returns 1 if error + + def block_minimum_gridding(self, i, field, output, use_z=False, cell_size=None, base=None, callback=None): + """Creates a raster grid based on a set of vector points and assigns grid values using a block minimum scheme. + + Keyword arguments: + + i -- Input vector Points file. + field -- Input field name in attribute table. + use_z -- Use z-coordinate instead of field?. + output -- Output raster file. + cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. + base -- Optionally specified input base raster file. Not used when a cell size is specified. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--field='{}'".format(field)) + if use_z: args.append("--use_z") + args.append("--output='{}'".format(output)) + if cell_size is not None: args.append("--cell_size='{}'".format(cell_size)) + if base is not None: args.append("--base='{}'".format(base)) + return self.run_tool('block_minimum_gridding', args, callback) # returns 1 if error + + def centroid(self, i, output, text_output=False, callback=None): + """Calculates the centroid, or average location, of raster polygon objects. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + text_output -- Optional text output. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + if text_output: args.append("--text_output") + return self.run_tool('centroid', args, callback) # returns 1 if error + + def centroid_vector(self, i, output, callback=None): + """Identifes the centroid point of a vector polyline or polygon feature or a group of vector points. + + Keyword arguments: + + i -- Input vector file. + output -- Output vector file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('centroid_vector', args, callback) # returns 1 if error + + def clump(self, i, output, diag=True, zero_back=False, callback=None): + """Groups cells that form discrete areas, assigning them unique identifiers. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + diag -- Flag indicating whether diagonal connections should be considered. + zero_back -- Flag indicating whether zero values should be treated as a background. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + if diag: args.append("--diag") + if zero_back: args.append("--zero_back") + return self.run_tool('clump', args, callback) # returns 1 if error + + def construct_vector_tin(self, i, output, field=None, use_z=False, max_triangle_edge_length=None, callback=None): + """Creates a vector triangular irregular network (TIN) for a set of vector points. + + Keyword arguments: + + i -- Input vector points file. + field -- Input field name in attribute table. + use_z -- Use the 'z' dimension of the Shapefile's geometry instead of an attribute field?. + output -- Output vector polygon file. + max_triangle_edge_length -- Optional maximum triangle edge length; triangles larger than this size will not be gridded. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + if field is not None: args.append("--field='{}'".format(field)) + if use_z: args.append("--use_z") + args.append("--output='{}'".format(output)) + if max_triangle_edge_length is not None: args.append("--max_triangle_edge_length='{}'".format(max_triangle_edge_length)) + return self.run_tool('construct_vector_tin', args, callback) # returns 1 if error + + def create_hexagonal_vector_grid(self, i, output, width, orientation="horizontal", callback=None): + """Creates a hexagonal vector grid. + + Keyword arguments: + + i -- Input base file. + output -- Output vector polygon file. + width -- The grid cell width. + orientation -- Grid Orientation, 'horizontal' or 'vertical'. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--width='{}'".format(width)) + args.append("--orientation={}".format(orientation)) + return self.run_tool('create_hexagonal_vector_grid', args, callback) # returns 1 if error + + def create_plane(self, base, output, gradient=15.0, aspect=90.0, constant=0.0, callback=None): + """Creates a raster image based on the equation for a simple plane. + + Keyword arguments: + + base -- Input base raster file. + output -- Output raster file. + gradient -- Slope gradient in degrees (-85.0 to 85.0). + aspect -- Aspect (direction) in degrees clockwise from north (0.0-360.0). + constant -- Constant value. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--base='{}'".format(base)) + args.append("--output='{}'".format(output)) + args.append("--gradient={}".format(gradient)) + args.append("--aspect={}".format(aspect)) + args.append("--constant={}".format(constant)) + return self.run_tool('create_plane', args, callback) # returns 1 if error + + def create_rectangular_vector_grid(self, i, output, width, height, xorig=0, yorig=0, callback=None): + """Creates a rectangular vector grid. + + Keyword arguments: + + i -- Input base file. + output -- Output vector polygon file. + width -- The grid cell width. + height -- The grid cell height. + xorig -- The grid origin x-coordinate. + yorig -- The grid origin y-coordinate. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--width='{}'".format(width)) + args.append("--height='{}'".format(height)) + args.append("--xorig={}".format(xorig)) + args.append("--yorig={}".format(yorig)) + return self.run_tool('create_rectangular_vector_grid', args, callback) # returns 1 if error + + def dissolve(self, i, output, field=None, snap=0.0, callback=None): + """Removes the interior, or shared, boundaries within a vector polygon coverage. + + Keyword arguments: + + i -- Input vector file. + field -- Dissolve field attribute (optional). + output -- Output vector file. + snap -- Snap tolerance. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + if field is not None: args.append("--field='{}'".format(field)) + args.append("--output='{}'".format(output)) + args.append("--snap={}".format(snap)) + return self.run_tool('dissolve', args, callback) # returns 1 if error + + def eliminate_coincident_points(self, i, output, tolerance, callback=None): + """Removes any coincident, or nearly coincident, points from a vector points file. + + Keyword arguments: + + i -- Input vector file. + output -- Output vector polygon file. + tolerance -- The distance tolerance for points. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--tolerance='{}'".format(tolerance)) + return self.run_tool('eliminate_coincident_points', args, callback) # returns 1 if error + + def extend_vector_lines(self, i, output, dist, extend="both ends", callback=None): + """Extends vector lines by a specified distance. + + Keyword arguments: + + i -- Input vector polyline file. + output -- Output vector polyline file. + dist -- The distance to extend. + extend -- Extend direction, 'both ends' (default), 'line start', 'line end'. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--dist='{}'".format(dist)) + args.append("--extend={}".format(extend)) + return self.run_tool('extend_vector_lines', args, callback) # returns 1 if error + + def extract_nodes(self, i, output, callback=None): + """Converts vector lines or polygons into vertex points. + + Keyword arguments: + + i -- Input vector lines or polygon file. + output -- Output vector points file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('extract_nodes', args, callback) # returns 1 if error + + def extract_raster_values_at_points(self, inputs, points, out_text=False, callback=None): + """Extracts the values of raster(s) at vector point locations. + + Keyword arguments: + + inputs -- Input raster files. + points -- Input vector points file. + out_text -- Output point values as text? Otherwise, the only output is to to the points file's attribute table. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--inputs='{}'".format(inputs)) + args.append("--points='{}'".format(points)) + if out_text: args.append("--out_text") + return self.run_tool('extract_raster_values_at_points', args, callback) # returns 1 if error + + def find_lowest_or_highest_points(self, i, output, out_type="lowest", callback=None): + """Locates the lowest and/or highest valued cells in a raster. + + Keyword arguments: + + i -- Input raster file. + output -- Output vector points file. + out_type -- Output type; one of 'area' (default) and 'volume'. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--out_type={}".format(out_type)) + return self.run_tool('find_lowest_or_highest_points', args, callback) # returns 1 if error + + def idw_interpolation(self, i, field, output, use_z=False, weight=2.0, radius=None, min_points=None, cell_size=None, base=None, callback=None): + """Interpolates vector points into a raster surface using an inverse-distance weighted scheme. + + Keyword arguments: + + i -- Input vector Points file. + field -- Input field name in attribute table. + use_z -- Use z-coordinate instead of field?. + output -- Output raster file. + weight -- IDW weight value. + radius -- Search Radius in map units. + min_points -- Minimum number of points. + cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. + base -- Optionally specified input base raster file. Not used when a cell size is specified. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--field='{}'".format(field)) + if use_z: args.append("--use_z") + args.append("--output='{}'".format(output)) + args.append("--weight={}".format(weight)) + if radius is not None: args.append("--radius='{}'".format(radius)) + if min_points is not None: args.append("--min_points='{}'".format(min_points)) + if cell_size is not None: args.append("--cell_size='{}'".format(cell_size)) + if base is not None: args.append("--base='{}'".format(base)) + return self.run_tool('idw_interpolation', args, callback) # returns 1 if error + + def layer_footprint(self, i, output, callback=None): + """Creates a vector polygon footprint of the area covered by a raster grid or vector layer. + + Keyword arguments: + + i -- Input raster or vector file. + output -- Output vector polygon file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('layer_footprint', args, callback) # returns 1 if error + + def medoid(self, i, output, callback=None): + """Calculates the medoid for a series of vector features contained in a shapefile. + + Keyword arguments: + + i -- Input vector file. + output -- Output vector file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('medoid', args, callback) # returns 1 if error + + def minimum_bounding_box(self, i, output, criterion="area", features=True, callback=None): + """Creates a vector minimum bounding rectangle around vector features. + + Keyword arguments: + + i -- Input vector file. + output -- Output vector polygon file. + criterion -- Minimization criterion; options include 'area' (default), 'length', 'width', and 'perimeter'. + features -- Find the minimum bounding rectangles around each individual vector feature. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--criterion={}".format(criterion)) + if features: args.append("--features") + return self.run_tool('minimum_bounding_box', args, callback) # returns 1 if error + + def minimum_bounding_circle(self, i, output, features=True, callback=None): + """Delineates the minimum bounding circle (i.e. smallest enclosing circle) for a group of vectors. + + Keyword arguments: + + i -- Input vector file. + output -- Output vector polygon file. + features -- Find the minimum bounding circle around each individual vector feature. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + if features: args.append("--features") + return self.run_tool('minimum_bounding_circle', args, callback) # returns 1 if error + + def minimum_bounding_envelope(self, i, output, features=True, callback=None): + """Creates a vector axis-aligned minimum bounding rectangle (envelope) around vector features. + + Keyword arguments: + + i -- Input vector file. + output -- Output vector polygon file. + features -- Find the minimum bounding envelop around each individual vector feature. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + if features: args.append("--features") + return self.run_tool('minimum_bounding_envelope', args, callback) # returns 1 if error + + def minimum_convex_hull(self, i, output, features=True, callback=None): + """Creates a vector convex polygon around vector features. + + Keyword arguments: + + i -- Input vector file. + output -- Output vector polygon file. + features -- Find the hulls around each vector feature. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + if features: args.append("--features") + return self.run_tool('minimum_convex_hull', args, callback) # returns 1 if error + + def natural_neighbour_interpolation(self, i, output, field=None, use_z=False, cell_size=None, base=None, clip=True, callback=None): + """Creates a raster grid based on Sibson's natural neighbour method. + + Keyword arguments: + + i -- Input vector points file. + field -- Input field name in attribute table. + use_z -- Use the 'z' dimension of the Shapefile's geometry instead of an attribute field?. + output -- Output raster file. + cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. + base -- Optionally specified input base raster file. Not used when a cell size is specified. + clip -- Clip the data to the convex hull of the points?. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + if field is not None: args.append("--field='{}'".format(field)) + if use_z: args.append("--use_z") + args.append("--output='{}'".format(output)) + if cell_size is not None: args.append("--cell_size='{}'".format(cell_size)) + if base is not None: args.append("--base='{}'".format(base)) + if clip: args.append("--clip") + return self.run_tool('natural_neighbour_interpolation', args, callback) # returns 1 if error + + def nearest_neighbour_gridding(self, i, field, output, use_z=False, cell_size=None, base=None, max_dist=None, callback=None): + """Creates a raster grid based on a set of vector points and assigns grid values using the nearest neighbour. + + Keyword arguments: + + i -- Input vector Points file. + field -- Input field name in attribute table. + use_z -- Use z-coordinate instead of field?. + output -- Output raster file. + cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. + base -- Optionally specified input base raster file. Not used when a cell size is specified. + max_dist -- Maximum search distance (optional). + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--field='{}'".format(field)) + if use_z: args.append("--use_z") + args.append("--output='{}'".format(output)) + if cell_size is not None: args.append("--cell_size='{}'".format(cell_size)) + if base is not None: args.append("--base='{}'".format(base)) + if max_dist is not None: args.append("--max_dist='{}'".format(max_dist)) + return self.run_tool('nearest_neighbour_gridding', args, callback) # returns 1 if error + + def polygon_area(self, i, callback=None): + """Calculates the area of vector polygons. + + Keyword arguments: + + i -- Input vector polygon file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + return self.run_tool('polygon_area', args, callback) # returns 1 if error + + def polygon_long_axis(self, i, output, callback=None): + """This tool can be used to map the long axis of polygon features. + + Keyword arguments: + + i -- Input vector polygons file. + output -- Output vector polyline file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('polygon_long_axis', args, callback) # returns 1 if error + + def polygon_perimeter(self, i, callback=None): + """Calculates the perimeter of vector polygons. + + Keyword arguments: + + i -- Input vector polygon file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + return self.run_tool('polygon_perimeter', args, callback) # returns 1 if error + + def polygon_short_axis(self, i, output, callback=None): + """This tool can be used to map the short axis of polygon features. + + Keyword arguments: + + i -- Input vector polygons file. + output -- Output vector polyline file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('polygon_short_axis', args, callback) # returns 1 if error + + def radial_basis_function_interpolation(self, i, field, output, use_z=False, radius=None, min_points=None, func_type="ThinPlateSpline", poly_order="none", weight=0.1, cell_size=None, base=None, callback=None): + """Interpolates vector points into a raster surface using a radial basis function scheme. + + Keyword arguments: + + i -- Input vector points file. + field -- Input field name in attribute table. + use_z -- Use z-coordinate instead of field?. + output -- Output raster file. + radius -- Search Radius (in map units). + min_points -- Minimum number of points. + func_type -- Radial basis function type; options are 'ThinPlateSpline' (default), 'PolyHarmonic', 'Gaussian', 'MultiQuadric', 'InverseMultiQuadric'. + poly_order -- Polynomial order; options are 'none' (default), 'constant', 'affine'. + weight -- Weight parameter used in basis function. + cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. + base -- Optionally specified input base raster file. Not used when a cell size is specified. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--field='{}'".format(field)) + if use_z: args.append("--use_z") + args.append("--output='{}'".format(output)) + if radius is not None: args.append("--radius='{}'".format(radius)) + if min_points is not None: args.append("--min_points='{}'".format(min_points)) + args.append("--func_type={}".format(func_type)) + args.append("--poly_order={}".format(poly_order)) + args.append("--weight={}".format(weight)) + if cell_size is not None: args.append("--cell_size='{}'".format(cell_size)) + if base is not None: args.append("--base='{}'".format(base)) + return self.run_tool('radial_basis_function_interpolation', args, callback) # returns 1 if error + + def raster_area(self, i, output=None, out_text=False, units="grid cells", zero_back=False, callback=None): + """Calculates the area of polygons or classes within a raster image. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + out_text -- Would you like to output polygon areas to text?. + units -- Area units; options include 'grid cells' and 'map units'. + zero_back -- Flag indicating whether zero values should be treated as a background. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + if output is not None: args.append("--output='{}'".format(output)) + if out_text: args.append("--out_text") + args.append("--units={}".format(units)) + if zero_back: args.append("--zero_back") + return self.run_tool('raster_area', args, callback) # returns 1 if error + + def raster_cell_assignment(self, i, output, assign="column", callback=None): + """Assign row or column number to cells. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + assign -- Which variable would you like to assign to grid cells? Options include 'column', 'row', 'x', and 'y'. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--assign={}".format(assign)) + return self.run_tool('raster_cell_assignment', args, callback) # returns 1 if error + + def raster_perimeter(self, i, output=None, out_text=False, units="grid cells", zero_back=False, callback=None): + """Calculates the perimeters of polygons or classes within a raster image. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + out_text -- Would you like to output polygon areas to text?. + units -- Area units; options include 'grid cells' and 'map units'. + zero_back -- Flag indicating whether zero values should be treated as a background. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + if output is not None: args.append("--output='{}'".format(output)) + if out_text: args.append("--out_text") + args.append("--units={}".format(units)) + if zero_back: args.append("--zero_back") + return self.run_tool('raster_perimeter', args, callback) # returns 1 if error + + def reclass(self, i, output, reclass_vals, assign_mode=False, callback=None): + """Reclassifies the values in a raster image. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + reclass_vals -- Reclassification triplet values (new value; from value; to less than), e.g. '0.0;0.0;1.0;1.0;1.0;2.0'. + assign_mode -- Optional Boolean flag indicating whether to operate in assign mode, reclass_vals values are interpreted as new value; old value pairs. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--reclass_vals='{}'".format(reclass_vals)) + if assign_mode: args.append("--assign_mode") + return self.run_tool('reclass', args, callback) # returns 1 if error + + def reclass_equal_interval(self, i, output, interval=10.0, start_val=None, end_val=None, callback=None): + """Reclassifies the values in a raster image based on equal-ranges. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + interval -- Class interval size. + start_val -- Optional starting value (default is input minimum value). + end_val -- Optional ending value (default is input maximum value). + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--interval={}".format(interval)) + if start_val is not None: args.append("--start_val='{}'".format(start_val)) + if end_val is not None: args.append("--end_val='{}'".format(end_val)) + return self.run_tool('reclass_equal_interval', args, callback) # returns 1 if error + + def reclass_from_file(self, i, reclass_file, output, callback=None): + """Reclassifies the values in a raster image using reclass ranges in a text file. + + Keyword arguments: + + i -- Input raster file. + reclass_file -- Input text file containing reclass ranges. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--reclass_file='{}'".format(reclass_file)) + args.append("--output='{}'".format(output)) + return self.run_tool('reclass_from_file', args, callback) # returns 1 if error + + def smooth_vectors(self, i, output, filter=3, callback=None): + """Smooths a vector coverage of either a POLYLINE or POLYGON base ShapeType. + + Keyword arguments: + + i -- Input vector POLYLINE or POLYGON file. + output -- Output vector file. + filter -- The filter size, any odd integer greater than or equal to 3; default is 3. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--filter={}".format(filter)) + return self.run_tool('smooth_vectors', args, callback) # returns 1 if error + + def tin_gridding(self, i, output, field=None, use_z=False, resolution=None, base=None, max_triangle_edge_length=None, callback=None): + """Creates a raster grid based on a triangular irregular network (TIN) fitted to vector points. + + Keyword arguments: + + i -- Input vector points file. + field -- Input field name in attribute table. + use_z -- Use the 'z' dimension of the Shapefile's geometry instead of an attribute field?. + output -- Output raster file. + resolution -- Output raster's grid resolution. + base -- Optionally specified input base raster file. Not used when a cell size is specified. + max_triangle_edge_length -- Optional maximum triangle edge length; triangles larger than this size will not be gridded. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + if field is not None: args.append("--field='{}'".format(field)) + if use_z: args.append("--use_z") + args.append("--output='{}'".format(output)) + if resolution is not None: args.append("--resolution='{}'".format(resolution)) + if base is not None: args.append("--base='{}'".format(base)) + if max_triangle_edge_length is not None: args.append("--max_triangle_edge_length='{}'".format(max_triangle_edge_length)) + return self.run_tool('tin_gridding', args, callback) # returns 1 if error + + def vector_hex_binning(self, i, output, width, orientation="horizontal", callback=None): + """Hex-bins a set of vector points. + + Keyword arguments: + + i -- Input base file. + output -- Output vector polygon file. + width -- The grid cell width. + orientation -- Grid Orientation, 'horizontal' or 'vertical'. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--width='{}'".format(width)) + args.append("--orientation={}".format(orientation)) + return self.run_tool('vector_hex_binning', args, callback) # returns 1 if error + + def voronoi_diagram(self, i, output, callback=None): + """Creates a vector Voronoi diagram for a set of vector points. + + Keyword arguments: + + i -- Input vector points file. + output -- Output vector polygon file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('voronoi_diagram', args, callback) # returns 1 if error + + ############################### + # GIS Analysis/Distance Tools # + ############################### + + def buffer_raster(self, i, output, size, gridcells=False, callback=None): + """Maps a distance-based buffer around each non-background (non-zero/non-nodata) grid cell in an input image. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + size -- Buffer size. + gridcells -- Optional flag to indicate that the 'size' threshold should be measured in grid cells instead of the default map units. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--size='{}'".format(size)) + if gridcells: args.append("--gridcells") + return self.run_tool('buffer_raster', args, callback) # returns 1 if error + + def cost_allocation(self, source, backlink, output, callback=None): + """Identifies the source cell to which each grid cell is connected by a least-cost pathway in a cost-distance analysis. + + Keyword arguments: + + source -- Input source raster file. + backlink -- Input backlink raster file generated by the cost-distance tool. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--source='{}'".format(source)) + args.append("--backlink='{}'".format(backlink)) + args.append("--output='{}'".format(output)) + return self.run_tool('cost_allocation', args, callback) # returns 1 if error + + def cost_distance(self, source, cost, out_accum, out_backlink, callback=None): + """Performs cost-distance accumulation on a cost surface and a group of source cells. + + Keyword arguments: + + source -- Input source raster file. + cost -- Input cost (friction) raster file. + out_accum -- Output cost accumulation raster file. + out_backlink -- Output backlink raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--source='{}'".format(source)) + args.append("--cost='{}'".format(cost)) + args.append("--out_accum='{}'".format(out_accum)) + args.append("--out_backlink='{}'".format(out_backlink)) + return self.run_tool('cost_distance', args, callback) # returns 1 if error + + def cost_pathway(self, destination, backlink, output, zero_background=False, callback=None): + """Performs cost-distance pathway analysis using a series of destination grid cells. + + Keyword arguments: + + destination -- Input destination raster file. + backlink -- Input backlink raster file generated by the cost-distance tool. + output -- Output cost pathway raster file. + zero_background -- Flag indicating whether zero values should be treated as a background. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--destination='{}'".format(destination)) + args.append("--backlink='{}'".format(backlink)) + args.append("--output='{}'".format(output)) + if zero_background: args.append("--zero_background") + return self.run_tool('cost_pathway', args, callback) # returns 1 if error + + def euclidean_allocation(self, i, output, callback=None): + """Assigns grid cells in the output raster the value of the nearest target cell in the input image, measured by the Shih and Wu (2004) Euclidean distance transform. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('euclidean_allocation', args, callback) # returns 1 if error + + def euclidean_distance(self, i, output, callback=None): + """Calculates the Shih and Wu (2004) Euclidean distance transform. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('euclidean_distance', args, callback) # returns 1 if error + + ############################## + # GIS Analysis/Overlay Tools # + ############################## + + def average_overlay(self, inputs, output, callback=None): + """Calculates the average for each grid cell from a group of raster images. + + Keyword arguments: + + inputs -- Input raster files. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--inputs='{}'".format(inputs)) + args.append("--output='{}'".format(output)) + return self.run_tool('average_overlay', args, callback) # returns 1 if error + + def clip(self, i, clip, output, callback=None): + """Extract all the features, or parts of features, that overlap with the features of the clip vector. + + Keyword arguments: + + i -- Input vector file. + clip -- Input clip polygon vector file. + output -- Output vector file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--clip='{}'".format(clip)) + args.append("--output='{}'".format(output)) + return self.run_tool('clip', args, callback) # returns 1 if error + + def clip_raster_to_polygon(self, i, polygons, output, maintain_dimensions=False, callback=None): + """Clips a raster to a vector polygon. + + Keyword arguments: + + i -- Input raster file. + polygons -- Input vector polygons file. + output -- Output raster file. + maintain_dimensions -- Maintain input raster dimensions?. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--polygons='{}'".format(polygons)) + args.append("--output='{}'".format(output)) + if maintain_dimensions: args.append("--maintain_dimensions") + return self.run_tool('clip_raster_to_polygon', args, callback) # returns 1 if error + + def count_if(self, inputs, output, value, callback=None): + """Counts the number of occurrences of a specified value in a cell-stack of rasters. + + Keyword arguments: + + inputs -- Input raster files. + output -- Output raster file. + value -- Search value (e.g. countif value = 5.0). + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--inputs='{}'".format(inputs)) + args.append("--output='{}'".format(output)) + args.append("--value='{}'".format(value)) + return self.run_tool('count_if', args, callback) # returns 1 if error + + def difference(self, i, overlay, output, callback=None): + """Outputs the features that occur in one of the two vector inputs but not both, i.e. no overlapping features. + + Keyword arguments: + + i -- Input vector file. + overlay -- Input overlay vector file. + output -- Output vector file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--overlay='{}'".format(overlay)) + args.append("--output='{}'".format(output)) + return self.run_tool('difference', args, callback) # returns 1 if error + + def erase(self, i, erase, output, callback=None): + """Removes all the features, or parts of features, that overlap with the features of the erase vector polygon. + + Keyword arguments: + + i -- Input vector file. + erase -- Input erase polygon vector file. + output -- Output vector file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--erase='{}'".format(erase)) + args.append("--output='{}'".format(output)) + return self.run_tool('erase', args, callback) # returns 1 if error + + def erase_polygon_from_raster(self, i, polygons, output, callback=None): + """Erases (cuts out) a vector polygon from a raster. + + Keyword arguments: + + i -- Input raster file. + polygons -- Input vector polygons file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--polygons='{}'".format(polygons)) + args.append("--output='{}'".format(output)) + return self.run_tool('erase_polygon_from_raster', args, callback) # returns 1 if error + + def highest_position(self, inputs, output, callback=None): + """Identifies the stack position of the maximum value within a raster stack on a cell-by-cell basis. + + Keyword arguments: + + inputs -- Input raster files. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--inputs='{}'".format(inputs)) + args.append("--output='{}'".format(output)) + return self.run_tool('highest_position', args, callback) # returns 1 if error + + def intersect(self, i, overlay, output, snap=0.0, callback=None): + """Identifies the parts of features in common between two input vector layers. + + Keyword arguments: + + i -- Input vector file. + overlay -- Input overlay vector file. + output -- Output vector file. + snap -- Snap tolerance. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--overlay='{}'".format(overlay)) + args.append("--output='{}'".format(output)) + args.append("--snap={}".format(snap)) + return self.run_tool('intersect', args, callback) # returns 1 if error + + def line_intersections(self, input1, input2, output, callback=None): + """Identifies points where the features of two vector line layers intersect. + + Keyword arguments: + + input1 -- Input vector polyline file. + input2 -- Input vector polyline file. + output -- Output vector point file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input1='{}'".format(input1)) + args.append("--input2='{}'".format(input2)) + args.append("--output='{}'".format(output)) + return self.run_tool('line_intersections', args, callback) # returns 1 if error + + def lowest_position(self, inputs, output, callback=None): + """Identifies the stack position of the minimum value within a raster stack on a cell-by-cell basis. + + Keyword arguments: + + inputs -- Input raster files. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--inputs='{}'".format(inputs)) + args.append("--output='{}'".format(output)) + return self.run_tool('lowest_position', args, callback) # returns 1 if error + + def max_absolute_overlay(self, inputs, output, callback=None): + """Evaluates the maximum absolute value for each grid cell from a stack of input rasters. + + Keyword arguments: + + inputs -- Input raster files. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--inputs='{}'".format(inputs)) + args.append("--output='{}'".format(output)) + return self.run_tool('max_absolute_overlay', args, callback) # returns 1 if error + + def max_overlay(self, inputs, output, callback=None): + """Evaluates the maximum value for each grid cell from a stack of input rasters. + + Keyword arguments: + + inputs -- Input raster files. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--inputs='{}'".format(inputs)) + args.append("--output='{}'".format(output)) + return self.run_tool('max_overlay', args, callback) # returns 1 if error + + def merge_line_segments(self, i, output, snap=0.0, callback=None): + """Merges vector line segments into larger features. + + Keyword arguments: + + i -- Input vector file. + output -- Output vector file. + snap -- Snap tolerance. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--snap={}".format(snap)) + return self.run_tool('merge_line_segments', args, callback) # returns 1 if error + + def min_absolute_overlay(self, inputs, output, callback=None): + """Evaluates the minimum absolute value for each grid cell from a stack of input rasters. + + Keyword arguments: + + inputs -- Input raster files. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--inputs='{}'".format(inputs)) + args.append("--output='{}'".format(output)) + return self.run_tool('min_absolute_overlay', args, callback) # returns 1 if error + + def min_overlay(self, inputs, output, callback=None): + """Evaluates the minimum value for each grid cell from a stack of input rasters. + + Keyword arguments: + + inputs -- Input raster files. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--inputs='{}'".format(inputs)) + args.append("--output='{}'".format(output)) + return self.run_tool('min_overlay', args, callback) # returns 1 if error + + def percent_equal_to(self, inputs, comparison, output, callback=None): + """Calculates the percentage of a raster stack that have cell values equal to an input on a cell-by-cell basis. + + Keyword arguments: + + inputs -- Input raster files. + comparison -- Input comparison raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--inputs='{}'".format(inputs)) + args.append("--comparison='{}'".format(comparison)) + args.append("--output='{}'".format(output)) + return self.run_tool('percent_equal_to', args, callback) # returns 1 if error + + def percent_greater_than(self, inputs, comparison, output, callback=None): + """Calculates the percentage of a raster stack that have cell values greather than an input on a cell-by-cell basis. + + Keyword arguments: + + inputs -- Input raster files. + comparison -- Input comparison raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--inputs='{}'".format(inputs)) + args.append("--comparison='{}'".format(comparison)) + args.append("--output='{}'".format(output)) + return self.run_tool('percent_greater_than', args, callback) # returns 1 if error + + def percent_less_than(self, inputs, comparison, output, callback=None): + """Calculates the percentage of a raster stack that have cell values less than an input on a cell-by-cell basis. + + Keyword arguments: + + inputs -- Input raster files. + comparison -- Input comparison raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--inputs='{}'".format(inputs)) + args.append("--comparison='{}'".format(comparison)) + args.append("--output='{}'".format(output)) + return self.run_tool('percent_less_than', args, callback) # returns 1 if error + + def pick_from_list(self, inputs, pos_input, output, callback=None): + """Outputs the value from a raster stack specified by a position raster. + + Keyword arguments: + + inputs -- Input raster files. + pos_input -- Input position raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--inputs='{}'".format(inputs)) + args.append("--pos_input='{}'".format(pos_input)) + args.append("--output='{}'".format(output)) + return self.run_tool('pick_from_list', args, callback) # returns 1 if error + + def polygonize(self, inputs, output, callback=None): + """Creates a polygon layer from two or more intersecting line features contained in one or more input vector line files. + + Keyword arguments: + + inputs -- Input vector polyline file. + output -- Output vector polygon file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--inputs='{}'".format(inputs)) + args.append("--output='{}'".format(output)) + return self.run_tool('polygonize', args, callback) # returns 1 if error + + def split_with_lines(self, i, split, output, callback=None): + """Splits the lines or polygons in one layer using the lines in another layer. + + Keyword arguments: + + i -- Input vector line or polygon file. + split -- Input vector polyline file. + output -- Output vector file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--split='{}'".format(split)) + args.append("--output='{}'".format(output)) + return self.run_tool('split_with_lines', args, callback) # returns 1 if error + + def sum_overlay(self, inputs, output, callback=None): + """Calculates the sum for each grid cell from a group of raster images. + + Keyword arguments: + + inputs -- Input raster files. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--inputs='{}'".format(inputs)) + args.append("--output='{}'".format(output)) + return self.run_tool('sum_overlay', args, callback) # returns 1 if error + + def symmetrical_difference(self, i, overlay, output, snap=0.0, callback=None): + """Outputs the features that occur in one of the two vector inputs but not both, i.e. no overlapping features. + + Keyword arguments: + + i -- Input vector file. + overlay -- Input overlay vector file. + output -- Output vector file. + snap -- Snap tolerance. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--overlay='{}'".format(overlay)) + args.append("--output='{}'".format(output)) + args.append("--snap={}".format(snap)) + return self.run_tool('symmetrical_difference', args, callback) # returns 1 if error + + def union(self, i, overlay, output, snap=0.0, callback=None): + """Splits vector layers at their overlaps, creating a layer containing all the portions from both input and overlay layers. + + Keyword arguments: + + i -- Input vector file. + overlay -- Input overlay vector file. + output -- Output vector file. + snap -- Snap tolerance. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--overlay='{}'".format(overlay)) + args.append("--output='{}'".format(output)) + args.append("--snap={}".format(snap)) + return self.run_tool('union', args, callback) # returns 1 if error + + def update_nodata_cells(self, input1, input2, output, callback=None): + """Replaces the NoData values in an input raster with the corresponding values contained in a second update layer. + + Keyword arguments: + + input1 -- Input raster file 1. + input2 -- Input raster file 2; update layer. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input1='{}'".format(input1)) + args.append("--input2='{}'".format(input2)) + args.append("--output='{}'".format(output)) + return self.run_tool('update_nodata_cells', args, callback) # returns 1 if error + + def weighted_overlay(self, factors, weights, output, cost=None, constraints=None, scale_max=1.0, callback=None): + """Performs a weighted sum on multiple input rasters after converting each image to a common scale. The tool performs a multi-criteria evaluation (MCE). + + Keyword arguments: + + factors -- Input factor raster files. + weights -- Weight values, contained in quotes and separated by commas or semicolons. Must have the same number as factors. + cost -- Weight values, contained in quotes and separated by commas or semicolons. Must have the same number as factors. + constraints -- Input constraints raster files. + output -- Output raster file. + scale_max -- Suitability scale maximum value (common values are 1.0, 100.0, and 255.0). + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--factors='{}'".format(factors)) + args.append("--weights='{}'".format(weights)) + if cost is not None: args.append("--cost='{}'".format(cost)) + if constraints is not None: args.append("--constraints='{}'".format(constraints)) + args.append("--output='{}'".format(output)) + args.append("--scale_max={}".format(scale_max)) + return self.run_tool('weighted_overlay', args, callback) # returns 1 if error + + def weighted_sum(self, inputs, weights, output, callback=None): + """Performs a weighted-sum overlay on multiple input raster images. + + Keyword arguments: + + inputs -- Input raster files. + weights -- Weight values, contained in quotes and separated by commas or semicolons. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--inputs='{}'".format(inputs)) + args.append("--weights='{}'".format(weights)) + args.append("--output='{}'".format(output)) + return self.run_tool('weighted_sum', args, callback) # returns 1 if error + + ################################## + # GIS Analysis/Patch Shape Tools # + ################################## + + def boundary_shape_complexity(self, i, output, callback=None): + """Calculates the complexity of the boundaries of raster polygons. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('boundary_shape_complexity', args, callback) # returns 1 if error + + def compactness_ratio(self, i, callback=None): + """Calculates the compactness ratio (A/P), a measure of shape complexity, for vector polygons. + + Keyword arguments: + + i -- Input vector polygon file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + return self.run_tool('compactness_ratio', args, callback) # returns 1 if error + + def edge_proportion(self, i, output, output_text=False, callback=None): + """Calculate the proportion of cells in a raster polygon that are edge cells. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + output_text -- flag indicating whether a text report should also be output. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + if output_text: args.append("--output_text") + return self.run_tool('edge_proportion', args, callback) # returns 1 if error + + def elongation_ratio(self, i, callback=None): + """Calculates the elongation ratio for vector polygons. + + Keyword arguments: + + i -- Input vector polygon file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + return self.run_tool('elongation_ratio', args, callback) # returns 1 if error + + def find_patch_or_class_edge_cells(self, i, output, callback=None): + """Finds all cells located on the edge of patch or class features. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('find_patch_or_class_edge_cells', args, callback) # returns 1 if error + + def hole_proportion(self, i, callback=None): + """Calculates the proportion of the total area of a polygon's holes relative to the area of the polygon's hull. + + Keyword arguments: + + i -- Input vector polygon file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + return self.run_tool('hole_proportion', args, callback) # returns 1 if error + + def linearity_index(self, i, callback=None): + """Calculates the linearity index for vector polygons. + + Keyword arguments: + + i -- Input vector polygon file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + return self.run_tool('linearity_index', args, callback) # returns 1 if error + + def narrowness_index(self, i, output, callback=None): + """Calculates the narrowness of raster polygons. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('narrowness_index', args, callback) # returns 1 if error + + def patch_orientation(self, i, callback=None): + """Calculates the orientation of vector polygons. + + Keyword arguments: + + i -- Input vector polygon file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + return self.run_tool('patch_orientation', args, callback) # returns 1 if error + + def perimeter_area_ratio(self, i, callback=None): + """Calculates the perimeter-area ratio of vector polygons. + + Keyword arguments: + + i -- Input vector polygon file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + return self.run_tool('perimeter_area_ratio', args, callback) # returns 1 if error + + def radius_of_gyration(self, i, output, text_output=False, callback=None): + """Calculates the distance of cells from their polygon's centroid. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + text_output -- Optional text output. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + if text_output: args.append("--text_output") + return self.run_tool('radius_of_gyration', args, callback) # returns 1 if error + + def related_circumscribing_circle(self, i, callback=None): + """Calculates the related circumscribing circle of vector polygons. + + Keyword arguments: + + i -- Input vector polygon file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + return self.run_tool('related_circumscribing_circle', args, callback) # returns 1 if error + + def shape_complexity_index(self, i, callback=None): + """Calculates overall polygon shape complexity or irregularity. + + Keyword arguments: + + i -- Input vector polygon file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + return self.run_tool('shape_complexity_index', args, callback) # returns 1 if error + + def shape_complexity_index_raster(self, i, output, callback=None): + """Calculates the complexity of raster polygons or classes. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('shape_complexity_index_raster', args, callback) # returns 1 if error + + ############################ + # Geomorphometric Analysis # + ############################ + + def aspect(self, dem, output, zfactor=1.0, callback=None): + """Calculates an aspect raster from an input DEM. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + args.append("--zfactor={}".format(zfactor)) + return self.run_tool('aspect', args, callback) # returns 1 if error + + def average_normal_vector_angular_deviation(self, dem, output, filter=11, callback=None): + """Calculates the circular variance of aspect at a scale for a DEM. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + filter -- Size of the filter kernel. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + args.append("--filter={}".format(filter)) + return self.run_tool('average_normal_vector_angular_deviation', args, callback) # returns 1 if error + + def circular_variance_of_aspect(self, dem, output, filter=11, callback=None): + """Calculates the circular variance of aspect at a scale for a DEM. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + filter -- Size of the filter kernel. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + args.append("--filter={}".format(filter)) + return self.run_tool('circular_variance_of_aspect', args, callback) # returns 1 if error + + def contours_from_points(self, i, output, field=None, use_z=False, max_triangle_edge_length=None, interval=10.0, base=0.0, smooth=5, callback=None): + """Creates a contour coverage from a set of input points. + + Keyword arguments: + + i -- Input vector points file. + field -- Input field name in attribute table. + use_z -- Use the 'z' dimension of the Shapefile's geometry instead of an attribute field?. + output -- Output vector lines file. + max_triangle_edge_length -- Optional maximum triangle edge length; triangles larger than this size will not be gridded. + interval -- Contour interval. + base -- Base contour height. + smooth -- Smoothing filter size (in num. points), e.g. 3, 5, 7, 9, 11. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + if field is not None: args.append("--field='{}'".format(field)) + if use_z: args.append("--use_z") + args.append("--output='{}'".format(output)) + if max_triangle_edge_length is not None: args.append("--max_triangle_edge_length='{}'".format(max_triangle_edge_length)) + args.append("--interval={}".format(interval)) + args.append("--base={}".format(base)) + args.append("--smooth={}".format(smooth)) + return self.run_tool('contours_from_points', args, callback) # returns 1 if error + + def contours_from_raster(self, i, output, interval=10.0, base=0.0, smooth=9, tolerance=10.0, callback=None): + """Derives a vector contour coverage from a raster surface. + + Keyword arguments: + + i -- Input surface raster file. + output -- Output vector contour file. + interval -- Contour interval. + base -- Base contour height. + smooth -- Smoothing filter size (in num. points), e.g. 3, 5, 7, 9, 11. + tolerance -- Tolerance factor, in degrees (0-45); determines generalization level. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--interval={}".format(interval)) + args.append("--base={}".format(base)) + args.append("--smooth={}".format(smooth)) + args.append("--tolerance={}".format(tolerance)) + return self.run_tool('contours_from_raster', args, callback) # returns 1 if error + + def dev_from_mean_elev(self, dem, output, filterx=11, filtery=11, callback=None): + """Calculates deviation from mean elevation. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + filterx -- Size of the filter kernel in the x-direction. + filtery -- Size of the filter kernel in the y-direction. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + args.append("--filterx={}".format(filterx)) + args.append("--filtery={}".format(filtery)) + return self.run_tool('dev_from_mean_elev', args, callback) # returns 1 if error + + def diff_from_mean_elev(self, dem, output, filterx=11, filtery=11, callback=None): + """Calculates difference from mean elevation (equivalent to a high-pass filter). + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + filterx -- Size of the filter kernel in the x-direction. + filtery -- Size of the filter kernel in the y-direction. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + args.append("--filterx={}".format(filterx)) + args.append("--filtery={}".format(filtery)) + return self.run_tool('diff_from_mean_elev', args, callback) # returns 1 if error + + def directional_relief(self, dem, output, azimuth=0.0, max_dist=None, callback=None): + """Calculates relief for cells in an input DEM for a specified direction. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + azimuth -- Wind azimuth in degrees. + max_dist -- Optional maximum search distance (unspecified if none; in xy units). + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + args.append("--azimuth={}".format(azimuth)) + if max_dist is not None: args.append("--max_dist='{}'".format(max_dist)) + return self.run_tool('directional_relief', args, callback) # returns 1 if error + + def downslope_index(self, dem, output, drop=2.0, out_type="tangent", callback=None): + """Calculates the Hjerdt et al. (2004) downslope index. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + drop -- Vertical drop value (default is 2.0). + out_type -- Output type, options include 'tangent', 'degrees', 'radians', 'distance' (default is 'tangent'). + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + args.append("--drop={}".format(drop)) + args.append("--out_type={}".format(out_type)) + return self.run_tool('downslope_index', args, callback) # returns 1 if error + + def edge_density(self, dem, output, filter=11, norm_diff=5.0, zfactor=1.0, callback=None): + """Calculates the density of edges, or breaks-in-slope within DEMs. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + filter -- Size of the filter kernel. + norm_diff -- Maximum difference in normal vectors, in degrees. + zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + args.append("--filter={}".format(filter)) + args.append("--norm_diff={}".format(norm_diff)) + args.append("--zfactor={}".format(zfactor)) + return self.run_tool('edge_density', args, callback) # returns 1 if error + + def elev_above_pit(self, dem, output, callback=None): + """Calculate the elevation of each grid cell above the nearest downstream pit cell or grid edge cell. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + return self.run_tool('elev_above_pit', args, callback) # returns 1 if error + + def elev_percentile(self, dem, output, filterx=11, filtery=11, sig_digits=2, callback=None): + """Calculates the elevation percentile raster from a DEM. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + filterx -- Size of the filter kernel in the x-direction. + filtery -- Size of the filter kernel in the y-direction. + sig_digits -- Number of significant digits. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + args.append("--filterx={}".format(filterx)) + args.append("--filtery={}".format(filtery)) + args.append("--sig_digits={}".format(sig_digits)) + return self.run_tool('elev_percentile', args, callback) # returns 1 if error + + def elev_relative_to_min_max(self, dem, output, callback=None): + """Calculates the elevation of a location relative to the minimum and maximum elevations in a DEM. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + return self.run_tool('elev_relative_to_min_max', args, callback) # returns 1 if error + + def elev_relative_to_watershed_min_max(self, dem, watersheds, output, callback=None): + """Calculates the elevation of a location relative to the minimum and maximum elevations in a watershed. + + Keyword arguments: + + dem -- Input raster DEM file. + watersheds -- Input raster watersheds file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--watersheds='{}'".format(watersheds)) + args.append("--output='{}'".format(output)) + return self.run_tool('elev_relative_to_watershed_min_max', args, callback) # returns 1 if error + + def feature_preserving_smoothing(self, dem, output, filter=11, norm_diff=15.0, num_iter=3, max_diff=0.5, zfactor=1.0, callback=None): + """Reduces short-scale variation in an input DEM using a modified Sun et al. (2007) algorithm. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + filter -- Size of the filter kernel. + norm_diff -- Maximum difference in normal vectors, in degrees. + num_iter -- Number of iterations. + max_diff -- Maximum allowable absolute elevation change (optional). + zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + args.append("--filter={}".format(filter)) + args.append("--norm_diff={}".format(norm_diff)) + args.append("--num_iter={}".format(num_iter)) + args.append("--max_diff={}".format(max_diff)) + args.append("--zfactor={}".format(zfactor)) + return self.run_tool('feature_preserving_smoothing', args, callback) # returns 1 if error + + def fetch_analysis(self, dem, output, azimuth=0.0, hgt_inc=0.05, callback=None): + """Performs an analysis of fetch or upwind distance to an obstacle. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + azimuth -- Wind azimuth in degrees in degrees. + hgt_inc -- Height increment value. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + args.append("--azimuth={}".format(azimuth)) + args.append("--hgt_inc={}".format(hgt_inc)) + return self.run_tool('fetch_analysis', args, callback) # returns 1 if error + + def fill_missing_data(self, i, output, filter=11, weight=2.0, no_edges=True, callback=None): + """Fills NoData holes in a DEM. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + filter -- Filter size (cells). + weight -- IDW weight value. + no_edges -- Optional flag indicating whether to exclude NoData cells in edge regions. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--filter={}".format(filter)) + args.append("--weight={}".format(weight)) + if no_edges: args.append("--no_edges") + return self.run_tool('fill_missing_data', args, callback) # returns 1 if error + + def find_ridges(self, dem, output, line_thin=True, callback=None): + """Identifies potential ridge and peak grid cells. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + line_thin -- Optional flag indicating whether post-processing line-thinning should be performed. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + if line_thin: args.append("--line_thin") + return self.run_tool('find_ridges', args, callback) # returns 1 if error + + def hillshade(self, dem, output, azimuth=315.0, altitude=30.0, zfactor=1.0, callback=None): + """Calculates a hillshade raster from an input DEM. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + azimuth -- Illumination source azimuth in degrees. + altitude -- Illumination source altitude in degrees. + zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + args.append("--azimuth={}".format(azimuth)) + args.append("--altitude={}".format(altitude)) + args.append("--zfactor={}".format(zfactor)) + return self.run_tool('hillshade', args, callback) # returns 1 if error + + def horizon_angle(self, dem, output, azimuth=0.0, max_dist=None, callback=None): + """Calculates horizon angle (maximum upwind slope) for each grid cell in an input DEM. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + azimuth -- Wind azimuth in degrees. + max_dist -- Optional maximum search distance (unspecified if none; in xy units). + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + args.append("--azimuth={}".format(azimuth)) + if max_dist is not None: args.append("--max_dist='{}'".format(max_dist)) + return self.run_tool('horizon_angle', args, callback) # returns 1 if error + + def hypsometric_analysis(self, inputs, output, watershed=None, callback=None): + """Calculates a hypsometric curve for one or more DEMs. + + Keyword arguments: + + inputs -- Input DEM files. + watershed -- Input watershed files (optional). + output -- Output HTML file (default name will be based on input file if unspecified). + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--inputs='{}'".format(inputs)) + if watershed is not None: args.append("--watershed='{}'".format(watershed)) + args.append("--output='{}'".format(output)) + return self.run_tool('hypsometric_analysis', args, callback) # returns 1 if error + + def hypsometrically_tinted_hillshade(self, dem, output, altitude=45.0, hs_weight=0.5, brightness=0.5, atmospheric=0.0, palette="atlas", reverse=False, zfactor=1.0, full_mode=False, callback=None): + """Creates an colour shaded relief image from an input DEM. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + altitude -- Illumination source altitude in degrees. + hs_weight -- Weight given to hillshade relative to relief (0.0-1.0). + brightness -- Brightness factor (0.0-1.0). + atmospheric -- Atmospheric effects weight (0.0-1.0). + palette -- Options include 'atlas', 'high_relief', 'arid', 'soft', 'muted', 'purple', 'viridi', 'gn_yl', 'pi_y_g', 'bl_yl_rd', and 'deep. + reverse -- Optional flag indicating whether to use reverse the palette. + zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. + full_mode -- Optional flag indicating whether to use full 360-degrees of illumination sources. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + args.append("--altitude={}".format(altitude)) + args.append("--hs_weight={}".format(hs_weight)) + args.append("--brightness={}".format(brightness)) + args.append("--atmospheric={}".format(atmospheric)) + args.append("--palette={}".format(palette)) + if reverse: args.append("--reverse") + args.append("--zfactor={}".format(zfactor)) + if full_mode: args.append("--full_mode") + return self.run_tool('hypsometrically_tinted_hillshade', args, callback) # returns 1 if error + + def max_anisotropy_dev(self, dem, out_mag, out_scale, max_scale, min_scale=3, step=2, callback=None): + """Calculates the maximum anisotropy (directionality) in elevation deviation over a range of spatial scales. + + Keyword arguments: + + dem -- Input raster DEM file. + out_mag -- Output raster DEVmax magnitude file. + out_scale -- Output raster DEVmax scale file. + min_scale -- Minimum search neighbourhood radius in grid cells. + max_scale -- Maximum search neighbourhood radius in grid cells. + step -- Step size as any positive non-zero integer. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--out_mag='{}'".format(out_mag)) + args.append("--out_scale='{}'".format(out_scale)) + args.append("--min_scale={}".format(min_scale)) + args.append("--max_scale='{}'".format(max_scale)) + args.append("--step={}".format(step)) + return self.run_tool('max_anisotropy_dev', args, callback) # returns 1 if error + + def max_anisotropy_dev_signature(self, dem, points, output, max_scale, min_scale=1, step=1, callback=None): + """Calculates the anisotropy in deviation from mean for points over a range of spatial scales. + + Keyword arguments: + + dem -- Input raster DEM file. + points -- Input vector points file. + output -- Output HTML file. + min_scale -- Minimum search neighbourhood radius in grid cells. + max_scale -- Maximum search neighbourhood radius in grid cells. + step -- Step size as any positive non-zero integer. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--points='{}'".format(points)) + args.append("--output='{}'".format(output)) + args.append("--min_scale={}".format(min_scale)) + args.append("--max_scale='{}'".format(max_scale)) + args.append("--step={}".format(step)) + return self.run_tool('max_anisotropy_dev_signature', args, callback) # returns 1 if error + + def max_branch_length(self, dem, output, log=False, callback=None): + """Lindsay and Seibert's (2013) branch length index is used to map drainage divides or ridge lines. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + log -- Optional flag to request the output be log-transformed. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + if log: args.append("--log") + return self.run_tool('max_branch_length', args, callback) # returns 1 if error + + def max_difference_from_mean(self, dem, out_mag, out_scale, min_scale, max_scale, step=1, callback=None): + """Calculates the maximum difference from mean elevation over a range of spatial scales. + + Keyword arguments: + + dem -- Input raster DEM file. + out_mag -- Output raster DIFFmax magnitude file. + out_scale -- Output raster DIFFmax scale file. + min_scale -- Minimum search neighbourhood radius in grid cells. + max_scale -- Maximum search neighbourhood radius in grid cells. + step -- Step size as any positive non-zero integer. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--out_mag='{}'".format(out_mag)) + args.append("--out_scale='{}'".format(out_scale)) + args.append("--min_scale='{}'".format(min_scale)) + args.append("--max_scale='{}'".format(max_scale)) + args.append("--step={}".format(step)) + return self.run_tool('max_difference_from_mean', args, callback) # returns 1 if error + + def max_downslope_elev_change(self, dem, output, callback=None): + """Calculates the maximum downslope change in elevation between a grid cell and its eight downslope neighbors. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + return self.run_tool('max_downslope_elev_change', args, callback) # returns 1 if error + + def max_elev_dev_signature(self, dem, points, output, min_scale, max_scale, step=10, callback=None): + """Calculates the maximum elevation deviation over a range of spatial scales and for a set of points. + + Keyword arguments: + + dem -- Input raster DEM file. + points -- Input vector points file. + output -- Output HTML file. + min_scale -- Minimum search neighbourhood radius in grid cells. + max_scale -- Maximum search neighbourhood radius in grid cells. + step -- Step size as any positive non-zero integer. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--points='{}'".format(points)) + args.append("--output='{}'".format(output)) + args.append("--min_scale='{}'".format(min_scale)) + args.append("--max_scale='{}'".format(max_scale)) + args.append("--step={}".format(step)) + return self.run_tool('max_elev_dev_signature', args, callback) # returns 1 if error + + def max_elevation_deviation(self, dem, out_mag, out_scale, min_scale, max_scale, step=1, callback=None): + """Calculates the maximum elevation deviation over a range of spatial scales. + + Keyword arguments: + + dem -- Input raster DEM file. + out_mag -- Output raster DEVmax magnitude file. + out_scale -- Output raster DEVmax scale file. + min_scale -- Minimum search neighbourhood radius in grid cells. + max_scale -- Maximum search neighbourhood radius in grid cells. + step -- Step size as any positive non-zero integer. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--out_mag='{}'".format(out_mag)) + args.append("--out_scale='{}'".format(out_scale)) + args.append("--min_scale='{}'".format(min_scale)) + args.append("--max_scale='{}'".format(max_scale)) + args.append("--step={}".format(step)) + return self.run_tool('max_elevation_deviation', args, callback) # returns 1 if error + + def min_downslope_elev_change(self, dem, output, callback=None): + """Calculates the minimum downslope change in elevation between a grid cell and its eight downslope neighbors. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + return self.run_tool('min_downslope_elev_change', args, callback) # returns 1 if error + + def multidirectional_hillshade(self, dem, output, altitude=45.0, zfactor=1.0, full_mode=False, callback=None): + """Calculates a multi-direction hillshade raster from an input DEM. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + altitude -- Illumination source altitude in degrees. + zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. + full_mode -- Optional flag indicating whether to use full 360-degrees of illumination sources. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + args.append("--altitude={}".format(altitude)) + args.append("--zfactor={}".format(zfactor)) + if full_mode: args.append("--full_mode") + return self.run_tool('multidirectional_hillshade', args, callback) # returns 1 if error + + def multiscale_elevation_percentile(self, dem, out_mag, out_scale, sig_digits=3, min_scale=4, step=1, num_steps=10, step_nonlinearity=1.0, callback=None): + """Calculates surface roughness over a range of spatial scales. + + Keyword arguments: + + dem -- Input raster DEM file. + out_mag -- Output raster roughness magnitude file. + out_scale -- Output raster roughness scale file. + sig_digits -- Number of significant digits. + min_scale -- Minimum search neighbourhood radius in grid cells. + step -- Step size as any positive non-zero integer. + num_steps -- Number of steps. + step_nonlinearity -- Step nonlinearity factor (1.0-2.0 is typical). + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--out_mag='{}'".format(out_mag)) + args.append("--out_scale='{}'".format(out_scale)) + args.append("--sig_digits={}".format(sig_digits)) + args.append("--min_scale={}".format(min_scale)) + args.append("--step={}".format(step)) + args.append("--num_steps={}".format(num_steps)) + args.append("--step_nonlinearity={}".format(step_nonlinearity)) + return self.run_tool('multiscale_elevation_percentile', args, callback) # returns 1 if error + + def multiscale_roughness(self, dem, out_mag, out_scale, max_scale, min_scale=1, step=1, callback=None): + """Calculates surface roughness over a range of spatial scales. + + Keyword arguments: + + dem -- Input raster DEM file. + out_mag -- Output raster roughness magnitude file. + out_scale -- Output raster roughness scale file. + min_scale -- Minimum search neighbourhood radius in grid cells. + max_scale -- Maximum search neighbourhood radius in grid cells. + step -- Step size as any positive non-zero integer. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--out_mag='{}'".format(out_mag)) + args.append("--out_scale='{}'".format(out_scale)) + args.append("--min_scale={}".format(min_scale)) + args.append("--max_scale='{}'".format(max_scale)) + args.append("--step={}".format(step)) + return self.run_tool('multiscale_roughness', args, callback) # returns 1 if error + + def multiscale_roughness_signature(self, dem, points, output, max_scale, min_scale=1, step=1, callback=None): + """Calculates the surface roughness for points over a range of spatial scales. + + Keyword arguments: + + dem -- Input raster DEM file. + points -- Input vector points file. + output -- Output HTML file. + min_scale -- Minimum search neighbourhood radius in grid cells. + max_scale -- Maximum search neighbourhood radius in grid cells. + step -- Step size as any positive non-zero integer. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--points='{}'".format(points)) + args.append("--output='{}'".format(output)) + args.append("--min_scale={}".format(min_scale)) + args.append("--max_scale='{}'".format(max_scale)) + args.append("--step={}".format(step)) + return self.run_tool('multiscale_roughness_signature', args, callback) # returns 1 if error + + def multiscale_std_dev_normals(self, dem, out_mag, out_scale, min_scale=1, step=1, num_steps=10, step_nonlinearity=1.0, callback=None): + """Calculates surface roughness over a range of spatial scales. + + Keyword arguments: + + dem -- Input raster DEM file. + out_mag -- Output raster roughness magnitude file. + out_scale -- Output raster roughness scale file. + min_scale -- Minimum search neighbourhood radius in grid cells. + step -- Step size as any positive non-zero integer. + num_steps -- Number of steps. + step_nonlinearity -- Step nonlinearity factor (1.0-2.0 is typical). + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--out_mag='{}'".format(out_mag)) + args.append("--out_scale='{}'".format(out_scale)) + args.append("--min_scale={}".format(min_scale)) + args.append("--step={}".format(step)) + args.append("--num_steps={}".format(num_steps)) + args.append("--step_nonlinearity={}".format(step_nonlinearity)) + return self.run_tool('multiscale_std_dev_normals', args, callback) # returns 1 if error + + def multiscale_std_dev_normals_signature(self, dem, points, output, min_scale=1, step=1, num_steps=10, step_nonlinearity=1.0, callback=None): + """Calculates the surface roughness for points over a range of spatial scales. + + Keyword arguments: + + dem -- Input raster DEM file. + points -- Input vector points file. + output -- Output HTML file. + min_scale -- Minimum search neighbourhood radius in grid cells. + step -- Step size as any positive non-zero integer. + num_steps -- Number of steps. + step_nonlinearity -- Step nonlinearity factor (1.0-2.0 is typical). + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--points='{}'".format(points)) + args.append("--output='{}'".format(output)) + args.append("--min_scale={}".format(min_scale)) + args.append("--step={}".format(step)) + args.append("--num_steps={}".format(num_steps)) + args.append("--step_nonlinearity={}".format(step_nonlinearity)) + return self.run_tool('multiscale_std_dev_normals_signature', args, callback) # returns 1 if error + + def multiscale_topographic_position_image(self, local, meso, broad, output, lightness=1.2, callback=None): + """Creates a multiscale topographic position image from three DEVmax rasters of differing spatial scale ranges. + + Keyword arguments: + + local -- Input local-scale topographic position (DEVmax) raster file. + meso -- Input meso-scale topographic position (DEVmax) raster file. + broad -- Input broad-scale topographic position (DEVmax) raster file. + output -- Output raster file. + lightness -- Image lightness value (default is 1.2). + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--local='{}'".format(local)) + args.append("--meso='{}'".format(meso)) + args.append("--broad='{}'".format(broad)) + args.append("--output='{}'".format(output)) + args.append("--lightness={}".format(lightness)) + return self.run_tool('multiscale_topographic_position_image', args, callback) # returns 1 if error + + def num_downslope_neighbours(self, dem, output, callback=None): + """Calculates the number of downslope neighbours to each grid cell in a DEM. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + return self.run_tool('num_downslope_neighbours', args, callback) # returns 1 if error + + def num_upslope_neighbours(self, dem, output, callback=None): + """Calculates the number of upslope neighbours to each grid cell in a DEM. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + return self.run_tool('num_upslope_neighbours', args, callback) # returns 1 if error + + def pennock_landform_class(self, dem, output, slope=3.0, prof=0.1, plan=0.0, zfactor=1.0, callback=None): + """Classifies hillslope zones based on slope, profile curvature, and plan curvature. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + slope -- Slope threshold value, in degrees (default is 3.0). + prof -- Profile curvature threshold value (default is 0.1). + plan -- Plan curvature threshold value (default is 0.0). + zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + args.append("--slope={}".format(slope)) + args.append("--prof={}".format(prof)) + args.append("--plan={}".format(plan)) + args.append("--zfactor={}".format(zfactor)) + return self.run_tool('pennock_landform_class', args, callback) # returns 1 if error + + def percent_elev_range(self, dem, output, filterx=3, filtery=3, callback=None): + """Calculates percent of elevation range from a DEM. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + filterx -- Size of the filter kernel in the x-direction. + filtery -- Size of the filter kernel in the y-direction. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + args.append("--filterx={}".format(filterx)) + args.append("--filtery={}".format(filtery)) + return self.run_tool('percent_elev_range', args, callback) # returns 1 if error + + def plan_curvature(self, dem, output, zfactor=1.0, callback=None): + """Calculates a plan (contour) curvature raster from an input DEM. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + args.append("--zfactor={}".format(zfactor)) + return self.run_tool('plan_curvature', args, callback) # returns 1 if error + + def profile(self, lines, surface, output, callback=None): + """Plots profiles from digital surface models. + + Keyword arguments: + + lines -- Input vector line file. + surface -- Input raster surface file. + output -- Output HTML file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--lines='{}'".format(lines)) + args.append("--surface='{}'".format(surface)) + args.append("--output='{}'".format(output)) + return self.run_tool('profile', args, callback) # returns 1 if error + + def profile_curvature(self, dem, output, zfactor=1.0, callback=None): + """Calculates a profile curvature raster from an input DEM. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + args.append("--zfactor={}".format(zfactor)) + return self.run_tool('profile_curvature', args, callback) # returns 1 if error + + def relative_aspect(self, dem, output, azimuth=0.0, zfactor=1.0, callback=None): + """Calculates relative aspect (relative to a user-specified direction) from an input DEM. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + azimuth -- Illumination source azimuth. + zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + args.append("--azimuth={}".format(azimuth)) + args.append("--zfactor={}".format(zfactor)) + return self.run_tool('relative_aspect', args, callback) # returns 1 if error + + def relative_topographic_position(self, dem, output, filterx=11, filtery=11, callback=None): + """Calculates the relative topographic position index from a DEM. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + filterx -- Size of the filter kernel in the x-direction. + filtery -- Size of the filter kernel in the y-direction. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + args.append("--filterx={}".format(filterx)) + args.append("--filtery={}".format(filtery)) + return self.run_tool('relative_topographic_position', args, callback) # returns 1 if error + + def remove_off_terrain_objects(self, dem, output, filter=11, slope=15.0, callback=None): + """Removes off-terrain objects from a raster digital elevation model (DEM). + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + filter -- Filter size (cells). + slope -- Slope threshold value. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + args.append("--filter={}".format(filter)) + args.append("--slope={}".format(slope)) + return self.run_tool('remove_off_terrain_objects', args, callback) # returns 1 if error + + def ruggedness_index(self, dem, output, zfactor=1.0, callback=None): + """Calculates the Riley et al.'s (1999) terrain ruggedness index from an input DEM. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + args.append("--zfactor={}".format(zfactor)) + return self.run_tool('ruggedness_index', args, callback) # returns 1 if error + + def sediment_transport_index(self, sca, slope, output, sca_exponent=0.4, slope_exponent=1.3, callback=None): + """Calculates the sediment transport index. + + Keyword arguments: + + sca -- Input raster specific contributing area (SCA) file. + slope -- Input raster slope file. + output -- Output raster file. + sca_exponent -- SCA exponent value. + slope_exponent -- Slope exponent value. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--sca='{}'".format(sca)) + args.append("--slope='{}'".format(slope)) + args.append("--output='{}'".format(output)) + args.append("--sca_exponent={}".format(sca_exponent)) + args.append("--slope_exponent={}".format(slope_exponent)) + return self.run_tool('sediment_transport_index', args, callback) # returns 1 if error + + def slope(self, dem, output, zfactor=1.0, units="degrees", callback=None): + """Calculates a slope raster from an input DEM. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. + units -- Units of output raster; options include 'degrees', 'radians', 'percent'. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + args.append("--zfactor={}".format(zfactor)) + args.append("--units={}".format(units)) + return self.run_tool('slope', args, callback) # returns 1 if error + + def slope_vs_elevation_plot(self, inputs, output, watershed=None, callback=None): + """Creates a slope vs. elevation plot for one or more DEMs. + + Keyword arguments: + + inputs -- Input DEM files. + watershed -- Input watershed files (optional). + output -- Output HTML file (default name will be based on input file if unspecified). + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--inputs='{}'".format(inputs)) + if watershed is not None: args.append("--watershed='{}'".format(watershed)) + args.append("--output='{}'".format(output)) + return self.run_tool('slope_vs_elevation_plot', args, callback) # returns 1 if error + + def spherical_std_dev_of_normals(self, dem, output, filter=11, callback=None): + """Calculates the spherical standard deviation of surface normals for a DEM. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + filter -- Size of the filter kernel. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + args.append("--filter={}".format(filter)) + return self.run_tool('spherical_std_dev_of_normals', args, callback) # returns 1 if error + + def standard_deviation_of_slope(self, i, output, zfactor=1.0, filterx=11, filtery=11, callback=None): + """Calculates the standard deviation of slope from an input DEM. + + Keyword arguments: + + i -- Input raster DEM file. + output -- Output raster DEM file. + zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. + filterx -- Size of the filter kernel in the x-direction. + filtery -- Size of the filter kernel in the y-direction. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--zfactor={}".format(zfactor)) + args.append("--filterx={}".format(filterx)) + args.append("--filtery={}".format(filtery)) + return self.run_tool('standard_deviation_of_slope', args, callback) # returns 1 if error + + def stream_power_index(self, sca, slope, output, exponent=1.0, callback=None): + """Calculates the relative stream power index. + + Keyword arguments: + + sca -- Input raster specific contributing area (SCA) file. + slope -- Input raster slope file. + output -- Output raster file. + exponent -- SCA exponent value. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--sca='{}'".format(sca)) + args.append("--slope='{}'".format(slope)) + args.append("--output='{}'".format(output)) + args.append("--exponent={}".format(exponent)) + return self.run_tool('stream_power_index', args, callback) # returns 1 if error + + def surface_area_ratio(self, dem, output, callback=None): + """Calculates a the surface area ratio of each grid cell in an input DEM. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + return self.run_tool('surface_area_ratio', args, callback) # returns 1 if error + + def tangential_curvature(self, dem, output, zfactor=1.0, callback=None): + """Calculates a tangential curvature raster from an input DEM. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + args.append("--zfactor={}".format(zfactor)) + return self.run_tool('tangential_curvature', args, callback) # returns 1 if error + + def total_curvature(self, dem, output, zfactor=1.0, callback=None): + """Calculates a total curvature raster from an input DEM. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + zfactor -- Optional multiplier for when the vertical and horizontal units are not the same. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + args.append("--zfactor={}".format(zfactor)) + return self.run_tool('total_curvature', args, callback) # returns 1 if error + + def viewshed(self, dem, stations, output, height=2.0, callback=None): + """Identifies the viewshed for a point or set of points. + + Keyword arguments: + + dem -- Input raster DEM file. + stations -- Input viewing station vector file. + output -- Output raster file. + height -- Viewing station height, in z units. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--stations='{}'".format(stations)) + args.append("--output='{}'".format(output)) + args.append("--height={}".format(height)) + return self.run_tool('viewshed', args, callback) # returns 1 if error + + def visibility_index(self, dem, output, height=2.0, res_factor=2, callback=None): + """Estimates the relative visibility of sites in a DEM. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + height -- Viewing station height, in z units. + res_factor -- The resolution factor determines the density of measured viewsheds. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + args.append("--height={}".format(height)) + args.append("--res_factor={}".format(res_factor)) + return self.run_tool('visibility_index', args, callback) # returns 1 if error + + def wetness_index(self, sca, slope, output, callback=None): + """Calculates the topographic wetness index, Ln(A / tan(slope)). + + Keyword arguments: + + sca -- Input raster specific contributing area (SCA) file. + slope -- Input raster slope file (in degrees). + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--sca='{}'".format(sca)) + args.append("--slope='{}'".format(slope)) + args.append("--output='{}'".format(output)) + return self.run_tool('wetness_index', args, callback) # returns 1 if error + + ######################### + # Hydrological Analysis # + ######################### + + def average_flowpath_slope(self, dem, output, callback=None): + """Measures the average slope gradient from each grid cell to all upslope divide cells. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + return self.run_tool('average_flowpath_slope', args, callback) # returns 1 if error + + def average_upslope_flowpath_length(self, dem, output, callback=None): + """Measures the average length of all upslope flowpaths draining each grid cell. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + return self.run_tool('average_upslope_flowpath_length', args, callback) # returns 1 if error + + def basins(self, d8_pntr, output, esri_pntr=False, callback=None): + """Identifies drainage basins that drain to the DEM edge. + + Keyword arguments: + + d8_pntr -- Input raster D8 pointer file. + output -- Output raster file. + esri_pntr -- D8 pointer uses the ESRI style scheme. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--d8_pntr='{}'".format(d8_pntr)) + args.append("--output='{}'".format(output)) + if esri_pntr: args.append("--esri_pntr") + return self.run_tool('basins', args, callback) # returns 1 if error + + def breach_depressions(self, dem, output, max_depth=None, max_length=None, flat_increment=None, fill_pits=False, callback=None): + """Breaches all of the depressions in a DEM using Lindsay's (2016) algorithm. This should be preferred over depression filling in most cases. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + max_depth -- Optional maximum breach depth (default is Inf). + max_length -- Optional maximum breach channel length (in grid cells; default is Inf). + flat_increment -- Optional elevation increment applied to flat areas. + fill_pits -- Optional flag indicating whether to fill single-cell pits. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + if max_depth is not None: args.append("--max_depth='{}'".format(max_depth)) + if max_length is not None: args.append("--max_length='{}'".format(max_length)) + if flat_increment is not None: args.append("--flat_increment='{}'".format(flat_increment)) + if fill_pits: args.append("--fill_pits") + return self.run_tool('breach_depressions', args, callback) # returns 1 if error + + def breach_depressions_least_cost(self, dem, output, dist, max_cost=None, min_dist=True, flat_increment=None, fill=True, callback=None): + """Breaches the depressions in a DEM using a least-cost pathway method. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + dist -- Maximum search distance for breach paths in cells. + max_cost -- Optional maximum breach cost (default is Inf). + min_dist -- Optional flag indicating whether to minimize breach distances. + flat_increment -- Optional elevation increment applied to flat areas. + fill -- Optional flag indicating whether to fill any remaining unbreached depressions. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + args.append("--dist='{}'".format(dist)) + if max_cost is not None: args.append("--max_cost='{}'".format(max_cost)) + if min_dist: args.append("--min_dist") + if flat_increment is not None: args.append("--flat_increment='{}'".format(flat_increment)) + if fill: args.append("--fill") + return self.run_tool('breach_depressions_least_cost', args, callback) # returns 1 if error + + def breach_single_cell_pits(self, dem, output, callback=None): + """Removes single-cell pits from an input DEM by breaching. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + return self.run_tool('breach_single_cell_pits', args, callback) # returns 1 if error + + def burn_streams_at_roads(self, dem, streams, roads, output, width=None, callback=None): + """Burns-in streams at the sites of road embankments. + + Keyword arguments: + + dem -- Input raster digital elevation model (DEM) file. + streams -- Input vector streams file. + roads -- Input vector roads file. + output -- Output raster file. + width -- Maximum road embankment width, in map units. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--streams='{}'".format(streams)) + args.append("--roads='{}'".format(roads)) + args.append("--output='{}'".format(output)) + if width is not None: args.append("--width='{}'".format(width)) + return self.run_tool('burn_streams_at_roads', args, callback) # returns 1 if error + + def d8_flow_accumulation(self, i, output, out_type="cells", log=False, clip=False, pntr=False, esri_pntr=False, callback=None): + """Calculates a D8 flow accumulation raster from an input DEM or flow pointer. + + Keyword arguments: + + i -- Input raster DEM or D8 pointer file. + output -- Output raster file. + out_type -- Output type; one of 'cells' (default), 'catchment area', and 'specific contributing area'. + log -- Optional flag to request the output be log-transformed. + clip -- Optional flag to request clipping the display max by 1%. + pntr -- Is the input raster a D8 flow pointer rather than a DEM?. + esri_pntr -- Input D8 pointer uses the ESRI style scheme. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--out_type={}".format(out_type)) + if log: args.append("--log") + if clip: args.append("--clip") + if pntr: args.append("--pntr") + if esri_pntr: args.append("--esri_pntr") + return self.run_tool('d8_flow_accumulation', args, callback) # returns 1 if error + + def d8_mass_flux(self, dem, loading, efficiency, absorption, output, callback=None): + """Performs a D8 mass flux calculation. + + Keyword arguments: + + dem -- Input raster DEM file. + loading -- Input loading raster file. + efficiency -- Input efficiency raster file. + absorption -- Input absorption raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--loading='{}'".format(loading)) + args.append("--efficiency='{}'".format(efficiency)) + args.append("--absorption='{}'".format(absorption)) + args.append("--output='{}'".format(output)) + return self.run_tool('d8_mass_flux', args, callback) # returns 1 if error + + def d8_pointer(self, dem, output, esri_pntr=False, callback=None): + """Calculates a D8 flow pointer raster from an input DEM. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + esri_pntr -- D8 pointer uses the ESRI style scheme. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + if esri_pntr: args.append("--esri_pntr") + return self.run_tool('d8_pointer', args, callback) # returns 1 if error + + def d_inf_flow_accumulation(self, i, output, out_type="Specific Contributing Area", threshold=None, log=False, clip=False, pntr=False, callback=None): + """Calculates a D-infinity flow accumulation raster from an input DEM. + + Keyword arguments: + + i -- Input raster DEM or D-infinity pointer file. + output -- Output raster file. + out_type -- Output type; one of 'cells', 'sca' (default), and 'ca'. + threshold -- Optional convergence threshold parameter, in grid cells; default is inifinity. + log -- Optional flag to request the output be log-transformed. + clip -- Optional flag to request clipping the display max by 1%. + pntr -- Is the input raster a D-infinity flow pointer rather than a DEM?. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--out_type={}".format(out_type)) + if threshold is not None: args.append("--threshold='{}'".format(threshold)) + if log: args.append("--log") + if clip: args.append("--clip") + if pntr: args.append("--pntr") + return self.run_tool('d_inf_flow_accumulation', args, callback) # returns 1 if error + + def d_inf_mass_flux(self, dem, loading, efficiency, absorption, output, callback=None): + """Performs a D-infinity mass flux calculation. + + Keyword arguments: + + dem -- Input raster DEM file. + loading -- Input loading raster file. + efficiency -- Input efficiency raster file. + absorption -- Input absorption raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--loading='{}'".format(loading)) + args.append("--efficiency='{}'".format(efficiency)) + args.append("--absorption='{}'".format(absorption)) + args.append("--output='{}'".format(output)) + return self.run_tool('d_inf_mass_flux', args, callback) # returns 1 if error + + def d_inf_pointer(self, dem, output, callback=None): + """Calculates a D-infinity flow pointer (flow direction) raster from an input DEM. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + return self.run_tool('d_inf_pointer', args, callback) # returns 1 if error + + def depth_in_sink(self, dem, output, zero_background=False, callback=None): + """Measures the depth of sinks (depressions) in a DEM. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + zero_background -- Flag indicating whether the background value of zero should be used. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + if zero_background: args.append("--zero_background") + return self.run_tool('depth_in_sink', args, callback) # returns 1 if error + + def downslope_distance_to_stream(self, dem, streams, output, callback=None): + """Measures distance to the nearest downslope stream cell. + + Keyword arguments: + + dem -- Input raster DEM file. + streams -- Input raster streams file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--streams='{}'".format(streams)) + args.append("--output='{}'".format(output)) + return self.run_tool('downslope_distance_to_stream', args, callback) # returns 1 if error + + def downslope_flowpath_length(self, d8_pntr, output, watersheds=None, weights=None, esri_pntr=False, callback=None): + """Calculates the downslope flowpath length from each cell to basin outlet. + + Keyword arguments: + + d8_pntr -- Input D8 pointer raster file. + watersheds -- Optional input watershed raster file. + weights -- Optional input weights raster file. + output -- Output raster file. + esri_pntr -- D8 pointer uses the ESRI style scheme. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--d8_pntr='{}'".format(d8_pntr)) + if watersheds is not None: args.append("--watersheds='{}'".format(watersheds)) + if weights is not None: args.append("--weights='{}'".format(weights)) + args.append("--output='{}'".format(output)) + if esri_pntr: args.append("--esri_pntr") + return self.run_tool('downslope_flowpath_length', args, callback) # returns 1 if error + + def elevation_above_stream(self, dem, streams, output, callback=None): + """Calculates the elevation of cells above the nearest downslope stream cell. + + Keyword arguments: + + dem -- Input raster DEM file. + streams -- Input raster streams file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--streams='{}'".format(streams)) + args.append("--output='{}'".format(output)) + return self.run_tool('elevation_above_stream', args, callback) # returns 1 if error + + def elevation_above_stream_euclidean(self, dem, streams, output, callback=None): + """Calculates the elevation of cells above the nearest (Euclidean distance) stream cell. + + Keyword arguments: + + dem -- Input raster DEM file. + streams -- Input raster streams file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--streams='{}'".format(streams)) + args.append("--output='{}'".format(output)) + return self.run_tool('elevation_above_stream_euclidean', args, callback) # returns 1 if error + + def fd8_flow_accumulation(self, dem, output, out_type="specific contributing area", exponent=1.1, threshold=None, log=False, clip=False, callback=None): + """Calculates an FD8 flow accumulation raster from an input DEM. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + out_type -- Output type; one of 'cells', 'specific contributing area' (default), and 'catchment area'. + exponent -- Optional exponent parameter; default is 1.1. + threshold -- Optional convergence threshold parameter, in grid cells; default is inifinity. + log -- Optional flag to request the output be log-transformed. + clip -- Optional flag to request clipping the display max by 1%. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + args.append("--out_type={}".format(out_type)) + args.append("--exponent={}".format(exponent)) + if threshold is not None: args.append("--threshold='{}'".format(threshold)) + if log: args.append("--log") + if clip: args.append("--clip") + return self.run_tool('fd8_flow_accumulation', args, callback) # returns 1 if error + + def fd8_pointer(self, dem, output, callback=None): + """Calculates an FD8 flow pointer raster from an input DEM. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + return self.run_tool('fd8_pointer', args, callback) # returns 1 if error + + def fill_burn(self, dem, streams, output, callback=None): + """Burns streams into a DEM using the FillBurn (Saunders, 1999) method. + + Keyword arguments: + + dem -- Input raster DEM file. + streams -- Input vector streams file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--streams='{}'".format(streams)) + args.append("--output='{}'".format(output)) + return self.run_tool('fill_burn', args, callback) # returns 1 if error + + def fill_depressions(self, dem, output, fix_flats=True, flat_increment=None, max_depth=None, callback=None): + """Fills all of the depressions in a DEM. Depression breaching should be preferred in most cases. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + fix_flats -- Optional flag indicating whether flat areas should have a small gradient applied. + flat_increment -- Optional elevation increment applied to flat areas. + max_depth -- Optional maximum depression depth to fill. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + if fix_flats: args.append("--fix_flats") + if flat_increment is not None: args.append("--flat_increment='{}'".format(flat_increment)) + if max_depth is not None: args.append("--max_depth='{}'".format(max_depth)) + return self.run_tool('fill_depressions', args, callback) # returns 1 if error + + def fill_depressions_planchon_and_darboux(self, dem, output, fix_flats=True, flat_increment=None, callback=None): + """Fills all of the depressions in a DEM using the Planchon and Darboux (2002) method. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + fix_flats -- Optional flag indicating whether flat areas should have a small gradient applied. + flat_increment -- Optional elevation increment applied to flat areas. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + if fix_flats: args.append("--fix_flats") + if flat_increment is not None: args.append("--flat_increment='{}'".format(flat_increment)) + return self.run_tool('fill_depressions_planchon_and_darboux', args, callback) # returns 1 if error + + def fill_depressions_wang_and_liu(self, dem, output, fix_flats=True, flat_increment=None, callback=None): + """Fills all of the depressions in a DEM using the Wang and Liu (2006) method. Depression breaching should be preferred in most cases. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + fix_flats -- Optional flag indicating whether flat areas should have a small gradient applied. + flat_increment -- Optional elevation increment applied to flat areas. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + if fix_flats: args.append("--fix_flats") + if flat_increment is not None: args.append("--flat_increment='{}'".format(flat_increment)) + return self.run_tool('fill_depressions_wang_and_liu', args, callback) # returns 1 if error + + def fill_single_cell_pits(self, dem, output, callback=None): + """Raises pit cells to the elevation of their lowest neighbour. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + return self.run_tool('fill_single_cell_pits', args, callback) # returns 1 if error + + def find_no_flow_cells(self, dem, output, callback=None): + """Finds grid cells with no downslope neighbours. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + return self.run_tool('find_no_flow_cells', args, callback) # returns 1 if error + + def find_parallel_flow(self, d8_pntr, streams, output, callback=None): + """Finds areas of parallel flow in D8 flow direction rasters. + + Keyword arguments: + + d8_pntr -- Input D8 pointer raster file. + streams -- Input raster streams file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--d8_pntr='{}'".format(d8_pntr)) + args.append("--streams='{}'".format(streams)) + args.append("--output='{}'".format(output)) + return self.run_tool('find_parallel_flow', args, callback) # returns 1 if error + + def flatten_lakes(self, dem, lakes, output, callback=None): + """Flattens lake polygons in a raster DEM. + + Keyword arguments: + + dem -- Input raster DEM file. + lakes -- Input lakes vector polygons file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--lakes='{}'".format(lakes)) + args.append("--output='{}'".format(output)) + return self.run_tool('flatten_lakes', args, callback) # returns 1 if error + + def flood_order(self, dem, output, callback=None): + """Assigns each DEM grid cell its order in the sequence of inundations that are encountered during a search starting from the edges, moving inward at increasing elevations. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + return self.run_tool('flood_order', args, callback) # returns 1 if error + + def flow_accumulation_full_workflow(self, dem, out_dem, out_pntr, out_accum, out_type="Specific Contributing Area", log=False, clip=False, esri_pntr=False, callback=None): + """Resolves all of the depressions in a DEM, outputting a breached DEM, an aspect-aligned non-divergent flow pointer, and a flow accumulation raster. + + Keyword arguments: + + dem -- Input raster DEM file. + out_dem -- Output raster DEM file. + out_pntr -- Output raster flow pointer file. + out_accum -- Output raster flow accumulation file. + out_type -- Output type; one of 'cells', 'sca' (default), and 'ca'. + log -- Optional flag to request the output be log-transformed. + clip -- Optional flag to request clipping the display max by 1%. + esri_pntr -- D8 pointer uses the ESRI style scheme. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--out_dem='{}'".format(out_dem)) + args.append("--out_pntr='{}'".format(out_pntr)) + args.append("--out_accum='{}'".format(out_accum)) + args.append("--out_type={}".format(out_type)) + if log: args.append("--log") + if clip: args.append("--clip") + if esri_pntr: args.append("--esri_pntr") + return self.run_tool('flow_accumulation_full_workflow', args, callback) # returns 1 if error + + def flow_length_diff(self, d8_pntr, output, esri_pntr=False, callback=None): + """Calculates the local maximum absolute difference in downslope flowpath length, useful in mapping drainage divides and ridges. + + Keyword arguments: + + d8_pntr -- Input D8 pointer raster file. + output -- Output raster file. + esri_pntr -- D8 pointer uses the ESRI style scheme. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--d8_pntr='{}'".format(d8_pntr)) + args.append("--output='{}'".format(output)) + if esri_pntr: args.append("--esri_pntr") + return self.run_tool('flow_length_diff', args, callback) # returns 1 if error + + def hillslopes(self, d8_pntr, streams, output, esri_pntr=False, callback=None): + """Identifies the individual hillslopes draining to each link in a stream network. + + Keyword arguments: + + d8_pntr -- Input raster D8 pointer file. + streams -- Input raster streams file. + output -- Output raster file. + esri_pntr -- D8 pointer uses the ESRI style scheme. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--d8_pntr='{}'".format(d8_pntr)) + args.append("--streams='{}'".format(streams)) + args.append("--output='{}'".format(output)) + if esri_pntr: args.append("--esri_pntr") + return self.run_tool('hillslopes', args, callback) # returns 1 if error + + def impoundment_size_index(self, dem, output, damlength, out_type="mean depth", callback=None): + """Calculates the impoundment size resulting from damming a DEM. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output file. + out_type -- Output type; one of 'mean depth' (default), 'volume', 'area', 'max depth'. + damlength -- Maximum length of the dam. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + args.append("--out_type={}".format(out_type)) + args.append("--damlength='{}'".format(damlength)) + return self.run_tool('impoundment_size_index', args, callback) # returns 1 if error + + def insert_dams(self, dem, dam_pts, output, damlength, callback=None): + """Calculates the impoundment size resulting from damming a DEM. + + Keyword arguments: + + dem -- Input raster DEM file. + dam_pts -- Input vector dam points file. + output -- Output file. + damlength -- Maximum length of the dam. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--dam_pts='{}'".format(dam_pts)) + args.append("--output='{}'".format(output)) + args.append("--damlength='{}'".format(damlength)) + return self.run_tool('insert_dams', args, callback) # returns 1 if error + + def isobasins(self, dem, output, size, callback=None): + """Divides a landscape into nearly equal sized drainage basins (i.e. watersheds). + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + size -- Target basin size, in grid cells. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + args.append("--size='{}'".format(size)) + return self.run_tool('isobasins', args, callback) # returns 1 if error + + def jenson_snap_pour_points(self, pour_pts, streams, output, snap_dist, callback=None): + """Moves outlet points used to specify points of interest in a watershedding operation to the nearest stream cell. + + Keyword arguments: + + pour_pts -- Input vector pour points (outlet) file. + streams -- Input raster streams file. + output -- Output vector file. + snap_dist -- Maximum snap distance in map units. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--pour_pts='{}'".format(pour_pts)) + args.append("--streams='{}'".format(streams)) + args.append("--output='{}'".format(output)) + args.append("--snap_dist='{}'".format(snap_dist)) + return self.run_tool('jenson_snap_pour_points', args, callback) # returns 1 if error + + def longest_flowpath(self, dem, basins, output, callback=None): + """Delineates the longest flowpaths for a group of subbasins or watersheds. + + Keyword arguments: + + dem -- Input raster DEM file. + basins -- Input raster basins file. + output -- Output vector file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--basins='{}'".format(basins)) + args.append("--output='{}'".format(output)) + return self.run_tool('longest_flowpath', args, callback) # returns 1 if error + + def max_upslope_flowpath_length(self, dem, output, callback=None): + """Measures the maximum length of all upslope flowpaths draining each grid cell. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + return self.run_tool('max_upslope_flowpath_length', args, callback) # returns 1 if error + + def md_inf_flow_accumulation(self, dem, output, out_type="specific contributing area", exponent=1.1, threshold=None, log=False, clip=False, callback=None): + """Calculates an FD8 flow accumulation raster from an input DEM. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + out_type -- Output type; one of 'cells', 'specific contributing area' (default), and 'catchment area'. + exponent -- Optional exponent parameter; default is 1.1. + threshold -- Optional convergence threshold parameter, in grid cells; default is inifinity. + log -- Optional flag to request the output be log-transformed. + clip -- Optional flag to request clipping the display max by 1%. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + args.append("--out_type={}".format(out_type)) + args.append("--exponent={}".format(exponent)) + if threshold is not None: args.append("--threshold='{}'".format(threshold)) + if log: args.append("--log") + if clip: args.append("--clip") + return self.run_tool('md_inf_flow_accumulation', args, callback) # returns 1 if error + + def num_inflowing_neighbours(self, dem, output, callback=None): + """Computes the number of inflowing neighbours to each cell in an input DEM based on the D8 algorithm. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + return self.run_tool('num_inflowing_neighbours', args, callback) # returns 1 if error + + def raise_walls(self, i, dem, output, breach=None, height=100.0, callback=None): + """Raises walls in a DEM along a line or around a polygon, e.g. a watershed. + + Keyword arguments: + + i -- Input vector lines or polygons file. + breach -- Optional input vector breach lines. + dem -- Input raster DEM file. + output -- Output raster file. + height -- Wall height. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + if breach is not None: args.append("--breach='{}'".format(breach)) + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + args.append("--height={}".format(height)) + return self.run_tool('raise_walls', args, callback) # returns 1 if error + + def rho8_pointer(self, dem, output, esri_pntr=False, callback=None): + """Calculates a stochastic Rho8 flow pointer raster from an input DEM. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + esri_pntr -- D8 pointer uses the ESRI style scheme. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + if esri_pntr: args.append("--esri_pntr") + return self.run_tool('rho8_pointer', args, callback) # returns 1 if error + + def sink(self, i, output, zero_background=False, callback=None): + """Identifies the depressions in a DEM, giving each feature a unique identifier. + + Keyword arguments: + + i -- Input raster DEM file. + output -- Output raster file. + zero_background -- Flag indicating whether a background value of zero should be used. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + if zero_background: args.append("--zero_background") + return self.run_tool('sink', args, callback) # returns 1 if error + + def snap_pour_points(self, pour_pts, flow_accum, output, snap_dist, callback=None): + """Moves outlet points used to specify points of interest in a watershedding operation to the cell with the highest flow accumulation in its neighbourhood. + + Keyword arguments: + + pour_pts -- Input vector pour points (outlet) file. + flow_accum -- Input raster D8 flow accumulation file. + output -- Output vector file. + snap_dist -- Maximum snap distance in map units. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--pour_pts='{}'".format(pour_pts)) + args.append("--flow_accum='{}'".format(flow_accum)) + args.append("--output='{}'".format(output)) + args.append("--snap_dist='{}'".format(snap_dist)) + return self.run_tool('snap_pour_points', args, callback) # returns 1 if error + + def stochastic_depression_analysis(self, dem, output, rmse, range, iterations=100, callback=None): + """Preforms a stochastic analysis of depressions within a DEM. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output file. + rmse -- The DEM's root-mean-square-error (RMSE), in z units. This determines error magnitude. + range -- The error field's correlation length, in xy-units. + iterations -- The number of iterations. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + args.append("--rmse='{}'".format(rmse)) + args.append("--range='{}'".format(range)) + args.append("--iterations={}".format(iterations)) + return self.run_tool('stochastic_depression_analysis', args, callback) # returns 1 if error + + def strahler_order_basins(self, d8_pntr, streams, output, esri_pntr=False, callback=None): + """Identifies Strahler-order basins from an input stream network. + + Keyword arguments: + + d8_pntr -- Input raster D8 pointer file. + streams -- Input raster streams file. + output -- Output raster file. + esri_pntr -- D8 pointer uses the ESRI style scheme. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--d8_pntr='{}'".format(d8_pntr)) + args.append("--streams='{}'".format(streams)) + args.append("--output='{}'".format(output)) + if esri_pntr: args.append("--esri_pntr") + return self.run_tool('strahler_order_basins', args, callback) # returns 1 if error + + def subbasins(self, d8_pntr, streams, output, esri_pntr=False, callback=None): + """Identifies the catchments, or sub-basin, draining to each link in a stream network. + + Keyword arguments: + + d8_pntr -- Input D8 pointer raster file. + streams -- Input raster streams file. + output -- Output raster file. + esri_pntr -- D8 pointer uses the ESRI style scheme. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--d8_pntr='{}'".format(d8_pntr)) + args.append("--streams='{}'".format(streams)) + args.append("--output='{}'".format(output)) + if esri_pntr: args.append("--esri_pntr") + return self.run_tool('subbasins', args, callback) # returns 1 if error + + def trace_downslope_flowpaths(self, seed_pts, d8_pntr, output, esri_pntr=False, zero_background=False, callback=None): + """Traces downslope flowpaths from one or more target sites (i.e. seed points). + + Keyword arguments: + + seed_pts -- Input vector seed points file. + d8_pntr -- Input D8 pointer raster file. + output -- Output raster file. + esri_pntr -- D8 pointer uses the ESRI style scheme. + zero_background -- Flag indicating whether a background value of zero should be used. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--seed_pts='{}'".format(seed_pts)) + args.append("--d8_pntr='{}'".format(d8_pntr)) + args.append("--output='{}'".format(output)) + if esri_pntr: args.append("--esri_pntr") + if zero_background: args.append("--zero_background") + return self.run_tool('trace_downslope_flowpaths', args, callback) # returns 1 if error + + def unnest_basins(self, d8_pntr, pour_pts, output, esri_pntr=False, callback=None): + """Extract whole watersheds for a set of outlet points. + + Keyword arguments: + + d8_pntr -- Input D8 pointer raster file. + pour_pts -- Input vector pour points (outlet) file. + output -- Output raster file. + esri_pntr -- D8 pointer uses the ESRI style scheme. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--d8_pntr='{}'".format(d8_pntr)) + args.append("--pour_pts='{}'".format(pour_pts)) + args.append("--output='{}'".format(output)) + if esri_pntr: args.append("--esri_pntr") + return self.run_tool('unnest_basins', args, callback) # returns 1 if error + + def upslope_depression_storage(self, dem, output, callback=None): + """Estimates the average upslope depression storage depth. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + return self.run_tool('upslope_depression_storage', args, callback) # returns 1 if error + + def watershed(self, d8_pntr, pour_pts, output, esri_pntr=False, callback=None): + """Identifies the watershed, or drainage basin, draining to a set of target cells. + + Keyword arguments: + + d8_pntr -- Input D8 pointer raster file. + pour_pts -- Input pour points (outlet) file. + output -- Output raster file. + esri_pntr -- D8 pointer uses the ESRI style scheme. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--d8_pntr='{}'".format(d8_pntr)) + args.append("--pour_pts='{}'".format(pour_pts)) + args.append("--output='{}'".format(output)) + if esri_pntr: args.append("--esri_pntr") + return self.run_tool('watershed', args, callback) # returns 1 if error + + ########################## + # Image Processing Tools # + ########################## + + def change_vector_analysis(self, date1, date2, magnitude, direction, callback=None): + """Performs a change vector analysis on a two-date multi-spectral dataset. + + Keyword arguments: + + date1 -- Input raster files for the earlier date. + date2 -- Input raster files for the later date. + magnitude -- Output vector magnitude raster file. + direction -- Output vector Direction raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--date1='{}'".format(date1)) + args.append("--date2='{}'".format(date2)) + args.append("--magnitude='{}'".format(magnitude)) + args.append("--direction='{}'".format(direction)) + return self.run_tool('change_vector_analysis', args, callback) # returns 1 if error + + def closing(self, i, output, filterx=11, filtery=11, callback=None): + """A closing is a mathematical morphology operation involving an erosion (min filter) of a dilation (max filter) set. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + filterx -- Size of the filter kernel in the x-direction. + filtery -- Size of the filter kernel in the y-direction. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--filterx={}".format(filterx)) + args.append("--filtery={}".format(filtery)) + return self.run_tool('closing', args, callback) # returns 1 if error + + def create_colour_composite(self, red, green, blue, output, opacity=None, enhance=True, zeros=False, callback=None): + """Creates a colour-composite image from three bands of multispectral imagery. + + Keyword arguments: + + red -- Input red band image file. + green -- Input green band image file. + blue -- Input blue band image file. + opacity -- Input opacity band image file (optional). + output -- Output colour composite file. + enhance -- Optional flag indicating whether a balance contrast enhancement is performed. + zeros -- Optional flag to indicate if zeros are nodata values. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--red='{}'".format(red)) + args.append("--green='{}'".format(green)) + args.append("--blue='{}'".format(blue)) + if opacity is not None: args.append("--opacity='{}'".format(opacity)) + args.append("--output='{}'".format(output)) + if enhance: args.append("--enhance") + if zeros: args.append("--zeros") + return self.run_tool('create_colour_composite', args, callback) # returns 1 if error + + def flip_image(self, i, output, direction="vertical", callback=None): + """Reflects an image in the vertical or horizontal axis. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + direction -- Direction of reflection; options include 'v' (vertical), 'h' (horizontal), and 'b' (both). + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--direction={}".format(direction)) + return self.run_tool('flip_image', args, callback) # returns 1 if error + + def ihs_to_rgb(self, intensity, hue, saturation, red=None, green=None, blue=None, output=None, callback=None): + """Converts intensity, hue, and saturation (IHS) images into red, green, and blue (RGB) images. + + Keyword arguments: + + intensity -- Input intensity file. + hue -- Input hue file. + saturation -- Input saturation file. + red -- Output red band file. Optionally specified if colour-composite not specified. + green -- Output green band file. Optionally specified if colour-composite not specified. + blue -- Output blue band file. Optionally specified if colour-composite not specified. + output -- Output colour-composite file. Only used if individual bands are not specified. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--intensity='{}'".format(intensity)) + args.append("--hue='{}'".format(hue)) + args.append("--saturation='{}'".format(saturation)) + if red is not None: args.append("--red='{}'".format(red)) + if green is not None: args.append("--green='{}'".format(green)) + if blue is not None: args.append("--blue='{}'".format(blue)) + if output is not None: args.append("--output='{}'".format(output)) + return self.run_tool('ihs_to_rgb', args, callback) # returns 1 if error + + def image_stack_profile(self, inputs, points, output, callback=None): + """Plots an image stack profile (i.e. signature) for a set of points and multispectral images. + + Keyword arguments: + + inputs -- Input multispectral image files. + points -- Input vector points file. + output -- Output HTML file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--inputs='{}'".format(inputs)) + args.append("--points='{}'".format(points)) + args.append("--output='{}'".format(output)) + return self.run_tool('image_stack_profile', args, callback) # returns 1 if error + + def integral_image(self, i, output, callback=None): + """Transforms an input image (summed area table) into its integral image equivalent. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('integral_image', args, callback) # returns 1 if error + + def k_means_clustering(self, inputs, output, classes, out_html=None, max_iterations=10, class_change=2.0, initialize="diagonal", min_class_size=10, callback=None): + """Performs a k-means clustering operation on a multi-spectral dataset. + + Keyword arguments: + + inputs -- Input raster files. + output -- Output raster file. + out_html -- Output HTML report file. + classes -- Number of classes. + max_iterations -- Maximum number of iterations. + class_change -- Minimum percent of cells changed between iterations before completion. + initialize -- How to initialize cluster centres?. + min_class_size -- Minimum class size, in pixels. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--inputs='{}'".format(inputs)) + args.append("--output='{}'".format(output)) + if out_html is not None: args.append("--out_html='{}'".format(out_html)) + args.append("--classes='{}'".format(classes)) + args.append("--max_iterations={}".format(max_iterations)) + args.append("--class_change={}".format(class_change)) + args.append("--initialize={}".format(initialize)) + args.append("--min_class_size={}".format(min_class_size)) + return self.run_tool('k_means_clustering', args, callback) # returns 1 if error + + def line_thinning(self, i, output, callback=None): + """Performs line thinning a on Boolean raster image; intended to be used with the RemoveSpurs tool. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('line_thinning', args, callback) # returns 1 if error + + def modified_k_means_clustering(self, inputs, output, out_html=None, start_clusters=1000, merge_dist=None, max_iterations=10, class_change=2.0, callback=None): + """Performs a modified k-means clustering operation on a multi-spectral dataset. + + Keyword arguments: + + inputs -- Input raster files. + output -- Output raster file. + out_html -- Output HTML report file. + start_clusters -- Initial number of clusters. + merge_dist -- Cluster merger distance. + max_iterations -- Maximum number of iterations. + class_change -- Minimum percent of cells changed between iterations before completion. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--inputs='{}'".format(inputs)) + args.append("--output='{}'".format(output)) + if out_html is not None: args.append("--out_html='{}'".format(out_html)) + args.append("--start_clusters={}".format(start_clusters)) + if merge_dist is not None: args.append("--merge_dist='{}'".format(merge_dist)) + args.append("--max_iterations={}".format(max_iterations)) + args.append("--class_change={}".format(class_change)) + return self.run_tool('modified_k_means_clustering', args, callback) # returns 1 if error + + def mosaic(self, output, inputs=None, method="nn", callback=None): + """Mosaics two or more images together. + + Keyword arguments: + + inputs -- Input raster files. + output -- Output raster file. + method -- Resampling method; options include 'nn' (nearest neighbour), 'bilinear', and 'cc' (cubic convolution). + callback -- Custom function for handling tool text outputs. + """ + args = [] + if inputs is not None: args.append("--inputs='{}'".format(inputs)) + args.append("--output='{}'".format(output)) + args.append("--method={}".format(method)) + return self.run_tool('mosaic', args, callback) # returns 1 if error + + def mosaic_with_feathering(self, input1, input2, output, method="cc", weight=4.0, callback=None): + """Mosaics two images together using a feathering technique in overlapping areas to reduce edge-effects. + + Keyword arguments: + + input1 -- Input raster file to modify. + input2 -- Input reference raster file. + output -- Output raster file. + method -- Resampling method; options include 'nn' (nearest neighbour), 'bilinear', and 'cc' (cubic convolution). + weight -- . + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input1='{}'".format(input1)) + args.append("--input2='{}'".format(input2)) + args.append("--output='{}'".format(output)) + args.append("--method={}".format(method)) + args.append("--weight={}".format(weight)) + return self.run_tool('mosaic_with_feathering', args, callback) # returns 1 if error + + def normalized_difference_index(self, input1, input2, output, clip=0.0, correction=0.0, callback=None): + """Calculate a normalized-difference index (NDI) from two bands of multispectral image data. + + Keyword arguments: + + input1 -- Input image 1 (e.g. near-infrared band). + input2 -- Input image 2 (e.g. red band). + output -- Output raster file. + clip -- Optional amount to clip the distribution tails by, in percent. + correction -- Optional adjustment value (e.g. 1, or 0.16 for the optimal soil adjusted vegetation index, OSAVI). + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input1='{}'".format(input1)) + args.append("--input2='{}'".format(input2)) + args.append("--output='{}'".format(output)) + args.append("--clip={}".format(clip)) + args.append("--correction={}".format(correction)) + return self.run_tool('normalized_difference_index', args, callback) # returns 1 if error + + def opening(self, i, output, filterx=11, filtery=11, callback=None): + """An opening is a mathematical morphology operation involving a dilation (max filter) of an erosion (min filter) set. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + filterx -- Size of the filter kernel in the x-direction. + filtery -- Size of the filter kernel in the y-direction. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--filterx={}".format(filterx)) + args.append("--filtery={}".format(filtery)) + return self.run_tool('opening', args, callback) # returns 1 if error + + def remove_spurs(self, i, output, iterations=10, callback=None): + """Removes the spurs (pruning operation) from a Boolean line image; intended to be used on the output of the LineThinning tool. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + iterations -- Maximum number of iterations. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--iterations={}".format(iterations)) + return self.run_tool('remove_spurs', args, callback) # returns 1 if error + + def resample(self, inputs, destination, method="cc", callback=None): + """Resamples one or more input images into a destination image. + + Keyword arguments: + + inputs -- Input raster files. + destination -- Destination raster file. + method -- Resampling method; options include 'nn' (nearest neighbour), 'bilinear', and 'cc' (cubic convolution). + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--inputs='{}'".format(inputs)) + args.append("--destination='{}'".format(destination)) + args.append("--method={}".format(method)) + return self.run_tool('resample', args, callback) # returns 1 if error + + def rgb_to_ihs(self, intensity, hue, saturation, red=None, green=None, blue=None, composite=None, callback=None): + """Converts red, green, and blue (RGB) images into intensity, hue, and saturation (IHS) images. + + Keyword arguments: + + red -- Input red band image file. Optionally specified if colour-composite not specified. + green -- Input green band image file. Optionally specified if colour-composite not specified. + blue -- Input blue band image file. Optionally specified if colour-composite not specified. + composite -- Input colour-composite image file. Only used if individual bands are not specified. + intensity -- Output intensity raster file. + hue -- Output hue raster file. + saturation -- Output saturation raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + if red is not None: args.append("--red='{}'".format(red)) + if green is not None: args.append("--green='{}'".format(green)) + if blue is not None: args.append("--blue='{}'".format(blue)) + if composite is not None: args.append("--composite='{}'".format(composite)) + args.append("--intensity='{}'".format(intensity)) + args.append("--hue='{}'".format(hue)) + args.append("--saturation='{}'".format(saturation)) + return self.run_tool('rgb_to_ihs', args, callback) # returns 1 if error + + def split_colour_composite(self, i, red=None, green=None, blue=None, callback=None): + """This tool splits an RGB colour composite image into seperate multispectral images. + + Keyword arguments: + + i -- Input colour composite image file. + red -- Output red band file. + green -- Output green band file. + blue -- Output blue band file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + if red is not None: args.append("--red='{}'".format(red)) + if green is not None: args.append("--green='{}'".format(green)) + if blue is not None: args.append("--blue='{}'".format(blue)) + return self.run_tool('split_colour_composite', args, callback) # returns 1 if error + + def thicken_raster_line(self, i, output, callback=None): + """Thickens single-cell wide lines within a raster image. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('thicken_raster_line', args, callback) # returns 1 if error + + def tophat_transform(self, i, output, filterx=11, filtery=11, variant="white", callback=None): + """Performs either a white or black top-hat transform on an input image. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + filterx -- Size of the filter kernel in the x-direction. + filtery -- Size of the filter kernel in the y-direction. + variant -- Optional variant value. Options include 'white' and 'black'. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--filterx={}".format(filterx)) + args.append("--filtery={}".format(filtery)) + args.append("--variant={}".format(variant)) + return self.run_tool('tophat_transform', args, callback) # returns 1 if error + + def write_function_memory_insertion(self, input1, input2, output, input3=None, callback=None): + """Performs a write function memory insertion for single-band multi-date change detection. + + Keyword arguments: + + input1 -- Input raster file associated with the first date. + input2 -- Input raster file associated with the second date. + input3 -- Optional input raster file associated with the third date. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input1='{}'".format(input1)) + args.append("--input2='{}'".format(input2)) + if input3 is not None: args.append("--input3='{}'".format(input3)) + args.append("--output='{}'".format(output)) + return self.run_tool('write_function_memory_insertion', args, callback) # returns 1 if error + + ################################## + # Image Processing Tools/Filters # + ################################## + + def adaptive_filter(self, i, output, filterx=11, filtery=11, threshold=2.0, callback=None): + """Performs an adaptive filter on an image. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + filterx -- Size of the filter kernel in the x-direction. + filtery -- Size of the filter kernel in the y-direction. + threshold -- Difference from mean threshold, in standard deviations. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--filterx={}".format(filterx)) + args.append("--filtery={}".format(filtery)) + args.append("--threshold={}".format(threshold)) + return self.run_tool('adaptive_filter', args, callback) # returns 1 if error + + def bilateral_filter(self, i, output, sigma_dist=0.75, sigma_int=1.0, callback=None): + """A bilateral filter is an edge-preserving smoothing filter introduced by Tomasi and Manduchi (1998). + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + sigma_dist -- Standard deviation in distance in pixels. + sigma_int -- Standard deviation in intensity in pixels. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--sigma_dist={}".format(sigma_dist)) + args.append("--sigma_int={}".format(sigma_int)) + return self.run_tool('bilateral_filter', args, callback) # returns 1 if error + + def conservative_smoothing_filter(self, i, output, filterx=3, filtery=3, callback=None): + """Performs a conservative-smoothing filter on an image. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + filterx -- Size of the filter kernel in the x-direction. + filtery -- Size of the filter kernel in the y-direction. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--filterx={}".format(filterx)) + args.append("--filtery={}".format(filtery)) + return self.run_tool('conservative_smoothing_filter', args, callback) # returns 1 if error + + def corner_detection(self, i, output, callback=None): + """Identifies corner patterns in boolean images using hit-and-miss pattern matching. + + Keyword arguments: + + i -- Input boolean image. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('corner_detection', args, callback) # returns 1 if error + + def diff_of_gaussian_filter(self, i, output, sigma1=2.0, sigma2=4.0, callback=None): + """Performs a Difference of Gaussian (DoG) filter on an image. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + sigma1 -- Standard deviation distance in pixels. + sigma2 -- Standard deviation distance in pixels. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--sigma1={}".format(sigma1)) + args.append("--sigma2={}".format(sigma2)) + return self.run_tool('diff_of_gaussian_filter', args, callback) # returns 1 if error + + def diversity_filter(self, i, output, filterx=11, filtery=11, callback=None): + """Assigns each cell in the output grid the number of different values in a moving window centred on each grid cell in the input raster. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + filterx -- Size of the filter kernel in the x-direction. + filtery -- Size of the filter kernel in the y-direction. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--filterx={}".format(filterx)) + args.append("--filtery={}".format(filtery)) + return self.run_tool('diversity_filter', args, callback) # returns 1 if error + + def edge_preserving_mean_filter(self, i, output, threshold, filter=11, callback=None): + """Performs a simple edge-preserving mean filter on an input image. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + filter -- Size of the filter kernel. + threshold -- Maximum difference in values. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--filter={}".format(filter)) + args.append("--threshold='{}'".format(threshold)) + return self.run_tool('edge_preserving_mean_filter', args, callback) # returns 1 if error + + def emboss_filter(self, i, output, direction="n", clip=0.0, callback=None): + """Performs an emboss filter on an image, similar to a hillshade operation. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + direction -- Direction of reflection; options include 'n', 's', 'e', 'w', 'ne', 'se', 'nw', 'sw'. + clip -- Optional amount to clip the distribution tails by, in percent. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--direction={}".format(direction)) + args.append("--clip={}".format(clip)) + return self.run_tool('emboss_filter', args, callback) # returns 1 if error + + def fast_almost_gaussian_filter(self, i, output, sigma=1.8, callback=None): + """Performs a fast approximate Gaussian filter on an image. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + sigma -- Standard deviation distance in pixels. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--sigma={}".format(sigma)) + return self.run_tool('fast_almost_gaussian_filter', args, callback) # returns 1 if error + + def gaussian_filter(self, i, output, sigma=0.75, callback=None): + """Performs a Gaussian filter on an image. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + sigma -- Standard deviation distance in pixels. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--sigma={}".format(sigma)) + return self.run_tool('gaussian_filter', args, callback) # returns 1 if error + + def high_pass_filter(self, i, output, filterx=11, filtery=11, callback=None): + """Performs a high-pass filter on an input image. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + filterx -- Size of the filter kernel in the x-direction. + filtery -- Size of the filter kernel in the y-direction. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--filterx={}".format(filterx)) + args.append("--filtery={}".format(filtery)) + return self.run_tool('high_pass_filter', args, callback) # returns 1 if error + + def high_pass_median_filter(self, i, output, filterx=11, filtery=11, sig_digits=2, callback=None): + """Performs a high pass median filter on an input image. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + filterx -- Size of the filter kernel in the x-direction. + filtery -- Size of the filter kernel in the y-direction. + sig_digits -- Number of significant digits. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--filterx={}".format(filterx)) + args.append("--filtery={}".format(filtery)) + args.append("--sig_digits={}".format(sig_digits)) + return self.run_tool('high_pass_median_filter', args, callback) # returns 1 if error + + def k_nearest_mean_filter(self, i, output, filterx=11, filtery=11, k=5, callback=None): + """A k-nearest mean filter is a type of edge-preserving smoothing filter. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + filterx -- Size of the filter kernel in the x-direction. + filtery -- Size of the filter kernel in the y-direction. + k -- k-value in pixels; this is the number of nearest-valued neighbours to use. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--filterx={}".format(filterx)) + args.append("--filtery={}".format(filtery)) + args.append("-k={}".format(k)) + return self.run_tool('k_nearest_mean_filter', args, callback) # returns 1 if error + + def laplacian_filter(self, i, output, variant="3x3(1)", clip=0.0, callback=None): + """Performs a Laplacian filter on an image. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + variant -- Optional variant value. Options include 3x3(1), 3x3(2), 3x3(3), 3x3(4), 5x5(1), and 5x5(2) (default is 3x3(1)). + clip -- Optional amount to clip the distribution tails by, in percent. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--variant={}".format(variant)) + args.append("--clip={}".format(clip)) + return self.run_tool('laplacian_filter', args, callback) # returns 1 if error + + def laplacian_of_gaussian_filter(self, i, output, sigma=0.75, callback=None): + """Performs a Laplacian-of-Gaussian (LoG) filter on an image. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + sigma -- Standard deviation in pixels. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--sigma={}".format(sigma)) + return self.run_tool('laplacian_of_gaussian_filter', args, callback) # returns 1 if error + + def lee_sigma_filter(self, i, output, filterx=11, filtery=11, sigma=10.0, m=5.0, callback=None): + """Performs a Lee (Sigma) smoothing filter on an image. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + filterx -- Size of the filter kernel in the x-direction. + filtery -- Size of the filter kernel in the y-direction. + sigma -- Sigma value should be related to the standarad deviation of the distribution of image speckle noise. + m -- M-threshold value the minimum allowable number of pixels within the intensity range. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--filterx={}".format(filterx)) + args.append("--filtery={}".format(filtery)) + args.append("--sigma={}".format(sigma)) + args.append("-m={}".format(m)) + return self.run_tool('lee_sigma_filter', args, callback) # returns 1 if error + + def line_detection_filter(self, i, output, variant="vertical", absvals=False, clip=0.0, callback=None): + """Performs a line-detection filter on an image. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + variant -- Optional variant value. Options include 'v' (vertical), 'h' (horizontal), '45', and '135' (default is 'v'). + absvals -- Optional flag indicating whether outputs should be absolute values. + clip -- Optional amount to clip the distribution tails by, in percent. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--variant={}".format(variant)) + if absvals: args.append("--absvals") + args.append("--clip={}".format(clip)) + return self.run_tool('line_detection_filter', args, callback) # returns 1 if error + + def majority_filter(self, i, output, filterx=11, filtery=11, callback=None): + """Assigns each cell in the output grid the most frequently occurring value (mode) in a moving window centred on each grid cell in the input raster. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + filterx -- Size of the filter kernel in the x-direction. + filtery -- Size of the filter kernel in the y-direction. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--filterx={}".format(filterx)) + args.append("--filtery={}".format(filtery)) + return self.run_tool('majority_filter', args, callback) # returns 1 if error + + def maximum_filter(self, i, output, filterx=11, filtery=11, callback=None): + """Assigns each cell in the output grid the maximum value in a moving window centred on each grid cell in the input raster. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + filterx -- Size of the filter kernel in the x-direction. + filtery -- Size of the filter kernel in the y-direction. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--filterx={}".format(filterx)) + args.append("--filtery={}".format(filtery)) + return self.run_tool('maximum_filter', args, callback) # returns 1 if error + + def mean_filter(self, i, output, filterx=3, filtery=3, callback=None): + """Performs a mean filter (low-pass filter) on an input image. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + filterx -- Size of the filter kernel in the x-direction. + filtery -- Size of the filter kernel in the y-direction. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--filterx={}".format(filterx)) + args.append("--filtery={}".format(filtery)) + return self.run_tool('mean_filter', args, callback) # returns 1 if error + + def median_filter(self, i, output, filterx=11, filtery=11, sig_digits=2, callback=None): + """Performs a median filter on an input image. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + filterx -- Size of the filter kernel in the x-direction. + filtery -- Size of the filter kernel in the y-direction. + sig_digits -- Number of significant digits. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--filterx={}".format(filterx)) + args.append("--filtery={}".format(filtery)) + args.append("--sig_digits={}".format(sig_digits)) + return self.run_tool('median_filter', args, callback) # returns 1 if error + + def minimum_filter(self, i, output, filterx=11, filtery=11, callback=None): + """Assigns each cell in the output grid the minimum value in a moving window centred on each grid cell in the input raster. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + filterx -- Size of the filter kernel in the x-direction. + filtery -- Size of the filter kernel in the y-direction. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--filterx={}".format(filterx)) + args.append("--filtery={}".format(filtery)) + return self.run_tool('minimum_filter', args, callback) # returns 1 if error + + def olympic_filter(self, i, output, filterx=11, filtery=11, callback=None): + """Performs an olympic smoothing filter on an image. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + filterx -- Size of the filter kernel in the x-direction. + filtery -- Size of the filter kernel in the y-direction. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--filterx={}".format(filterx)) + args.append("--filtery={}".format(filtery)) + return self.run_tool('olympic_filter', args, callback) # returns 1 if error + + def percentile_filter(self, i, output, filterx=11, filtery=11, sig_digits=2, callback=None): + """Performs a percentile filter on an input image. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + filterx -- Size of the filter kernel in the x-direction. + filtery -- Size of the filter kernel in the y-direction. + sig_digits -- Number of significant digits. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--filterx={}".format(filterx)) + args.append("--filtery={}".format(filtery)) + args.append("--sig_digits={}".format(sig_digits)) + return self.run_tool('percentile_filter', args, callback) # returns 1 if error + + def prewitt_filter(self, i, output, clip=0.0, callback=None): + """Performs a Prewitt edge-detection filter on an image. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + clip -- Optional amount to clip the distribution tails by, in percent. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--clip={}".format(clip)) + return self.run_tool('prewitt_filter', args, callback) # returns 1 if error + + def range_filter(self, i, output, filterx=11, filtery=11, callback=None): + """Assigns each cell in the output grid the range of values in a moving window centred on each grid cell in the input raster. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + filterx -- Size of the filter kernel in the x-direction. + filtery -- Size of the filter kernel in the y-direction. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--filterx={}".format(filterx)) + args.append("--filtery={}".format(filtery)) + return self.run_tool('range_filter', args, callback) # returns 1 if error + + def roberts_cross_filter(self, i, output, clip=0.0, callback=None): + """Performs a Robert's cross edge-detection filter on an image. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + clip -- Optional amount to clip the distribution tails by, in percent. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--clip={}".format(clip)) + return self.run_tool('roberts_cross_filter', args, callback) # returns 1 if error + + def scharr_filter(self, i, output, clip=0.0, callback=None): + """Performs a Scharr edge-detection filter on an image. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + clip -- Optional amount to clip the distribution tails by, in percent. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--clip={}".format(clip)) + return self.run_tool('scharr_filter', args, callback) # returns 1 if error + + def sobel_filter(self, i, output, variant="3x3", clip=0.0, callback=None): + """Performs a Sobel edge-detection filter on an image. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + variant -- Optional variant value. Options include 3x3 and 5x5 (default is 3x3). + clip -- Optional amount to clip the distribution tails by, in percent (default is 0.0). + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--variant={}".format(variant)) + args.append("--clip={}".format(clip)) + return self.run_tool('sobel_filter', args, callback) # returns 1 if error + + def standard_deviation_filter(self, i, output, filterx=11, filtery=11, callback=None): + """Assigns each cell in the output grid the standard deviation of values in a moving window centred on each grid cell in the input raster. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + filterx -- Size of the filter kernel in the x-direction. + filtery -- Size of the filter kernel in the y-direction. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--filterx={}".format(filterx)) + args.append("--filtery={}".format(filtery)) + return self.run_tool('standard_deviation_filter', args, callback) # returns 1 if error + + def total_filter(self, i, output, filterx=11, filtery=11, callback=None): + """Performs a total filter on an input image. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + filterx -- Size of the filter kernel in the x-direction. + filtery -- Size of the filter kernel in the y-direction. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--filterx={}".format(filterx)) + args.append("--filtery={}".format(filtery)) + return self.run_tool('total_filter', args, callback) # returns 1 if error + + def unsharp_masking(self, i, output, sigma=0.75, amount=100.0, threshold=0.0, callback=None): + """An image sharpening technique that enhances edges. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + sigma -- Standard deviation distance in pixels. + amount -- A percentage and controls the magnitude of each overshoot. + threshold -- Controls the minimal brightness change that will be sharpened. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--sigma={}".format(sigma)) + args.append("--amount={}".format(amount)) + args.append("--threshold={}".format(threshold)) + return self.run_tool('unsharp_masking', args, callback) # returns 1 if error + + def user_defined_weights_filter(self, i, weights, output, center="center", normalize=False, callback=None): + """Performs a user-defined weights filter on an image. + + Keyword arguments: + + i -- Input raster file. + weights -- Input weights file. + output -- Output raster file. + center -- Kernel center cell; options include 'center', 'upper-left', 'upper-right', 'lower-left', 'lower-right'. + normalize -- Normalize kernel weights? This can reduce edge effects and lessen the impact of data gaps (nodata) but is not suited when the kernel weights sum to zero. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--weights='{}'".format(weights)) + args.append("--output='{}'".format(output)) + args.append("--center={}".format(center)) + if normalize: args.append("--normalize") + return self.run_tool('user_defined_weights_filter', args, callback) # returns 1 if error + + ############################################ + # Image Processing Tools/Image Enhancement # + ############################################ + + def balance_contrast_enhancement(self, i, output, band_mean=100.0, callback=None): + """Performs a balance contrast enhancement on a colour-composite image of multispectral data. + + Keyword arguments: + + i -- Input colour composite image file. + output -- Output raster file. + band_mean -- Band mean value. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--band_mean={}".format(band_mean)) + return self.run_tool('balance_contrast_enhancement', args, callback) # returns 1 if error + + def correct_vignetting(self, i, pp, output, focal_length=304.8, image_width=228.6, n=4.0, callback=None): + """Corrects the darkening of images towards corners. + + Keyword arguments: + + i -- Input raster file. + pp -- Input principal point file. + output -- Output raster file. + focal_length -- Camera focal length, in millimeters. + image_width -- Distance between photograph edges, in millimeters. + n -- The 'n' parameter. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--pp='{}'".format(pp)) + args.append("--output='{}'".format(output)) + args.append("--focal_length={}".format(focal_length)) + args.append("--image_width={}".format(image_width)) + args.append("-n={}".format(n)) + return self.run_tool('correct_vignetting', args, callback) # returns 1 if error + + def direct_decorrelation_stretch(self, i, output, k=0.5, clip=1.0, callback=None): + """Performs a direct decorrelation stretch enhancement on a colour-composite image of multispectral data. + + Keyword arguments: + + i -- Input colour composite image file. + output -- Output raster file. + k -- Achromatic factor (k) ranges between 0 (no effect) and 1 (full saturation stretch), although typical values range from 0.3 to 0.7. + clip -- Optional percent to clip the upper tail by during the stretch. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("-k={}".format(k)) + args.append("--clip={}".format(clip)) + return self.run_tool('direct_decorrelation_stretch', args, callback) # returns 1 if error + + def gamma_correction(self, i, output, gamma=0.5, callback=None): + """Performs a gamma correction on an input images. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + gamma -- Gamma value. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--gamma={}".format(gamma)) + return self.run_tool('gamma_correction', args, callback) # returns 1 if error + + def gaussian_contrast_stretch(self, i, output, num_tones=256, callback=None): + """Performs a Gaussian contrast stretch on input images. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + num_tones -- Number of tones in the output image. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--num_tones={}".format(num_tones)) + return self.run_tool('gaussian_contrast_stretch', args, callback) # returns 1 if error + + def histogram_equalization(self, i, output, num_tones=256, callback=None): + """Performs a histogram equalization contrast enhancment on an image. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + num_tones -- Number of tones in the output image. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--num_tones={}".format(num_tones)) + return self.run_tool('histogram_equalization', args, callback) # returns 1 if error + + def histogram_matching(self, i, histo_file, output, callback=None): + """Alters the statistical distribution of a raster image matching it to a specified PDF. + + Keyword arguments: + + i -- Input raster file. + histo_file -- Input reference probability distribution function (pdf) text file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--histo_file='{}'".format(histo_file)) + args.append("--output='{}'".format(output)) + return self.run_tool('histogram_matching', args, callback) # returns 1 if error + + def histogram_matching_two_images(self, input1, input2, output, callback=None): + """This tool alters the cumulative distribution function of a raster image to that of another image. + + Keyword arguments: + + input1 -- Input raster file to modify. + input2 -- Input reference raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input1='{}'".format(input1)) + args.append("--input2='{}'".format(input2)) + args.append("--output='{}'".format(output)) + return self.run_tool('histogram_matching_two_images', args, callback) # returns 1 if error + + def min_max_contrast_stretch(self, i, output, min_val, max_val, num_tones=256, callback=None): + """Performs a min-max contrast stretch on an input greytone image. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + min_val -- Lower tail clip value. + max_val -- Upper tail clip value. + num_tones -- Number of tones in the output image. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--min_val='{}'".format(min_val)) + args.append("--max_val='{}'".format(max_val)) + args.append("--num_tones={}".format(num_tones)) + return self.run_tool('min_max_contrast_stretch', args, callback) # returns 1 if error + + def panchromatic_sharpening(self, pan, output, red=None, green=None, blue=None, composite=None, method="brovey", callback=None): + """Increases the spatial resolution of image data by combining multispectral bands with panchromatic data. + + Keyword arguments: + + red -- Input red band image file. Optionally specified if colour-composite not specified. + green -- Input green band image file. Optionally specified if colour-composite not specified. + blue -- Input blue band image file. Optionally specified if colour-composite not specified. + composite -- Input colour-composite image file. Only used if individual bands are not specified. + pan -- Input panchromatic band file. + output -- Output colour composite file. + method -- Options include 'brovey' (default) and 'ihs'. + callback -- Custom function for handling tool text outputs. + """ + args = [] + if red is not None: args.append("--red='{}'".format(red)) + if green is not None: args.append("--green='{}'".format(green)) + if blue is not None: args.append("--blue='{}'".format(blue)) + if composite is not None: args.append("--composite='{}'".format(composite)) + args.append("--pan='{}'".format(pan)) + args.append("--output='{}'".format(output)) + args.append("--method={}".format(method)) + return self.run_tool('panchromatic_sharpening', args, callback) # returns 1 if error + + def percentage_contrast_stretch(self, i, output, clip=1.0, tail="both", num_tones=256, callback=None): + """Performs a percentage linear contrast stretch on input images. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + clip -- Optional amount to clip the distribution tails by, in percent. + tail -- Specified which tails to clip; options include 'upper', 'lower', and 'both' (default is 'both'). + num_tones -- Number of tones in the output image. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--clip={}".format(clip)) + args.append("--tail={}".format(tail)) + args.append("--num_tones={}".format(num_tones)) + return self.run_tool('percentage_contrast_stretch', args, callback) # returns 1 if error + + def sigmoidal_contrast_stretch(self, i, output, cutoff=0.0, gain=1.0, num_tones=256, callback=None): + """Performs a sigmoidal contrast stretch on input images. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + cutoff -- Cutoff value between 0.0 and 0.95. + gain -- Gain value. + num_tones -- Number of tones in the output image. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--cutoff={}".format(cutoff)) + args.append("--gain={}".format(gain)) + args.append("--num_tones={}".format(num_tones)) + return self.run_tool('sigmoidal_contrast_stretch', args, callback) # returns 1 if error + + def standard_deviation_contrast_stretch(self, i, output, stdev=2.0, num_tones=256, callback=None): + """Performs a standard-deviation contrast stretch on input images. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + stdev -- Standard deviation clip value. + num_tones -- Number of tones in the output image. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--stdev={}".format(stdev)) + args.append("--num_tones={}".format(num_tones)) + return self.run_tool('standard_deviation_contrast_stretch', args, callback) # returns 1 if error + + ############### + # LiDAR Tools # + ############### + + def ascii_to_las(self, inputs, pattern, proj=None, callback=None): + """Converts one or more ASCII files containing LiDAR points into LAS files. + + Keyword arguments: + + inputs -- Input LiDAR ASCII files (.csv). + pattern -- Input field pattern. + proj -- Well-known-text string or EPSG code describing projection. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--inputs='{}'".format(inputs)) + args.append("--pattern='{}'".format(pattern)) + if proj is not None: args.append("--proj='{}'".format(proj)) + return self.run_tool('ascii_to_las', args, callback) # returns 1 if error + + def classify_buildings_in_lidar(self, i, buildings, output, callback=None): + """Reclassifies a LiDAR points that lie within vector building footprints. + + Keyword arguments: + + i -- Input LiDAR file. + buildings -- Input vector polygons file. + output -- Output LiDAR file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--buildings='{}'".format(buildings)) + args.append("--output='{}'".format(output)) + return self.run_tool('classify_buildings_in_lidar', args, callback) # returns 1 if error + + def classify_overlap_points(self, i, output, resolution=2.0, filter=False, callback=None): + """Classifies or filters LAS points in regions of overlapping flight lines. + + Keyword arguments: + + i -- Input LiDAR file. + output -- Output LiDAR file. + resolution -- The size of the square area used to evaluate nearby points in the LiDAR data. + filter -- Filter out points from overlapping flightlines? If false, overlaps will simply be classified. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--resolution={}".format(resolution)) + if filter: args.append("--filter") + return self.run_tool('classify_overlap_points', args, callback) # returns 1 if error + + def clip_lidar_to_polygon(self, i, polygons, output, callback=None): + """Clips a LiDAR point cloud to a vector polygon or polygons. + + Keyword arguments: + + i -- Input LiDAR file. + polygons -- Input vector polygons file. + output -- Output LiDAR file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--polygons='{}'".format(polygons)) + args.append("--output='{}'".format(output)) + return self.run_tool('clip_lidar_to_polygon', args, callback) # returns 1 if error + + def erase_polygon_from_lidar(self, i, polygons, output, callback=None): + """Erases (cuts out) a vector polygon or polygons from a LiDAR point cloud. + + Keyword arguments: + + i -- Input LiDAR file. + polygons -- Input vector polygons file. + output -- Output LiDAR file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--polygons='{}'".format(polygons)) + args.append("--output='{}'".format(output)) + return self.run_tool('erase_polygon_from_lidar', args, callback) # returns 1 if error + + def filter_lidar_classes(self, i, output, exclude_cls=None, callback=None): + """Removes points in a LAS file with certain specified class values. + + Keyword arguments: + + i -- Input LiDAR file. + output -- Output LiDAR file. + exclude_cls -- Optional exclude classes from interpolation; Valid class values range from 0 to 18, based on LAS specifications. Example, --exclude_cls='3,4,5,6,7,18'. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + if exclude_cls is not None: args.append("--exclude_cls='{}'".format(exclude_cls)) + return self.run_tool('filter_lidar_classes', args, callback) # returns 1 if error + + def filter_lidar_scan_angles(self, i, output, threshold, callback=None): + """Removes points in a LAS file with scan angles greater than a threshold. + + Keyword arguments: + + i -- Input LiDAR file. + output -- Output LiDAR file. + threshold -- Scan angle threshold. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--threshold='{}'".format(threshold)) + return self.run_tool('filter_lidar_scan_angles', args, callback) # returns 1 if error + + def find_flightline_edge_points(self, i, output, callback=None): + """Identifies points along a flightline's edge in a LAS file. + + Keyword arguments: + + i -- Input LiDAR file. + output -- Output file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('find_flightline_edge_points', args, callback) # returns 1 if error + + def flightline_overlap(self, i=None, output=None, resolution=1.0, callback=None): + """Reads a LiDAR (LAS) point file and outputs a raster containing the number of overlapping flight lines in each grid cell. + + Keyword arguments: + + i -- Input LiDAR file. + output -- Output file. + resolution -- Output raster's grid resolution. + callback -- Custom function for handling tool text outputs. + """ + args = [] + if i is not None: args.append("--input='{}'".format(i)) + if output is not None: args.append("--output='{}'".format(output)) + args.append("--resolution={}".format(resolution)) + return self.run_tool('flightline_overlap', args, callback) # returns 1 if error + + def height_above_ground(self, i=None, output=None, callback=None): + """Normalizes a LiDAR point cloud, providing the height above the nearest ground-classified point. + + Keyword arguments: + + i -- Input LiDAR file (including extension). + output -- Output raster file (including extension). + callback -- Custom function for handling tool text outputs. + """ + args = [] + if i is not None: args.append("--input='{}'".format(i)) + if output is not None: args.append("--output='{}'".format(output)) + return self.run_tool('height_above_ground', args, callback) # returns 1 if error + + def las_to_ascii(self, inputs, callback=None): + """Converts one or more LAS files into ASCII text files. + + Keyword arguments: + + inputs -- Input LiDAR files. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--inputs='{}'".format(inputs)) + return self.run_tool('las_to_ascii', args, callback) # returns 1 if error + + def las_to_multipoint_shapefile(self, i=None, callback=None): + """Converts one or more LAS files into MultipointZ vector Shapefiles. When the input parameter is not specified, the tool grids all LAS files contained within the working directory. + + Keyword arguments: + + i -- Input LiDAR file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + if i is not None: args.append("--input='{}'".format(i)) + return self.run_tool('las_to_multipoint_shapefile', args, callback) # returns 1 if error + + def las_to_shapefile(self, i=None, callback=None): + """Converts one or more LAS files into a vector Shapefile of POINT ShapeType. + + Keyword arguments: + + i -- Input LiDAR file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + if i is not None: args.append("--input='{}'".format(i)) + return self.run_tool('las_to_shapefile', args, callback) # returns 1 if error + + def las_to_zlidar(self, inputs=None, outdir=None, callback=None): + """Converts one or more LAS files into the zlidar compressed LiDAR data format. + + Keyword arguments: + + inputs -- Input LAS files. + outdir -- Output directory into which zlidar files are created. If unspecified, it is assumed to be the same as the inputs. + callback -- Custom function for handling tool text outputs. + """ + args = [] + if inputs is not None: args.append("--inputs='{}'".format(inputs)) + if outdir is not None: args.append("--outdir='{}'".format(outdir)) + return self.run_tool('las_to_zlidar', args, callback) # returns 1 if error + + def lidar_block_maximum(self, i=None, output=None, resolution=1.0, callback=None): + """Creates a block-maximum raster from an input LAS file. When the input/output parameters are not specified, the tool grids all LAS files contained within the working directory. + + Keyword arguments: + + i -- Input LiDAR file. + output -- Output file. + resolution -- Output raster's grid resolution. + callback -- Custom function for handling tool text outputs. + """ + args = [] + if i is not None: args.append("--input='{}'".format(i)) + if output is not None: args.append("--output='{}'".format(output)) + args.append("--resolution={}".format(resolution)) + return self.run_tool('lidar_block_maximum', args, callback) # returns 1 if error + + def lidar_block_minimum(self, i=None, output=None, resolution=1.0, callback=None): + """Creates a block-minimum raster from an input LAS file. When the input/output parameters are not specified, the tool grids all LAS files contained within the working directory. + + Keyword arguments: + + i -- Input LiDAR file. + output -- Output file. + resolution -- Output raster's grid resolution. + callback -- Custom function for handling tool text outputs. + """ + args = [] + if i is not None: args.append("--input='{}'".format(i)) + if output is not None: args.append("--output='{}'".format(output)) + args.append("--resolution={}".format(resolution)) + return self.run_tool('lidar_block_minimum', args, callback) # returns 1 if error + + def lidar_classify_subset(self, base, subset, output, subset_class, nonsubset_class=None, callback=None): + """Classifies the values in one LiDAR point cloud that correpond with points in a subset cloud. + + Keyword arguments: + + base -- Input base LiDAR file. + subset -- Input subset LiDAR file. + output -- Output LiDAR file. + subset_class -- Subset point class value (must be 0-18; see LAS specifications). + nonsubset_class -- Non-subset point class value (must be 0-18; see LAS specifications). + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--base='{}'".format(base)) + args.append("--subset='{}'".format(subset)) + args.append("--output='{}'".format(output)) + args.append("--subset_class='{}'".format(subset_class)) + if nonsubset_class is not None: args.append("--nonsubset_class='{}'".format(nonsubset_class)) + return self.run_tool('lidar_classify_subset', args, callback) # returns 1 if error + + def lidar_colourize(self, in_lidar, in_image, output, callback=None): + """Adds the red-green-blue colour fields of a LiDAR (LAS) file based on an input image. + + Keyword arguments: + + in_lidar -- Input LiDAR file. + in_image -- Input colour image file. + output -- Output LiDAR file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--in_lidar='{}'".format(in_lidar)) + args.append("--in_image='{}'".format(in_image)) + args.append("--output='{}'".format(output)) + return self.run_tool('lidar_colourize', args, callback) # returns 1 if error + + def lidar_elevation_slice(self, i, output, minz=None, maxz=None, cls=False, inclassval=2, outclassval=1, callback=None): + """Outputs all of the points within a LiDAR (LAS) point file that lie between a specified elevation range. + + Keyword arguments: + + i -- Input LiDAR file. + output -- Output LiDAR file. + minz -- Minimum elevation value (optional). + maxz -- Maximum elevation value (optional). + cls -- Optional boolean flag indicating whether points outside the range should be retained in output but reclassified. + inclassval -- Optional parameter specifying the class value assigned to points within the slice. + outclassval -- Optional parameter specifying the class value assigned to points within the slice. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + if minz is not None: args.append("--minz='{}'".format(minz)) + if maxz is not None: args.append("--maxz='{}'".format(maxz)) + if cls: args.append("--class") + args.append("--inclassval={}".format(inclassval)) + args.append("--outclassval={}".format(outclassval)) + return self.run_tool('lidar_elevation_slice', args, callback) # returns 1 if error + + def lidar_ground_point_filter(self, i, output, radius=2.0, min_neighbours=0, slope_threshold=45.0, height_threshold=1.0, classify=True, slope_norm=True, height_above_ground=False, callback=None): + """Identifies ground points within LiDAR dataset using a slope-based method. + + Keyword arguments: + + i -- Input LiDAR file. + output -- Output LiDAR file. + radius -- Search Radius. + min_neighbours -- The minimum number of neighbouring points within search areas. If fewer points than this threshold are idenfied during the fixed-radius search, a subsequent kNN search is performed to identify the k number of neighbours. + slope_threshold -- Maximum inter-point slope to be considered an off-terrain point. + height_threshold -- Inter-point height difference to be considered an off-terrain point. + classify -- Classify points as ground (2) or off-ground (1). + slope_norm -- Perform initial ground slope normalization?. + height_above_ground -- Transform output to height above average ground elevation?. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--radius={}".format(radius)) + args.append("--min_neighbours={}".format(min_neighbours)) + args.append("--slope_threshold={}".format(slope_threshold)) + args.append("--height_threshold={}".format(height_threshold)) + if classify: args.append("--classify") + if slope_norm: args.append("--slope_norm") + if height_above_ground: args.append("--height_above_ground") + return self.run_tool('lidar_ground_point_filter', args, callback) # returns 1 if error + + def lidar_hex_binning(self, i, output, width, orientation="horizontal", callback=None): + """Hex-bins a set of LiDAR points. + + Keyword arguments: + + i -- Input base file. + output -- Output vector polygon file. + width -- The grid cell width. + orientation -- Grid Orientation, 'horizontal' or 'vertical'. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--width='{}'".format(width)) + args.append("--orientation={}".format(orientation)) + return self.run_tool('lidar_hex_binning', args, callback) # returns 1 if error + + def lidar_hillshade(self, i, output, azimuth=315.0, altitude=30.0, radius=1.0, callback=None): + """Calculates a hillshade value for points within a LAS file and stores these data in the RGB field. + + Keyword arguments: + + i -- Input LiDAR file. + output -- Output file. + azimuth -- Illumination source azimuth in degrees. + altitude -- Illumination source altitude in degrees. + radius -- Search Radius. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--azimuth={}".format(azimuth)) + args.append("--altitude={}".format(altitude)) + args.append("--radius={}".format(radius)) + return self.run_tool('lidar_hillshade', args, callback) # returns 1 if error + + def lidar_histogram(self, i, output, parameter="elevation", clip=1.0, callback=None): + """Creates a histogram of LiDAR data. + + Keyword arguments: + + i -- Input LiDAR file. + output -- Output HTML file (default name will be based on input file if unspecified). + parameter -- Parameter; options are 'elevation' (default), 'intensity', 'scan angle', 'class'. + clip -- Amount to clip distribution tails (in percent). + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--parameter={}".format(parameter)) + args.append("--clip={}".format(clip)) + return self.run_tool('lidar_histogram', args, callback) # returns 1 if error + + def lidar_idw_interpolation(self, i=None, output=None, parameter="elevation", returns="all", resolution=1.0, weight=1.0, radius=2.5, exclude_cls=None, minz=None, maxz=None, callback=None): + """Interpolates LAS files using an inverse-distance weighted (IDW) scheme. When the input/output parameters are not specified, the tool interpolates all LAS files contained within the working directory. + + Keyword arguments: + + i -- Input LiDAR file (including extension). + output -- Output raster file (including extension). + parameter -- Interpolation parameter; options are 'elevation' (default), 'intensity', 'class', 'return_number', 'number_of_returns', 'scan angle', 'rgb', 'user data'. + returns -- Point return types to include; options are 'all' (default), 'last', 'first'. + resolution -- Output raster's grid resolution. + weight -- IDW weight value. + radius -- Search Radius. + exclude_cls -- Optional exclude classes from interpolation; Valid class values range from 0 to 18, based on LAS specifications. Example, --exclude_cls='3,4,5,6,7,18'. + minz -- Optional minimum elevation for inclusion in interpolation. + maxz -- Optional maximum elevation for inclusion in interpolation. + callback -- Custom function for handling tool text outputs. + """ + args = [] + if i is not None: args.append("--input='{}'".format(i)) + if output is not None: args.append("--output='{}'".format(output)) + args.append("--parameter={}".format(parameter)) + args.append("--returns={}".format(returns)) + args.append("--resolution={}".format(resolution)) + args.append("--weight={}".format(weight)) + args.append("--radius={}".format(radius)) + if exclude_cls is not None: args.append("--exclude_cls='{}'".format(exclude_cls)) + if minz is not None: args.append("--minz='{}'".format(minz)) + if maxz is not None: args.append("--maxz='{}'".format(maxz)) + return self.run_tool('lidar_idw_interpolation', args, callback) # returns 1 if error + + def lidar_info(self, i, output=None, vlr=True, geokeys=True, callback=None): + """Prints information about a LiDAR (LAS) dataset, including header, point return frequency, and classification data and information about the variable length records (VLRs) and geokeys. + + Keyword arguments: + + i -- Input LiDAR file. + output -- Output HTML file for summary report. + vlr -- Flag indicating whether or not to print the variable length records (VLRs). + geokeys -- Flag indicating whether or not to print the geokeys. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + if output is not None: args.append("--output='{}'".format(output)) + if vlr: args.append("--vlr") + if geokeys: args.append("--geokeys") + return self.run_tool('lidar_info', args, callback) # returns 1 if error + + def lidar_join(self, inputs, output, callback=None): + """Joins multiple LiDAR (LAS) files into a single LAS file. + + Keyword arguments: + + inputs -- Input LiDAR files. + output -- Output LiDAR file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--inputs='{}'".format(inputs)) + args.append("--output='{}'".format(output)) + return self.run_tool('lidar_join', args, callback) # returns 1 if error + + def lidar_kappa_index(self, input1, input2, output, class_accuracy, resolution=1.0, callback=None): + """Performs a kappa index of agreement (KIA) analysis on the classifications of two LAS files. + + Keyword arguments: + + input1 -- Input LiDAR classification file. + input2 -- Input LiDAR reference file. + output -- Output HTML file. + class_accuracy -- Output classification accuracy raster file. + resolution -- Output raster's grid resolution. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input1='{}'".format(input1)) + args.append("--input2='{}'".format(input2)) + args.append("--output='{}'".format(output)) + args.append("--class_accuracy='{}'".format(class_accuracy)) + args.append("--resolution={}".format(resolution)) + return self.run_tool('lidar_kappa_index', args, callback) # returns 1 if error + + def lidar_nearest_neighbour_gridding(self, i=None, output=None, parameter="elevation", returns="all", resolution=1.0, radius=2.5, exclude_cls=None, minz=None, maxz=None, callback=None): + """Grids LAS files using nearest-neighbour scheme. When the input/output parameters are not specified, the tool grids all LAS files contained within the working directory. + + Keyword arguments: + + i -- Input LiDAR file (including extension). + output -- Output raster file (including extension). + parameter -- Interpolation parameter; options are 'elevation' (default), 'intensity', 'class', 'return_number', 'number_of_returns', 'scan angle', 'rgb', 'user data'. + returns -- Point return types to include; options are 'all' (default), 'last', 'first'. + resolution -- Output raster's grid resolution. + radius -- Search Radius. + exclude_cls -- Optional exclude classes from interpolation; Valid class values range from 0 to 18, based on LAS specifications. Example, --exclude_cls='3,4,5,6,7,18'. + minz -- Optional minimum elevation for inclusion in interpolation. + maxz -- Optional maximum elevation for inclusion in interpolation. + callback -- Custom function for handling tool text outputs. + """ + args = [] + if i is not None: args.append("--input='{}'".format(i)) + if output is not None: args.append("--output='{}'".format(output)) + args.append("--parameter={}".format(parameter)) + args.append("--returns={}".format(returns)) + args.append("--resolution={}".format(resolution)) + args.append("--radius={}".format(radius)) + if exclude_cls is not None: args.append("--exclude_cls='{}'".format(exclude_cls)) + if minz is not None: args.append("--minz='{}'".format(minz)) + if maxz is not None: args.append("--maxz='{}'".format(maxz)) + return self.run_tool('lidar_nearest_neighbour_gridding', args, callback) # returns 1 if error + + def lidar_point_density(self, i=None, output=None, returns="all", resolution=1.0, radius=2.5, exclude_cls=None, minz=None, maxz=None, callback=None): + """Calculates the spatial pattern of point density for a LiDAR data set. When the input/output parameters are not specified, the tool grids all LAS files contained within the working directory. + + Keyword arguments: + + i -- Input LiDAR file (including extension). + output -- Output raster file (including extension). + returns -- Point return types to include; options are 'all' (default), 'last', 'first'. + resolution -- Output raster's grid resolution. + radius -- Search radius. + exclude_cls -- Optional exclude classes from interpolation; Valid class values range from 0 to 18, based on LAS specifications. Example, --exclude_cls='3,4,5,6,7,18'. + minz -- Optional minimum elevation for inclusion in interpolation. + maxz -- Optional maximum elevation for inclusion in interpolation. + callback -- Custom function for handling tool text outputs. + """ + args = [] + if i is not None: args.append("--input='{}'".format(i)) + if output is not None: args.append("--output='{}'".format(output)) + args.append("--returns={}".format(returns)) + args.append("--resolution={}".format(resolution)) + args.append("--radius={}".format(radius)) + if exclude_cls is not None: args.append("--exclude_cls='{}'".format(exclude_cls)) + if minz is not None: args.append("--minz='{}'".format(minz)) + if maxz is not None: args.append("--maxz='{}'".format(maxz)) + return self.run_tool('lidar_point_density', args, callback) # returns 1 if error + + def lidar_point_stats(self, i=None, resolution=1.0, num_points=True, num_pulses=False, avg_points_per_pulse=True, z_range=False, intensity_range=False, predom_class=False, callback=None): + """Creates several rasters summarizing the distribution of LAS point data. When the input/output parameters are not specified, the tool works on all LAS files contained within the working directory. + + Keyword arguments: + + i -- Input LiDAR file. + resolution -- Output raster's grid resolution. + num_points -- Flag indicating whether or not to output the number of points (returns) raster. + num_pulses -- Flag indicating whether or not to output the number of pulses raster. + avg_points_per_pulse -- Flag indicating whether or not to output the average number of points (returns) per pulse raster. + z_range -- Flag indicating whether or not to output the elevation range raster. + intensity_range -- Flag indicating whether or not to output the intensity range raster. + predom_class -- Flag indicating whether or not to output the predominant classification raster. + callback -- Custom function for handling tool text outputs. + """ + args = [] + if i is not None: args.append("--input='{}'".format(i)) + args.append("--resolution={}".format(resolution)) + if num_points: args.append("--num_points") + if num_pulses: args.append("--num_pulses") + if avg_points_per_pulse: args.append("--avg_points_per_pulse") + if z_range: args.append("--z_range") + if intensity_range: args.append("--intensity_range") + if predom_class: args.append("--predom_class") + return self.run_tool('lidar_point_stats', args, callback) # returns 1 if error + + def lidar_ransac_planes(self, i, output, radius=2.0, num_iter=50, num_samples=5, threshold=0.35, model_size=8, max_slope=80.0, classify=False, callback=None): + """Performs a RANSAC analysis to identify points within a LiDAR point cloud that belong to linear planes. + + Keyword arguments: + + i -- Input LiDAR file. + output -- Output LiDAR file. + radius -- Search Radius. + num_iter -- Number of iterations. + num_samples -- Number of sample points on which to build the model. + threshold -- Threshold used to determine inlier points. + model_size -- Acceptable model size. + max_slope -- Maximum planar slope. + classify -- Classify points as ground (2) or off-ground (1). + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--radius={}".format(radius)) + args.append("--num_iter={}".format(num_iter)) + args.append("--num_samples={}".format(num_samples)) + args.append("--threshold={}".format(threshold)) + args.append("--model_size={}".format(model_size)) + args.append("--max_slope={}".format(max_slope)) + if classify: args.append("--classify") + return self.run_tool('lidar_ransac_planes', args, callback) # returns 1 if error + + def lidar_rbf_interpolation(self, i=None, output=None, parameter="elevation", returns="all", resolution=1.0, num_points=20, exclude_cls=None, minz=None, maxz=None, func_type="ThinPlateSpline", poly_order="none", weight=5, callback=None): + """Interpolates LAS files using a radial basis function (RBF) scheme. When the input/output parameters are not specified, the tool interpolates all LAS files contained within the working directory. + + Keyword arguments: + + i -- Input LiDAR file (including extension). + output -- Output raster file (including extension). + parameter -- Interpolation parameter; options are 'elevation' (default), 'intensity', 'class', 'return_number', 'number_of_returns', 'scan angle', 'rgb', 'user data'. + returns -- Point return types to include; options are 'all' (default), 'last', 'first'. + resolution -- Output raster's grid resolution. + num_points -- Number of points. + exclude_cls -- Optional exclude classes from interpolation; Valid class values range from 0 to 18, based on LAS specifications. Example, --exclude_cls='3,4,5,6,7,18'. + minz -- Optional minimum elevation for inclusion in interpolation. + maxz -- Optional maximum elevation for inclusion in interpolation. + func_type -- Radial basis function type; options are 'ThinPlateSpline' (default), 'PolyHarmonic', 'Gaussian', 'MultiQuadric', 'InverseMultiQuadric'. + poly_order -- Polynomial order; options are 'none' (default), 'constant', 'affine'. + weight -- Weight parameter used in basis function. + callback -- Custom function for handling tool text outputs. + """ + args = [] + if i is not None: args.append("--input='{}'".format(i)) + if output is not None: args.append("--output='{}'".format(output)) + args.append("--parameter={}".format(parameter)) + args.append("--returns={}".format(returns)) + args.append("--resolution={}".format(resolution)) + args.append("--num_points={}".format(num_points)) + if exclude_cls is not None: args.append("--exclude_cls='{}'".format(exclude_cls)) + if minz is not None: args.append("--minz='{}'".format(minz)) + if maxz is not None: args.append("--maxz='{}'".format(maxz)) + args.append("--func_type={}".format(func_type)) + args.append("--poly_order={}".format(poly_order)) + args.append("--weight={}".format(weight)) + return self.run_tool('lidar_rbf_interpolation', args, callback) # returns 1 if error + + def lidar_remove_duplicates(self, i, output, include_z=False, callback=None): + """Removes duplicate points from a LiDAR data set. + + Keyword arguments: + + i -- Input LiDAR file. + output -- Output LiDAR file. + include_z -- Include z-values in point comparison?. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + if include_z: args.append("--include_z") + return self.run_tool('lidar_remove_duplicates', args, callback) # returns 1 if error + + def lidar_remove_outliers(self, i, output, radius=2.0, elev_diff=50.0, use_median=False, classify=True, callback=None): + """Removes outliers (high and low points) in a LiDAR point cloud. + + Keyword arguments: + + i -- Input LiDAR file. + output -- Output LiDAR file. + radius -- Search Radius. + elev_diff -- Max. elevation difference. + use_median -- Optional flag indicating whether to use the difference from median elevation rather than mean. + classify -- Classify points as ground (2) or off-ground (1). + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--radius={}".format(radius)) + args.append("--elev_diff={}".format(elev_diff)) + if use_median: args.append("--use_median") + if classify: args.append("--classify") + return self.run_tool('lidar_remove_outliers', args, callback) # returns 1 if error + + def lidar_rooftop_analysis(self, buildings, output, i=None, radius=2.0, num_iter=50, num_samples=10, threshold=0.15, model_size=15, max_slope=65.0, norm_diff=10.0, azimuth=180.0, altitude=30.0, callback=None): + """Identifies roof segments in a LiDAR point cloud. + + Keyword arguments: + + i -- Input LiDAR file. + buildings -- Input vector build footprint polygons file. + output -- Output vector polygon file. + radius -- Search Radius. + num_iter -- Number of iterations. + num_samples -- Number of sample points on which to build the model. + threshold -- Threshold used to determine inlier points. + model_size -- Acceptable model size. + max_slope -- Maximum planar slope. + norm_diff -- Maximum difference in normal vectors, in degrees. + azimuth -- Illumination source azimuth in degrees. + altitude -- Illumination source altitude in degrees. + callback -- Custom function for handling tool text outputs. + """ + args = [] + if i is not None: args.append("--input='{}'".format(i)) + args.append("--buildings='{}'".format(buildings)) + args.append("--output='{}'".format(output)) + args.append("--radius={}".format(radius)) + args.append("--num_iter={}".format(num_iter)) + args.append("--num_samples={}".format(num_samples)) + args.append("--threshold={}".format(threshold)) + args.append("--model_size={}".format(model_size)) + args.append("--max_slope={}".format(max_slope)) + args.append("--norm_diff={}".format(norm_diff)) + args.append("--azimuth={}".format(azimuth)) + args.append("--altitude={}".format(altitude)) + return self.run_tool('lidar_rooftop_analysis', args, callback) # returns 1 if error + + def lidar_segmentation(self, i, output, radius=2.0, num_iter=50, num_samples=10, threshold=0.15, model_size=15, max_slope=80.0, norm_diff=10.0, maxzdiff=1.0, classes=False, ground=False, callback=None): + """Segments a LiDAR point cloud based on differences in the orientation of fitted planar surfaces and point proximity. + + Keyword arguments: + + i -- Input LiDAR file. + output -- Output LiDAR file. + radius -- Search Radius. + num_iter -- Number of iterations. + num_samples -- Number of sample points on which to build the model. + threshold -- Threshold used to determine inlier points. + model_size -- Acceptable model size. + max_slope -- Maximum planar slope. + norm_diff -- Maximum difference in normal vectors, in degrees. + maxzdiff -- Maximum difference in elevation (z units) between neighbouring points of the same segment. + classes -- Segments don't cross class boundaries. + ground -- Classify the largest segment as ground points?. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--radius={}".format(radius)) + args.append("--num_iter={}".format(num_iter)) + args.append("--num_samples={}".format(num_samples)) + args.append("--threshold={}".format(threshold)) + args.append("--model_size={}".format(model_size)) + args.append("--max_slope={}".format(max_slope)) + args.append("--norm_diff={}".format(norm_diff)) + args.append("--maxzdiff={}".format(maxzdiff)) + if classes: args.append("--classes") + if ground: args.append("--ground") + return self.run_tool('lidar_segmentation', args, callback) # returns 1 if error + + def lidar_segmentation_based_filter(self, i, output, radius=5.0, norm_diff=2.0, maxzdiff=1.0, classify=False, callback=None): + """Identifies ground points within LiDAR point clouds using a segmentation based approach. + + Keyword arguments: + + i -- Input LiDAR file. + output -- Output file. + radius -- Search Radius. + norm_diff -- Maximum difference in normal vectors, in degrees. + maxzdiff -- Maximum difference in elevation (z units) between neighbouring points of the same segment. + classify -- Classify points as ground (2) or off-ground (1). + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--radius={}".format(radius)) + args.append("--norm_diff={}".format(norm_diff)) + args.append("--maxzdiff={}".format(maxzdiff)) + if classify: args.append("--classify") + return self.run_tool('lidar_segmentation_based_filter', args, callback) # returns 1 if error + + def lidar_thin(self, i, output, resolution=2.0, method="lowest", save_filtered=False, callback=None): + """Thins a LiDAR point cloud, reducing point density. + + Keyword arguments: + + i -- Input LiDAR file. + output -- Output LiDAR file. + resolution -- The size of the square area used to evaluate nearby points in the LiDAR data. + method -- Point selection method; options are 'first', 'last', 'lowest' (default), 'highest', 'nearest'. + save_filtered -- Save filtered points to seperate file?. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--resolution={}".format(resolution)) + args.append("--method={}".format(method)) + if save_filtered: args.append("--save_filtered") + return self.run_tool('lidar_thin', args, callback) # returns 1 if error + + def lidar_thin_high_density(self, i, output, density, resolution=1.0, save_filtered=False, callback=None): + """Thins points from high density areas within a LiDAR point cloud. + + Keyword arguments: + + i -- Input LiDAR file. + output -- Output LiDAR file. + resolution -- Output raster's grid resolution. + density -- Max. point density (points / m^3). + save_filtered -- Save filtered points to seperate file?. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--resolution={}".format(resolution)) + args.append("--density='{}'".format(density)) + if save_filtered: args.append("--save_filtered") + return self.run_tool('lidar_thin_high_density', args, callback) # returns 1 if error + + def lidar_tile(self, i, width=1000.0, height=1000.0, origin_x=0.0, origin_y=0.0, min_points=2, callback=None): + """Tiles a LiDAR LAS file into multiple LAS files. + + Keyword arguments: + + i -- Input LiDAR file. + width -- Width of tiles in the X dimension; default 1000.0. + height -- Height of tiles in the Y dimension. + origin_x -- Origin point X coordinate for tile grid. + origin_y -- Origin point Y coordinate for tile grid. + min_points -- Minimum number of points contained in a tile for it to be saved. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--width={}".format(width)) + args.append("--height={}".format(height)) + args.append("--origin_x={}".format(origin_x)) + args.append("--origin_y={}".format(origin_y)) + args.append("--min_points={}".format(min_points)) + return self.run_tool('lidar_tile', args, callback) # returns 1 if error + + def lidar_tile_footprint(self, output, i=None, hull=False, callback=None): + """Creates a vector polygon of the convex hull of a LiDAR point cloud. When the input/output parameters are not specified, the tool works with all LAS files contained within the working directory. + + Keyword arguments: + + i -- Input LiDAR file. + output -- Output vector polygon file. + hull -- Identify the convex hull around points. + callback -- Custom function for handling tool text outputs. + """ + args = [] + if i is not None: args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + if hull: args.append("--hull") + return self.run_tool('lidar_tile_footprint', args, callback) # returns 1 if error + + def lidar_tin_gridding(self, i=None, output=None, parameter="elevation", returns="all", resolution=1.0, exclude_cls=None, minz=None, maxz=None, max_triangle_edge_length=None, callback=None): + """Creates a raster grid based on a Delaunay triangular irregular network (TIN) fitted to LiDAR points. + + Keyword arguments: + + i -- Input LiDAR file (including extension). + output -- Output raster file (including extension). + parameter -- Interpolation parameter; options are 'elevation' (default), 'intensity', 'class', 'return_number', 'number_of_returns', 'scan angle', 'rgb', 'user data'. + returns -- Point return types to include; options are 'all' (default), 'last', 'first'. + resolution -- Output raster's grid resolution. + exclude_cls -- Optional exclude classes from interpolation; Valid class values range from 0 to 18, based on LAS specifications. Example, --exclude_cls='3,4,5,6,7,18'. + minz -- Optional minimum elevation for inclusion in interpolation. + maxz -- Optional maximum elevation for inclusion in interpolation. + max_triangle_edge_length -- Optional maximum triangle edge length; triangles larger than this size will not be gridded. + callback -- Custom function for handling tool text outputs. + """ + args = [] + if i is not None: args.append("--input='{}'".format(i)) + if output is not None: args.append("--output='{}'".format(output)) + args.append("--parameter={}".format(parameter)) + args.append("--returns={}".format(returns)) + args.append("--resolution={}".format(resolution)) + if exclude_cls is not None: args.append("--exclude_cls='{}'".format(exclude_cls)) + if minz is not None: args.append("--minz='{}'".format(minz)) + if maxz is not None: args.append("--maxz='{}'".format(maxz)) + if max_triangle_edge_length is not None: args.append("--max_triangle_edge_length='{}'".format(max_triangle_edge_length)) + return self.run_tool('lidar_tin_gridding', args, callback) # returns 1 if error + + def lidar_tophat_transform(self, i, output, radius=1.0, callback=None): + """Performs a white top-hat transform on a Lidar dataset; as an estimate of height above ground, this is useful for modelling the vegetation canopy. + + Keyword arguments: + + i -- Input LiDAR file. + output -- Output LiDAR file. + radius -- Search Radius. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--radius={}".format(radius)) + return self.run_tool('lidar_tophat_transform', args, callback) # returns 1 if error + + def normal_vectors(self, i, output, radius=1.0, callback=None): + """Calculates normal vectors for points within a LAS file and stores these data (XYZ vector components) in the RGB field. + + Keyword arguments: + + i -- Input LiDAR file. + output -- Output LiDAR file. + radius -- Search Radius. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--radius={}".format(radius)) + return self.run_tool('normal_vectors', args, callback) # returns 1 if error + + def select_tiles_by_polygon(self, indir, outdir, polygons, callback=None): + """Copies LiDAR tiles overlapping with a polygon into an output directory. + + Keyword arguments: + + indir -- Input LAS file source directory. + outdir -- Output directory into which LAS files within the polygon are copied. + polygons -- Input vector polygons file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--indir='{}'".format(indir)) + args.append("--outdir='{}'".format(outdir)) + args.append("--polygons='{}'".format(polygons)) + return self.run_tool('select_tiles_by_polygon', args, callback) # returns 1 if error + + def zlidar_to_las(self, inputs=None, outdir=None, callback=None): + """Converts one or more zlidar files into the LAS data format. + + Keyword arguments: + + inputs -- Input ZLidar files. + outdir -- Output directory into which zlidar files are created. If unspecified, it is assumed to be the same as the inputs. + callback -- Custom function for handling tool text outputs. + """ + args = [] + if inputs is not None: args.append("--inputs='{}'".format(inputs)) + if outdir is not None: args.append("--outdir='{}'".format(outdir)) + return self.run_tool('zlidar_to_las', args, callback) # returns 1 if error + + ######################## + # Math and Stats Tools # + ######################## + + def And(self, input1, input2, output, callback=None): + """Performs a logical AND operator on two Boolean raster images. + + Keyword arguments: + + input1 -- Input raster file. + input2 -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input1='{}'".format(input1)) + args.append("--input2='{}'".format(input2)) + args.append("--output='{}'".format(output)) + return self.run_tool('and', args, callback) # returns 1 if error + + def Not(self, input1, input2, output, callback=None): + """Performs a logical NOT operator on two Boolean raster images. + + Keyword arguments: + + input1 -- Input raster file. + input2 -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input1='{}'".format(input1)) + args.append("--input2='{}'".format(input2)) + args.append("--output='{}'".format(output)) + return self.run_tool('not', args, callback) # returns 1 if error + + def Or(self, input1, input2, output, callback=None): + """Performs a logical OR operator on two Boolean raster images. + + Keyword arguments: + + input1 -- Input raster file. + input2 -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input1='{}'".format(input1)) + args.append("--input2='{}'".format(input2)) + args.append("--output='{}'".format(output)) + return self.run_tool('or', args, callback) # returns 1 if error + + def absolute_value(self, i, output, callback=None): + """Calculates the absolute value of every cell in a raster. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('absolute_value', args, callback) # returns 1 if error + + def add(self, input1, input2, output, callback=None): + """Performs an addition operation on two rasters or a raster and a constant value. + + Keyword arguments: + + input1 -- Input raster file or constant value. + input2 -- Input raster file or constant value. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input1='{}'".format(input1)) + args.append("--input2='{}'".format(input2)) + args.append("--output='{}'".format(output)) + return self.run_tool('add', args, callback) # returns 1 if error + + def anova(self, i, features, output, callback=None): + """Performs an analysis of variance (ANOVA) test on a raster dataset. + + Keyword arguments: + + i -- Input raster file. + features -- Feature definition (or class) raster. + output -- Output HTML file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--features='{}'".format(features)) + args.append("--output='{}'".format(output)) + return self.run_tool('anova', args, callback) # returns 1 if error + + def arc_cos(self, i, output, callback=None): + """Returns the inverse cosine (arccos) of each values in a raster. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('arc_cos', args, callback) # returns 1 if error + + def arc_sin(self, i, output, callback=None): + """Returns the inverse sine (arcsin) of each values in a raster. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('arc_sin', args, callback) # returns 1 if error + + def arc_tan(self, i, output, callback=None): + """Returns the inverse tangent (arctan) of each values in a raster. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('arc_tan', args, callback) # returns 1 if error + + def arcosh(self, i, output, callback=None): + """Returns the inverse hyperbolic cosine (arcosh) of each values in a raster. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('arcosh', args, callback) # returns 1 if error + + def arsinh(self, i, output, callback=None): + """Returns the inverse hyperbolic sine (arsinh) of each values in a raster. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('arsinh', args, callback) # returns 1 if error + + def artanh(self, i, output, callback=None): + """Returns the inverse hyperbolic tangent (arctanh) of each values in a raster. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('artanh', args, callback) # returns 1 if error + + def atan2(self, input_y, input_x, output, callback=None): + """Returns the 2-argument inverse tangent (atan2). + + Keyword arguments: + + input_y -- Input y raster file or constant value (rise). + input_x -- Input x raster file or constant value (run). + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input_y='{}'".format(input_y)) + args.append("--input_x='{}'".format(input_x)) + args.append("--output='{}'".format(output)) + return self.run_tool('atan2', args, callback) # returns 1 if error + + def attribute_correlation(self, i, output=None, callback=None): + """Performs a correlation analysis on attribute fields from a vector database. + + Keyword arguments: + + i -- Input vector file. + output -- Output HTML file (default name will be based on input file if unspecified). + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + if output is not None: args.append("--output='{}'".format(output)) + return self.run_tool('attribute_correlation', args, callback) # returns 1 if error + + def attribute_correlation_neighbourhood_analysis(self, i, field1, field2, radius=None, min_points=None, stat="pearson", callback=None): + """Performs a correlation on two input vector attributes within a neighbourhood search windows. + + Keyword arguments: + + i -- Input vector file. + field1 -- First input field name (dependent variable) in attribute table. + field2 -- Second input field name (independent variable) in attribute table. + radius -- Search Radius (in map units). + min_points -- Minimum number of points. + stat -- Correlation type; one of 'pearson' (default) and 'spearman'. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--field1='{}'".format(field1)) + args.append("--field2='{}'".format(field2)) + if radius is not None: args.append("--radius='{}'".format(radius)) + if min_points is not None: args.append("--min_points='{}'".format(min_points)) + args.append("--stat={}".format(stat)) + return self.run_tool('attribute_correlation_neighbourhood_analysis', args, callback) # returns 1 if error + + def attribute_histogram(self, i, field, output, callback=None): + """Creates a histogram for the field values of a vector's attribute table. + + Keyword arguments: + + i -- Input raster file. + field -- Input field name in attribute table. + output -- Output HTML file (default name will be based on input file if unspecified). + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--field='{}'".format(field)) + args.append("--output='{}'".format(output)) + return self.run_tool('attribute_histogram', args, callback) # returns 1 if error + + def attribute_scattergram(self, i, fieldx, fieldy, output, trendline=False, callback=None): + """Creates a scattergram for two field values of a vector's attribute table. + + Keyword arguments: + + i -- Input raster file. + fieldx -- Input field name in attribute table for the x-axis. + fieldy -- Input field name in attribute table for the y-axis. + output -- Output HTML file (default name will be based on input file if unspecified). + trendline -- Draw the trendline. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--fieldx='{}'".format(fieldx)) + args.append("--fieldy='{}'".format(fieldy)) + args.append("--output='{}'".format(output)) + if trendline: args.append("--trendline") + return self.run_tool('attribute_scattergram', args, callback) # returns 1 if error + + def ceil(self, i, output, callback=None): + """Returns the smallest (closest to negative infinity) value that is greater than or equal to the values in a raster. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('ceil', args, callback) # returns 1 if error + + def cos(self, i, output, callback=None): + """Returns the cosine (cos) of each values in a raster. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('cos', args, callback) # returns 1 if error + + def cosh(self, i, output, callback=None): + """Returns the hyperbolic cosine (cosh) of each values in a raster. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('cosh', args, callback) # returns 1 if error + + def crispness_index(self, i, output=None, callback=None): + """Calculates the Crispness Index, which is used to quantify how crisp (or conversely how fuzzy) a probability image is. + + Keyword arguments: + + i -- Input raster file. + output -- Optional output html file (default name will be based on input file if unspecified). + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + if output is not None: args.append("--output='{}'".format(output)) + return self.run_tool('crispness_index', args, callback) # returns 1 if error + + def cross_tabulation(self, input1, input2, output, callback=None): + """Performs a cross-tabulation on two categorical images. + + Keyword arguments: + + input1 -- Input raster file 1. + input2 -- Input raster file 1. + output -- Output HTML file (default name will be based on input file if unspecified). + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input1='{}'".format(input1)) + args.append("--input2='{}'".format(input2)) + args.append("--output='{}'".format(output)) + return self.run_tool('cross_tabulation', args, callback) # returns 1 if error + + def cumulative_distribution(self, i, output, callback=None): + """Converts a raster image to its cumulative distribution function. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('cumulative_distribution', args, callback) # returns 1 if error + + def decrement(self, i, output, callback=None): + """Decreases the values of each grid cell in an input raster by 1.0 (see also InPlaceSubtract). + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('decrement', args, callback) # returns 1 if error + + def divide(self, input1, input2, output, callback=None): + """Performs a division operation on two rasters or a raster and a constant value. + + Keyword arguments: + + input1 -- Input raster file or constant value. + input2 -- Input raster file or constant value. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input1='{}'".format(input1)) + args.append("--input2='{}'".format(input2)) + args.append("--output='{}'".format(output)) + return self.run_tool('divide', args, callback) # returns 1 if error + + def equal_to(self, input1, input2, output, callback=None): + """Performs a equal-to comparison operation on two rasters or a raster and a constant value. + + Keyword arguments: + + input1 -- Input raster file or constant value. + input2 -- Input raster file or constant value. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input1='{}'".format(input1)) + args.append("--input2='{}'".format(input2)) + args.append("--output='{}'".format(output)) + return self.run_tool('equal_to', args, callback) # returns 1 if error + + def exp(self, i, output, callback=None): + """Returns the exponential (base e) of values in a raster. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('exp', args, callback) # returns 1 if error + + def exp2(self, i, output, callback=None): + """Returns the exponential (base 2) of values in a raster. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('exp2', args, callback) # returns 1 if error + + def floor(self, i, output, callback=None): + """Returns the largest (closest to positive infinity) value that is less than or equal to the values in a raster. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('floor', args, callback) # returns 1 if error + + def greater_than(self, input1, input2, output, incl_equals=False, callback=None): + """Performs a greater-than comparison operation on two rasters or a raster and a constant value. + + Keyword arguments: + + input1 -- Input raster file or constant value. + input2 -- Input raster file or constant value. + output -- Output raster file. + incl_equals -- Perform a greater-than-or-equal-to operation. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input1='{}'".format(input1)) + args.append("--input2='{}'".format(input2)) + args.append("--output='{}'".format(output)) + if incl_equals: args.append("--incl_equals") + return self.run_tool('greater_than', args, callback) # returns 1 if error + + def image_autocorrelation(self, inputs, output, contiguity="Rook", callback=None): + """Performs Moran's I analysis on two or more input images. + + Keyword arguments: + + inputs -- Input raster files. + contiguity -- Contiguity type. + output -- Output HTML file (default name will be based on input file if unspecified). + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--inputs='{}'".format(inputs)) + args.append("--contiguity={}".format(contiguity)) + args.append("--output='{}'".format(output)) + return self.run_tool('image_autocorrelation', args, callback) # returns 1 if error + + def image_correlation(self, inputs, output=None, callback=None): + """Performs image correlation on two or more input images. + + Keyword arguments: + + inputs -- Input raster files. + output -- Output HTML file (default name will be based on input file if unspecified). + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--inputs='{}'".format(inputs)) + if output is not None: args.append("--output='{}'".format(output)) + return self.run_tool('image_correlation', args, callback) # returns 1 if error + + def image_correlation_neighbourhood_analysis(self, input1, input2, output1, output2, filter=11, stat="pearson", callback=None): + """Performs image correlation on two input images neighbourhood search windows. + + Keyword arguments: + + input1 -- Input raster file. + input2 -- Input raster file. + output1 -- Output correlation (r-value or rho) raster file. + output2 -- Output significance (p-value) raster file. + filter -- Size of the filter kernel. + stat -- Correlation type; one of 'pearson' (default) and 'spearman'. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input1='{}'".format(input1)) + args.append("--input2='{}'".format(input2)) + args.append("--output1='{}'".format(output1)) + args.append("--output2='{}'".format(output2)) + args.append("--filter={}".format(filter)) + args.append("--stat={}".format(stat)) + return self.run_tool('image_correlation_neighbourhood_analysis', args, callback) # returns 1 if error + + def image_regression(self, input1, input2, output, out_residuals=None, standardize=False, scattergram=False, num_samples=1000, callback=None): + """Performs image regression analysis on two input images. + + Keyword arguments: + + input1 -- Input raster file (independent variable, X). + input2 -- Input raster file (dependent variable, Y). + output -- Output HTML file for regression summary report. + out_residuals -- Output raster regression resdidual file. + standardize -- Optional flag indicating whether to standardize the residuals map. + scattergram -- Optional flag indicating whether to output a scattergram. + num_samples -- Number of samples used to create scattergram. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input1='{}'".format(input1)) + args.append("--input2='{}'".format(input2)) + args.append("--output='{}'".format(output)) + if out_residuals is not None: args.append("--out_residuals='{}'".format(out_residuals)) + if standardize: args.append("--standardize") + if scattergram: args.append("--scattergram") + args.append("--num_samples={}".format(num_samples)) + return self.run_tool('image_regression', args, callback) # returns 1 if error + + def in_place_add(self, input1, input2, callback=None): + """Performs an in-place addition operation (input1 += input2). + + Keyword arguments: + + input1 -- Input raster file. + input2 -- Input raster file or constant value. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input1='{}'".format(input1)) + args.append("--input2='{}'".format(input2)) + return self.run_tool('in_place_add', args, callback) # returns 1 if error + + def in_place_divide(self, input1, input2, callback=None): + """Performs an in-place division operation (input1 /= input2). + + Keyword arguments: + + input1 -- Input raster file. + input2 -- Input raster file or constant value. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input1='{}'".format(input1)) + args.append("--input2='{}'".format(input2)) + return self.run_tool('in_place_divide', args, callback) # returns 1 if error + + def in_place_multiply(self, input1, input2, callback=None): + """Performs an in-place multiplication operation (input1 *= input2). + + Keyword arguments: + + input1 -- Input raster file. + input2 -- Input raster file or constant value. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input1='{}'".format(input1)) + args.append("--input2='{}'".format(input2)) + return self.run_tool('in_place_multiply', args, callback) # returns 1 if error + + def in_place_subtract(self, input1, input2, callback=None): + """Performs an in-place subtraction operation (input1 -= input2). + + Keyword arguments: + + input1 -- Input raster file. + input2 -- Input raster file or constant value. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input1='{}'".format(input1)) + args.append("--input2='{}'".format(input2)) + return self.run_tool('in_place_subtract', args, callback) # returns 1 if error + + def increment(self, i, output, callback=None): + """Increases the values of each grid cell in an input raster by 1.0. (see also InPlaceAdd). + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('increment', args, callback) # returns 1 if error + + def integer_division(self, input1, input2, output, callback=None): + """Performs an integer division operation on two rasters or a raster and a constant value. + + Keyword arguments: + + input1 -- Input raster file or constant value. + input2 -- Input raster file or constant value. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input1='{}'".format(input1)) + args.append("--input2='{}'".format(input2)) + args.append("--output='{}'".format(output)) + return self.run_tool('integer_division', args, callback) # returns 1 if error + + def is_no_data(self, i, output, callback=None): + """Identifies NoData valued pixels in an image. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('is_no_data', args, callback) # returns 1 if error + + def kappa_index(self, input1, input2, output, callback=None): + """Performs a kappa index of agreement (KIA) analysis on two categorical raster files. + + Keyword arguments: + + input1 -- Input classification raster file. + input2 -- Input reference raster file. + output -- Output HTML file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input1='{}'".format(input1)) + args.append("--input2='{}'".format(input2)) + args.append("--output='{}'".format(output)) + return self.run_tool('kappa_index', args, callback) # returns 1 if error + + def ks_test_for_normality(self, i, output, num_samples=None, callback=None): + """Evaluates whether the values in a raster are normally distributed. + + Keyword arguments: + + i -- Input raster file. + output -- Output HTML file. + num_samples -- Number of samples. Leave blank to use whole image. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + if num_samples is not None: args.append("--num_samples='{}'".format(num_samples)) + return self.run_tool('ks_test_for_normality', args, callback) # returns 1 if error + + def less_than(self, input1, input2, output, incl_equals=False, callback=None): + """Performs a less-than comparison operation on two rasters or a raster and a constant value. + + Keyword arguments: + + input1 -- Input raster file or constant value. + input2 -- Input raster file or constant value. + output -- Output raster file. + incl_equals -- Perform a less-than-or-equal-to operation. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input1='{}'".format(input1)) + args.append("--input2='{}'".format(input2)) + args.append("--output='{}'".format(output)) + if incl_equals: args.append("--incl_equals") + return self.run_tool('less_than', args, callback) # returns 1 if error + + def list_unique_values(self, i, field, output, callback=None): + """Lists the unique values contained in a field witin a vector's attribute table. + + Keyword arguments: + + i -- Input raster file. + field -- Input field name in attribute table. + output -- Output HTML file (default name will be based on input file if unspecified). + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--field='{}'".format(field)) + args.append("--output='{}'".format(output)) + return self.run_tool('list_unique_values', args, callback) # returns 1 if error + + def ln(self, i, output, callback=None): + """Returns the natural logarithm of values in a raster. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('ln', args, callback) # returns 1 if error + + def log10(self, i, output, callback=None): + """Returns the base-10 logarithm of values in a raster. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('log10', args, callback) # returns 1 if error + + def log2(self, i, output, callback=None): + """Returns the base-2 logarithm of values in a raster. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('log2', args, callback) # returns 1 if error + + def max(self, input1, input2, output, callback=None): + """Performs a MAX operation on two rasters or a raster and a constant value. + + Keyword arguments: + + input1 -- Input raster file or constant value. + input2 -- Input raster file or constant value. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input1='{}'".format(input1)) + args.append("--input2='{}'".format(input2)) + args.append("--output='{}'".format(output)) + return self.run_tool('max', args, callback) # returns 1 if error + + def min(self, input1, input2, output, callback=None): + """Performs a MIN operation on two rasters or a raster and a constant value. + + Keyword arguments: + + input1 -- Input raster file or constant value. + input2 -- Input raster file or constant value. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input1='{}'".format(input1)) + args.append("--input2='{}'".format(input2)) + args.append("--output='{}'".format(output)) + return self.run_tool('min', args, callback) # returns 1 if error + + def modulo(self, input1, input2, output, callback=None): + """Performs a modulo operation on two rasters or a raster and a constant value. + + Keyword arguments: + + input1 -- Input raster file or constant value. + input2 -- Input raster file or constant value. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input1='{}'".format(input1)) + args.append("--input2='{}'".format(input2)) + args.append("--output='{}'".format(output)) + return self.run_tool('modulo', args, callback) # returns 1 if error + + def multiply(self, input1, input2, output, callback=None): + """Performs a multiplication operation on two rasters or a raster and a constant value. + + Keyword arguments: + + input1 -- Input raster file or constant value. + input2 -- Input raster file or constant value. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input1='{}'".format(input1)) + args.append("--input2='{}'".format(input2)) + args.append("--output='{}'".format(output)) + return self.run_tool('multiply', args, callback) # returns 1 if error + + def negate(self, i, output, callback=None): + """Changes the sign of values in a raster or the 0-1 values of a Boolean raster. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('negate', args, callback) # returns 1 if error + + def not_equal_to(self, input1, input2, output, callback=None): + """Performs a not-equal-to comparison operation on two rasters or a raster and a constant value. + + Keyword arguments: + + input1 -- Input raster file or constant value. + input2 -- Input raster file or constant value. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input1='{}'".format(input1)) + args.append("--input2='{}'".format(input2)) + args.append("--output='{}'".format(output)) + return self.run_tool('not_equal_to', args, callback) # returns 1 if error + + def paired_sample_t_test(self, input1, input2, output, num_samples=None, callback=None): + """Performs a 2-sample K-S test for significant differences on two input rasters. + + Keyword arguments: + + input1 -- First input raster file. + input2 -- Second input raster file. + output -- Output HTML file. + num_samples -- Number of samples. Leave blank to use whole image. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input1='{}'".format(input1)) + args.append("--input2='{}'".format(input2)) + args.append("--output='{}'".format(output)) + if num_samples is not None: args.append("--num_samples='{}'".format(num_samples)) + return self.run_tool('paired_sample_t_test', args, callback) # returns 1 if error + + def power(self, input1, input2, output, callback=None): + """Raises the values in grid cells of one rasters, or a constant value, by values in another raster or constant value. + + Keyword arguments: + + input1 -- Input raster file or constant value. + input2 -- Input raster file or constant value. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input1='{}'".format(input1)) + args.append("--input2='{}'".format(input2)) + args.append("--output='{}'".format(output)) + return self.run_tool('power', args, callback) # returns 1 if error + + def principal_component_analysis(self, inputs, output, num_comp=None, standardized=False, callback=None): + """Performs a principal component analysis (PCA) on a multi-spectral dataset. + + Keyword arguments: + + inputs -- Input raster files. + output -- Output HTML report file. + num_comp -- Number of component images to output; <= to num. input images. + standardized -- Perform standardized PCA?. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--inputs='{}'".format(inputs)) + args.append("--output='{}'".format(output)) + if num_comp is not None: args.append("--num_comp='{}'".format(num_comp)) + if standardized: args.append("--standardized") + return self.run_tool('principal_component_analysis', args, callback) # returns 1 if error + + def quantiles(self, i, output, num_quantiles=5, callback=None): + """Transforms raster values into quantiles. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + num_quantiles -- Number of quantiles. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--num_quantiles={}".format(num_quantiles)) + return self.run_tool('quantiles', args, callback) # returns 1 if error + + def random_field(self, base, output, callback=None): + """Creates an image containing random values. + + Keyword arguments: + + base -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--base='{}'".format(base)) + args.append("--output='{}'".format(output)) + return self.run_tool('random_field', args, callback) # returns 1 if error + + def random_sample(self, base, output, num_samples=1000, callback=None): + """Creates an image containing randomly located sample grid cells with unique IDs. + + Keyword arguments: + + base -- Input raster file. + output -- Output raster file. + num_samples -- Number of samples. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--base='{}'".format(base)) + args.append("--output='{}'".format(output)) + args.append("--num_samples={}".format(num_samples)) + return self.run_tool('random_sample', args, callback) # returns 1 if error + + def raster_histogram(self, i, output, callback=None): + """Creates a histogram from raster values. + + Keyword arguments: + + i -- Input raster file. + output -- Output HTML file (default name will be based on input file if unspecified). + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('raster_histogram', args, callback) # returns 1 if error + + def raster_summary_stats(self, i, callback=None): + """Measures a rasters min, max, average, standard deviation, num. non-nodata cells, and total. + + Keyword arguments: + + i -- Input raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + return self.run_tool('raster_summary_stats', args, callback) # returns 1 if error + + def reciprocal(self, i, output, callback=None): + """Returns the reciprocal (i.e. 1 / z) of values in a raster. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('reciprocal', args, callback) # returns 1 if error + + def rescale_value_range(self, i, output, out_min_val, out_max_val, clip_min=None, clip_max=None, callback=None): + """Performs a min-max contrast stretch on an input greytone image. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + out_min_val -- New minimum value in output image. + out_max_val -- New maximum value in output image. + clip_min -- Optional lower tail clip value. + clip_max -- Optional upper tail clip value. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--out_min_val='{}'".format(out_min_val)) + args.append("--out_max_val='{}'".format(out_max_val)) + if clip_min is not None: args.append("--clip_min='{}'".format(clip_min)) + if clip_max is not None: args.append("--clip_max='{}'".format(clip_max)) + return self.run_tool('rescale_value_range', args, callback) # returns 1 if error + + def root_mean_square_error(self, i, base, callback=None): + """Calculates the RMSE and other accuracy statistics. + + Keyword arguments: + + i -- Input raster file. + base -- Input base raster file used for comparison. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--base='{}'".format(base)) + return self.run_tool('root_mean_square_error', args, callback) # returns 1 if error + + def round(self, i, output, callback=None): + """Rounds the values in an input raster to the nearest integer value. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('round', args, callback) # returns 1 if error + + def sin(self, i, output, callback=None): + """Returns the sine (sin) of each values in a raster. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('sin', args, callback) # returns 1 if error + + def sinh(self, i, output, callback=None): + """Returns the hyperbolic sine (sinh) of each values in a raster. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('sinh', args, callback) # returns 1 if error + + def square(self, i, output, callback=None): + """Squares the values in a raster. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('square', args, callback) # returns 1 if error + + def square_root(self, i, output, callback=None): + """Returns the square root of the values in a raster. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('square_root', args, callback) # returns 1 if error + + def subtract(self, input1, input2, output, callback=None): + """Performs a differencing operation on two rasters or a raster and a constant value. + + Keyword arguments: + + input1 -- Input raster file or constant value. + input2 -- Input raster file or constant value. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input1='{}'".format(input1)) + args.append("--input2='{}'".format(input2)) + args.append("--output='{}'".format(output)) + return self.run_tool('subtract', args, callback) # returns 1 if error + + def tan(self, i, output, callback=None): + """Returns the tangent (tan) of each values in a raster. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('tan', args, callback) # returns 1 if error + + def tanh(self, i, output, callback=None): + """Returns the hyperbolic tangent (tanh) of each values in a raster. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('tanh', args, callback) # returns 1 if error + + def to_degrees(self, i, output, callback=None): + """Converts a raster from radians to degrees. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('to_degrees', args, callback) # returns 1 if error + + def to_radians(self, i, output, callback=None): + """Converts a raster from degrees to radians. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('to_radians', args, callback) # returns 1 if error + + def trend_surface(self, i, output, order=1, callback=None): + """Estimates the trend surface of an input raster file. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + order -- Polynomial order (1 to 10). + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + args.append("--order={}".format(order)) + return self.run_tool('trend_surface', args, callback) # returns 1 if error + + def trend_surface_vector_points(self, i, field, output, cell_size, order=1, callback=None): + """Estimates a trend surface from vector points. + + Keyword arguments: + + i -- Input vector Points file. + field -- Input field name in attribute table. + output -- Output raster file. + order -- Polynomial order (1 to 10). + cell_size -- Optionally specified cell size of output raster. Not used when base raster is specified. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--field='{}'".format(field)) + args.append("--output='{}'".format(output)) + args.append("--order={}".format(order)) + args.append("--cell_size='{}'".format(cell_size)) + return self.run_tool('trend_surface_vector_points', args, callback) # returns 1 if error + + def truncate(self, i, output, num_decimals=None, callback=None): + """Truncates the values in a raster to the desired number of decimal places. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + num_decimals -- Number of decimals left after truncation (default is zero). + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + if num_decimals is not None: args.append("--num_decimals='{}'".format(num_decimals)) + return self.run_tool('truncate', args, callback) # returns 1 if error + + def turning_bands_simulation(self, base, output, range, iterations=1000, callback=None): + """Creates an image containing random values based on a turning-bands simulation. + + Keyword arguments: + + base -- Input base raster file. + output -- Output file. + range -- The field's range, in xy-units, related to the extent of spatial autocorrelation. + iterations -- The number of iterations. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--base='{}'".format(base)) + args.append("--output='{}'".format(output)) + args.append("--range='{}'".format(range)) + args.append("--iterations={}".format(iterations)) + return self.run_tool('turning_bands_simulation', args, callback) # returns 1 if error + + def two_sample_ks_test(self, input1, input2, output, num_samples=None, callback=None): + """Performs a 2-sample K-S test for significant differences on two input rasters. + + Keyword arguments: + + input1 -- First input raster file. + input2 -- Second input raster file. + output -- Output HTML file. + num_samples -- Number of samples. Leave blank to use whole image. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input1='{}'".format(input1)) + args.append("--input2='{}'".format(input2)) + args.append("--output='{}'".format(output)) + if num_samples is not None: args.append("--num_samples='{}'".format(num_samples)) + return self.run_tool('two_sample_ks_test', args, callback) # returns 1 if error + + def wilcoxon_signed_rank_test(self, input1, input2, output, num_samples=None, callback=None): + """Performs a 2-sample K-S test for significant differences on two input rasters. + + Keyword arguments: + + input1 -- First input raster file. + input2 -- Second input raster file. + output -- Output HTML file. + num_samples -- Number of samples. Leave blank to use whole image. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input1='{}'".format(input1)) + args.append("--input2='{}'".format(input2)) + args.append("--output='{}'".format(output)) + if num_samples is not None: args.append("--num_samples='{}'".format(num_samples)) + return self.run_tool('wilcoxon_signed_rank_test', args, callback) # returns 1 if error + + def xor(self, input1, input2, output, callback=None): + """Performs a logical XOR operator on two Boolean raster images. + + Keyword arguments: + + input1 -- Input raster file. + input2 -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input1='{}'".format(input1)) + args.append("--input2='{}'".format(input2)) + args.append("--output='{}'".format(output)) + return self.run_tool('xor', args, callback) # returns 1 if error + + def z_scores(self, i, output, callback=None): + """Standardizes the values in an input raster by converting to z-scores. + + Keyword arguments: + + i -- Input raster file. + output -- Output raster file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--output='{}'".format(output)) + return self.run_tool('z_scores', args, callback) # returns 1 if error + + def zonal_statistics(self, i, features, output=None, stat="mean", out_table=None, callback=None): + """Extracts descriptive statistics for a group of patches in a raster. + + Keyword arguments: + + i -- Input data raster file. + features -- Input feature definition raster file. + output -- Output raster file. + stat -- Statistic to extract, including 'mean', 'median', 'minimum', 'maximum', 'range', 'standard deviation', and 'total'. + out_table -- Output HTML Table file. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--input='{}'".format(i)) + args.append("--features='{}'".format(features)) + if output is not None: args.append("--output='{}'".format(output)) + args.append("--stat={}".format(stat)) + if out_table is not None: args.append("--out_table='{}'".format(out_table)) + return self.run_tool('zonal_statistics', args, callback) # returns 1 if error + + ########################### + # Stream Network Analysis # + ########################### + + def distance_to_outlet(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None): + """Calculates the distance of stream grid cells to the channel network outlet cell. + + Keyword arguments: + + d8_pntr -- Input raster D8 pointer file. + streams -- Input raster streams file. + output -- Output raster file. + esri_pntr -- D8 pointer uses the ESRI style scheme. + zero_background -- Flag indicating whether a background value of zero should be used. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--d8_pntr='{}'".format(d8_pntr)) + args.append("--streams='{}'".format(streams)) + args.append("--output='{}'".format(output)) + if esri_pntr: args.append("--esri_pntr") + if zero_background: args.append("--zero_background") + return self.run_tool('distance_to_outlet', args, callback) # returns 1 if error + + def extract_streams(self, flow_accum, output, threshold, zero_background=False, callback=None): + """Extracts stream grid cells from a flow accumulation raster. + + Keyword arguments: + + flow_accum -- Input raster D8 flow accumulation file. + output -- Output raster file. + threshold -- Threshold in flow accumulation values for channelization. + zero_background -- Flag indicating whether a background value of zero should be used. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--flow_accum='{}'".format(flow_accum)) + args.append("--output='{}'".format(output)) + args.append("--threshold='{}'".format(threshold)) + if zero_background: args.append("--zero_background") + return self.run_tool('extract_streams', args, callback) # returns 1 if error + + def extract_valleys(self, dem, output, variant="LQ", line_thin=True, filter=5, callback=None): + """Identifies potential valley bottom grid cells based on local topolography alone. + + Keyword arguments: + + dem -- Input raster DEM file. + output -- Output raster file. + variant -- Options include 'LQ' (lower quartile), 'JandR' (Johnston and Rosenfeld), and 'PandD' (Peucker and Douglas); default is 'LQ'. + line_thin -- Optional flag indicating whether post-processing line-thinning should be performed. + filter -- Optional argument (only used when variant='lq') providing the filter size, in grid cells, used for lq-filtering (default is 5). + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + args.append("--variant={}".format(variant)) + if line_thin: args.append("--line_thin") + args.append("--filter={}".format(filter)) + return self.run_tool('extract_valleys', args, callback) # returns 1 if error + + def farthest_channel_head(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None): + """Calculates the distance to the furthest upstream channel head for each stream cell. + + Keyword arguments: + + d8_pntr -- Input raster D8 pointer file. + streams -- Input raster streams file. + output -- Output raster file. + esri_pntr -- D8 pointer uses the ESRI style scheme. + zero_background -- Flag indicating whether a background value of zero should be used. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--d8_pntr='{}'".format(d8_pntr)) + args.append("--streams='{}'".format(streams)) + args.append("--output='{}'".format(output)) + if esri_pntr: args.append("--esri_pntr") + if zero_background: args.append("--zero_background") + return self.run_tool('farthest_channel_head', args, callback) # returns 1 if error + + def find_main_stem(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None): + """Finds the main stem, based on stream lengths, of each stream network. + + Keyword arguments: + + d8_pntr -- Input raster D8 pointer file. + streams -- Input raster streams file. + output -- Output raster file. + esri_pntr -- D8 pointer uses the ESRI style scheme. + zero_background -- Flag indicating whether a background value of zero should be used. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--d8_pntr='{}'".format(d8_pntr)) + args.append("--streams='{}'".format(streams)) + args.append("--output='{}'".format(output)) + if esri_pntr: args.append("--esri_pntr") + if zero_background: args.append("--zero_background") + return self.run_tool('find_main_stem', args, callback) # returns 1 if error + + def hack_stream_order(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None): + """Assigns the Hack stream order to each tributary in a stream network. + + Keyword arguments: + + d8_pntr -- Input raster D8 pointer file. + streams -- Input raster streams file. + output -- Output raster file. + esri_pntr -- D8 pointer uses the ESRI style scheme. + zero_background -- Flag indicating whether a background value of zero should be used. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--d8_pntr='{}'".format(d8_pntr)) + args.append("--streams='{}'".format(streams)) + args.append("--output='{}'".format(output)) + if esri_pntr: args.append("--esri_pntr") + if zero_background: args.append("--zero_background") + return self.run_tool('hack_stream_order', args, callback) # returns 1 if error + + def horton_stream_order(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None): + """Assigns the Horton stream order to each tributary in a stream network. + + Keyword arguments: + + d8_pntr -- Input raster D8 pointer file. + streams -- Input raster streams file. + output -- Output raster file. + esri_pntr -- D8 pointer uses the ESRI style scheme. + zero_background -- Flag indicating whether a background value of zero should be used. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--d8_pntr='{}'".format(d8_pntr)) + args.append("--streams='{}'".format(streams)) + args.append("--output='{}'".format(output)) + if esri_pntr: args.append("--esri_pntr") + if zero_background: args.append("--zero_background") + return self.run_tool('horton_stream_order', args, callback) # returns 1 if error + + def length_of_upstream_channels(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None): + """Calculates the total length of channels upstream. + + Keyword arguments: + + d8_pntr -- Input raster D8 pointer file. + streams -- Input raster streams file. + output -- Output raster file. + esri_pntr -- D8 pointer uses the ESRI style scheme. + zero_background -- Flag indicating whether a background value of zero should be used. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--d8_pntr='{}'".format(d8_pntr)) + args.append("--streams='{}'".format(streams)) + args.append("--output='{}'".format(output)) + if esri_pntr: args.append("--esri_pntr") + if zero_background: args.append("--zero_background") + return self.run_tool('length_of_upstream_channels', args, callback) # returns 1 if error + + def long_profile(self, d8_pntr, streams, dem, output, esri_pntr=False, callback=None): + """Plots the stream longitudinal profiles for one or more rivers. + + Keyword arguments: + + d8_pntr -- Input raster D8 pointer file. + streams -- Input raster streams file. + dem -- Input raster DEM file. + output -- Output HTML file. + esri_pntr -- D8 pointer uses the ESRI style scheme. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--d8_pntr='{}'".format(d8_pntr)) + args.append("--streams='{}'".format(streams)) + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + if esri_pntr: args.append("--esri_pntr") + return self.run_tool('long_profile', args, callback) # returns 1 if error + + def long_profile_from_points(self, d8_pntr, points, dem, output, esri_pntr=False, callback=None): + """Plots the longitudinal profiles from flow-paths initiating from a set of vector points. + + Keyword arguments: + + d8_pntr -- Input raster D8 pointer file. + points -- Input vector points file. + dem -- Input raster DEM file. + output -- Output HTML file. + esri_pntr -- D8 pointer uses the ESRI style scheme. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--d8_pntr='{}'".format(d8_pntr)) + args.append("--points='{}'".format(points)) + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + if esri_pntr: args.append("--esri_pntr") + return self.run_tool('long_profile_from_points', args, callback) # returns 1 if error + + def raster_streams_to_vector(self, streams, d8_pntr, output, esri_pntr=False, callback=None): + """Converts a raster stream file into a vector file. + + Keyword arguments: + + streams -- Input raster streams file. + d8_pntr -- Input raster D8 pointer file. + output -- Output vector file. + esri_pntr -- D8 pointer uses the ESRI style scheme. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--streams='{}'".format(streams)) + args.append("--d8_pntr='{}'".format(d8_pntr)) + args.append("--output='{}'".format(output)) + if esri_pntr: args.append("--esri_pntr") + return self.run_tool('raster_streams_to_vector', args, callback) # returns 1 if error + + def rasterize_streams(self, streams, base, output, nodata=True, feature_id=False, callback=None): + """Rasterizes vector streams based on Lindsay (2016) method. + + Keyword arguments: + + streams -- Input vector streams file. + base -- Input base raster file. + output -- Output raster file. + nodata -- Use NoData value for background?. + feature_id -- Use feature number as output value?. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--streams='{}'".format(streams)) + args.append("--base='{}'".format(base)) + args.append("--output='{}'".format(output)) + if nodata: args.append("--nodata") + if feature_id: args.append("--feature_id") + return self.run_tool('rasterize_streams', args, callback) # returns 1 if error + + def remove_short_streams(self, d8_pntr, streams, output, min_length, esri_pntr=False, callback=None): + """Removes short first-order streams from a stream network. + + Keyword arguments: + + d8_pntr -- Input raster D8 pointer file. + streams -- Input raster streams file. + output -- Output raster file. + min_length -- Minimum tributary length (in map units) used for network prunning. + esri_pntr -- D8 pointer uses the ESRI style scheme. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--d8_pntr='{}'".format(d8_pntr)) + args.append("--streams='{}'".format(streams)) + args.append("--output='{}'".format(output)) + args.append("--min_length='{}'".format(min_length)) + if esri_pntr: args.append("--esri_pntr") + return self.run_tool('remove_short_streams', args, callback) # returns 1 if error + + def shreve_stream_magnitude(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None): + """Assigns the Shreve stream magnitude to each link in a stream network. + + Keyword arguments: + + d8_pntr -- Input raster D8 pointer file. + streams -- Input raster streams file. + output -- Output raster file. + esri_pntr -- D8 pointer uses the ESRI style scheme. + zero_background -- Flag indicating whether a background value of zero should be used. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--d8_pntr='{}'".format(d8_pntr)) + args.append("--streams='{}'".format(streams)) + args.append("--output='{}'".format(output)) + if esri_pntr: args.append("--esri_pntr") + if zero_background: args.append("--zero_background") + return self.run_tool('shreve_stream_magnitude', args, callback) # returns 1 if error + + def strahler_stream_order(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None): + """Assigns the Strahler stream order to each link in a stream network. + + Keyword arguments: + + d8_pntr -- Input raster D8 pointer file. + streams -- Input raster streams file. + output -- Output raster file. + esri_pntr -- D8 pointer uses the ESRI style scheme. + zero_background -- Flag indicating whether a background value of zero should be used. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--d8_pntr='{}'".format(d8_pntr)) + args.append("--streams='{}'".format(streams)) + args.append("--output='{}'".format(output)) + if esri_pntr: args.append("--esri_pntr") + if zero_background: args.append("--zero_background") + return self.run_tool('strahler_stream_order', args, callback) # returns 1 if error + + def stream_link_class(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None): + """Identifies the exterior/interior links and nodes in a stream network. + + Keyword arguments: + + d8_pntr -- Input raster D8 pointer file. + streams -- Input raster streams file. + output -- Output raster file. + esri_pntr -- D8 pointer uses the ESRI style scheme. + zero_background -- Flag indicating whether a background value of zero should be used. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--d8_pntr='{}'".format(d8_pntr)) + args.append("--streams='{}'".format(streams)) + args.append("--output='{}'".format(output)) + if esri_pntr: args.append("--esri_pntr") + if zero_background: args.append("--zero_background") + return self.run_tool('stream_link_class', args, callback) # returns 1 if error + + def stream_link_identifier(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None): + """Assigns a unique identifier to each link in a stream network. + + Keyword arguments: + + d8_pntr -- Input raster D8 pointer file. + streams -- Input raster streams file. + output -- Output raster file. + esri_pntr -- D8 pointer uses the ESRI style scheme. + zero_background -- Flag indicating whether a background value of zero should be used. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--d8_pntr='{}'".format(d8_pntr)) + args.append("--streams='{}'".format(streams)) + args.append("--output='{}'".format(output)) + if esri_pntr: args.append("--esri_pntr") + if zero_background: args.append("--zero_background") + return self.run_tool('stream_link_identifier', args, callback) # returns 1 if error + + def stream_link_length(self, d8_pntr, linkid, output, esri_pntr=False, zero_background=False, callback=None): + """Estimates the length of each link (or tributary) in a stream network. + + Keyword arguments: + + d8_pntr -- Input raster D8 pointer file. + linkid -- Input raster streams link ID (or tributary ID) file. + output -- Output raster file. + esri_pntr -- D8 pointer uses the ESRI style scheme. + zero_background -- Flag indicating whether a background value of zero should be used. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--d8_pntr='{}'".format(d8_pntr)) + args.append("--linkid='{}'".format(linkid)) + args.append("--output='{}'".format(output)) + if esri_pntr: args.append("--esri_pntr") + if zero_background: args.append("--zero_background") + return self.run_tool('stream_link_length', args, callback) # returns 1 if error + + def stream_link_slope(self, d8_pntr, linkid, dem, output, esri_pntr=False, zero_background=False, callback=None): + """Estimates the average slope of each link (or tributary) in a stream network. + + Keyword arguments: + + d8_pntr -- Input raster D8 pointer file. + linkid -- Input raster streams link ID (or tributary ID) file. + dem -- Input raster DEM file. + output -- Output raster file. + esri_pntr -- D8 pointer uses the ESRI style scheme. + zero_background -- Flag indicating whether a background value of zero should be used. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--d8_pntr='{}'".format(d8_pntr)) + args.append("--linkid='{}'".format(linkid)) + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + if esri_pntr: args.append("--esri_pntr") + if zero_background: args.append("--zero_background") + return self.run_tool('stream_link_slope', args, callback) # returns 1 if error + + def stream_slope_continuous(self, d8_pntr, streams, dem, output, esri_pntr=False, zero_background=False, callback=None): + """Estimates the slope of each grid cell in a stream network. + + Keyword arguments: + + d8_pntr -- Input raster D8 pointer file. + streams -- Input raster streams file. + dem -- Input raster DEM file. + output -- Output raster file. + esri_pntr -- D8 pointer uses the ESRI style scheme. + zero_background -- Flag indicating whether a background value of zero should be used. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--d8_pntr='{}'".format(d8_pntr)) + args.append("--streams='{}'".format(streams)) + args.append("--dem='{}'".format(dem)) + args.append("--output='{}'".format(output)) + if esri_pntr: args.append("--esri_pntr") + if zero_background: args.append("--zero_background") + return self.run_tool('stream_slope_continuous', args, callback) # returns 1 if error + + def topological_stream_order(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None): + """Assigns each link in a stream network its topological order. + + Keyword arguments: + + d8_pntr -- Input raster D8 pointer file. + streams -- Input raster streams file. + output -- Output raster file. + esri_pntr -- D8 pointer uses the ESRI style scheme. + zero_background -- Flag indicating whether a background value of zero should be used. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--d8_pntr='{}'".format(d8_pntr)) + args.append("--streams='{}'".format(streams)) + args.append("--output='{}'".format(output)) + if esri_pntr: args.append("--esri_pntr") + if zero_background: args.append("--zero_background") + return self.run_tool('topological_stream_order', args, callback) # returns 1 if error + + def tributary_identifier(self, d8_pntr, streams, output, esri_pntr=False, zero_background=False, callback=None): + """Assigns a unique identifier to each tributary in a stream network. + + Keyword arguments: + + d8_pntr -- Input raster D8 pointer file. + streams -- Input raster streams file. + output -- Output raster file. + esri_pntr -- D8 pointer uses the ESRI style scheme. + zero_background -- Flag indicating whether a background value of zero should be used. + callback -- Custom function for handling tool text outputs. + """ + args = [] + args.append("--d8_pntr='{}'".format(d8_pntr)) + args.append("--streams='{}'".format(streams)) + args.append("--output='{}'".format(output)) + if esri_pntr: args.append("--esri_pntr") + if zero_background: args.append("--zero_background") + return self.run_tool('tributary_identifier', args, callback) # returns 1 if error diff --git a/WhiteboxTools.pyt b/WhiteboxTools.pyt index a165241..3c9ddf0 100644 --- a/WhiteboxTools.pyt +++ b/WhiteboxTools.pyt @@ -174,6 +174,7 @@ tool_labels.append("Hole Proportion") tool_labels.append("Horizon Angle") tool_labels.append("Horton Stream Order") tool_labels.append("Hypsometric Analysis") +tool_labels.append("Hypsometrically Tinted Hillshade") tool_labels.append("Idw Interpolation") tool_labels.append("Ihs To Rgb") tool_labels.append("Image Autocorrelation") @@ -229,6 +230,7 @@ tool_labels.append("Lidar Ransac Planes") tool_labels.append("Lidar Rbf Interpolation") tool_labels.append("Lidar Remove Duplicates") tool_labels.append("Lidar Remove Outliers") +tool_labels.append("Lidar Rooftop Analysis") tool_labels.append("Lidar Segmentation") tool_labels.append("Lidar Segmentation Based Filter") tool_labels.append("Lidar Thin") @@ -286,6 +288,7 @@ tool_labels.append("Modulo") tool_labels.append("Mosaic") tool_labels.append("Mosaic With Feathering") tool_labels.append("Multi Part To Single Part") +tool_labels.append("Multidirectional Hillshade") tool_labels.append("Multiply") tool_labels.append("Multiscale Elevation Percentile") tool_labels.append("Multiscale Roughness") @@ -603,6 +606,7 @@ class Toolbox(object): tools.append(Hillshade) tools.append(HorizonAngle) tools.append(HypsometricAnalysis) + tools.append(HypsometricallyTintedHillshade) tools.append(MaxAnisotropyDev) tools.append(MaxAnisotropyDevSignature) tools.append(MaxBranchLength) @@ -611,6 +615,7 @@ class Toolbox(object): tools.append(MaxElevDevSignature) tools.append(MaxElevationDeviation) tools.append(MinDownslopeElevChange) + tools.append(MultidirectionalHillshade) tools.append(MultiscaleElevationPercentile) tools.append(MultiscaleRoughness) tools.append(MultiscaleRoughnessSignature) @@ -792,6 +797,7 @@ class Toolbox(object): tools.append(LidarRbfInterpolation) tools.append(LidarRemoveDuplicates) tools.append(LidarRemoveOutliers) + tools.append(LidarRooftopAnalysis) tools.append(LidarSegmentation) tools.append(LidarSegmentationBasedFilter) tools.append(LidarThin) @@ -10745,6 +10751,145 @@ class HypsometricAnalysis(object): return +class HypsometricallyTintedHillshade(object): + def __init__(self): + self.label = "Hypsometrically Tinted Hillshade" + self.description = "Creates an colour shaded relief image from an input DEM. View detailed help documentation on WhiteboxTools User Manual and source code on GitHub." + self.category = "Geomorphometric Analysis" + + def getParameterInfo(self): + dem = arcpy.Parameter( + displayName="Input DEM File", + name="dem", + datatype="GPRasterLayer", + parameterType="Required", + direction="Input") + + output = arcpy.Parameter( + displayName="Output File", + name="output", + datatype="DEFile", + parameterType="Required", + direction="Output") + output.filter.list = ["tif"] + + altitude = arcpy.Parameter( + displayName="Illumination Source Altitude (degrees)", + name="altitude", + datatype="GPDouble", + parameterType="Optional", + direction="Input") + + altitude.value = "45.0" + + hs_weight = arcpy.Parameter( + displayName="Hillshade Weight", + name="hs_weight", + datatype="GPDouble", + parameterType="Optional", + direction="Input") + + hs_weight.value = "0.5" + + brightness = arcpy.Parameter( + displayName="Brightness", + name="brightness", + datatype="GPDouble", + parameterType="Optional", + direction="Input") + + brightness.value = "0.5" + + atmospheric = arcpy.Parameter( + displayName="Atmospheric Effects", + name="atmospheric", + datatype="GPDouble", + parameterType="Optional", + direction="Input") + + atmospheric.value = "0.0" + + palette = arcpy.Parameter( + displayName="Palette", + name="palette", + datatype="GPString", + parameterType="Optional", + direction="Input") + palette.filter.type = "ValueList" + palette.filter.list = ['atlas', 'high_relief', 'arid', 'soft', 'muted', 'purple', 'viridi', 'gn_yl', 'pi_y_g', 'bl_yl_rd', 'deep'] + + palette.value = "atlas" + + reverse = arcpy.Parameter( + displayName="Reverse palette?", + name="reverse", + datatype="GPBoolean", + parameterType="Optional", + direction="Input") + + reverse.value = False + + zfactor = arcpy.Parameter( + displayName="Z Conversion Factor", + name="zfactor", + datatype="GPDouble", + parameterType="Optional", + direction="Input") + + zfactor.value = "1.0" + + full_mode = arcpy.Parameter( + displayName="Full 360-degree hillshade mode?", + name="full_mode", + datatype="GPBoolean", + parameterType="Optional", + direction="Input") + + full_mode.value = False + + params = [dem, output, altitude, hs_weight, brightness, atmospheric, palette, reverse, zfactor, full_mode] + + return params + + def updateParameters(self, parameters): + return + + def updateMessages(self, parameters): + for param in parameters: + param_str = param.valueAsText + if param_str is not None: + try: + desc = arcpy.Describe(param_str) + if (".gdb\\" in desc.catalogPath) or (".mdb\\" in desc.catalogPath): + param.setErrorMessage("Datasets stored in a Geodatabase are not supported.") + except: + param.clearMessage() + return + + def execute(self, parameters, messages): + dem = parameters[0].valueAsText + if dem is not None: + desc = arcpy.Describe(dem) + dem = desc.catalogPath + output = parameters[1].valueAsText + altitude = parameters[2].valueAsText + hs_weight = parameters[3].valueAsText + brightness = parameters[4].valueAsText + atmospheric = parameters[5].valueAsText + palette = parameters[6].valueAsText + reverse = parameters[7].valueAsText + zfactor = parameters[8].valueAsText + full_mode = parameters[9].valueAsText + old_stdout = sys.stdout + result = StringIO() + sys.stdout = result + wbt.hypsometrically_tinted_hillshade(dem=dem, output=output, altitude=altitude, hs_weight=hs_weight, brightness=brightness, atmospheric=atmospheric, palette=palette, reverse=reverse, zfactor=zfactor, full_mode=full_mode) + sys.stdout = old_stdout + result_string = result.getvalue() + messages.addMessage(result_string) + return + + class MaxAnisotropyDev(object): def __init__(self): self.label = "Max Anisotropy Dev" @@ -11394,6 +11539,93 @@ class MinDownslopeElevChange(object): return +class MultidirectionalHillshade(object): + def __init__(self): + self.label = "Multidirectional Hillshade" + self.description = "Calculates a multi-direction hillshade raster from an input DEM. View detailed help documentation on WhiteboxTools User Manual and source code on GitHub." + self.category = "Geomorphometric Analysis" + + def getParameterInfo(self): + dem = arcpy.Parameter( + displayName="Input DEM File", + name="dem", + datatype="GPRasterLayer", + parameterType="Required", + direction="Input") + + output = arcpy.Parameter( + displayName="Output File", + name="output", + datatype="DEFile", + parameterType="Required", + direction="Output") + output.filter.list = ["tif"] + + altitude = arcpy.Parameter( + displayName="Altitude (degrees)", + name="altitude", + datatype="GPDouble", + parameterType="Optional", + direction="Input") + + altitude.value = "45.0" + + zfactor = arcpy.Parameter( + displayName="Z Conversion Factor", + name="zfactor", + datatype="GPDouble", + parameterType="Optional", + direction="Input") + + zfactor.value = "1.0" + + full_mode = arcpy.Parameter( + displayName="Full 360-degree mode?", + name="full_mode", + datatype="GPBoolean", + parameterType="Optional", + direction="Input") + + full_mode.value = False + + params = [dem, output, altitude, zfactor, full_mode] + + return params + + def updateParameters(self, parameters): + return + + def updateMessages(self, parameters): + for param in parameters: + param_str = param.valueAsText + if param_str is not None: + try: + desc = arcpy.Describe(param_str) + if (".gdb\\" in desc.catalogPath) or (".mdb\\" in desc.catalogPath): + param.setErrorMessage("Datasets stored in a Geodatabase are not supported.") + except: + param.clearMessage() + return + + def execute(self, parameters, messages): + dem = parameters[0].valueAsText + if dem is not None: + desc = arcpy.Describe(dem) + dem = desc.catalogPath + output = parameters[1].valueAsText + altitude = parameters[2].valueAsText + zfactor = parameters[3].valueAsText + full_mode = parameters[4].valueAsText + old_stdout = sys.stdout + result = StringIO() + sys.stdout = result + wbt.multidirectional_hillshade(dem=dem, output=output, altitude=altitude, zfactor=zfactor, full_mode=full_mode) + sys.stdout = old_stdout + result_string = result.getvalue() + messages.addMessage(result_string) + return + + class MultiscaleElevationPercentile(object): def __init__(self): self.label = "Multiscale Elevation Percentile" @@ -25557,6 +25789,163 @@ class LidarRemoveOutliers(object): return +class LidarRooftopAnalysis(object): + def __init__(self): + self.label = "Lidar Rooftop Analysis" + self.description = "Identifies roof segments in a LiDAR point cloud. View detailed help documentation on WhiteboxTools User Manual and source code on GitHub." + self.category = "LiDAR Tools" + + def getParameterInfo(self): + i = arcpy.Parameter( + displayName="Input File", + name="i", + datatype="DEFile", + parameterType="Optional", + direction="Input") + i.filter.list = ["las", "zip"] + + buildings = arcpy.Parameter( + displayName="Input Building Footprint Polygon File", + name="buildings", + datatype="GPFeatureLayer", + parameterType="Required", + direction="Input") + buildings.filter.list = ["Polygon"] + + output = arcpy.Parameter( + displayName="Output Polygon File", + name="output", + datatype="DEShapefile", + parameterType="Required", + direction="Output") + output.filter.list = ["Polygon"] + + radius = arcpy.Parameter( + displayName="Search Radius", + name="radius", + datatype="GPDouble", + parameterType="Optional", + direction="Input") + + radius.value = "2.0" + + num_iter = arcpy.Parameter( + displayName="Number of Iterations", + name="num_iter", + datatype="GPLong", + parameterType="Optional", + direction="Input") + + num_iter.value = "50" + + num_samples = arcpy.Parameter( + displayName="Number of Sample Points", + name="num_samples", + datatype="GPLong", + parameterType="Optional", + direction="Input") + + num_samples.value = "10" + + threshold = arcpy.Parameter( + displayName="Inlier Threshold", + name="threshold", + datatype="GPDouble", + parameterType="Optional", + direction="Input") + + threshold.value = "0.15" + + model_size = arcpy.Parameter( + displayName="Acceptable Model Size", + name="model_size", + datatype="GPLong", + parameterType="Optional", + direction="Input") + + model_size.value = "15" + + max_slope = arcpy.Parameter( + displayName="Maximum Planar Slope", + name="max_slope", + datatype="GPDouble", + parameterType="Optional", + direction="Input") + + max_slope.value = "65.0" + + norm_diff = arcpy.Parameter( + displayName="Normal Difference Threshold", + name="norm_diff", + datatype="GPDouble", + parameterType="Optional", + direction="Input") + + norm_diff.value = "10.0" + + azimuth = arcpy.Parameter( + displayName="Azimuth (degrees)", + name="azimuth", + datatype="GPDouble", + parameterType="Optional", + direction="Input") + + azimuth.value = "180.0" + + altitude = arcpy.Parameter( + displayName="Altitude (degrees)", + name="altitude", + datatype="GPDouble", + parameterType="Optional", + direction="Input") + + altitude.value = "30.0" + + params = [i, buildings, output, radius, num_iter, num_samples, threshold, model_size, max_slope, norm_diff, azimuth, altitude] + + return params + + def updateParameters(self, parameters): + return + + def updateMessages(self, parameters): + for param in parameters: + param_str = param.valueAsText + if param_str is not None: + try: + desc = arcpy.Describe(param_str) + if (".gdb\\" in desc.catalogPath) or (".mdb\\" in desc.catalogPath): + param.setErrorMessage("Datasets stored in a Geodatabase are not supported.") + except: + param.clearMessage() + return + + def execute(self, parameters, messages): + i = parameters[0].valueAsText + buildings = parameters[1].valueAsText + if buildings is not None: + desc = arcpy.Describe(buildings) + buildings = desc.catalogPath + output = parameters[2].valueAsText + radius = parameters[3].valueAsText + num_iter = parameters[4].valueAsText + num_samples = parameters[5].valueAsText + threshold = parameters[6].valueAsText + model_size = parameters[7].valueAsText + max_slope = parameters[8].valueAsText + norm_diff = parameters[9].valueAsText + azimuth = parameters[10].valueAsText + altitude = parameters[11].valueAsText + old_stdout = sys.stdout + result = StringIO() + sys.stdout = result + wbt.lidar_rooftop_analysis(i=i, buildings=buildings, output=output, radius=radius, num_iter=num_iter, num_samples=num_samples, threshold=threshold, model_size=model_size, max_slope=max_slope, norm_diff=norm_diff, azimuth=azimuth, altitude=altitude) + sys.stdout = old_stdout + result_string = result.getvalue() + messages.addMessage(result_string) + return + + class LidarSegmentation(object): def __init__(self): self.label = "Lidar Segmentation"