├── .gitignore ├── DESCRIPTION ├── DEVELOP.md ├── FAQ.md ├── LICENSE ├── NAMESPACE ├── R ├── .gitignore ├── CM.calculateCenterline.r ├── CM.generatePolygon.r ├── CM.ini.r ├── CM.par.r ├── CM.plotMetrics.r ├── CM.plotPlanView.r ├── CM.plotWidth.r ├── CM.processCenterline.r ├── CM.resampleCenterline.r ├── CM.run.r ├── CM.writeData.r ├── cmgo-package.r ├── demo.r ├── demo1.r ├── demo2.r └── demo3.r ├── README.md ├── data ├── demo.RData ├── demo1.RData ├── demo2.RData └── demo3.RData ├── man-roxygen ├── Examples.url ├── param_global_data_object.r ├── param_set.r ├── section_all_default_parameters.r ├── section_getting_started.r ├── section_global_data_object.r ├── section_input_data.r ├── section_parameters.r ├── section_run_cmgo.r ├── section_technical_fails.r ├── section_time_series.r └── section_work_flow.r └── man ├── CM.calculateCenterline.Rd ├── CM.generatePolygon.Rd ├── CM.ini.Rd ├── CM.par.Rd ├── CM.plotMetrics.Rd ├── CM.plotPlanView.Rd ├── CM.plotWidth.Rd ├── CM.processCenterline.Rd ├── CM.resampleCenterline.Rd ├── CM.run.Rd ├── CM.writeData.Rd ├── cmgo.Rd ├── demo.Rd ├── demo1.Rd ├── demo2.Rd ├── demo3.Rd └── figures ├── 01-processing.pdf ├── 01-processing.png ├── 02-gap.png ├── 03-sep-spacing.png ├── 04-transect-span.png ├── 06-processing.pdf ├── 06-processing.png ├── 07-filtering.pdf ├── 07-filtering.png ├── 08-processing.pdf ├── 08-processing.png ├── 09_original_and_smoothed.png ├── 10-documentation.png ├── 10_documentation.png ├── 10b_documentation.png ├── 11_documentation.png ├── basins.png ├── plotCheckPolygon.pdf └── plotCheckPolygon.png /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | .Ruserdata 5 | /.Rhistory 6 | /cmgo.Rproj 7 | *.Rbuildignore 8 | .idea -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: cmgo 2 | Type: Package 3 | Title: Derive principle Channel metrics from bank points 4 | Version: 0.2.0 5 | Author: Antonius Golly 6 | Maintainer: Antonius Golly 7 | Description: The package generates principle channel metrics (gradient, width, etc.) from channel bank points. The channel bank points can be GPS survey points or can be digitized banks from a GIS. Based on this channel geometry cmgo calculates the width at each location. It also allows to compare series of channel shapes. cmgo can write the files for further use in R or other scripting languages and offers to plotting functions to compare the results. 8 | License: GPL-3 9 | Encoding: UTF-8 10 | Imports: rgl, shapefiles, sp, spatstat.geom, stringr, zoo 11 | Depends: R (>= 4.0.0) 12 | LazyData: true 13 | RoxygenNote: 7.1.1 14 | -------------------------------------------------------------------------------- /DEVELOP.md: -------------------------------------------------------------------------------- 1 | ## Develop 2 | 3 | * checkout source code 4 | * `library(devtools)` 5 | * `library(roxygen2)` 6 | 7 | ## Compile documentation 8 | * change working directory to "cmgo" 9 | * run `devtools::document()` 10 | 11 | ## Install 12 | * change working directory to "cmgo" parent 13 | * run `devtools::check()` 14 | * run `install("cmgo")` 15 | 16 | ## Distribute 17 | * push changes to Github 18 | -------------------------------------------------------------------------------- /FAQ.md: -------------------------------------------------------------------------------- 1 | # FAQ 2 | 3 | ## Support 4 | 5 | If you experience problems with the package, please send an email to antonius.golly@gmail.com with following this checklist: 6 | * read the [publication](https://www.earth-surf-dynam.net/5/557/2017/esurf-5-557-2017.html) first, it will give you a lot of technical details 7 | * attach a list of input files (ASCII files with river bank points) 8 | * attach an R script with the relevant run commands you used 9 | * attach images showing the problem (optional) 10 | 11 | ## Common technical fails 12 | 13 | ### 1. Maximum iterations 14 | ``` 15 | ### exit due to maximum iterations (max. iterations = 20) ### 16 | Note: this may be caused by gaps that opened in the centerline due to 17 | jagged centerline paths. First, check for gaps visually with CM.plotPlanView(cmgo.obj, set="set1", error=1). 18 | You can than either repair these gaps by editing the centerline paths manually or 19 | simply increase the bank resolution via parameter par$bank.interpolation.max.dist! 20 | ``` 21 | 22 | There is two common issues with that. To find out, which applies use the suggested command from the error message and enter a _zoom.length_ to show the problem: 23 | 24 | `CM.plotPlanView(cmgo.obj, set="set1", error=1, zoom.length=20)` 25 | 26 | #### 1.1 Gaps occurred in the centerline 27 | drawing 28 | 29 | If your plot shows something similar to the left image decrease the value of the parameter `par$bank.interpolate.max.dist` and run the program again. 30 | 31 | #### 1.2 Segment cut-off not yet finished 32 | drawing 33 | 34 | In case you image shows open side arms of the centerline cmgo will handle that case if you increase the parameter `par$bank.filter2.max.it`. By default there is 20 iterations to remove those sidearms. Increase to a higher value (e.g. 50) and rerun the program. -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(CM.calculateCenterline) 4 | export(CM.generatePolygon) 5 | export(CM.ini) 6 | export(CM.par) 7 | export(CM.plotMetrics) 8 | export(CM.plotPlanView) 9 | export(CM.plotWidth) 10 | export(CM.processCenterline) 11 | export(CM.resampleCenterline) 12 | export(CM.run) 13 | export(CM.writeData) 14 | importFrom(grDevices,colors) 15 | importFrom(grDevices,dev.copy) 16 | importFrom(grDevices,dev.copy2pdf) 17 | importFrom(grDevices,dev.off) 18 | importFrom(grDevices,graphics.off) 19 | importFrom(grDevices,png) 20 | importFrom(graphics,abline) 21 | importFrom(graphics,legend) 22 | importFrom(graphics,lines) 23 | importFrom(graphics,plot) 24 | importFrom(graphics,points) 25 | importFrom(graphics,segments) 26 | importFrom(graphics,text) 27 | importFrom(rgl,abclines3d) 28 | importFrom(rgl,clear3d) 29 | importFrom(rgl,plot3d) 30 | importFrom(rgl,points3d) 31 | importFrom(rgl,segments3d) 32 | importFrom(shapefiles,convert.to.shapefile) 33 | importFrom(shapefiles,write.shapefile) 34 | importFrom(sp,point.in.polygon) 35 | importFrom(spatstat.geom,dirichlet) 36 | importFrom(spatstat.geom,nncross) 37 | importFrom(spatstat.geom,owin) 38 | importFrom(spatstat.geom,ppp) 39 | importFrom(spatstat.geom,psp) 40 | importFrom(stats,lm) 41 | importFrom(stats,median) 42 | importFrom(stats,princomp) 43 | importFrom(stringr,str_pad) 44 | importFrom(utils,data) 45 | importFrom(utils,head) 46 | importFrom(utils,modifyList) 47 | importFrom(utils,packageVersion) 48 | importFrom(utils,read.table) 49 | importFrom(utils,str) 50 | importFrom(utils,tail) 51 | importFrom(utils,write.table) 52 | importFrom(zoo,rollapply) 53 | -------------------------------------------------------------------------------- /R/.gitignore: -------------------------------------------------------------------------------- 1 | /.Rhistory 2 | -------------------------------------------------------------------------------- /R/CM.generatePolygon.r: -------------------------------------------------------------------------------- 1 | #' Generate polygon from bank points 2 | #' 3 | #' Generates an object of type polygon from the bank points. The bank points must be 4 | #' ordered and must have an attribute "left" or "right". 5 | #' 6 | #' \code{CM.generatePolygon()} creates a polygon from the bank points which were previously 7 | #' loaded with \code{\link[=CM.ini]{CM.ini()}}. The polygon generation is mainly 8 | #' a type conversion but involves also the chaining of the points in the correct 9 | #' order. That is, taking all bank points from the left bank and 10 | #' chain them with all reversed points of the right bank. The bank points from the right side 11 | #' have to be reversed so that a valid, circular polygon results (see figure). Since this process 12 | #' is prone to error when the points are not provided in the expected order, there is a visual feedback 13 | #' of this process. An overview of the generated polygon will be plotted to check the polygon's consistency. This 14 | #' plot is by default enabled but can be suppressed by setting \code{par$plot.polygoncheck} to \code{FALSE}. 15 | #' 16 | #' \if{html}{\figure{plotCheckPolygon.png}{options: width="600px" alt="Figure: check polygon"}} 17 | #' \if{latex}{\figure{plotCheckPolygon.pdf}{options: width=8cm}} 18 | #' \emph{Figure 5: The plot shows the polygon check plot for two data sets (two rows). The columns are: overview of the full channel (left), 19 | #' start of the polygon (middle) and end of the polygon (right). For the first data set everything looks fine. The 20 | #' polygon is circular and the ends look consistent (note, the starting end (middle) is open). The second data 21 | #' set is corrupt. You can see a line crossing the entire channel (left). Also, at the start and end 22 | #' of the channel there are discrepancies. This means that the order of bank points was not given properly. In this 23 | #' case, run \code{\link[=CM.ini]{CM.ini()}} again after re-arranging the channel bank points.} 24 | #' 25 | #' \code{CM.generatePolygon()} also applies a linear interpolation to the bank points if desired. The spacing of the 26 | #' bank points directly affects the resolution of the centerline (see \link[=cmgo]{paragraph "Work flow" 27 | #' of package documentation}). Generally, a high resolution of the centerline represents the channel course 28 | #' better but leads to more data points and higher computational costs. The linear interpolation will 29 | #' insert equidistant points in between existing bank points where the added points have a maximum distance defined by 30 | #' the parameter \code{bank.interpolate.max.dist}. This value is by default 6 and needs to be adjusted 31 | #' to the individual geometry. As a rule of thumb it is advised to \strong{change bank.interpolate.max.dist to 32 | #' the value of the expected channel width}! Note, that the units of this value is always the same unit 33 | #' as your input coordinates. The \emph{best} resolution of the centerline, however, depends also on the shape of 34 | #' the channel. If you experience problems with the chosen interpolation distance read the \link[=cmgo]{paragraph 35 | #' "Technical fails and how to prevent them" of the package documentation}). 36 | #' 37 | #' \code{CM.generatePolygon()} requires the global data object as argument and -- within this -- a list of bank points. 38 | #' The list of bank points must be previously created with \code{\link[=CM.ini]{CM.ini()}}. See 39 | #' the example section for the structure of the expected input. If multiple data sets (time series) 40 | #' are available, the polygon generation will be performed on each data set. 41 | #' 42 | #' @template param_global_data_object 43 | #' @return returns the global data object extended by the polygon data \code{$polygon} for the respective data set(s) 44 | #' @author Antonius Golly 45 | #' @examples 46 | #' # get demo data (find instructions on how to use own data in the documentation of CM.ini()) 47 | #' cmgo.obj = CM.ini("demo") 48 | #' 49 | #' # check structure of the required input for CM.generatePolygon() 50 | #' set = "set1" 51 | #' print(str(cmgo.obj$data[[set]]$channel)) 52 | #' 53 | #' #List of 4 54 | #' # $ x : num [1:396] 401601 401587 401568 401558 401552 ... 55 | #' # $ y : num [1:396] 3106437 3106407 3106384 3106364 3106329 ... 56 | #' # $ z : NULL 57 | #' # $ bank: chr [1:396] "right" "right" "right" "right" ... 58 | #' 59 | #' # generate the polygon from the bank points 60 | #' cmgo.obj = CM.generatePolygon(cmgo.obj) 61 | #' 62 | #' @export CM.generatePolygon 63 | 64 | CM.generatePolygon <- function(cmgo.obj){ 65 | 66 | plotCheckPolygon <- function(cmgo.obj){ 67 | 68 | par = cmgo.obj$par 69 | data = cmgo.obj$data 70 | 71 | notice = function(x,prim=FALSE){cat(paste((if(prim) "\n--> " else " "), x, sep=""), sep="\n")} 72 | 73 | notice("check topology of generated channel polygon in the plan view plot...", TRUE) 74 | 75 | #par(mfrow=c(length(names(data)),3)) 76 | par(mfrow=c(1,1)) 77 | for(set in names(data)){ 78 | 79 | plot(data[[set]]$polygon$y ~ data[[set]]$polygon$x, asp=1, type="l", xlab="X", ylab="Y", main=paste(paste("Channel overview ", set, " (", data[[set]]$survey, ")", sep=""))) 80 | if(par$plot.polygoncheck.colors == TRUE) points(data[[set]]$polygon$y ~ data[[set]]$polygon$x, asp=1, cex=0.3, col=colorRampPalette(c("blue", "red"))(length(data[[set]]$polygon$x))) 81 | n = 0 82 | 83 | ## produce an overview plot on both ends of the river polygon 84 | if(FALSE){ 85 | for(i in c(min(which(data[[set]]$channel$bank=="left")), max(which(data[[set]]$channel$bank=="right")))){ 86 | 87 | n = n+1 88 | title = "end"; if(n == 1) title ="start"; 89 | title = paste(title, "of polygon", set) 90 | 91 | x.lim = c(data[[set]]$channel$x[i] - par$plot.zoom.extent.length, data[[set]]$channel$x[i] + par$plot.zoom.extent.length) 92 | y.lim = c(data[[set]]$channel$y[i] - par$plot.zoom.extent.length, data[[set]]$channel$y[i] + par$plot.zoom.extent.length) 93 | 94 | 95 | plot(data[[set]]$polygon$y ~ data[[set]]$polygon$x, 96 | asp=1, type="l", xlab="X", ylab="Y", xlim = x.lim, ylim = y.lim, main = title 97 | ) 98 | 99 | points(data[[set]]$polygon$y ~ data[[set]]$polygon$x, pch=4, cex=0.5, col="red" ) 100 | points(data[[set]]$channel$y ~ data[[set]]$channel$x, pch=4, cex=1, col="blue") 101 | 102 | } 103 | } 104 | 105 | if(length(names(data)) > 1) {cat ("Press [Enter] to continue"); line <- readline()} 106 | 107 | } 108 | 109 | notice("plotting done!") 110 | 111 | } # plotCheckPolygon 112 | 113 | par = cmgo.obj$par 114 | data = cmgo.obj$data 115 | 116 | notice = function(x,prim=FALSE){cat(paste((if(prim) "\n--> " else " "), x, sep=""), sep="\n")} 117 | error = function(x){stop(x, call.=FALSE)} 118 | alert = function(x, y=""){if(y!=""){message(paste("--> ",x, y, sep=""))}else{message(paste("--> ", x, sep=""))}} 119 | warn = function(x){warning(x, call.=FALSE)} 120 | plot.file = function(par){if(!par$plot.to.file) return(NULL); file.no = 0 + par$plot.index; file.name = paste(par$plot.directory, str_pad(file.no, 3, pad="0"), "_", par$plot.filename, sep=""); while(file.exists(paste(file.name, ".png", sep="")) || file.exists(paste(file.name, ".pdf", sep=""))){ file.no = file.no + 1; file.name = paste(par$plot.directory, str_pad(file.no, 3, pad="0"), "_", par$plot.filename, sep="") }; dev.copy(png, filename=paste(file.name, ".png", sep=""), width=800, height=600); dev.off(); dev.copy2pdf(file=paste(file.name, ".pdf", sep=""));} 121 | 122 | notice(paste("generate polygon from bank points for", length(names(data)), "set(s)"), TRUE) 123 | 124 | notice(paste("> bank.interpolate =", par$bank.interpolate)) 125 | notice(paste("> bank.interpolate.max.dist =", par$bank.interpolate.max.dist)) 126 | notice(paste("> bank.reduce =", par$bank.reduce)) 127 | notice(paste("> bank.reduce.min.dist =", par$bank.reduce.min.dist)) 128 | 129 | for(set in names(data)){ 130 | 131 | if(is.null(data[[set]]$polygon) 132 | 133 | || isTRUE(data[[set]]$polygon.bank.interpolate != par$bank.interpolate) || isTRUE(data[[set]]$polygon.bank.interpolate.max.dist != par$bank.interpolate.max.dist) 134 | || isTRUE(data[[set]]$polygon.bank.reduce != par$bank.reduce) || isTRUE(data[[set]]$polygon.bank.reduce.min.dist != par$bank.reduce.min.dist) 135 | 136 | ){ 137 | 138 | notice(paste("\nprocessing ", set, " (", data[[set]]$survey, ")...", sep="")) 139 | 140 | data[[set]]$polygon.bank.interpolate = par$bank.interpolate 141 | data[[set]]$polygon.bank.interpolate.max.dist = NULL 142 | 143 | data[[set]]$polygon.bank.reduce = par$bank.reduce 144 | data[[set]]$polygon.bank.reduce.min.dist = NULL 145 | 146 | 147 | ix.l = which(data[[set]]$channel$bank == "left") 148 | ix.r = which(data[[set]]$channel$bank == "right") 149 | 150 | # check for existing bank codes 151 | if(length(ix.l) == 0) error(paste("no bank points found with the given code \"", par$bank.code.left, "\". Check parameters!", sep="")) 152 | if(length(ix.r) == 0) error(paste("no bank points found with the given code \"", par$bank.code.right, "\". Check parameters!", sep="")) 153 | 154 | data[[set]]$ix.l = ix.l 155 | data[[set]]$ix.r = ix.r 156 | 157 | # create bank object from original bank points 158 | banks = list( 159 | x = list(left = data[[set]]$channel$x[ix.l], right = data[[set]]$channel$x[ix.r]), 160 | y = list(left = data[[set]]$channel$y[ix.l], right = data[[set]]$channel$y[ix.r]) 161 | ) 162 | 163 | banks_original = banks 164 | 165 | 166 | 167 | 168 | # interpolate bank points (optional) 169 | if(par$bank.interpolate){ 170 | 171 | notice("interpolate bank points to generate a denser polygon...") 172 | 173 | # create (empty) bank point object 174 | banks = list( 175 | x = list(left = c(), right = c()), 176 | y = list(left = c(), right = c()) 177 | ) 178 | ap = 0 # counter to sum the points added 179 | 180 | # linearly interpolate bank points 181 | for(bank in c("left", "right")){ 182 | 183 | for(i in c(2:length(banks_original$x[[bank]]))){ 184 | 185 | # add the actual point 186 | banks$x[[bank]] = append(banks$x[[bank]], banks_original$x[[bank]][i-1]) 187 | banks$y[[bank]] = append(banks$y[[bank]], banks_original$y[[bank]][i-1]) 188 | 189 | # calculate distance between consecutive bank points 190 | cb_dist = ( ( banks_original$x[[bank]][i] - banks_original$x[[bank]][i-1] )^2 + ( banks_original$y[[bank]][i] - banks_original$y[[bank]][i-1] )^2 ) ^(1/2) 191 | 192 | # if distance larger than threshold distance interpolate 193 | if(cb_dist > par$bank.interpolate.max.dist){ 194 | 195 | # calculate number of artificial points 196 | nr_of_pts = ceiling(cb_dist / par$bank.interpolate.max.dist) 197 | ap = ap + nr_of_pts 198 | 199 | # add artificial points 200 | for(ido in c(1: (nr_of_pts-1))){ 201 | 202 | banks$x[[bank]] = append(banks$x[[bank]], banks_original$x[[bank]][i-1] + ( ( (banks_original$x[[bank]][i] - banks_original$x[[bank]][i-1]) / nr_of_pts ) * ido ) ) 203 | banks$y[[bank]] = append(banks$y[[bank]], banks_original$y[[bank]][i-1] + ( ( (banks_original$y[[bank]][i] - banks_original$y[[bank]][i-1]) / nr_of_pts ) * ido ) ) 204 | 205 | } 206 | 207 | } # if(cb_dist > par$bank.man.dist) 208 | 209 | } # for(i in c(2:length(ix))) 210 | 211 | # add the final point 212 | banks$x[[bank]] = append(banks$x[[bank]], tail(banks_original$x[[bank]], n=1)) 213 | banks$y[[bank]] = append(banks$y[[bank]], tail(banks_original$y[[bank]], n=1)) 214 | 215 | } # for(bank in c("left", "right")) 216 | 217 | data[[set]]$polygon.bank.interpolate.max.dist = par$bank.interpolate.max.dist 218 | banks_original = banks 219 | 220 | notice(paste("banks of", set, "interpolated with", ap, "points added!")) 221 | 222 | } # if(par$bank.interpolate) 223 | 224 | 225 | 226 | 227 | # reduce bank points (optional) 228 | if(par$bank.reduce){ 229 | 230 | notice("reduce bank points to generate a coarser polygon...") 231 | 232 | ap = 0 # counter to sum the points added 233 | 234 | banks = list( 235 | x = list(left = c(banks_original$x$left[1]), right = c(banks_original$x$right[1])), 236 | y = list(left = c(banks_original$y$left[1]), right = c(banks_original$y$right[1])) 237 | ) 238 | 239 | # linearly interpolate bank points 240 | for(bank in c("left", "right")){ 241 | 242 | for(i in c(2:length(banks_original$x[[bank]]))){ 243 | 244 | # calculate distance between consecutive bank points 245 | cb_dist = ( ( banks_original$x[[bank]][i] - banks$x[[bank]][length(banks$x[[bank]])] )^2 + ( banks_original$y[[bank]][i] - banks$y[[bank]][length(banks$y[[bank]])] )^2 ) ^(1/2) 246 | 247 | # if distance larger than threshold distance interpolate 248 | if(cb_dist < par$bank.reduce.min.dist){ 249 | 250 | ap = ap + 1 251 | 252 | } else { # if(cb_dist > par$bank.man.dist) 253 | 254 | # add the final point 255 | banks$x[[bank]] = append(banks$x[[bank]], banks_original$x[[bank]][i]) 256 | banks$y[[bank]] = append(banks$y[[bank]], banks_original$y[[bank]][i]) 257 | 258 | } # if(cb_dist > par$bank.man.dist) {} else 259 | 260 | } # for(i in c(2:length(ix))) 261 | 262 | } # for(bank in c("left", "right")) 263 | 264 | data[[set]]$polygon.bank.reduce.min.dist = par$bank.reduce.min.dist 265 | 266 | notice(paste("banks of", set, "reduced with", ap, "points removed!")) 267 | 268 | } # if(par$bank.interpolate) 269 | 270 | 271 | 272 | # store the final bank points as a polygon 273 | data[[set]]$polygon = ppp( 274 | c(banks$x$left, rev(banks$x$right)), 275 | c(banks$y$left, rev(banks$y$right)), 276 | window=owin( 277 | range(banks$x, na.rm=TRUE), 278 | range(banks$y, na.rm=TRUE) 279 | ) 280 | ) 281 | 282 | } else { 283 | 284 | notice(paste("(polygon for", set, "taken from cache)")) 285 | 286 | } 287 | 288 | } # for(set in names(data)) 289 | 290 | notice("CM.generatePolygon() has ended successfully!", TRUE) 291 | 292 | object = list( 293 | data = data, 294 | par = par 295 | ) 296 | 297 | if(par$plot.polygoncheck) plotCheckPolygon(object) # create a plot to check polygon consistency (optional) 298 | 299 | # return 300 | return(object) 301 | 302 | } 303 | -------------------------------------------------------------------------------- /R/CM.ini.r: -------------------------------------------------------------------------------- 1 | #' Get the global data object 2 | #' 3 | #' Create the global data object with data and parameters (information on the global data object in section 4 | #' "General information on the global data object). Depending on the arguments passed to 5 | #' \code{CM.ini()}, the data are either created from input files, a work space file or from a demo data set. 6 | #' The parameters are either created from defaults, from a parameter file 7 | #' or merged with a passed list of parameters. 8 | #' 9 | #' \code{CM.ini()} returns a global data object based on the arguments passed to it. Initially, 10 | #' the function builds a parameter object. If you leave the \code{par} argument empty, the default configuration 11 | #' is loaded. You can also pass everything to \code{par} that is accepted by \code{\link[=CM.par]{CM.par()}} as 12 | #' this argument will be directly passed to this function (see the documentation of CM.par() for further information). 13 | #' Once the parameter object is built, the function will create the data object by the following rules (if one rule 14 | #' was successfull, the routine stops and returns the global data object): 15 | #' 16 | #' \enumerate{ 17 | #' 18 | #' \item If \code{$workspace.read} is \code{TRUE} (default) the function looks for an .RData user workspace 19 | #' named \code{$workspace.filename} (defaults to "./user_workspace.RData"). Note: there will be no such workspace file 20 | #' once you start a project, since it needs to be saved by the user with \code{\link[=CM.writeData]{CM.writeData()}}. 21 | #' If such a workspace file exists the global data object will be created from this source, otherwise the next source 22 | #' is tested. 23 | #' \item If data input files are available in the directory \code{$input.dir} (defaults to "./input") the function 24 | #' interates over all files in this directory and create the data object from this source (see section "Input data" below 25 | #' for further information on the data format). If this rule applies you will start with a clean data set, that 26 | #' contains nothing than the bank geometry and you will need to process the data from scratch. Otherwise the next source is tested. 27 | #' \item If \code{object} is a string, the function will check for a demo data set with the same name. Available demo data 28 | #' sets are \code{"demo"}, \code{"demo1"} and \code{"demo2"}. See section "Demo data sets" below. 29 | #' } 30 | #' 31 | #' @template section_global_data_object 32 | #' 33 | #' @template section_input_data 34 | #' 35 | #' @section Demo data sets: 36 | #' Four demo data sets are available, which contain a few kilometer long section of a channel. The data sets 37 | #' differ in the degree of data processing. The data set \strong{demo} only contains the channel bank points, thus 38 | #' contains a global data object how it looks directly after reading the input files (check 39 | #' structure with \code{str(cmgo.obj$data[[set]]$channel)}). The data set \strong{demo1} has passed the first steps 40 | #' of the processing: CM.generatePolygon() and CM.calculateCenterlin(). Thus, it contains successfully created 41 | #' centerlines (check structure with \code{str(cmgo.obj$data[[set]]$cl)}). The data set \strong{demo2} has gone through 42 | #' the full stack of processing of cmgo, e.g. CM.processCenterline() , and all metrics are calculated (check 43 | #' structure with \code{str(cmgo.obj$data[[set]]$metrics)}). Thus you can use this data set for testing the 44 | #' plotting functions CM.plotPlanView() and CM.plotWidth(). Note, that demo data set demo3 uses the standard 45 | #' mode for the calculation of the metrics (default) 46 | #' and not the reference centerline mode. To see the reference centerline mode in action use data set \strong{demo3}. In addition 47 | #' to the previously mentioned plotting functions, here also CM.plotMetrics() is available. 48 | #' 49 | #' @param object either a global data object of type list or a string to specify a demo data set (see Details) 50 | #' @param par either a parameter list, a string to specify a parameter file or NULL to load default parameters (see also \code{\link[=CM.par]{CM.par()}}) 51 | #' @return returns the global data object containing data and parameters that will be passed to all main functions of \code{cmgo}. 52 | #' @author Antonius Golly 53 | #' @examples 54 | #' # example 1: get data set from demo data 55 | #' cmgo.obj = CM.ini("demo") 56 | #' 57 | #' # example 2: get data set from input files 58 | #' par = CM.par() 59 | #' print(cmgo.obj$par$input.dir) 60 | #' par$input.dir = "custom_input_folder" 61 | #' #cmgo.obj = CM.ini(NULL, par) # works if 'custom_input_folder' contains file(s) 62 | #' 63 | #' # example 3: load existing workspace 64 | #' # (see CM.writeData() to learn how to write your workspace) 65 | #' cmgo.obj$par$workspace.filename = "custom_workspace.RData" 66 | #' #cmgo.obj = CM.ini(NULL, par) # works if 'custom_workspace.RData' exists 67 | #' 68 | #' @export CM.ini 69 | 70 | CM.ini <- function(object = "demo", par = NULL){ 71 | 72 | notice = function(x,prim=FALSE){ cat(paste((if(prim) "\n--> " else " "), x, sep=""), sep="\n") } 73 | error = function(x){stop(x, call.=FALSE)} 74 | 75 | # print program information to the screen 76 | cat(rep("\n",10), "\n", paste(rep("-",54), collapse=""), "\n---", paste(rep(" ",48), collapse=""), "---\n---", paste(rep(" ",15), collapse=""),"ChannelMetrics v.1",paste(rep(" ",15), collapse=""),"---\n---", paste(rep(" ",48), collapse=""), "---\n",paste(rep("-",54), collapse=""), "\nv",as.character(packageVersion("cmgo"))," by Antonius Golly (antonius.golly@gmail.com)\n", sep=""); 77 | 78 | 79 | # user notice 80 | notice("load data", TRUE) 81 | 82 | # get parameters 83 | par = CM.par(par) 84 | 85 | # object is a valid data object 86 | if(typeof(object) == "list"){ 87 | 88 | notice("data is already existing, no data loaded!", TRUE) 89 | return(object) 90 | 91 | } 92 | 93 | # try to load from workspace 94 | if(par$workspace.read){ 95 | 96 | if(file.exists(par$workspace.filename)){ 97 | 98 | cmgo.obj = NULL 99 | 100 | load(par$workspace.filename) 101 | 102 | if(typeof(cmgo.obj) == "list"){ 103 | 104 | notice(paste("data set: workspace '", par$workspace.filename, "' loaded!", sep=""), TRUE) 105 | 106 | return(cmgo.obj) 107 | 108 | } else { 109 | 110 | error("tried to load workspace but workspace does not contain a valid global data object!") 111 | 112 | } 113 | 114 | } else { notice(paste("workspace", par$workspace.filename, "does not exist!"))} 115 | 116 | } else { notice("workspace reading disabled")} 117 | 118 | files = list.files(par$input.dir) 119 | if(length(files) > 0 ){ 120 | 121 | data = list() 122 | 123 | # read all files in $input.dir 124 | for(file in files){ 125 | 126 | table = read.table(paste(par$input.dir, "/", file, sep=""), sep=par$input.sep, header=TRUE, stringsAsFactors=FALSE, na.strings="-") 127 | set = paste("set", which(files == file), sep="") 128 | 129 | 130 | data[[set]] = list( 131 | 132 | filename = file, 133 | survey = substring(file, 0, rev(gregexpr("\\.", file)[[1]])[1]-1), 134 | channel = list( 135 | x = table[[par$input.col.easting]], 136 | y = table[[par$input.col.northing]], 137 | z = table[[par$input.col.elevation]], 138 | bank = table[[par$input.col.bank]] 139 | ) 140 | 141 | ) 142 | 143 | ix.l = which(data[[set]]$channel$bank == par$bank.code.left) 144 | ix.r = which(data[[set]]$channel$bank == par$bank.code.right) 145 | 146 | # give regular names 147 | data[[set]]$channel$bank[ix.l] = "left" 148 | data[[set]]$channel$bank[ix.r] = "right" 149 | 150 | if(par$bank.reverse.left){ 151 | 152 | data[[set]]$channel$x[ix.l] = rev(data[[set]]$channel$x[ix.l]) 153 | data[[set]]$channel$y[ix.l] = rev(data[[set]]$channel$y[ix.l]) 154 | data[[set]]$channel$z[ix.l] = rev(data[[set]]$channel$z[ix.l]) 155 | 156 | } 157 | 158 | if(par$bank.reverse.right){ 159 | 160 | data[[set]]$channel$x[ix.r] = rev(data[[set]]$channel$x[ix.r]) 161 | data[[set]]$channel$y[ix.r] = rev(data[[set]]$channel$y[ix.r]) 162 | data[[set]]$channel$z[ix.r] = rev(data[[set]]$channel$z[ix.r]) 163 | 164 | } 165 | 166 | # check for x-y coordinate duplicates 167 | d.ixs = duplicated(data.frame( 168 | x = data[[set]]$channel$x, 169 | y = data[[set]]$channel$y 170 | )) 171 | if(any(d.ixs)){ 172 | notice(paste("found", length(which(d.ixs)), "points in input data with identical x-y-coordinates")) 173 | data[[set]]$channel$x = data[[set]]$channel$x[!d.ixs] 174 | data[[set]]$channel$y = data[[set]]$channel$y[!d.ixs] 175 | data[[set]]$channel$z = data[[set]]$channel$z[!d.ixs] 176 | data[[set]]$channel$bank = data[[set]]$channel$bank[!d.ixs] 177 | notice("duplicates removed!") 178 | } 179 | 180 | 181 | 182 | 183 | notice(paste("file '", file, "' assigned to ", set, sep="")) 184 | 185 | } 186 | 187 | notice(paste("data set: ", length(files), " file(s) read from directory '", par$input.dir, "'!", sep=""), TRUE) 188 | 189 | return(list(data = data, par = par)) 190 | 191 | } else { 192 | 193 | notice(paste("no input files in folder '", par$input.dir, "' available, load demo data!", sep="")) 194 | 195 | if(is.null(object)) object = "demo" 196 | 197 | } 198 | 199 | 200 | # data specifies a demo workspace 201 | if(typeof(object) == "character"){ 202 | 203 | if(exists(object)){ 204 | 205 | notice(paste("data set '", object, "' loaded!", sep="")) 206 | object = get(object) 207 | return(object) 208 | 209 | } else error(paste("data set '", object, "' does not exist!", sep="")) 210 | 211 | } 212 | 213 | } 214 | -------------------------------------------------------------------------------- /R/CM.par.r: -------------------------------------------------------------------------------- 1 | #' Get the parameter object 2 | #' 3 | #' Create a parameter list containing all model and plotting parameters. Depending on the arguments passed to 4 | #' \code{CM.par()}, the parameter list is either created from the defaults or from a specified parameter file. 5 | #' 6 | #' \code{CM.par()} creates or renews a parameter list based on the arguments passed to it. The list contains all 7 | #' model and plot parameters and is stored within the global data object, for example \code{cmgo.obj$par} 8 | #' (see \link[=cmgo]{package documentation}). Thus, the returned parameter object must be assigned to the global data 9 | #' object as in \code{cmgo.obj$par = CM.par()}. 10 | #' 11 | #' If you call \code{CM.par()} without arguments (example #1), the default parameter list 12 | #' is returned (see section "All default parameters and their defaults"). For larger projects, it can be desired to easily switch between 13 | #' parameter sets, for example to reproduce different plots. You can save these customized parameter sets in files 14 | #' (see section "Make a custom parameter file"). These files are loaded with \code{CM.par("path_to_parameter_file")} (example #2). The file is 15 | #' \strong{not required} to host \strong{all} parameters, since the list will be merged with the defaults on loading. That means, a parameter file 16 | #' has to host only those parameters differing from the defaults. As a third option, you can pass directly a list to 17 | #' \code{CM.par()} (example #3). The directly passed parameters will be merged with defaults, as well. 18 | #' 19 | #' @template section_all_default_parameters 20 | #' 21 | #' @section Make a custom parameter file: 22 | #' Create an empty .r-file with the following code:\preformatted{ 23 | #' par = list( 24 | #' plot.to.file = TRUE, 25 | #' other_par = "value" 26 | #' # other_par = "other value" 27 | #' ) 28 | #' } 29 | #' A full list of available parameters can be found in the paragraph "All parameters and their defaults" above. In a parameter file you 30 | #' don't have to specify \strong{all} parameters. Just list parameters that you like to differ from the defaults. The parameter object that 31 | #' will be created by CM.par() if you specify a file name will be merged with the defaults, where specified parameters overwrite the defaults. 32 | #' 33 | #' @param par.set either NULL (default parameters are returned), of type string to specify a filename or of type list to specify parameters 34 | #' @return The resulting parameters list. 35 | #' @author Antonius Golly 36 | #' @examples 37 | #' # instantiate your global data object first, for example with CM.ini() 38 | #' cmgo.obj = list() 39 | #' 40 | #' # example #1: get the default parameters 41 | #' cmgo.obj$par = CM.par() 42 | #' 43 | #' # example #2: get parameters from a configuration file (see also "Make a custom parameter file") 44 | #' #cmgo.obj$par = CM.par("par/custom_parameters.r")#' 45 | #' 46 | #' # example 3: get modified default parameters 47 | #' cmgo.obj$par = CM.par(list( 48 | #' plot.to.file = TRUE, 49 | #' plot.directory = "/my_figures" 50 | #' )) 51 | #' 52 | #' @export CM.par 53 | 54 | CM.par <- function(par.set=NULL){ 55 | 56 | notice = function(x,prim=FALSE){cat(paste((if(prim) "\n--> " else " "), x, sep=""), sep="\n")} 57 | error = function(x){stop(x, call.=FALSE)} 58 | 59 | par.default = list( 60 | 61 | # name of the parameter set 62 | name = "default", 63 | version = "0.2.0", 64 | 65 | # workspace 66 | workspace.read = TRUE, # if [TRUE] it is tried to load the global data object from a workspace file in CM.ini() 67 | workspace.write = FALSE, # if [TRUE] a workspace with the global data object will be written in CM.writeData() 68 | workspace.replace = FALSE, # if [TRUE] a workspace will be replaced when existing in CM.writeData() 69 | workspace.filename = "user_workspace.RData", # the filename used in CM.ini() and CM.writeData() 70 | 71 | # input settings 72 | input.dir = "input", # the directory from which all input files will be read in by CM.ini() 73 | input.sep = "\t", # the column separator sign, e.g. ",", ";", "\t" (tab) passed to read.table (?read.table for more information) 74 | input.col.easting = "POINT_X", # the column name for the x-value 75 | input.col.northing = "POINT_Y", # s.a. 76 | input.col.elevation = "POINT_Z", # s.a. 77 | input.units = "m", # units of input coordinates (will be used for axis labels in plotting functions) 78 | input.col.bank = "Name", # the column name of the side (left/right bank) 79 | bank.code.left = "left", # the string code used for the left bank 80 | bank.code.right = "right", # the string code used for the right bank 81 | bank.reverse.left = FALSE, # reverse bank points of left bank from input data 82 | bank.reverse.right = FALSE, # reverse bank points of right bank from input data 83 | 84 | # output settings 85 | output.replace = FALSE, # if [TRUE] the output files are replaced when existing in CM.writeFiles() 86 | output.write.centerline = FALSE, # if [TRUE] the geometry of the centerline will be written in CM.writeFiles() 87 | output.write.metrics = TRUE, # if [TRUE] the calculated channel metrics will be written in CM.writeFiles() 88 | output.write.metrics.d = TRUE, # switch on/off the variable d.r and d.l (distances from centerline to banks) 89 | output.write.metrics.w = TRUE, # switch on/off the variable w (channel width) 90 | output.write.metrics.r = TRUE, # switch on/off the variable r.r and r.l (direction factor of d.r and d.l) 91 | output.write.metrics.diff = TRUE, # switch on/off the variable diff.r and diff.l (distances between two banks) 92 | output.write.steps = FALSE, # 93 | 94 | output.dir = "output", 95 | output.sep = "\t", 96 | 97 | # enable/disable plots and configure them 98 | plot.polygoncheck = TRUE, # if [TRUE], a three-column plot is generated showing the entire river and both ends to rouhgly check the polygon consitency (see also CM.generatePolygon()) 99 | plot.polygoncheck.colors = FALSE, # if [TRUE], a polygoncheck will be colored 100 | 101 | plot.planview = TRUE, # create a plan view overview plot 102 | plot.planview.secondary = TRUE, # in the plan view plot, add a secodary data set for comparison (will be displayed in dashed lines) 103 | plot.planview.bankpoints = FALSE, # in the plan view plot, add the bank points of a data set 104 | plot.planview.bankpoints.col= FALSE, # if [TRUE] bank points will be colored by side (left/right) 105 | plot.planview.bankpoints.interpolated = FALSE, # in the plan view plot, add the interpolated bank points of a data set 106 | plot.planview.polygon = TRUE, # in the plan view plot, add the channel borders 107 | plot.planview.voronoi = FALSE, # in the plan view plot, add voronoi polygons in plan view plot 108 | plot.planview.cl.original = FALSE, # in the plan view plot, add the rough centerline (before smoothing) 109 | plot.planview.cl.smoothed = TRUE, # in the plan view plot, add the smoothed centerline 110 | plot.planview.cl.points = FALSE, # when a centerline is plotted should the points representing the line be emphasized 111 | plot.planview.cl.tx = FALSE, # in the plan view plot, add a label with the number next to the centerline points 112 | plot.planview.cl.selection = TRUE, # if [TRUE] and plot window is determined by cl points (see docu) the cl points are highlighted 113 | plot.planview.cl.binned = FALSE, # if [TRUE] plot the re-binned centerline produced by CM.resampleCenterline() 114 | plot.planview.transects = FALSE, # in the plan view plot, add transects (perpendiculars to centerline) 115 | plot.planview.transects.len = 20, # give the length of transects in the unit of the input coordinates 116 | plot.planview.dist2banks = TRUE, # in the plan view plot, add transect segments from centerline to the banks (left and right) 117 | plot.planview.grid = TRUE, # in the plan view plot, add a grid in the background 118 | plot.planview.grid.dist = NULL, # the distance of the grid lines in the unit of the input coordinates, if NULL it will be calculated automatically 119 | plot.planview.legend = TRUE, # in the plan view plot, add a legend 120 | plot.planview.legend.pos = "topleft", # keyword to position legend (see ?legend) 121 | plot.planview.scalebar = TRUE, # in the plan view plot, add a scalebar (width of one plot.planview.grid.dist) 122 | plot.planview.use.names = TRUE, # if [TRUE] set names will be used for display, otherwise "set1", "set2", etc. 123 | 124 | plot.metrics.use.names = TRUE, # if [TRUE] set names will be used for display, otherwise "set1", "set2", etc. 125 | plot.metrics.width = TRUE, # if [TRUE] plot width 126 | 127 | 128 | # plot options 129 | plot.zoom = TRUE, # if [TRUE] the plan view plot is zoomed in (see also CM.plotPlanView()) 130 | plot.zoom.extent.length = NULL, # zoom window extent for the plan view plot in the unit of the input coordinates 131 | plot.zoom.extent = "e1", # applied zoom window name (see also CM.plotPlanView()) 132 | plot.zoom.extents = list( # presets (customizable list) of zoom windows 133 | e1 = c(400480, 3103130), 134 | e2 = c(399445, 3096220), 135 | e3 = c(401623, 3105925) 136 | ), 137 | plot.cl.range = "cl1", # applied zoom cl range (see also CM.plotPlanView) 138 | plot.cl.ranges = list( # presets (customizable list) of cl ranges 139 | cl1 = c(1235, 1260) 140 | ), 141 | plot.cl.range.use.reference = TRUE, # determines whether to look for reference centerline [TRUE] or current centerline when centering around cl.range 142 | plot.to.file = FALSE, # if [TRUE] all plots will be copied to file devices 143 | plot.to.pdf = TRUE, # if [TRUE] the plot will be saved as pdf 144 | plot.to.png = TRUE, # if [TRUE] the plot will be saved as png 145 | plot.index = 0, # numbering for filenames (see also CM.plotPlanView()) 146 | plot.directory = "plots/", # directory for saving plots if plot.to.file = TRUE 147 | plot.filename = "documentation", # plot file name 148 | 149 | # model parameters 150 | force.calc.voronoi = FALSE, # if [TRUE] the voronoi polygons are always re-calculated and never taken from cache 151 | force.calc.cl = FALSE, # if [TRUE] the centerline is always re-calculated and never taken from cache 152 | bank.interpolate = TRUE, # if [TRUE] the provided bank points are linearly interpolated to generate a denser polygon (see CM.generatePolygon()) 153 | bank.interpolate.max.dist = 6, # if bank.interpolate is [TRUE] this is the maximum distance all bank points will have 154 | bank.reduce = FALSE, # if [TRUE] the provided bank points are reduced by points that are closer to each other than bank.reduce.min.dist 155 | bank.reduce.min.dist = 0.5, # if bank.reduce is [TRUE] this is the minimum distance all bank point will have 156 | bank.filter2.max.it = 20, # number of the maximum iterations for filter 2 to prevent the program to run infinitely 157 | centerline.smoothing.width = 7, # smoothing window width of mean filter in number of observations (see CM.calculateCenterline()) 158 | centerline.local.slope.range= 15, 159 | transects.span = 3, # span of centerline points used for calculating the transects (see CM.processCenterline()) 160 | centerline.bin.length = 5, # for simplifying the centerline give the spacing in the unit of the input coordinates (see CM.reduceCenterline()) 161 | centerline.use.reference = FALSE, # sets method for calculating distance centerline to banks, if [FALSE] (default) each river profile will be compared to its own centerline, if [TRUE] the centerline of centerline.reference will be taken (see CM.processCenterline()) 162 | centerline.reference = "set1", # sets the reference data set if centerline.use.reference is [TRUE] 163 | force.calc.metrics = FALSE, # if [TRUE] the metrics are always re-calculated and never taken from cache 164 | calculate.metrics = TRUE, # if [TRUE] all centerline metrics are calculated (see CM.processCenterline()) 165 | calculate.metrics.dw = FALSE, # defines whether or not the change of the width shall be calculated 166 | metrics.local.change.range = 5, # the upstream range over which metric changes are derived (e.g. width change) 167 | 168 | # step identification after Zimmermann et. al 2008 [Zimmermann, A.E., Church, M., and Hassan, M. a., 2008, Identification of steps and pools from stream longitudinal profile data: Geomorphology, v. 102, no. 3–4, p. 395–406, doi: 10.1016/j.geomorph.2008.04.009.)] 169 | steps.identify = FALSE, 170 | steps.verbose = FALSE, # should there be information printed to the screen during step identification 171 | steps.thalweg.dist = "3d", # chose method of distance calculation "3d" or "2d" 172 | steps.minimum.step.length = 2.25, # as percentage of Wb [%] 173 | steps.maximum.step.length = 200, # as percentage of Wb [%] 174 | steps.minimum.pool.length = 10, # as percentage of Wb [%] 175 | steps.minimum.residual.depth= 0.23, # as percentage of Wb [%] 176 | steps.minimum.drop.height = 3.3, # as percentage of Wb [%] 177 | steps.bank.full.width.fix = TRUE, # TRUE: use a fix bank full width for the whole stream, FALSE: calculate from banks 178 | steps.bank.full.width = 3.7, # [m] 179 | steps.average.slope.fix = FALSE, 180 | steps.average.slope = 12.5, # 8.34, #12.5, # [deg] 181 | 182 | # ignore 183 | dummy = TRUE 184 | 185 | ) 186 | 187 | notice("load parameters", TRUE) 188 | 189 | # par.set is not specified: return default or existing parameter set 190 | if(is.null(par.set)){ 191 | 192 | # set to default 193 | par = par.default 194 | tx = "default parameters" 195 | 196 | } 197 | 198 | # par.set is a filename: open file and merge with defaults 199 | if(typeof(par.set) == "character"){ 200 | 201 | # check if parameter file exists 202 | if(!file.exists(par.set)) error(paste("parameter file ", par.set, " does not exist!", sep="")) 203 | 204 | # source parameter file 205 | source(par.set, local=TRUE) 206 | 207 | # check for a valid par list 208 | if(!exists("par")) error(paste("parameter file", par.set, "does not contain a parameter list!")) 209 | if(typeof(par) != "list") error(paste("parameter file", par.set, "does not contain a parameter list!")) 210 | 211 | # merge with defaults (specified parameters have higher priorities 212 | par = modifyList(par.default, par) 213 | tx = paste("parameters from file '", par.set, "' merged with defaults", sep="") 214 | 215 | } 216 | 217 | if(typeof(par.set) == "list"){ 218 | 219 | par = modifyList(par.default, par.set) 220 | tx = "passed parameters merged with defaults" 221 | 222 | } 223 | 224 | # manipulate defaults 225 | if(is.null(par$centerline.smoothing.width)) par$centerline.smoothing.width = ceiling(par$bank.interpolate.max.dist) 226 | 227 | notice(paste("parameter set:", tx)) 228 | 229 | return(par) 230 | 231 | } 232 | -------------------------------------------------------------------------------- /R/CM.plotMetrics.r: -------------------------------------------------------------------------------- 1 | #' Plot changes of the banks (erosion and aggradation) 2 | #' 3 | #' If multiple channel surveys are present (time series analyses) and the reference centerline mode is 4 | #' used, this function allows to plot the shift of the banks (bank erosion and aggradation) along the channel. 5 | #' 6 | #' \code{CM.plotMetrics()} allows to plot the position of banks with regard to the centerline in downstream 7 | #' direction. If only one survey is present, the plot will only show the distance of the right and left bank 8 | #' to the centerline over the centerline distance (downstream length of the channel). If multiple surveys of a 9 | #' channel exists (time series analyses) the differences of the channel banks can be calculated if a reference 10 | #' centerline is used (reference centerline mode). The differences (bank ersosion and aggradation) are plotted 11 | #' with this function. 12 | #' 13 | #' Without passing something to the function, the banks of the whole channel are plotted. To specify a region 14 | #' use the \code{cl} and \code{d} parameters. See the parameter definition and the example section for details. 15 | #' 16 | #' @template param_global_data_object 17 | #' @param set the reference data set 18 | #' @param cl the range of centerline points to be plotted, if NULL (default) the full channel length will be plotted, if 19 | #' a vector of two elements is provided (e.g. c(200, 500)) this cl range is plotted, if a string is provided (e.g. "cl1"), 20 | #' the range defined in \code{par$plot.cl.ranges$cl1} will be plotted 21 | #' @param d the distance range of the centerline downstream to be plotted, NULL (default) cl defintions are taken, if a 22 | #' single value (e.g. d=500) is given 50 m around this distance is plotted, if a vector with two elements is given (e.g. 23 | #' c(280, 620)) this distance range will be plotted 24 | #' @return desc 25 | #' @author Antonius Golly 26 | #' @examples 27 | #' 28 | #' # open demo 29 | #' cmgo.obj = CM.ini("demo3") 30 | #' 31 | #' # example 1: plot the distance of channel banks to centerline 32 | #' CM.plotMetrics(cmgo.obj) 33 | #' 34 | #' # example 2: plot the change of the channel banks (aggradation/erosion) 35 | #' CM.plotMetrics(cmgo.obj, set="set2") 36 | #' 37 | #' # example 3: plot only a range 38 | #' CM.plotMetrics(cmgo.obj, set="set2", cl=c(800, 850)) 39 | #' CM.plotPlanView(cmgo.obj, set="set2", cl=c(800, 850)) # compare with plan view map 40 | #' 41 | #' @export CM.plotMetrics 42 | 43 | CM.plotMetrics <- function(cmgo.obj, set="set1", cl=NULL, d=NULL){ 44 | 45 | par = cmgo.obj$par 46 | data = cmgo.obj$data 47 | 48 | notice = function(x,prim=FALSE){cat(paste((if(prim) "\n--> " else " "), x, sep=""), sep="\n")} 49 | error = function(x){stop(x, call.=FALSE)} 50 | alert = function(x, y=""){if(y!=""){message(paste("--> ",x, y, sep=""))}else{message(paste("--> ", x, sep=""))}} 51 | warn = function(x){warning(x, call.=FALSE)} 52 | plot.file = function(par){if(!par$plot.to.file) return(NULL); file.no = 0 + par$plot.index; file.name = paste(par$plot.directory, str_pad(file.no, 3, pad="0"), "_", par$plot.filename, sep=""); while(file.exists(paste(file.name, ".png", sep="")) || file.exists(paste(file.name, ".pdf", sep=""))){ file.no = file.no + 1; file.name = paste(par$plot.directory, str_pad(file.no, 3, pad="0"), "_", par$plot.filename, sep="") }; dev.copy(png, filename=paste(file.name, ".png", sep=""), width=800, height=600); dev.off(); dev.copy2pdf(file=paste(file.name, ".pdf", sep=""));} 53 | 54 | leg.add = function(leg, tx, item=NULL, lwd=1, lty=NA, pch=NA, cex=1, col="black"){ 55 | 56 | item = if(is.null(item)) paste("item_", length(leg)+1, sep="") else item 57 | 58 | leg[[item]] = list( 59 | tx = tx, 60 | lwd = lwd, 61 | lty = lty, 62 | pch = pch, 63 | cex = cex, 64 | col = col 65 | ) 66 | 67 | return(leg) 68 | 69 | } 70 | 71 | leg.make = function(leg){ 72 | 73 | tx = type = lwd = lty = pch = cex = col = c() 74 | 75 | 76 | for(item in c(1:length(leg))){ 77 | tx = append(tx, leg[[item]]$tx) 78 | lwd = append(lwd, leg[[item]]$lwd) 79 | lty = append(lty, leg[[item]]$lty) 80 | pch = append(pch, leg[[item]]$pch) 81 | cex = append(cex, leg[[item]]$cex) 82 | col = append(col, leg[[item]]$col) 83 | } 84 | 85 | leg.vec = function(x) return(if(length(unique(x))==1) x[1] else x) 86 | 87 | legend("topleft", inset=0.05, 88 | legend = leg.vec(tx), 89 | lwd = leg.vec(lwd), 90 | lty = leg.vec(lty), 91 | pch = leg.vec(pch), 92 | pt.cex = leg.vec(cex), 93 | col = leg.vec(col) 94 | ) 95 | } 96 | 97 | #dev.new(width=12, height=10) 98 | notice("create metrics plot...", TRUE) 99 | 100 | plots = c(1) 101 | par(mfcol=c(1,length(plots))) 102 | 103 | for(plot in plots){ 104 | 105 | ### get reference centerline 106 | set.ref = data[[set]]$metrics$cl.ref 107 | #set.secondary = if(is.null(set.compare)) set.ref else set.compare 108 | 109 | ## build names 110 | name.set = if(par$plot.metrics.use.names) data[[set]]$survey else set 111 | name.set.ref = if(par$plot.metrics.use.names) {if(!is.null(set.ref)) data[[set.ref]]$survey else "not set" } else set.ref 112 | 113 | ### define cl range 114 | if(is.null(cl)) cl = seq(along=data[[set.ref]]$cl$smoothed$x) 115 | if(typeof(cl) == "character"){ if(cl %in% names(par$plot.cl.ranges)) cl = par$plot.cl.ranges[[cl]] else stop(paste("given cl range", cl, "unknown!"))} 116 | if(length(cl) == 1) cl = c(cl, cl+1) 117 | if(length(cl) == 2) cl = seq(from = cl[1], to = cl[2]); 118 | 119 | if(!is.null(d)){ 120 | if(length(d) == 1) d = c(d-25, d+25) 121 | if(d[1] < 0 ) d[1] = 0; if(d[2] > tail(data[[set.ref]]$cl$smoothed$cum_dist_2d, n=1)) d[2] = tail(data[[set.ref]]$cl$smoothed$cum_dist_2d, n=1) 122 | if(length(d) == 2) d = seq(from = d[1], to = d[2]) 123 | cl = seq( 124 | from = which.min(abs(data[[set.ref]]$cl$smoothed$cum_dist_2d - d[1])), 125 | to = which.min(abs(data[[set.ref]]$cl$smoothed$cum_dist_2d - d[length(d)])) 126 | ) 127 | notice(paste("d range: distance", d[1], "to", d[length(d)])) 128 | } 129 | 130 | notice(paste("cl range: index", cl[1], "to", cl[length(cl)])) 131 | 132 | leg = list() 133 | 134 | y.lim = max(data[[set.ref]]$metrics$d.r[cl],data[[set.ref]]$metrics$d.l[cl], data[[set]]$metrics$d.r[cl], data[[set]]$metrics$d.l[cl], na.rm=TRUE) 135 | if(set != set.ref) y.lim = max(y.lim , data[[set]]$metrics$diff.r[cl], data[[set]]$metrics$diff.l[cl], na.rm=TRUE) 136 | 137 | plot( 138 | 0, 139 | main = if(set == set.ref) paste("Bank position of", name.set) else paste("Bank shift of", name.set, "(solid) over", name.set.ref, "(dashed)"), 140 | ylim = c(-y.lim, y.lim), 141 | xlim = c(data[[set.ref]]$cl$smoothed$cum_dist_2d[cl[1]], data[[set.ref]]$cl$smoothed$cum_dist_2d[cl[length(cl)]]), 142 | xlab = paste("Distance upstream [", par$input.unit, "]", sep=""), 143 | ylab = "Distance [m]", 144 | type = "n" 145 | ) 146 | abline(h=0, col="gray") 147 | 148 | ############ right bank ############# 149 | 150 | length = data[[set.ref]]$cl$smoothed$cum_dist_2d 151 | 152 | ## bank distance of set 153 | lines(data[[set]]$metrics$d.r * data[[set]]$metrics$r.r ~ length, col = "green", lty=1) 154 | leg = leg.add(leg, paste("right bank of", name.set, "(reference cl:", name.set.ref, ")"), col = "green", lty=1, lwd=1) 155 | 156 | ## bank distance of set.ref 157 | if(set != set.ref){ 158 | lines(data[[set.ref]]$metrics$d.r * data[[set.ref]]$metrics$r.r ~ length, col = "green", lty=2) 159 | leg = leg.add(leg, paste("right bank of", name.set.ref, "(reference cl:", name.set.ref,")"), col = "green", lty=2, lwd=1) 160 | } 161 | 162 | ## bank retreat 163 | if(set != set.ref){ 164 | lines(data[[set]]$metrics$diff.r ~ length, col = colors()[240], lty=1, lwd=8) 165 | lines(data[[set]]$metrics$diff.r ~ length, col = "green", lty=6, lwd=2) 166 | leg = leg.add(leg, paste("right bank shift", name.set, "over", name.set.ref), col = "green", lty=6, lwd=2) 167 | } 168 | 169 | 170 | ##### left bank ##################### 171 | ## bank distance of set 172 | lines(data[[set]]$metrics$d.l * data[[set]]$metrics$r.l ~ length, col = "red", lty=1) 173 | leg = leg.add(leg, paste("left bank of", name.set, "(reference cl:", name.set.ref, ")"), col = "red", lty=1, lwd=1) 174 | 175 | ## bank distance of set.ref 176 | if(set != set.ref){ 177 | lines(data[[set.ref]]$metrics$d.l * data[[set.ref]]$metrics$r.l ~ length , col = "red", lty=2) 178 | leg = leg.add(leg, paste("left bank of", name.set.ref, "(reference cl:", name.set.ref,")"), col = "red", lty=2, lwd=1) 179 | } 180 | 181 | ## bank retreat 182 | if(set != set.ref){ 183 | lines(data[[set]]$metrics$diff.l ~ length, col = colors()[240], lty=1, lwd=8) 184 | lines(data[[set]]$metrics$diff.l ~ length, col = "red", lty=6, lwd=2) 185 | leg = leg.add(leg, paste("left bank shift", name.set, "over", name.set.ref), col = "red", lty=6, lwd=2) 186 | } 187 | 188 | ## width 189 | #if() 190 | 191 | # legend and scale bar #################################################### 192 | if(par$plot.planview.legend) leg.make(leg) 193 | 194 | } # for(plot in plots) 195 | 196 | plot.file(par) 197 | 198 | notice("plotting done!") 199 | 200 | } -------------------------------------------------------------------------------- /R/CM.plotPlanView.r: -------------------------------------------------------------------------------- 1 | #' Plot a map of the channel 2 | #' 3 | #' Create a plan view map of the channel and various elements that can be switched on and off (banks, centerline, transects, 4 | #' grid, legend, etc.). 5 | #' 6 | #' \code{CM.plotPlanView()} creates a plan view plot. To specify the map extent (plot region) multiple settings exist. 7 | #' The map extent is the range of x and y coordinates shown on the map, speaking in R terms the xlim and ylim parameters of the plot function. 8 | #' In \code{CM.plotPlanView()} the map extent is defined by a center coordinate (x and one y coordinate where the plot is centered at), and a zoom length. You have multiple 9 | #' ways to determine the center coordinate: pre-defined extent, cl, error and direct x/y coordinates (see descriptions in the parameters). 10 | #' This list also represents the priority, meaning, the pre-defined extent indicates the lowest priority and x/y coordinates the highest if more than one 11 | #' parameter is set. The zoom length can be given via the global parameter object or directly with the parameter zoom. 12 | #' 13 | #' You can enable/disable the following plotting elements via the paramtere object:\preformatted{ 14 | #' plot.planview = TRUE, # plot an plan view overview plot 15 | #' plot.planview.secondary = TRUE, # plot a secondary channel polygon to the plot (for comparison of data sets) 16 | #' plot.planview.bank.points = TRUE, # plot channel bank points 17 | #' plot.planview.polygon = TRUE, # plot channel bank polygon 18 | #' plot.planview.voronoi = TRUE, # plot voronoi polygons in plan view plot 19 | #' plot.planview.cl.original = FALSE, # plot centerline in plan view plot 20 | #' plot.planview.cl.smoothed = TRUE, # plot centerline in plan view plot 21 | #' plot.planview.cl.tx = FALSE, # plot a label next to the centerline points 22 | #' plot.planview.transects = FALSE, # plot transects 23 | #' plot.planview.transects.len = 20, # the length of transects 24 | #' plot.planview.dist2banks = TRUE, # plot transect segments from bank to bank 25 | #' plot.planview.grid = TRUE, # plot a grid in the background of the plan view plot 26 | #' plot.planview.grid.dist = 20, # the distance of the grid lines 27 | #' plot.planview.legend = TRUE, # plot a legend 28 | #' plot.planview.scalebar = TRUE, # plot a scalebar 29 | #' } 30 | #' 31 | #' 32 | #' @template param_global_data_object 33 | #' @param set the data set to be plotted, "set1" if not specified. See documentation of CM.ini() to learn about data sets. 34 | #' @param title a title printed above the plot, if not specified a title will be composed from the enabled plot elements 35 | #' @param set.compare a second data set to be plotted in light color for comparison 36 | #' @param extent a string defining the plotting extent of the map (specifying an object of the list in par$plot.zoom.extents) or NULL (the default extent of par$plot.zoom.extent is taken) 37 | #' @param zoom defines if plot is zoomed (TRUE) or not (FALSE). In case of NULL (default) the value of par$plot.zoom is taken 38 | #' @param zoom.length a number defining the zoom length 39 | #' @param cl the centerline point or points with should be centered 40 | #' @param error an integer between 1 and (see Details for further information) 41 | #' @param error.type a string specifying which errors should be investigated ("errors.filter2", "errors.filter2.first" or "errors.sort") 42 | #' @param x an x-coordinate where the map is centered at 43 | #' @param y an y-coordinate where the map is centered at 44 | #' @return a list of applied plot parameters (this is useful for plotting the same extent in CM.plotMetrics()) 45 | #' @author Antonius Golly 46 | #' @examples 47 | #' # get demo data (find instructions on how to use own data in the documentation of CM.ini()) 48 | #' cmgo.obj = CM.ini("demo2") 49 | #' 50 | #' # example 1: overview plot 51 | #' CM.plotPlanView(cmgo.obj) 52 | #' 53 | #' @export CM.plotPlanView 54 | 55 | CM.plotPlanView <- function(cmgo.obj, set="set1", title=NULL, set.compare=NULL, extent=NULL, zoom = FALSE, zoom.length = NULL, cl=NULL, error=NULL, error.type="errors.filter2", x=NULL, y=NULL){ 56 | 57 | par = cmgo.obj$par 58 | data = cmgo.obj$data 59 | 60 | notice = function(x,prim=FALSE){cat(paste((if(prim) "\n--> " else " "), x, sep=""), sep="\n")} 61 | plot.file = function(par){if(!par$plot.to.file) return(NULL); file.no = 0 + par$plot.index; file.name = paste(par$plot.directory, str_pad(file.no, 3, pad="0"), "_", par$plot.filename, sep=""); while(file.exists(paste(file.name, ".png", sep="")) || file.exists(paste(file.name, ".pdf", sep=""))){ file.no = file.no + 1; file.name = paste(par$plot.directory, str_pad(file.no, 3, pad="0"), "_", par$plot.filename, sep="") }; dev.copy(png, filename=paste(file.name, ".png", sep=""), width=800, height=600); dev.off(); dev.copy2pdf(file=paste(file.name, ".pdf", sep=""));} 62 | 63 | leg.add = function(leg, tx, item=NULL, lwd=1, lty=NA, pch=NA, cex=1, col="black"){ 64 | 65 | item = if(is.null(item)) paste("item_", length(leg)+1, sep="") else item 66 | 67 | leg[[item]] = list( 68 | tx = tx, 69 | lwd = lwd, 70 | lty = lty, 71 | pch = pch, 72 | cex = cex, 73 | col = col 74 | ) 75 | 76 | return(leg) 77 | 78 | } 79 | 80 | leg.make = function(leg, par){ 81 | 82 | if(length(leg) == 0) return(NULL) 83 | 84 | tx = type = lwd = lty = pch = cex = col = c() 85 | 86 | for(item in c(1:length(leg))){ 87 | tx = append(tx, leg[[item]]$tx) 88 | lwd = append(lwd, leg[[item]]$lwd) 89 | lty = append(lty, leg[[item]]$lty) 90 | pch = append(pch, leg[[item]]$pch) 91 | cex = append(cex, leg[[item]]$cex) 92 | col = append(col, leg[[item]]$col) 93 | } 94 | 95 | leg.vec = function(x) return(if(length(unique(x))==1) x[1] else x) 96 | 97 | legend(par$plot.planview.legend.pos, inset = 0.05, 98 | legend = leg.vec(tx), 99 | lwd = leg.vec(lwd), 100 | lty = leg.vec(lty), 101 | pch = leg.vec(pch), 102 | pt.cex = leg.vec(cex), 103 | col = leg.vec(col) 104 | ) 105 | } 106 | 107 | #dev.new(width=6, height=10) 108 | #par(mfrow=c(1,1)) 109 | notice("create plan view plot", TRUE) 110 | 111 | #for(plot in plots){ 112 | 113 | ### get reference sets 114 | set.ref = data[[set]]$metrics$cl.ref ; if(is.null(set.ref)) set.ref = FALSE 115 | set.secondary = if(is.null(set.compare)) set.ref else set.compare; if(!is.null(set.secondary)) if(!set.secondary %in% names(data)) set.secondary = NULL 116 | set.cl.ref = if(par$plot.cl.range.use.reference) set.ref else set 117 | 118 | # specify zoom 119 | zoom = if(is.null(zoom)) par$plot.zoom else zoom 120 | zoom = if(is.null(error)) zoom else TRUE 121 | zoom.length = if(is.null(zoom.length)) par$plot.zoom.extent.length else zoom.length 122 | zoom.length = if(is.null(zoom.length)){ 123 | zoom.length = min( 124 | max(data[[set]]$channel$x) - min(data[[set]]$channel$x), 125 | max(data[[set]]$channel$y) - min(data[[set]]$channel$y) 126 | )/2 127 | } else zoom.length 128 | 129 | 130 | 131 | 132 | # specify plot extent ##################################################### 133 | 134 | plot.extent.rule = "full extent" 135 | plot.x = mean(data[[set]]$channel$x) 136 | plot.y = mean(data[[set]]$channel$y) 137 | 138 | if(zoom) plot.extent.rule = "zoom on center" 139 | 140 | # by set 141 | if(!is.null(extent)) { 142 | if(typeof(extent) == "character"){if(extent %in% names(par$plot.zoom.extents)) extent = par$plot.zoom.extents[[extent]] else stop(paste("given zoom extent", extent, "unknown!"))} 143 | plot.x = extent[1] 144 | plot.y = extent[2] 145 | plot.extent.rule = "predefined extent" 146 | } 147 | 148 | # by cl point 149 | if(!is.null(cl)){ 150 | if(typeof(cl) == "character"){ if(cl %in% names(par$plot.cl.ranges)) cl = par$plot.cl.ranges[[cl]] else stop(paste("given cl range", cl, "unknown!"))} 151 | if(length(cl) == 2) cl = seq(from = cl[1], to = cl[2]); 152 | plot.x = data[[set.cl.ref]]$cl$smoothed$x[round(mean(cl))] 153 | plot.y = data[[set.cl.ref]]$cl$smoothed$y[round(mean(cl))] 154 | plot.extent.rule = "cl point" 155 | } 156 | 157 | # by error in centerline generation 158 | if(!is.null(error)){ 159 | if(!is.null(data[[set]]$cl[[error.type]]) && !is.null(data[[set]]$cl$paths)){ 160 | plot.x = data[[set]]$cl[[error.type]][error,1] 161 | plot.y = data[[set]]$cl[[error.type]][error,2] 162 | plot.extent.rule = "centerline path errors" 163 | } else { print("not all data available to center at errors") } 164 | } 165 | 166 | # by x coordinate 167 | if(!is.null(x)){ 168 | plot.x = x; if(is.null(y)) plot.y = data[[set]]$cl$smoothed$y[which.min(abs(data[[set]]$cl$smoothed$x - x))] 169 | plot.extent.rule = "x-coordinate" 170 | } 171 | 172 | # by y coordinate 173 | if(!is.null(y)){ 174 | plot.y = y; if(is.null(x)) plot.x = data[[set]]$cl$smoothed$x[which.min(abs(data[[set]]$cl$smoothed$y - y))] 175 | plot.extent.rule = if(plot.extent.rule == "x-coordinate") "x/y-coordinates" else "y-coordinate" 176 | } 177 | 178 | 179 | ### determine extend 180 | x.lim = if(zoom) plot.x + c(-0.5 * zoom.length, + 0.5 * zoom.length) else range(data[[set]]$channel$x) 181 | y.lim = if(zoom) plot.y + c(-0.5 * zoom.length, + 0.5 * zoom.length) else range(data[[set]]$channel$y) 182 | 183 | 184 | 185 | # output to console 186 | notice(paste("plot extend determined by:", plot.extent.rule)) 187 | if(zoom) notice("to show full extend use CM.plotPlanView(cmgo.obj, zoom=FALSE)", TRUE) 188 | notice(paste("plot centered at x = ",plot.x, ", y = ", plot.y)) 189 | 190 | if(plot.extent.rule == "centerline path errors") notice(paste("selected error", error, "of available error span 1 to", nrow(data[[set]]$cl[[error.type]]))) 191 | leg = list() 192 | 193 | 194 | ### build set names ### 195 | name.set = if(par$plot.planview.use.names) data[[set]]$survey else set 196 | name.set.ref = if(set.ref != FALSE) {if(par$plot.planview.use.names) data[[set.ref]]$survey else set.ref} else "not used" 197 | name.set.secondary = if(!is.null(set.secondary)) {if(par$plot.planview.use.names) data[[set.secondary]]$survey else set.secondary} else "not used" 198 | 199 | 200 | 201 | 202 | ### create empty plot ### 203 | plot(0, 204 | main = if(is.null(title)){ paste("Plan view of", name.set, if(!is.null(set.compare)){ paste("(solid) and", if(is.null(set.compare)) "reference", name.set.secondary, "(dashed)")})} else {title}, 205 | xlim = x.lim, 206 | ylim = y.lim, 207 | asp=1, type="n", xlab="X", ylab="Y" 208 | ) 209 | 210 | # grid #################################################################### 211 | grid.dist = if(is.null(par$plot.planview.grid.dist)) signif(( (x.lim[2]- x.lim[1]) / 5),1) else par$plot.planview.grid.dist 212 | if(par$plot.planview.grid){ 213 | abline(v=seq(floor(floor(min(x.lim))/100)*100, ceiling(ceiling(max(x.lim))/100)*100, grid.dist), col=colors()[356]) 214 | abline(h=seq(floor(floor(min(y.lim))/100)*100, ceiling(ceiling(max(y.lim))/100)*100, grid.dist), col=colors()[356]) 215 | } 216 | 217 | # voronoi polygons ######################################################## 218 | if(par$plot.planview.voronoi){ 219 | #if(exists("voronoi")) for(tile in voronoi$tiles){ lines(tile$bdry[[1]], col="lightgray")} 220 | if(!is.null(data[[set]]$cl$paths)) {segments(data[[set]]$cl$paths$x1, data[[set]]$cl$paths$y1, data[[set]]$cl$paths$x2, data[[set]]$cl$paths$y2, col="lightgray"); leg = leg.add(leg, "voronoi polygons", lty=1, col="gray")} 221 | #if(!is.null(data[[set]]$cl$paths.in.polygon)){segments(data[[set]]$cl$paths.in.polygon$x1, data[[set]]$cl$paths.in.polygon$y1, data[[set]]$cl$paths.in.polygon$x2, data[[set]]$cl$paths.in.polygon$y2, col="red");leg = leg.add(leg, "paths in polygon", lty=1, col="red")} 222 | segments(data[[set]]$cl$cl.paths$x1, data[[set]]$cl$cl.paths$y1, data[[set]]$cl$cl.paths$x2, data[[set]]$cl$cl.paths$y2, col="black", lty=3,lwd=2); leg = leg.add(leg, "cl paths (filtered)", lty=3, lwd=2, col="black") 223 | } 224 | 225 | if(!is.null(error)){ 226 | if(!is.null(data[[set]]$cl$paths)) {segments(data[[set]]$cl$paths$x1, data[[set]]$cl$paths$y1, data[[set]]$cl$paths$x2, data[[set]]$cl$paths$y2, col="lightgray"); leg = leg.add(leg, "voronoi polygons", lty=1, col="gray")} 227 | if(!is.null(data[[set]]$cl$cl.paths)) {segments(data[[set]]$cl$cl.paths$x1, data[[set]]$cl$cl.paths$y1, data[[set]]$cl$cl.paths$x2, data[[set]]$cl$cl.paths$y2, col="red");leg = leg.add(leg, "cl paths during iteration", lty=1, col="red")} 228 | #segments(data[[set]]$cl$cl.paths$x1[ii], data[[set]]$cl$cl.paths$y1[ii], data[[set]]$cl$cl.paths$x2[ii], data[[set]]$cl$cl.paths$y2[ii], col="blue") 229 | } 230 | 231 | # second polygon for comparison 232 | if(!is.null(set.secondary) && set.secondary != set){ 233 | lines( data[[set.secondary]]$polygon$y ~ data[[set.secondary]]$polygon$x, lty=2, col="gray") 234 | leg = leg.add(leg, paste("banks of", name.set.secondary), lty=2, col="gray") 235 | } 236 | 237 | # tr = transects ########################################################## 238 | if(par$plot.planview.transects && !is.null(data[[set]]$metrics$tr)){ 239 | apply(data[[set]]$metrics$tr, 1, function(x){ 240 | m = x["m"]; a = ( ((par$plot.planview.transects.len)^2) / (1 + m^2) ) ^(1/2); xs = x["Px"] - a; ys = x["m"] * xs + x["n"]; xe = x["Px"] + a; ye = x["m"] * xe + x["n"] 241 | lines(c(xs,xe), c(ys, ye), lty=5, lwd=1.2, col="blue") 242 | }) 243 | leg = leg.add(leg, "transects", lty=5, lwd=1.2, col="blue") 244 | } 245 | 246 | # transects halfs ######################################################### 247 | if(par$plot.planview.dist2banks && !is.null(data[[set]]$metrics$tr) && !is.null(data[[set]]$metrics$cp.r) && !is.null(data[[set]]$metrics$cp.l)){ 248 | apply(cbind(data[[set]]$metrics$cp.r[,c(1,2)], data[[set]]$metrics$tr[,c(3,4)]), 1, function(x){ segments(x[1], x[2], x[3], x[4], col="green") }) 249 | apply(cbind(data[[set]]$metrics$cp.l[,c(1,2)], data[[set]]$metrics$tr[,c(3,4)]), 1, function(x){ segments(x[1], x[2], x[3], x[4], col="red") }) 250 | leg = leg.add(leg, paste("right bank of", name.set, "to reference of", data[[set]]$metrics$cl.ref), lty=1, col="green") 251 | leg = leg.add(leg, paste("left bank of", name.set, "to reference of", data[[set]]$metrics$cl.ref), lty=1, col="red") 252 | } 253 | 254 | # bank points ############################################################# 255 | if(par$plot.planview.bankpoints && !is.null(data[[set]]$channel$x)){ 256 | col.side = rep("black", length(data[[set]]$channel$x)) 257 | if(par$plot.planview.bankpoints.col){ 258 | col.side = rep("red", length(data[[set]]$channel$x)) 259 | col.side[which(data[[set]]$channel$bank == "right")] = "green" 260 | leg = leg.add(leg, paste("right bank points of", name.set), pch=19, col="green", cex=0.8) 261 | leg = leg.add(leg, paste("left bank points of", name.set), pch=19, col="red", cex=0.8) 262 | } else leg = leg.add(leg, paste("bank points of", name.set), pch=19, col="black", cex=0.8) 263 | points(data[[set]]$channel$y ~ data[[set]]$channel$x, pch=19, cex=0.8, col=col.side) 264 | } 265 | 266 | if(par$plot.planview.bankpoints.interpolated && !is.null(data[[set]]$polygon$x)){ 267 | points(data[[set]]$polygon$y ~ data[[set]]$polygon$x, pch=19, cex=0.5) 268 | } 269 | 270 | # channel bank polygon #################################################### 271 | if(par$plot.planview.polygon && !is.null(data[[set]]$polygon)){ 272 | lines(data[[set]]$polygon$y ~ data[[set]]$polygon$x, col="black") 273 | leg = leg.add(leg, paste("banks of", name.set), lty=1, col="black") 274 | } 275 | 276 | # centerline ############################################################## 277 | if(par$plot.planview.cl.original){ 278 | lines(data[[set]]$cl$original$y ~ data[[set]]$cl$original$x, col="red", lwd = 1.5) 279 | leg = leg.add(leg, paste("original centerline of", name.set, if(set==set.ref)"(reference)"), lty=1, lwd = 1, cex=0.4, col="red") 280 | } 281 | if(par$plot.planview.cl.smoothed && !is.null(data[[set]]$cl$smoothed)){ 282 | lines( data[[set]]$cl$smoothed$y ~ data[[set]]$cl$smoothed$x, col="blue",lwd = if(set==set.ref) 2.5 else 1) 283 | if(par$plot.planview.cl.points) points(data[[set]]$cl$smoothed$y ~ data[[set]]$cl$smoothed$x, cex=0.4, pch=19, col="blue") 284 | leg = leg.add(leg, paste("centerline of", name.set, if(set==set.ref)"(reference)"), lty=1, pch=19, lwd = if(set==set.ref) 2.5 else 1, cex=0.4, col="blue") 285 | 286 | # secondary 287 | if(!is.null(set.secondary) && set.secondary != set){ 288 | lines(data[[set.secondary]]$cl$smoothed$y ~ data[[set.secondary]]$cl$smoothed$x, lwd = if(set.secondary == set.ref) 2.5 else 1, col="blue") 289 | if(par$plot.planview.cl.points) points(data[[set.secondary]]$cl$smoothed$y ~ data[[set.secondary]]$cl$smoothed$x, cex=0.4, pch=19, col="blue") 290 | leg = leg.add(leg, paste("centerline of", name.set.secondary, if(set.secondary == set.ref) paste("(reference of ", name.set, ")", sep="")), pch=19, cex=0.4, lwd = if(set.secondary == set.ref) 2.5 else 1, col="blue", lty=1) 291 | } 292 | 293 | # numbering 294 | if(par$plot.planview.cl.tx){ 295 | for(i in c(1:length(data[[set]]$cl$smoothed$x))) text(data[[set]]$cl$smoothed$x[i], data[[set]]$cl$smoothed$y[i]-(par$plot.zoom.extent.length/100), i, cex=0.5) 296 | if(!is.null(set.secondary)) for(i in c(1:length(data[[set.secondary]]$cl$smoothed$x))) text(data[[set.secondary]]$cl$smoothed$x[i], data[[set.secondary]]$cl$smoothed$y[i]-(par$plot.zoom.extent.length/100), i, cex=0.5, col="gray") 297 | } 298 | 299 | } 300 | 301 | # cl range ################################################################ 302 | if(!is.null(cl) && par$plot.planview.cl.selection){ 303 | points(data[[set.cl.ref]]$cl$smoothed$x[cl], data[[set.cl.ref]]$cl$smoothed$y[cl], pch=19, col="red", cex=0.8) 304 | leg = leg.add(leg, "cl range selection", pch=19, col="red", cex=0.8) 305 | } 306 | 307 | # cl-binned ############################################################### 308 | if(par$plot.planview.cl.binned){ 309 | points(data[[set.cl.ref]]$cl$binned$x, data[[set.cl.ref]]$cl$binned$y, pch=18, col="blue", cex=2.2) 310 | #points(data[[set.cl.ref]]$cl$binned$bin_x, data[[set.cl.ref]]$cl$binned$bin_y, pch=18, col="blue", cex=2.2) 311 | leg = leg.add(leg, "re-binned centerline", pch=18, col="blue", cex=1.2) 312 | } 313 | 314 | # legend and scale bar #################################################### 315 | if(par$plot.planview.legend) leg.make(leg, par) 316 | if(par$plot.planview.scalebar){ 317 | 318 | bdry = par()$usr 319 | bar.len = signif((x.lim[2]-x.lim[1]) / 5,1) 320 | 321 | segments( 322 | bdry[2] - ((bdry[2]-bdry[1])*0.05) - bar.len, 323 | bdry[3] + ((bdry[4]-bdry[3])*0.05), 324 | bdry[2] - ((bdry[2]-bdry[1])*0.05), 325 | bdry[3] + ((bdry[4]-bdry[3])*0.05), 326 | lwd = 15, lend=2 327 | ) 328 | text( 329 | bdry[2] - ((bdry[2]-bdry[1])*0.05) - bar.len / 2, 330 | bdry[3] + ((bdry[4]-bdry[3])*0.1), 331 | paste(bar.len, par$input.units), 332 | cex=1.2 333 | 334 | ) 335 | 336 | } 337 | 338 | #} # for(plot in plots) 339 | 340 | plot.file(par) 341 | 342 | notice("plotting done!") 343 | 344 | return(list( 345 | x = plot.x, 346 | y = plot.y, 347 | set = set, 348 | cl = cl, 349 | zoom = zoom, 350 | zoom.length = if(zoom) zoom.length else NULL 351 | )) 352 | 353 | } -------------------------------------------------------------------------------- /R/CM.plotWidth.r: -------------------------------------------------------------------------------- 1 | #' Plot channel width 2 | #' 3 | #' Plot the channel width of the whole channel (default) or for a portion (use \code{cl} argument). The function can 4 | #' also compare two data sets if they have the same reference centerline. 5 | #' 6 | #' 7 | #' If more than one data set is defined in the global data object, of 8 | #' 9 | #' Details 10 | #' 11 | #' @template param_global_data_object 12 | #' @param set the primary data set to plot ("set1" by default) 13 | #' @param set.compare the secondary data set to plot (optional) 14 | #' @param cl the range of centerline points to be plotted, if NULL (default) the full channel length will be plotted, if 15 | #' a vector of two elements is provided (e.g. c(200, 500)) this cl range is plotted, if a string is provided (e.g. "cl1"), 16 | #' the range defined in \code{par$plot.cl.ranges$cl1} will be plotted 17 | #' @param d the distance range of the centerline downstream to be plotted, NULL (default) cl defintions are taken, if a 18 | #' single value (e.g. d=500) is given 50m around this distance is plotted, if a vector with two elements is given (e.g. 19 | #' c(280, 620)) this distance range will be plotted 20 | #' @return desc 21 | #' @author Antonius Golly 22 | #' @examples 23 | #' 24 | #' # open demo 25 | #' cmgo.obj = CM.ini("demo2") 26 | #' 27 | #' # example 1: plot channel width of whole channel 28 | #' CM.plotWidth(cmgo.obj) 29 | #' 30 | #' # example 2: plot channel width of a defined range (centerline points) 31 | #' CM.plotWidth(cmgo.obj, cl=c(800, 1000)) 32 | #' 33 | #' # example 2: plot channel width of a defined range (distance downstream) 34 | #' CM.plotWidth(cmgo.obj, d=c(200, 600)) 35 | #' 36 | #' @export CM.plotWidth 37 | 38 | CM.plotWidth <- function(cmgo.obj, set="set1", set.compare=NULL, cl=NULL, d=NULL){ 39 | 40 | par = cmgo.obj$par 41 | data = cmgo.obj$data 42 | 43 | notice = function(x,prim=FALSE){cat(paste((if(prim) "\n--> " else " "), x, sep=""), sep="\n")} 44 | error = function(x){stop(x, call.=FALSE)} 45 | alert = function(x, y=""){if(y!=""){message(paste("--> ",x, y, sep=""))}else{message(paste("--> ", x, sep=""))}} 46 | warn = function(x){warning(x, call.=FALSE)} 47 | plot.file = function(par){if(!par$plot.to.file) return(NULL); file.no = 0 + par$plot.index; file.name = paste(par$plot.directory, str_pad(file.no, 3, pad="0"), "_", par$plot.filename, sep=""); while(file.exists(paste(file.name, ".png", sep="")) || file.exists(paste(file.name, ".pdf", sep=""))){ file.no = file.no + 1; file.name = paste(par$plot.directory, str_pad(file.no, 3, pad="0"), "_", par$plot.filename, sep="") }; dev.copy(png, filename=paste(file.name, ".png", sep=""), width=800, height=600); dev.off(); dev.copy2pdf(file=paste(file.name, ".pdf", sep=""));} 48 | 49 | plot_secondary = FALSE 50 | 51 | leg.add = function(leg, tx, item=NULL, lwd=1, lty=NA, pch=NA, cex=1, col="black"){ 52 | 53 | item = if(is.null(item)) paste("item_", length(leg)+1, sep="") else item 54 | 55 | leg[[item]] = list( 56 | tx = tx, 57 | lwd = lwd, 58 | lty = lty, 59 | pch = pch, 60 | cex = cex, 61 | col = col 62 | ) 63 | 64 | return(leg) 65 | 66 | } 67 | 68 | leg.make = function(leg){ 69 | 70 | tx = type = lwd = lty = pch = cex = col = c() 71 | 72 | 73 | for(item in c(1:length(leg))){ 74 | tx = append(tx, leg[[item]]$tx) 75 | lwd = append(lwd, leg[[item]]$lwd) 76 | lty = append(lty, leg[[item]]$lty) 77 | pch = append(pch, leg[[item]]$pch) 78 | cex = append(cex, leg[[item]]$cex) 79 | col = append(col, leg[[item]]$col) 80 | } 81 | 82 | leg.vec = function(x) return(if(length(unique(x))==1) x[1] else x) 83 | 84 | legend("topleft", inset=0.05, 85 | legend = leg.vec(tx), 86 | lwd = leg.vec(lwd), 87 | lty = leg.vec(lty), 88 | pch = leg.vec(pch), 89 | pt.cex = leg.vec(cex), 90 | col = leg.vec(col) 91 | ) 92 | } 93 | 94 | #dev.new(width=12, height=10) 95 | notice("create channel width plot...", TRUE) 96 | 97 | plots = c(1) 98 | par(mfcol=c(1,length(plots))) 99 | 100 | for(plot in plots){ 101 | 102 | ### get reference centerline 103 | #set.ref = data[[set]]$metrics$cl.ref 104 | #set.secondary = if(is.null(set.compare)) set.ref else set.compare 105 | 106 | ### define cl range 107 | if(is.null(cl)) cl = seq(along=data[[set]]$cl$smoothed$x) 108 | if(typeof(cl) == "character"){ if(cl %in% names(par$plot.cl.ranges)) cl = par$plot.cl.ranges[[cl]] else stop(paste("given cl range", cl, "unknown!"))} 109 | if(length(cl) == 1) cl = c(cl, cl + 50) 110 | if(length(cl) == 2) cl = seq(from = cl[1], to = cl[2]); 111 | 112 | if(!is.null(d)){ 113 | if(length(d) == 1) d = c(d-25, d+25) 114 | if(d[1] < 0 ) d[1] = 0; if(d[2] > tail(data[[set]]$cl$smoothed$cum_dist_2d, n=1)) d[2] = tail(data[[set]]$cl$smoothed$cum_dist_2d, n=1) 115 | if(length(d) == 2) d = seq(from = d[1], to = d[2]) 116 | cl = seq( 117 | from = which.min(abs(data[[set]]$cl$smoothed$cum_dist_2d - d[1])), 118 | to = which.min(abs(data[[set]]$cl$smoothed$cum_dist_2d - d[length(d)])) 119 | ) 120 | notice(paste("d range: distance", d[1], "to", d[length(d)])) 121 | } 122 | 123 | notice(paste("cl range: index", cl[1], "to", cl[length(cl)])) 124 | notice(paste("plot ", set, " (reference ", data[[set]]$metrics$cl.ref, ")", sep="")) 125 | 126 | 127 | leg = list() 128 | 129 | y.lim = range(data[[set]]$metrics$w[cl], na.rm=TRUE) 130 | if(!is.null(set.compare)) y.lim = range(data[[set]]$metrics$w[cl],data[[set.compare]]$metrics$w[cl]) 131 | 132 | plot( 133 | 0, 134 | main = paste("Channel width of", set, if(!is.null(set.compare)) paste("(solid) and", set.compare, " (dashed)") else ""), 135 | ylim = y.lim, 136 | xlim = c(data[[set]]$cl$smoothed$cum_dist_2d[cl[1]],data[[set]]$cl$smoothed$cum_dist_2d[cl[length(cl)]]), 137 | xlab = paste("Distance upstream [", par$input.unit, "]", sep=""), 138 | ylab = paste("Width [", par$input.unit, "]", sep=""), 139 | type = "n" 140 | ) 141 | 142 | ## channel width main set 143 | lines(data[[set]]$metrics$w ~ data[[set]]$cl$smoothed$cum_dist_2d, col = "blue", lty=1, lwd=2) 144 | leg = leg.add(leg, paste("channel width of", set), col = "blue", lty=1, lwd=2) 145 | 146 | ## channel width compare set 147 | if(!is.null(set.compare)){ 148 | lines(data[[set.compare]]$metrics$w ~ data[[set.compare]]$cl$smoothed$cum_dist_2d, col = "green", lty=1, lwd=2) 149 | leg = leg.add(leg, paste("channel width of", set.compare), col = "green", lty=1, lwd=2) 150 | 151 | notice(paste("added ", set.compare, " (reference ", data[[set.compare]]$metrics$cl.ref, ") for comparison", sep="")) 152 | 153 | if(data[[set.compare]]$metrics$cl.ref == data[[set]]$metrics$cl.ref){ 154 | 155 | } 156 | 157 | 158 | } 159 | 160 | 161 | # legend and scale bar #################################################### 162 | if(par$plot.planview.legend) leg.make(leg) 163 | 164 | } # for(plot in plots) 165 | 166 | plot.file(par) 167 | 168 | notice("plotting done!", TRUE) 169 | 170 | } 171 | -------------------------------------------------------------------------------- /R/CM.resampleCenterline.r: -------------------------------------------------------------------------------- 1 | #' Resample centerline points 2 | #' 3 | #' Create an equally spaced centerline with a given interval length. 4 | #' 5 | #' The spatial resolution of the centerline depends on the spatial resolution of the bank points which is 6 | #' directly dependent on the parameter par$polygon.bank.interpolate.max.dist. A small interpolation distance is necessary for complex 7 | #' bed shapes. However, for further metric analyes a large number of centerline points is not necessary. Since they can introduce 8 | #' high computational costs during further calculation you can resample the centerline intervals with this function CM.resampleCenterline(). 9 | #' decreasing the resolution to a given value. This will have slight impact on the length of the centerline. Since you are losing 10 | #' detail a coarser interval will decrease the length of the centerline. 11 | #' 12 | #' @template param_global_data_object 13 | #' @template param_set 14 | #' @return the global data object 15 | #' @author Antonius Golly 16 | #' @examples 17 | #' 18 | #' # get the demo data set 19 | #' cmgo.obj = CM.ini("demo2") 20 | #' 21 | #' # resample centerline resolution 22 | #' cmgo.obj = CM.resampleCenterline(cmgo.obj) 23 | #' 24 | #' @export CM.resampleCenterline 25 | 26 | CM.resampleCenterline <- function(cmgo.obj, set = NULL){ 27 | 28 | par = cmgo.obj$par 29 | data = cmgo.obj$data 30 | sets = if(is.null(set)) names(data) else set 31 | 32 | notice = function(x,prim=FALSE){cat(paste((if(prim) "\n--> " else " "), x, sep=""), sep="\n")} 33 | error = function(x){stop(x, call.=FALSE)} 34 | alert = function(x, y=""){if(y!=""){message(paste("--> ",x, y, sep=""))}else{message(paste("--> ", x, sep=""))}} 35 | warn = function(x){warning(x, call.=FALSE)} 36 | plot.file = function(par){if(!par$plot.to.file) return(NULL); file.no = 0 + par$plot.index; file.name = paste(par$plot.directory, str_pad(file.no, 3, pad="0"), "_", par$plot.filename, sep=""); while(file.exists(paste(file.name, ".png", sep="")) || file.exists(paste(file.name, ".pdf", sep=""))){ file.no = file.no + 1; file.name = paste(par$plot.directory, str_pad(file.no, 3, pad="0"), "_", par$plot.filename, sep="") }; dev.copy(png, filename=paste(file.name, ".png", sep=""), width=800, height=600); dev.off(); dev.copy2pdf(file=paste(file.name, ".pdf", sep=""));} 37 | resample = function(polyline, interval_length = 20, add_original_points = FALSE, add_final_point = FALSE) { 38 | 39 | # The function splits a polyline into segments of a given length. 40 | # polyline: a spatial polyline data frame 41 | # interval_length: the length of the segments to split the lines into, in units of the polyline coordinates 42 | # add_original_points: whether or not the original points of the polyline should be added to the resulting line 43 | # if set FALSE, the resulting line will be shorter 44 | # add_final_point: whether or not the final point of the polyline should be added to the resulting line 45 | 46 | # transform input polyline 47 | linedf = data.frame( 48 | x = polyline$x[1:nrow(polyline)-1], 49 | y = polyline$y[1:nrow(polyline)-1], 50 | x2 = polyline$x[2:nrow(polyline)], 51 | y2 = polyline$y[2:nrow(polyline)] 52 | ) 53 | 54 | # prepare output 55 | df = data.frame( 56 | x = numeric(), 57 | y = numeric() 58 | ) 59 | 60 | residual_seg_length = 0 61 | for (i in 1:nrow(linedf)) { 62 | 63 | # for each line of the dataframe calculate segment length 64 | v_seg = linedf[i, ] 65 | seg_length = sqrt((v_seg$x - v_seg$x2) ^ 2 + (v_seg$y - v_seg$y2) ^ 2) 66 | 67 | # create a vector of direction for the segment 68 | v = c(v_seg$x2 - v_seg$x, v_seg$y2 - v_seg$y) 69 | 70 | # unit length 71 | u = c(v[1] / sqrt(v[1] ^ 2 + v[2] ^ 2), v[2] / sqrt(v[1] ^ 2 + v[2] ^ 2)) 72 | 73 | # calculate number of segment the segment is split into 74 | num_seg = floor((seg_length - residual_seg_length) / interval_length) 75 | 76 | # skip if next vertex is before interval_length 77 | if(num_seg >= 0) { 78 | 79 | # add interpolated segments 80 | for (i in 0:(num_seg)) { 81 | df[nrow(df) + 1,] = c( 82 | v_seg$x + u[1] * residual_seg_length + u[1] * interval_length * i , 83 | v_seg$y + u[2] * residual_seg_length + u[2] * interval_length * i 84 | ) 85 | } 86 | 87 | # add original point (optional) 88 | if(add_original_points){ 89 | df[nrow(df) + 1,] = c( 90 | v_seg$x2, 91 | v_seg$y2 92 | ) 93 | } 94 | 95 | } else { 96 | 97 | # add original point (optional) 98 | if(add_original_points){ 99 | df[nrow(df) + 1,] = c( 100 | v_seg$x2, 101 | v_seg$y2 102 | ) 103 | } 104 | 105 | residual_seg_length = residual_seg_length - seg_length 106 | next() 107 | 108 | } 109 | 110 | # calculate residual segment length 111 | residual_seg_length = interval_length - ((seg_length - residual_seg_length) - (num_seg * interval_length)) 112 | 113 | } 114 | 115 | # add final point (optional) 116 | if(add_final_point){ 117 | df = rbind(df, data.frame( 118 | x = tail(polyline$x, n=1), 119 | y = tail(polyline$y, n=1) 120 | )) 121 | } 122 | 123 | return(df) 124 | 125 | } 126 | 127 | cl.type = "smoothed" 128 | set = "set1" 129 | 130 | for(set in sets){ 131 | 132 | notice(paste("resample centerline of", set), TRUE) 133 | 134 | ixs = length(data[[set]]$cl$smoothed$cum_dist_2d) 135 | l = data[[set]]$cl$smoothed$cum_dist_2d[ixs] 136 | 137 | notice(paste("current average spacing: ", round(l/ixs, digits=3), par$input.unit)) 138 | notice(paste("intended spacing:", par$centerline.bin.length, par$input.unit)) 139 | 140 | if( par$centerline.bin.length < (round(l/ixs, digits=3))) error("intended spacing of resampled centerline must be larger than current average spacing") 141 | 142 | # re-bin centerline 143 | cl.rebinned = resample(data[[set]]$cl[[cl.type]][c("x","y")], par$centerline.bin.length) 144 | cum_dist = seq(from = 0, to = floor(max(data[[set]]$cl[[cl.type]]$cum_dist_2d)), by = par$centerline.bin.length) 145 | bin_metrics = do.call(rbind, apply(as.array(cum_dist), 1, function(x){ 146 | 147 | # determine closest index and index ranges 148 | ix = which.min(abs(data[[set]]$cl[[cl.type]]$cum_dist_2d - x)) 149 | bin_ix = which((data[[set]]$cl[[cl.type]]$cum_dist_2d > (x - par$centerline.bin.length/2)) & (data[[set]]$cl[[cl.type]]$cum_dist_2d < (x + par$centerline.bin.length/2))) 150 | 151 | if(length(bin_ix) == 0){ 152 | bin_ix = which.min(abs(data[[set]]$cl$smoothed$cum_dist_2d - x)) 153 | notice(paste("no points in bin ", x, "! take nearest point...", sep="")) 154 | } 155 | 156 | df = data.frame( 157 | 158 | bin_x = mean(data[[set]]$cl[[cl.type]]$x[bin_ix]), 159 | bin_y = mean(data[[set]]$cl[[cl.type]]$y[bin_ix]), 160 | bin_z = if(is.null(data[[set]]$channel$z)) NA else mean(data[[set]]$cl$original$z[bin_ix]), 161 | 162 | # widths 163 | width_median = median(data[[set]]$metrics$w[bin_ix]), 164 | width_mean = mean(data[[set]]$metrics$w[bin_ix]), 165 | width_closest = data[[set]]$metrics$w[ix] 166 | 167 | ) 168 | 169 | for(slope in par$centerline.local.slope.range){ 170 | 171 | df[[paste("slope_median_", slope, sep="")]] = if(is.null(data[[set]]$channel$z)) NA else median(data[[set]]$cl$smoothed[[paste("slope_avg_", slope, sep="")]][bin_ix]) 172 | df[[paste("slope_mean_", slope, sep="")]] = if(is.null(data[[set]]$channel$z)) NA else mean(data[[set]]$cl$smoothed[[paste("slope_avg_", slope, sep="")]][bin_ix]) 173 | df[[paste("slope_closest_", slope, sep="")]] = if(is.null(data[[set]]$channel$z)) NA else mean(data[[set]]$cl$smoothed[[paste("slope_avg_", slope, sep="")]][ix]) 174 | 175 | } 176 | 177 | return(df) 178 | 179 | })) 180 | 181 | # store 182 | data[[set]]$cl$binned = cbind(cl.rebinned, bin_metrics) # x and y coordinates 183 | data[[set]]$cl$binned$cum_dist_2d = cum_dist 184 | data[[set]]$cl$binned$bin.length = par$centerline.bin.length 185 | 186 | notice(paste("re-binning centerline of", set, "done!"), TRUE) 187 | 188 | } 189 | 190 | notice("CM.resampleCenterline() has ended successfully!", TRUE) 191 | 192 | # return 193 | return(list( 194 | data = data, 195 | par = par 196 | )) 197 | 198 | } 199 | -------------------------------------------------------------------------------- /R/CM.run.r: -------------------------------------------------------------------------------- 1 | #' Run the full stack of the main cmgo functions 2 | #' 3 | #' This function is a wrapper function for the main functions of the package \code{cmgo}. With no parameters 4 | #' passed, it initializes the global data object containing the demo data set and the default parameters. 5 | #' It returns the global data object - as all main function do - which can be used for further execution 6 | #' of the program. If your global data object already exists, you can pass this to \code{CM.run()} to execute 7 | #' all main functions at once. Alternatively, you can call \code{CM.run()} with a parameter object or a file 8 | #' name of a parameter configuration (see \code{\link[=CM.par]{CM.par()}} for further information.) 9 | #' 10 | #' CM.run represents a wrapper function of the main \code{cmgo} functions with the following code: 11 | #' \preformatted{ 12 | #' CM.ini() 13 | #' CM.generatePolygon() 14 | #' CM.calculateCenterline() 15 | #' CM.processCenterline() 16 | #' CM.writeData() 17 | #' CM.plotPlanView() 18 | #' } 19 | #' 20 | #' You can use \code{CM.run()} either for demo purposes (just call CM.run() without parameters) or to start 21 | #' a new project from scratch. To do this, make sure you have read about the input data preparation in the 22 | #' documentation of \code{\link[=CM.ini]{CM.ini()}}. If you are familiar with the input data preparation 23 | #' just call CM.run() while you place your valid input files to the specified input directory (defaults to \code{"./input"}). 24 | #' 25 | #' @param object Possible values include \code{NULL} and the global data object. 26 | #' @param par Possible values include \code{NULL}, filename or list of parameters. If \code{par} is not specified or 27 | #' NULL the default parameters are used (see documentation of CM.par() to learn about the default parameters). If \code{par} 28 | #' is a filename CM.ini() will try to open that file and look for a list \code{par} in that file. In case of success the parameters 29 | #' from that file are loaded and merged with the default parameters. Merging means, not all parameters have to be defined in the parameter 30 | #' file. Parameters that are not defined are taken from the default. In case \code{par} is a list, the default parameters are merged with this 31 | #' list. That means, if the actual parameters are handed over to CM.ini() - e.g. \code{global_data_object$par} - the parameters will be passed 32 | #' through. 33 | #' @return The global data object containing data ($data) and parameters ($par). The global data object must be passed to all main functions of \code{cmgo}. 34 | #' @author Antonius Golly 35 | #' @examples 36 | #' 37 | #' # example 1: open with demo data and default parameters 38 | #' cmgo.obj = CM.run() 39 | #' 40 | #' # example 2: re-create global data object with updated parameters 41 | #' #parameter_file = "par/new_config.r" # specify an existing parameter file 42 | #' parameter_file = NULL 43 | #' cmgo.obj = CM.run(cmgo.obj, parameter_file) 44 | #' 45 | #' @export CM.run 46 | CM.run <- function(object = NULL, par = NULL){ 47 | 48 | #par = if(is.null(par)) object$par else CM.par(par) 49 | #data = object$data 50 | 51 | 52 | ### define parameters 53 | par = CM.par(par) 54 | 55 | 56 | ### get data 57 | cmgo.obj = CM.ini(object, par) 58 | 59 | 60 | ### generate polygon 61 | cmgo.obj = CM.generatePolygon(cmgo.obj) 62 | 63 | 64 | ### get centerline (calculate or load) 65 | cmgo.obj = CM.calculateCenterline(cmgo.obj) 66 | 67 | 68 | ### process centerline (calculate width) 69 | cmgo.obj = CM.processCenterline(cmgo.obj) 70 | 71 | 72 | ### write data to workspace and export data to csv-files (see par) 73 | CM.writeData(cmgo.obj) 74 | 75 | 76 | ### plot plan view 77 | plot.par = CM.plotPlanView(cmgo.obj, "set1", cl="cl1") 78 | 79 | cat("\n--> ChannelMetrics ended successfully!\n") 80 | 81 | return(cmgo.obj) 82 | 83 | } 84 | 85 | -------------------------------------------------------------------------------- /R/CM.writeData.r: -------------------------------------------------------------------------------- 1 | #' Write data 2 | #' 3 | #' Write output files with channel metrics and the current workspace. 4 | #' 5 | #' \code{CM.writeData()} allows you to write the results to output files and to an R workspace file. 6 | #' The outputs written depend on the settings in the parameter object. If \code{cmgo.obj$par$workspace.write = TRUE} 7 | #' (default is FALSE) a workspace file is written containing the global data object. The 8 | #' filename is defined in \code{cmgo.obj$par$workspace.filename}. Further, ASCII tables can be written 9 | #' containing the centerline geometry and the calculated metrics. If \code{cmgo.obj$par$output.write = TRUE} 10 | #' (default is FALSE) an output file for each data set is written to the output folder specified 11 | #' in \code{cmgo.obj$par$output.dir}. The file names are the same as the input filenames with the 12 | #' prefixes cl_* and metrics_*. All parameters regarding the output generation are listed in \code{\link[=CM.par]{CM.par()}}. 13 | #' 14 | #' @template param_global_data_object 15 | #' @return This file function does not return any value. 16 | #' @author Antonius Golly 17 | #' @examples 18 | #' # get demo data (find instructions on how to use own data in the documentation of CM.ini()) 19 | #' cmgo.obj = CM.ini("demo2") 20 | #' 21 | #' # example 1: write workspace 22 | #' cmgo.obj$par$workspace.write = TRUE 23 | #' CM.writeData(cmgo.obj) 24 | #' 25 | #' # example 2: write output files 26 | #' cmgo.obj$par$output.write = TRUE 27 | #' cmgo.obj$par$output.write.centerline = TRUE 28 | #' cmgo.obj$par$output.write.metrics = TRUE 29 | #' cmgo.obj$par$output.dir = "custom_output_folder" 30 | #' cmgo.obj$par$workspace.write = FALSE 31 | #' 32 | #' CM.writeData(cmgo.obj) 33 | #' 34 | #' @export CM.writeData 35 | 36 | CM.writeData <- function(cmgo.obj){ 37 | 38 | par = cmgo.obj$par 39 | data = cmgo.obj$data 40 | 41 | notice = function(x,prim=FALSE){cat(paste((if(prim) "\n--> " else " "), x, sep=""), sep="\n")} 42 | error = function(x){stop(x, call.=FALSE)} 43 | alert = function(x, y=""){if(y!=""){message(paste("--> ",x, y, sep=""))}else{message(paste("--> ", x, sep=""))}} 44 | warn = function(x){warning(x, call.=FALSE)} 45 | plot.file = function(par){if(!par$plot.to.file) return(NULL); file.no = 0 + par$plot.index; file.name = paste(par$plot.directory, str_pad(file.no, 3, pad="0"), "_", par$plot.filename, sep=""); while(file.exists(paste(file.name, ".png", sep="")) || file.exists(paste(file.name, ".pdf", sep=""))){ file.no = file.no + 1; file.name = paste(par$plot.directory, str_pad(file.no, 3, pad="0"), "_", par$plot.filename, sep="") }; dev.copy(png, filename=paste(file.name, ".png", sep=""), width=800, height=600); dev.off(); dev.copy2pdf(file=paste(file.name, ".pdf", sep=""));} 46 | 47 | notice("write output files...", TRUE) 48 | 49 | 50 | 51 | ## write workspace data ############################################ 52 | 53 | if(par$workspace.write){ 54 | 55 | if(!file.exists(par$workspace.filename) || par$workspace.replace){ 56 | 57 | notice("write workspace now...") 58 | 59 | save("cmgo.obj", file = par$workspace.filename) 60 | notice(paste("workspace saved to",par$workspace.filename)) 61 | 62 | } else { 63 | 64 | notice("workspace not written since it exists") 65 | 66 | } 67 | 68 | } else { notice("write workspace: disabled") } 69 | 70 | #################################################################### 71 | 72 | 73 | ## write centerline data ########################################### 74 | 75 | if(par$output.write.centerline){ 76 | 77 | if(!file.exists(par$output.dir)) dir.create(par$output.dir) 78 | 79 | for(set in names(data)){ 80 | 81 | output.filename = paste(par$output.dir, "/cl_", data[[set]]$filename, sep="") 82 | 83 | notice(paste("write centerline of", set, "to", output.filename)) 84 | 85 | output = data.frame( 86 | centerline_x = data[[set]]$cl$smoothed$x, 87 | centerline_y = data[[set]]$cl$smoothed$y, 88 | centerline_z = if(is.null(data[[set]]$cl$smoothed$z)) rep(NA, length(data[[set]]$cl$smoothed$x)) else data[[set]]$cl$smoothed$z, 89 | length = data[[set]]$cl$smoothed$cum_dist_2d, 90 | seg_length = data[[set]]$cl$smoothed$seg_dist_2d 91 | ) 92 | 93 | write.table( 94 | output, 95 | file = output.filename, sep = par$output.sep, 96 | row.names = FALSE 97 | ) 98 | 99 | } 100 | 101 | } else { # if(par$output.write.centerline) 102 | 103 | notice("write centerline geometry: disabled") 104 | 105 | } # if(par$output.write.centerline) {} else 106 | 107 | #################################################################### 108 | 109 | 110 | ## write channel metrics ########################################### 111 | 112 | if(par$output.write.metrics){ 113 | 114 | if(!file.exists(par$output.dir)) dir.create(par$output.dir) 115 | 116 | for(set in names(data)){ 117 | 118 | output.filename = paste(par$output.dir, "/metrics_", data[[set]]$filename, sep="") 119 | 120 | if(!file.exists(output.filename) || par$output.replace){ 121 | 122 | notice(paste("write metrics of ", set, " to ", output.filename, "...", sep="")) 123 | 124 | output = data[[set]]$metrics 125 | 126 | # keep standard fields 127 | output = output[which(names(output) %in% c( 128 | "w", "d.r", "d.l", "r.r", "r.l", "diff.r", "diff.l" 129 | ))] 130 | 131 | # add centerline information: location and cumulative length of centerline points 132 | output = cbind(data.frame( 133 | x = data[[set]]$cl$smoothed$x, 134 | y = data[[set]]$cl$smoothed$y, 135 | cum_dist_2d = data[[set]]$cl$smoothed$cum_dist_2d 136 | ), output, stringsAsFactors = FALSE) 137 | 138 | 139 | # write output 140 | write.table( 141 | output, 142 | file = output.filename, sep = par$output.sep, 143 | row.names = FALSE 144 | ) 145 | 146 | } else { 147 | 148 | notice("metrics not written since it exists") 149 | 150 | } 151 | 152 | } # for(set in names(data)) 153 | 154 | } else { # if(par$output.write.metrics) 155 | 156 | notice("write metric files: disabled") 157 | 158 | } # if(par$output.write.metrics) {} else 159 | 160 | #################################################################### 161 | 162 | 163 | ## write steps data ################################################ 164 | 165 | if(par$output.write.steps){ 166 | 167 | if(!file.exists(par$output.dir)) dir.create(par$output.dir) 168 | 169 | for(set in names(data)){ 170 | 171 | output.filename = paste(par$output.dir, "/steps_", data[[set]]$filename, sep="") 172 | 173 | if(!file.exists(output.filename) || par$output.replace){ 174 | 175 | notice(paste("write steps table of ", set, " to ", output.filename, "...", sep="")) 176 | 177 | output = data[[set]]$steps 178 | 179 | # keep standard fields 180 | output = output[which(names(output) %in% c( 181 | "id", "ix", 182 | "start.of.step.x", "start.of.step.y", "start.of.step.z", "start.of.step.d", 183 | "pool.start.x", "pool.start.y", "pool.start.z", "pool.start.d", 184 | "pool.end.x", "pool.end.y", "pool.end.z", "pool.end.d", 185 | "pool.depth.x", "pool.depth.y", "pool.depth.z", "pool.depth.d", 186 | "pool.length", "step.height", "pool.depth.r" 187 | ))] 188 | 189 | write.table( 190 | output, 191 | file = output.filename, sep = par$output.sep, 192 | row.names = FALSE 193 | ) 194 | 195 | } else { 196 | 197 | notice("step data not written since it exists") 198 | 199 | } 200 | 201 | } # for(set in names(data)) 202 | 203 | } else { # if(par$output.write.metrics) 204 | 205 | notice("write step data files: disabled") 206 | 207 | } # if(par$output.write.metrics) {} else 208 | 209 | #################################################################### 210 | 211 | 212 | 213 | 214 | #################################################################### 215 | 216 | notice("CM.writeData() has ended successfully!", TRUE) 217 | 218 | } 219 | -------------------------------------------------------------------------------- /R/cmgo-package.r: -------------------------------------------------------------------------------- 1 | #' Deriving basic channel metrics from bank and long-profile geometry 2 | #' 3 | #' Principle channel metrics, as for example \strong{channel width or gradient}, 4 | #' convey immanent information that can be exploited for geomorphic research. 5 | #' For example, a snap-shot of the current local channel geometry can provide 6 | #' an integrated picture of the processes leading to its formation, if examined 7 | #' in a statistically sound manner. Repeated surveys, 8 | #' as time-series of channel gradients, can reveal local erosional characteristics 9 | #' that sharpen our understanding of the underlying processes and facilitate, 10 | #' inspire and motivate further research. However, these geometrical metrics 11 | #' are not directly available. Typically, the measurable quantities are limited 12 | #' to the position of features, such as the channel banks (or water surface) or 13 | #' the water flow path (thalweg) in two- or three-dimensional coordinates. This package 14 | #' derives with a scale-free approach principle 15 | #' channel metrics, as channel width and slope. It does that by first generating a 16 | #' reference line in the middle of the channel (centerline) based on which then the 17 | #' channel width is calculated. It also allows for analyzing the evolution of channel 18 | #' metrics over time if multiple surveys are provided. Furthermore, secondary spatial information (as for example the 19 | #' occurrence of knickpoints, the abundance of certain species, etc.) can be projected 20 | #' to the reference line allowing for a spatial correlation of different variables. 21 | #' 22 | #' @template section_getting_started 23 | #' 24 | #' @template section_global_data_object 25 | #' @section General information on the global data object: 26 | #' The global data object is \strong{initialized} with \code{cmgo.obj = CM.ini()} where 27 | #' \code{\link[=CM.ini]{CM.ini()}} will either create the object from input files, from a previously 28 | #' saved user workspace or from a demo data set. See the documentation of \code{\link[=CM.ini]{CM.ini()}} 29 | #' for detailed information on how to create the object. 30 | #' 31 | #' @template section_parameters 32 | #' @section Parameters: 33 | #' See the documentation of \code{\link[=CM.par]{CM.par()}} for detailed information on how to load parameters. 34 | #' 35 | #' @template section_work_flow 36 | #' 37 | #' @template section_run_cmgo 38 | #' 39 | #' @template section_time_series 40 | #' 41 | #' @template section_technical_fails 42 | #' 43 | #' @docType package 44 | #' @name cmgo 45 | #' @importFrom grDevices colors dev.copy dev.copy2pdf dev.off graphics.off png 46 | #' @importFrom graphics abline legend lines plot points segments text 47 | #' @importFrom stats lm median princomp 48 | #' @importFrom utils data head modifyList read.table tail write.table str packageVersion 49 | #' @importFrom stringr str_pad 50 | #' @importFrom spatstat.geom dirichlet ppp psp owin nncross 51 | #' @importFrom sp point.in.polygon 52 | #' @importFrom zoo rollapply 53 | #' @importFrom rgl clear3d plot3d abclines3d segments3d points3d 54 | #' @importFrom shapefiles convert.to.shapefile write.shapefile 55 | NULL 56 | -------------------------------------------------------------------------------- /R/demo.r: -------------------------------------------------------------------------------- 1 | #' Raw input demo data set to run the full stack of cmgo functions. 2 | #' Contains a list with sublists $par and $data. 3 | "demo" 4 | -------------------------------------------------------------------------------- /R/demo1.r: -------------------------------------------------------------------------------- 1 | #' Half processed demo data set to run test centerline processing of cmgo. The data set already contains a centerline. 2 | #' Contains a list with sublists $par and $data. 3 | "demo1" 4 | -------------------------------------------------------------------------------- /R/demo2.r: -------------------------------------------------------------------------------- 1 | #' Fully processed demo data set to run test the output and plotting functions of cmgo. 2 | #' Contains a list with sublists $par and $data. 3 | "demo2" 4 | -------------------------------------------------------------------------------- /R/demo3.r: -------------------------------------------------------------------------------- 1 | #' Fully processed demo data set to run test the output and plotting functions of cmgo. 2 | #' In contrast to demo data set 2 this data set uses the reference centerline mode. 3 | #' Contains a list with sublists $par and $data. 4 | "demo3" 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cmgo 2 | Deriving principle **c**hannel **m**etrics from bank and long-profile geometry with the R-package cmgo. 3 | 4 | ![Workflow](https://raw.githubusercontent.com/AntoniusGolly/cmgo/master/man/figures/01-processing.png) 5 | Figure 1: visualization of the work flow of the package, a) the channel bank points that represent the data input, b) a polygon is generated where bank points are linearly interpolated, c-e) the centerline is calculated via Voronoi polygons, f) transects are calculated, g) the channel width is derived from the transects. 6 | 7 | ## What is cmgo? 8 | 9 | **cmgo** performs geometrical calculations on your channel bank points (Fig. 1.a), which represent your basic input. The calculated geometry includes the centerline (Fig. 1.e) of one or multiple given channel shapes, channel length, local and average channel width, local and average slope, local and average bank retreat, or the distances from the centerline to the banks respectively, as well as allows to project additional spatial metrics to the centerline. 10 | 11 | ## Motivation 12 | 13 | Computer-aided products for studying rivers have a long tradition and numerous efforts exist to derive principle channel metrics from remote or in-situ measurements of channel banks. In [Golly et al. 2017b](http://www.earth-surf-dynam-discuss.net/esurf-2017-32/) we compare numerous tools for analyzing river geometry and conclude that *cmgo* adds a unique value to the available approaches by providing a tool for objectively deriving channel metrics, while being easy and free to use and modify and allowing a high degree of parametrization and fine-tuning. 14 | 15 | ## License / Citation 16 | 17 | The program is free to use, modify and redistribute under the terms of the GNU General Public License version 3 as published by the Free Software Foundation. If you make use of the work, please cite the work as follows: 18 | 19 | >Golly, A. and Turowski, J. M.: Deriving principal channel metrics from bank and long-profile geometry with the R package cmgo, Earth Surf. Dynam., 5, 557-570, https://doi.org/10.5194/esurf-5-557-2017, 2017. 20 | 21 | Find the [paper at ESURF](https://www.earth-surf-dynam.net/5/557/2017/esurf-5-557-2017.html). 22 | 23 | ## Installation 24 | 25 | [Get](https://cran.r-project.org/), install and open R and run the following code in the R console: 26 | 27 | ```R 28 | 29 | # install devtools 30 | install.packages("devtools") 31 | 32 | # load the devtool package 33 | library(devtools) 34 | 35 | # installation (required only once) 36 | install_github("AntoniusGolly/cmgo") 37 | ``` 38 | 39 | ## Run cmgo 40 | ``` 41 | # include the package (required for every start of an R session) 42 | library(cmgo) 43 | 44 | # set your working directory 45 | setwd("d:/your_folder") # in that folder an "input" folder must exist which contains one or more files with point data 46 | 47 | # load parameter 48 | par = CM.par() 49 | par$bank.interpolate.max.dist = 4 # set roughly to your expected channel width 50 | 51 | # load data assuming your file is lying in directory "input" 52 | cmgo.obj = CM.ini(NULL, par) 53 | 54 | # Generate a polygon from input data and plot // Fig. 1b 55 | cmgo.obj = CM.generatePolygon(cmgo.obj) 56 | 57 | # Generate the voronoi polygons and calculate the centerlin // Fig. 1c-e 58 | cmgo.obj = CM.calculateCenterline(cmgo.obj) 59 | 60 | # Process the centerline (generate width) // Fig. 1f-g 61 | cmgo.obj = CM.processCenterline(cmgo.obj) 62 | 63 | ``` 64 | 65 | ## Input data 66 | You can find more info on how the data is structured typing `$ ?CM.ini` which is the function to initialize the main object. It will expect a file `./input/*`, relative to your working directory. Note, the filename is not important as all files in that folder will be read in. 67 | 68 | The file by default should have this structure, where POINT_X and POINT_Y are ortorectified coordinates. The data can be either collected during field surveys with GPS or total stations or through remote sensing techniques with further digitizing for example in a GIS. The input can be given in any ASCII table format. By default, the program expects tab-delimited columns of a table with one header line with the header names Names (for the side) and POINT_X/_Y/Z (the coordinates of the bank points) where the z component is optional. The expected column names and tab delimiters are set in the parameters (see documentation of CM.par() for details). The order of the points can be either all right bank points first or all left bank points first but not mixed. 69 | ``` 70 | Name POINT_X POINT_Y 71 | right 401601.0819 3106437.335 72 | right 401586.5327 3106406.896 73 | right 401568.3238 3106383.586 74 | right 401558.4961 3106364.129 75 | ... 76 | left 401621.4337 3106431.134 77 | left 401602.9913 3106405.991 78 | left 401574.6073 3106352.232 79 | left 401582.2671 3106323.134 80 | ... 81 | ``` 82 | If you seek to change column names, column delimiters or alike, please check the default parameters and adapt them `$ ?CM.par` 83 | 84 | ## FAQ 85 | 86 | For support and common technical fails please see the [FAQ](FAQ.md) 87 | 88 | ## Documentation 89 | 90 | ``` 91 | # package documentation 92 | ?cmgo 93 | 94 | # function documentation 95 | ?cmgo.run # e.g. for the docu of cmgo.run() 96 | ``` 97 | 98 | -------------------------------------------------------------------------------- /data/demo.RData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntoniusGolly/cmgo/abce48b13cfeaa2c0e991ff02650aa569f5527b4/data/demo.RData -------------------------------------------------------------------------------- /data/demo1.RData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntoniusGolly/cmgo/abce48b13cfeaa2c0e991ff02650aa569f5527b4/data/demo1.RData -------------------------------------------------------------------------------- /data/demo2.RData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntoniusGolly/cmgo/abce48b13cfeaa2c0e991ff02650aa569f5527b4/data/demo2.RData -------------------------------------------------------------------------------- /data/demo3.RData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntoniusGolly/cmgo/abce48b13cfeaa2c0e991ff02650aa569f5527b4/data/demo3.RData -------------------------------------------------------------------------------- /man-roxygen/Examples.url: -------------------------------------------------------------------------------- 1 | [InternetShortcut] 2 | URL=javascript:void(0) 3 | -------------------------------------------------------------------------------- /man-roxygen/param_global_data_object.r: -------------------------------------------------------------------------------- 1 | #' @param cmgo.obj the global object of type list containing data and parameters created with \code{\link[=CM.ini]{CM.ini()}} 2 | -------------------------------------------------------------------------------- /man-roxygen/param_set.r: -------------------------------------------------------------------------------- 1 | #' @param set an optional argument for processing a specific data set, if \code{NULL} all available data sets are used 2 | -------------------------------------------------------------------------------- /man-roxygen/section_all_default_parameters.r: -------------------------------------------------------------------------------- 1 | #' @section All parameters and their defaults: 2 | #' The parameter list contains more than 50 parameters specifying the model and the plotting. 3 | #' All parameters can directly accessed via the global data object, for example 4 | #' \code{cmgo.obj$par$input.dir = "/my_folder"}. 5 | #' 6 | #' This is the full list with explanations: \preformatted{ 7 | #' 8 | #' # name of the parameter set 9 | #' name = "default", 10 | #' 11 | #' # workspace 12 | #' workspace.read = TRUE, # if [TRUE] it is tried to load the global data object from a workspace file in CM.ini() 13 | #' workspace.write = FALSE, # if [TRUE] a workspace with the global data object will be written in CM.writeData() 14 | #' workspace.replace = FALSE, # if [TRUE] a workspace will be replaced when existing in CM.writeData() 15 | #' workspace.filename = "user_workspace.RData", # the filename used in CM.ini() and CM.writeData() 16 | #' 17 | #' # input settings 18 | #' input.dir = "input", # the directory from which all input files will be read in by CM.ini() 19 | #' input.sep = "\t", # the column separator sign, e.g. ",", ";", "\t" (tab) passed to read.table (?read.table for more information) 20 | #' input.col.easting = "POINT_X", # the column name for the x-value 21 | #' input.col.northing = "POINT_Y", # s.a. 22 | #' input.col.elevation = "POINT_Z", # s.a. 23 | #' input.units = "m", # units of input coordinates (will be used for axis labels in plotting functions) 24 | #' input.col.bank = "Name", # the column name of the side (left/right bank) 25 | #' bank.code.left = "left", # the string code used for the left bank 26 | #' bank.code.right = "right", # the string code used for the right bank 27 | #' 28 | #' # output settings 29 | #' output.write = FALSE, # if [TRUE] output ASCII files will be written 30 | #' output.replace = FALSE, # if [TRUE] the output files are replaced when existing in CM.writeFiles() 31 | #' output.write.centerline = FALSE, # if [TRUE] the geometry of the centerline will be written in CM.writeFiles() 32 | #' output.write.metrics = TRUE, # if [TRUE] the calculated channel metrics will be written in CM.writeFiles() 33 | #' output.write.metrics.d = TRUE, # switch on/off the variable d.r and d.l (distances from centerline to banks) 34 | #' output.write.metrics.w = TRUE, # switch on/off the variable w (channel width) 35 | #' output.write.metrics.r = TRUE, # switch on/off the variable r.r and r.l (direction factor of d.r and d.l) 36 | #' output.write.metrics.diff = TRUE, # switch on/off the variable diff.r and diff.l (distances between two banks) 37 | #' 38 | #' output.dir = "output", 39 | #' output.sep = "\t", 40 | #' 41 | #' # enable/disable plots 42 | #' plot.polygoncheck = TRUE, # if [TRUE], a three-column plot is generated showing the entire river and both ends to rouhgly check the polygon consitency (see also CM.generatePolygon()) 43 | #' 44 | #' plot.planview = TRUE, # create a plan view overview plot 45 | #' plot.planview.secondary = TRUE, # in the plan view plot, add a secodary data set for comparison (will be displayed in dashed lines) 46 | #' plot.planview.bankpoints = FALSE, # in the plan view plot, add the bank points of a data set 47 | #' plot.planview.polygons = TRUE, # in the plan view plot, add the channel borders 48 | #' plot.planview.voronoi = FALSE, # in the plan view plot, add voronoi polygons in plan view plot 49 | #' plot.planview.cl.original = FALSE, # in the plan view plot, add the rough centerline (before smoothing) 50 | #' plot.planview.cl.smoothed = TRUE, # in the plan view plot, add the smoothed centerline 51 | #' plot.planview.cl.tx = FALSE, # in the plan view plot, add a label with the number next to the centerline points 52 | #' plot.planview.transects = FALSE, # in the plan view plot, add transects (perpendiculars to centerline) 53 | #' plot.planview.transects.len = 20, # give the length of transects in the unit of the input coordinates 54 | #' plot.planview.dist2banks = TRUE, # in the plan view plot, add transect segments from centerline to the banks (left and right) 55 | #' plot.planview.grid = TRUE, # in the plan view plot, add a grid in the background 56 | #' plot.planview.grid.dist = 20, # the distance of the grid lines in the unit of the input coordinates 57 | #' plot.planview.legend = TRUE, # in the plan view plot, add a legend 58 | #' plot.planview.scalebar = TRUE, # in the plan view plot, add a scalebar (width of one plot.planview.grid.dist) 59 | #' 60 | #' # plot options 61 | #' plot.zoom = TRUE, # if [TRUE] the plan view plot is zoomed in (see also CM.plotPlanView()) 62 | #' plot.zoom.extent.length = 140, # zoom window extent for the plan view plot in the unit of the input coordinates 63 | #' plot.zoom.extent = "e1", # applied zoom window name (see also CM.plotPlanView()) 64 | #' plot.zoom.extents = list( # presets (customizable list) of zoom windows 65 | #' e1 = c(400480, 3103130), 66 | #' e2 = c(399445, 3096220), 67 | #' e3 = c(401623, 3105925) 68 | #' ), 69 | #' plot.cl.range = "cl1", # applied zoom cl range (see also CM.plotPlanView) 70 | #' plot.cl.ranges = list( # presets (customizable list) of cl ranges 71 | #' cl1 = c(1235, 1260) 72 | #' ), 73 | #' plot.cl.range.use.reference = TRUE, # determines whether to look for reference centerline [TRUE] or current centerline when centering around cl.range 74 | #' plot.to.file = FALSE, # if [TRUE] all plots will be copied to file devices 75 | #' plot.to.pdf = TRUE, # if [TRUE] the plot will be saved as pdf 76 | #' plot.to.png = TRUE, # if [TRUE] the plot will be saved as png 77 | #' plot.index = 0, # numbering for filenames (see also CM.plotPlanView()) 78 | #' plot.directory = "plots/", # directory for saving plots if plot.to.file = TRUE 79 | #' plot.filename = "documentation", # plot file name 80 | #' 81 | #' # model parameters 82 | #' force.calc.voronoi = FALSE, # if [TRUE] the voronoi polygons are always re-calculated and never taken from cache 83 | #' force.calc.cl = FALSE, # if [TRUE] the centerline is always re-calculated and never taken from cache 84 | #' bank.interpolate = TRUE, # if [TRUE] the provided bank points are linearly interpolated to generate a denser polygon (see CM.generatePolygon()) 85 | #' bank.interpolate.max.dist = 6, # if bank.interpolate is [TRUE] this is the minimum distance all bank points will have 86 | #' bank.filter3.max.it = 12, # number of the maximum iterations for filter 3 to prevent the program to run infinitely 87 | #' centerline.smoothing.width = 7, # smoothing window width of mean filter in number of observations (see CM.calculateCenterline()) 88 | #' transects.span = 3, # span of centerline points used for calculating the transects (see CM.processCenterline()) 89 | #' centerline.bin.length = 5, # for simplifying the centerline give the spacing in the unit of the input coordinates (see CM.reduceCenterline()) 90 | #' centerline.use.reference = FALSE, # sets method for calculating distance centerline to banks, if [FALSE] (default) each river profile will be compared to its own centerline, if [TRUE] the centerline of centerline.reference will be taken (see CM.processCenterline()) 91 | #' centerline.reference = "set1", # sets the reference data set if centerline.use.reference is [TRUE] 92 | #' calculate.metrics = TRUE, # if [TRUE] all centerline metrics are calculated (see CM.processCenterline()) 93 | #' force.calc.metrics = FALSE, # if [TRUE] the metrics are always re-calculated and never taken from cache 94 | #' } 95 | #' 96 | -------------------------------------------------------------------------------- /man-roxygen/section_getting_started.r: -------------------------------------------------------------------------------- 1 | #' @section Getting started: 2 | #' To start a new project you will need to go through the full stack of the main functions 3 | #' of this package \code{cmgo}. To do this read the instructions under \strong{Run cmgo}. However, 4 | #' if you just want a quick demo run just write \code{\link[=CM.run]{CM.run()}} into the console and execute. 5 | -------------------------------------------------------------------------------- /man-roxygen/section_global_data_object.r: -------------------------------------------------------------------------------- 1 | #' @section General information on the global data object: 2 | #' All the data and parameters used in \code{cmgo} are stored in one variable of 3 | #' \href{http://www.r-tutor.com/r-introduction/list}{type list}: the global data object, 4 | #' in the following examples named \code{cmgo.obj}. Its structure is: 5 | #' \preformatted{cmgo.obj = list( 6 | #' data = list() # the data set(s), different surveys of the channel 7 | #' set1 = list(), # survey 1 8 | #' set2 = list() # survey 2 9 | #' # ... 10 | #' ), 11 | #' par = list() # all plotting and model parameters 12 | #' )} 13 | #' 14 | #' The global data object then has to be \strong{passed to} and is \strong{returned from} 15 | #' all main functions of the package as in 16 | #' 17 | #' \code{cmgo.obj = \link[=CM.generatePolygon]{CM.generatePolygon(cmgo.obj)}}\cr 18 | #' \code{cmgo.obj = \link[=CM.calculateCenterline]{CM.calculateCenterline(cmgo.obj)}}\cr 19 | #' \code{cmgo.obj = \link[=CM.processCenterline]{CM.processCenterline(cmgo.obj)}}\cr 20 | #' \code{\link[=CM.writeData]{CM.writeData(cmgo.obj)}}\cr 21 | #' \code{\link[=CM.plotPlanView]{CM.plotPlanView(cmgo.obj)}}\cr 22 | #' 23 | -------------------------------------------------------------------------------- /man-roxygen/section_input_data.r: -------------------------------------------------------------------------------- 1 | #' @section Input data: 2 | #' The package requires as \strong{input data} the bank points of a river in 2D- or 3 | #' 3D-coordinates along with the information of the side of the bank points 4 | #' (right or left), as for example: 5 | #' 6 | #' \code{Name POINT_X POINT_Y}\cr 7 | #' \code{right 401601.0819 3106437.335}\cr 8 | #' \code{right 401586.5327 3106406.896}\cr 9 | #' \code{right 401568.3238 3106383.586}\cr 10 | #' \code{right 401558.4961 3106364.129}\cr 11 | #' \code{...}\cr 12 | #' \code{left 401621.4337 3106431.134}\cr 13 | #' \code{left 401602.9913 3106405.991}\cr 14 | #' \code{left 401574.6073 3106352.232}\cr 15 | #' \code{left 401582.2671 3106323.134}\cr 16 | #' \code{...}\cr 17 | #' 18 | #' The data can be either collected during field 19 | #' surveys with GPS or total stations or through remote sensing techniques 20 | #' with further digitizing for example in a GIS. The input can be given in any ASCII 21 | #' table format. By default, the program expects tab-delimited columns of a table with one header 22 | #' line with the header names \strong{Names} (for the side) and \strong{POINT_X}/_Y/Z (the coordinates 23 | #' of the bank points) where the z component is optional. The expected column names and tab delimiters 24 | #' are set in the parameters (see documentation of \code{\link[=CM.par]{CM.par()}} for details). 25 | #' The order of the points can be either all right bank points first or all left bank points first but not mixed. 26 | #' 27 | #' The input file(s) have to be placed in the input directory specified in the parameters (defaults to "./input") 28 | #' and can have any file extension (.txt, .csv, etc.). The function \code{\link[=CM.ini]{CM.ini()}} will iterate 29 | #' over all files in that directory and create a data set for each file in the global data object of cmgo. 30 | -------------------------------------------------------------------------------- /man-roxygen/section_parameters.r: -------------------------------------------------------------------------------- 1 | #' @section Parameters: 2 | #' The parameters are stored in the global data object, for example \code{cmgo.obj$par}. They 3 | #' can always be accessed or edited directly by e.g. \preformatted{obj$par$plot.planview = TRUE} 4 | #' Alternatively, users can load custom parameters from files previously created (e.g. to save 5 | #' project settings or reproduce certain plots). Parameter files are loaded with \preformatted{cmgo.obj$par = CM.par("custom_par_list.r")} 6 | -------------------------------------------------------------------------------- /man-roxygen/section_run_cmgo.r: -------------------------------------------------------------------------------- 1 | #' @section Run cmgo: 2 | #' The main functions of cmgo (described in \strong{Work flow}) should be exectued in this order: \preformatted{ 3 | #' cmgo.obj = CM.ini(cmgo.obj, par="par/my_parameters.r") # read data, optional: path to a parameter file, alternatively leave empty to use defaults 4 | #' cmgo.obj = CM.generatePolygon(cmgo.obj) # generate polygon 5 | #' cmgo.obj = CM.calculateCenterline(cmgo.obj) # get centerline (calculate or load) 6 | #' cmgo.obj = CM.processCenterline(cmgo.obj) # process centerline (calculate width) 7 | #' CM.plotPlanView(cmgo.obj) # plot results 8 | #' CM.plotMetrics(cmgo.obj) # plot channel width and bank retreat 9 | #' CM.writeData(cmgo.obj) # data to workspace and export data to csv-files (see par)#' 10 | #'} 11 | #' 12 | #' If the generated polygon from CM.generatePolygon() has more than 10,000 vertices, the execution time can be extensive. 13 | #' Thus, CM.calculateCenterline(), as the other main CM functions, has a chaching mechanism of the data. If you call 14 | #' the function when the resulting data already exists, the data will not be processed. You will have to explicitly force the generation of the data. 15 | #' When you change a parameter regarding the generation of the polygon (see CM.generatePolygon()) the program will 16 | #' detect this change and will calculate the centerline without forcing it. 17 | -------------------------------------------------------------------------------- /man-roxygen/section_technical_fails.r: -------------------------------------------------------------------------------- 1 | #' @section Technical fails and how to prevent them: 2 | #' All parameters are stored in the global data object (see the section 'Global data object') under the sub-list 3 | #' $par. For example, if your global data object is named \code{obj} the parameter \code{$plot.planview} is 4 | #' accessible by \code{obj$par$transects.span}. The available parameters of the model are described in 5 | #' the documentation of the function \code{\link[=CM.par]{CM.par()}}. Here we only describe a few cases why editing the 6 | #' default parameters can be desired. 7 | #' 8 | #' There are certain geometrical cases in which the algorithm can fail with the default parametrization. 9 | #' To prevent this a wise parametrization of the model is required. The program will inform you during runtime 10 | #' if the generation of the centerline fails and will offer you ways to elaborate the issue. The main reason for 11 | #' failure occurs if the resolution of channel bank points (controlled via \code{$bank.interpolate.max.dist}) 12 | #' is relatively low compared to the channel width. The following image illustrates the problem: 13 | #' 14 | #' \if{html}{\figure{02-gap.png}{options: width="500px" alt="Figure: Gap in Centerline"}} 15 | #' \if{latex}{\figure{02-gap.png}{options: width=6cm}} 16 | #' \emph{Figure 2: A gap in the centerline occurs since the spacing of the bank points was too high.} 17 | #' 18 | #' Apparently, the centerline segments are too scraggy and do not lie entirely within the bank polygons. Since 19 | #' the filter mechanism (step \strong{c-d}) checks for segments within the polygon first, this will create a gap 20 | #' in the centerline. The program will not be able to fill this gap automatically. Thus, if you experience problems 21 | #' with the calculation of the centerline consider to increase the spatial resolution of bank points. The following 22 | #' example illustrates how this fixes the problem. 23 | #' 24 | #' \if{html}{\figure{03-sep-spacing.png}{options: width="500px" alt="Figure: fix"}} 25 | #' \if{latex}{\figure{03-sep-spacing.png}{options: width=6cm}} 26 | #' \emph{Figure 3: The same location of the channel with two different bank point spacings.} 27 | #' 28 | #' Another problem can arise from an unsuitable settings of the span for the calculation of the 29 | #' transects (step \strong{f}). The transects are perpendicular to a line that goes through the outer points 30 | #' of a group of \code{n} points of the centerline. This \code{n} equals 3 by default (parameter 31 | #' \code{$transects.span}). The following plan view plot illustrates to what misinterpretation of the channel width 32 | #' can lead: 33 | #' 34 | #' \if{html}{\figure{04-transect-span.png}{options: width="500px" alt="span_issues"}} 35 | #' \if{latex}{\figure{04-transect-span.png}{options: width=6cm}} 36 | #' \emph{Figure 4, left: the transects (perpendiculars to the centerline) do not intersect 37 | #' with banks properly, thus channel width is overrepresented. Right: an increased transect span fixes the problem 38 | #' and channel width is now identified correctly.} 39 | #' 40 | #' It can be seen that one of the red transects does not touch the left bank of the channel, thus leading to 41 | #' an overestimated channel width at this location. To prevent this, you can increase the span of the transect 42 | #' calculation. 43 | -------------------------------------------------------------------------------- /man-roxygen/section_time_series.r: -------------------------------------------------------------------------------- 1 | #' @section Time series analyses: 2 | #' The package cmgo can handle time series of channel geometries and offers the opportunity 3 | #' to compare them. To do this, simply put the an input file for each data set in the input directory 4 | #' (see \code{\link[=CM.ini]{CM.ini()}}). The function will create a data object for each file in the 5 | #' global data object under, \code{cmgo.obj$data$set1}, \code{cmgo.obj$data$set2}, \code{cmgo.obj$data$set3}, etc. 6 | #' All functions will iterate over the data sets automatically. 7 | #' 8 | #' If you want to address via a variable use \code{cmgo.obj$data[[set]]}, where is a string of the data set, 9 | #' e.g. \code{"set1"}. The order of data sets will be determined by the filenames. So, make sure to name the files 10 | #' accordingly, e.g. \code{"channelsurvey_a.csv"},\code{"channelsurvey_b.csv"}. The mapping of the filenames to 11 | #' data sets will be printed to the console. Also, you can view the file names belonging to a data set with 12 | #' \code{print(cmgo.obj$data[[set]]$filename)}. 13 | #' 14 | #' \strong{Reference centerline}\cr 15 | #' The channel metrics are calculated based on a centerline. Normally, for a river plan geometry one centerline exists 16 | #' and this is the basis for the metrics. However, when there are multiple time lines two options exist. 17 | #' Metrics are either calculated for each channel geometry individually. This way you have the most accurate 18 | #' representation of the channel metrics for that channel observation. For example, channel width is most 19 | #' accurately measured. However, different time series of observations are difficult to compare since the basis 20 | #' for the calculations -- the centerlines -- differ. Thus, when comparing time series, a second approach exists 21 | #' where you can determine a reference centerline for all metrics calculations. To do this set: \preformatted{ 22 | #' cmgo.obj$par$centerline.use.reference = TRUE 23 | #' cmgo.obj$par$centerline.reference = "set1" 24 | #' } 25 | #' Now, all metrics for the different bank surveys will be calculated based on the centerline 26 | #' of the data set "set1". Use this option only if your bank surveys differ only slightly. Otherwise, the 27 | #' calculated channel metrics might not be representative (see Fig. 10). 28 | #' 29 | #' \if{html}{\figure{10-documentation.png}{options: width="800px" alt="Figure: reference centerline"}} 30 | #' \if{latex}{\figure{10-documentation.png}{options: width=6cm}} 31 | #' \emph{Figure 10: For channel geometries that differ drastically, the usage of a reference centerline 32 | #' is not advised. The centerline of a data set (blue line) is not useful for calculating the metrics 33 | #' of the dashed channel geometry.} 34 | #' 35 | #' 36 | -------------------------------------------------------------------------------- /man-roxygen/section_work_flow.r: -------------------------------------------------------------------------------- 1 | #' @section Work flow: 2 | #' The program can be divided into three main parts which you will go through if you start a project: 3 | #' \strong{1. initialization} (loading data and parameters), 4 | #' \strong{2. data processing} (calculating channel metrics) and 5 | #' \strong{3. review results} (plotting or writing results to file). 6 | #' The initialization covers the loading of the parameters in \code{\link[=CM.par]{CM.par()}} and loading of 7 | #' the data in \code{\link[=CM.ini]{CM.ini()}}. See their documentation for details. The work flow of 8 | #' the data processing is shown in the plan view plots below. 9 | #' 10 | #' \if{html}{\figure{01-processing.png}{options: width="800px" alt="Figure: processing"}} 11 | #' \if{latex}{\figure{01-processing.pdf}{options: width=9cm}} 12 | #' \emph{Figure 1: A visualization of the work flow of the package, a) data input, b) polygon generation, 13 | #' c-e) centerline generation, f) transect generation, g) channel width calculation.} 14 | #' 15 | #' Channel bank points (Fig. 1a) represent the required input data for the package. The algorithm 16 | #' then creates a polygon from these points (Fig. 1b) where the points are linearly interpolated 17 | #' to increase their spatial resolution. The maximum distance the points have is defined by the parameter 18 | #' \code{bank.interpolate.max.dist}. From these points Voronoi polygons are calculated (Fig. 1c). 19 | #' Voronoi polygons around points denote the areas within which all points are closest to that point. 20 | #' In Fig. 1c you can already notice a centerline evolving in the middle of the channel polygon. Fig. 1d shows 21 | #' the segments that represent the centerline filtered by the algorithm. These centerline segments will be 22 | #' connected to one consistent line and get smoothed (Fig. 1e). The degree of smoothing can be adjusted 23 | #' through the parameter \code{centerline.smoothing.width} (defaults to the same value as 24 | #' \code{bank.interpolate.max.dist}). This centerline represents the reference of the river, for which 25 | #' length, local width and slope are calculated next. Note, that the length of the centerline depends on 26 | #' the smoothing in 1e). The pros and cons of the smoothing are explained in the documentation of the function 27 | #' \code{CM.calculateCenterline()}. To derive the local channel width, transects are calculated perpendicular 28 | #' to portions of the centerline (Fig. 1f). The transects are lines perpendicular to a group of centerline points 29 | #' where the size of that group is defined by the parameter \code{transects.span}. See 30 | #' \code{\link[=CM.processCenterline]{CM.processCenterline()}} for detailed information on how the transects 31 | #' are generated. In the final step the intersections of the 32 | #' transects with the banks are calculated (Fig. 1g). The distance of the 33 | #' centerline point to the bank is stored sepearately for the left and the right bank. When the transects 34 | #' cross the banks multiple times, the minimum distance is taken. 35 | #' 36 | #' The described algorithm is hosted in the following functions: 37 | #' \itemize{ 38 | #' \item load data points in \code{\link[=CM.ini]{CM.ini()}}, step \strong{a} 39 | #' \item generate a polygon from bank points in \code{\link[=CM.generatePolygon]{CM.generatePolygon()}}, step \strong{b} 40 | #' \item calculate centerlin from the polygon in \code{\link[=CM.calculateCenterline]{CM.calculateCenterline()}}, steps \strong{c-e} 41 | #' \item process the centerline in \code{\link[=CM.processCenterline]{CM.processCenterline()}}, steps \strong{f-g} 42 | #' } 43 | -------------------------------------------------------------------------------- /man/CM.calculateCenterline.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/CM.calculateCenterline.r 3 | \name{CM.calculateCenterline} 4 | \alias{CM.calculateCenterline} 5 | \title{Calculate channel centerline} 6 | \usage{ 7 | CM.calculateCenterline(cmgo.obj, set = NULL) 8 | } 9 | \arguments{ 10 | \item{cmgo.obj}{the global object of type list containing data and parameters created with \code{\link[=CM.ini]{CM.ini()}}} 11 | 12 | \item{set}{an optional argument for processing a specific data set, if \code{NULL} all available data sets are used} 13 | } 14 | \value{ 15 | returns the global data object extended by the centerline data \code{$cl} for the respective data set(s) 16 | } 17 | \description{ 18 | Calculate the centerline of the channel polygon in 5 steps: 19 | \enumerate{ 20 | \item creating Voronoi polygons of the bank points, convert to paths (line segments with two ends) and remove duplicates\cr 21 | \item filtering for path segments that lie within the banks\cr 22 | \item filtering for path segments that are dead ends (have less than 2 connected ends)\cr 23 | \item sorting of the centerline segments to generate centerline\cr 24 | \item smooth the centerline 25 | } 26 | } 27 | \details{ 28 | \code{CM.calculateCenterline()} calculates the centerline of the channel polygon (Fig. 7). 29 | 30 | \if{html}{\figure{06-processing.png}{options: width="800px" alt="Figure: processing"}} 31 | \if{latex}{\figure{06-processing.pdf}{options: width=9cm}} 32 | \emph{Figure 6: A visualization of the calculation of the centerline a) the channel polygon, b) the Voronoi polygons, 33 | c) extraction of the centerline segments, d) smoothing of the centerline path.} 34 | 35 | The function requires as input the channel polygon (Fig. 6a) which must be stored within the global data object 36 | previously generated with \code{\link[=CM.generatePolygon]{CM.generatePolygon()}}. 37 | The algorithm then creates Voronoi polygons around the bank points (Fig. 6b). 38 | Voronoi polygons around points denote the areas within which all points are closest to that point. The polygons 39 | are disassembled to single line segments. In Fig. 6b you can already notice a centerline evolving from the segments in 40 | the middle of the channel polygon. To get only these segments a filtering (Fig. 7) is applied to the Voronoi segments. 41 | 42 | \if{html}{\figure{07-filtering.png}{options: width="600px" alt="Figure: processing"}} 43 | \if{latex}{\figure{07-filtering.pdf}{options: width=6cm}} 44 | \emph{Figure 7: the filtering of the Voronoi segments: a) in blue all Voronoi segments, b) in red all segments fully within 45 | the channel polygon, c) in green all segments without dead ends.} 46 | 47 | To retrieve only the segments that represent the centerline all segments that do not lie entirely 48 | within the channel banks are removed (Fig. 7b). In a second step dead ends are removed (Fig. 7c). Dead ends are 49 | segments that branch from the centerline but are not part of it. 50 | 51 | These centerline segments will be 52 | chained to one consistent line and get smoothed (Fig. 7d). The degree of smoothing can be adjusted 53 | through the parameter \code{centerline.smoothing.width} (defaults to the same value as 54 | \code{bank.interpolate.max.dist}). This centerline represents the reference of the river, for which 55 | length, local width and slope are calculated next. Note, that the length of the centerline has decreased 56 | by the smoothing in d). It is important to understand, that the length of a river is not a well-defined measure. 57 | The length of a river depends on the resolution of the bank points. Similar to 58 | \href{https://en.wikipedia.org/wiki/Coast#Coastline_problem}{the coast line paradox}, the length depends on the 59 | scale of the observations. Technically, a bended river is a fractal, which 60 | means theoretically, the length diverges to infinity at an infinitely high resolution of the bank points. 61 | However, practically there is an appropriate choice of a minimum feature size. Every user has to determine this 62 | scale individually and should be aware of this choice. The decrease in length due to smoothing 63 | is saved as value in the global data object under \code{cmgo.obj$data[[set]]$cl$length.factor}. A value of 0.95 means 64 | that the length of the smoothed centerline is 95\% the length of the original centerline paths. 65 | } 66 | \examples{ 67 | # get demo data 68 | # (find instructions on how to use own data in the documentation of CM.ini()) 69 | cmgo.obj = CM.ini("demo") 70 | 71 | # generate the polygon from the bank points 72 | cmgo.obj = CM.generatePolygon(cmgo.obj) 73 | 74 | # calculate the centerline from the polygon 75 | cmgo.obj = CM.calculateCenterline(cmgo.obj) 76 | 77 | # check results 78 | plot.par = CM.plotPlanView(cmgo.obj) 79 | 80 | # change degree of smoothing, re-calculate centerline and plot 81 | cmgo.obj$par$centerline.smoothing.width = 12 82 | cmgo.obj = CM.calculateCenterline(cmgo.obj) 83 | plot.par = CM.plotPlanView(cmgo.obj) 84 | 85 | } 86 | \author{ 87 | Antonius Golly 88 | } 89 | -------------------------------------------------------------------------------- /man/CM.generatePolygon.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/CM.generatePolygon.r 3 | \name{CM.generatePolygon} 4 | \alias{CM.generatePolygon} 5 | \title{Generate polygon from bank points} 6 | \usage{ 7 | CM.generatePolygon(cmgo.obj) 8 | } 9 | \arguments{ 10 | \item{cmgo.obj}{the global object of type list containing data and parameters created with \code{\link[=CM.ini]{CM.ini()}}} 11 | } 12 | \value{ 13 | returns the global data object extended by the polygon data \code{$polygon} for the respective data set(s) 14 | } 15 | \description{ 16 | Generates an object of type polygon from the bank points. The bank points must be 17 | ordered and must have an attribute "left" or "right". 18 | } 19 | \details{ 20 | \code{CM.generatePolygon()} creates a polygon from the bank points which were previously 21 | loaded with \code{\link[=CM.ini]{CM.ini()}}. The polygon generation is mainly 22 | a type conversion but involves also the chaining of the points in the correct 23 | order. That is, taking all bank points from the left bank and 24 | chain them with all reversed points of the right bank. The bank points from the right side 25 | have to be reversed so that a valid, circular polygon results (see figure). Since this process 26 | is prone to error when the points are not provided in the expected order, there is a visual feedback 27 | of this process. An overview of the generated polygon will be plotted to check the polygon's consistency. This 28 | plot is by default enabled but can be suppressed by setting \code{par$plot.polygoncheck} to \code{FALSE}. 29 | 30 | \if{html}{\figure{plotCheckPolygon.png}{options: width="600px" alt="Figure: check polygon"}} 31 | \if{latex}{\figure{plotCheckPolygon.pdf}{options: width=8cm}} 32 | \emph{Figure 5: The plot shows the polygon check plot for two data sets (two rows). The columns are: overview of the full channel (left), 33 | start of the polygon (middle) and end of the polygon (right). For the first data set everything looks fine. The 34 | polygon is circular and the ends look consistent (note, the starting end (middle) is open). The second data 35 | set is corrupt. You can see a line crossing the entire channel (left). Also, at the start and end 36 | of the channel there are discrepancies. This means that the order of bank points was not given properly. In this 37 | case, run \code{\link[=CM.ini]{CM.ini()}} again after re-arranging the channel bank points.} 38 | 39 | \code{CM.generatePolygon()} also applies a linear interpolation to the bank points if desired. The spacing of the 40 | bank points directly affects the resolution of the centerline (see \link[=cmgo]{paragraph "Work flow" 41 | of package documentation}). Generally, a high resolution of the centerline represents the channel course 42 | better but leads to more data points and higher computational costs. The linear interpolation will 43 | insert equidistant points in between existing bank points where the added points have a maximum distance defined by 44 | the parameter \code{bank.interpolate.max.dist}. This value is by default 6 and needs to be adjusted 45 | to the individual geometry. As a rule of thumb it is advised to \strong{change bank.interpolate.max.dist to 46 | the value of the expected channel width}! Note, that the units of this value is always the same unit 47 | as your input coordinates. The \emph{best} resolution of the centerline, however, depends also on the shape of 48 | the channel. If you experience problems with the chosen interpolation distance read the \link[=cmgo]{paragraph 49 | "Technical fails and how to prevent them" of the package documentation}). 50 | 51 | \code{CM.generatePolygon()} requires the global data object as argument and -- within this -- a list of bank points. 52 | The list of bank points must be previously created with \code{\link[=CM.ini]{CM.ini()}}. See 53 | the example section for the structure of the expected input. If multiple data sets (time series) 54 | are available, the polygon generation will be performed on each data set. 55 | } 56 | \examples{ 57 | # get demo data (find instructions on how to use own data in the documentation of CM.ini()) 58 | cmgo.obj = CM.ini("demo") 59 | 60 | # check structure of the required input for CM.generatePolygon() 61 | set = "set1" 62 | print(str(cmgo.obj$data[[set]]$channel)) 63 | 64 | #List of 4 65 | # $ x : num [1:396] 401601 401587 401568 401558 401552 ... 66 | # $ y : num [1:396] 3106437 3106407 3106384 3106364 3106329 ... 67 | # $ z : NULL 68 | # $ bank: chr [1:396] "right" "right" "right" "right" ... 69 | 70 | # generate the polygon from the bank points 71 | cmgo.obj = CM.generatePolygon(cmgo.obj) 72 | 73 | } 74 | \author{ 75 | Antonius Golly 76 | } 77 | -------------------------------------------------------------------------------- /man/CM.ini.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/CM.ini.r 3 | \name{CM.ini} 4 | \alias{CM.ini} 5 | \title{Get the global data object} 6 | \usage{ 7 | CM.ini(object = "demo", par = NULL) 8 | } 9 | \arguments{ 10 | \item{object}{either a global data object of type list or a string to specify a demo data set (see Details)} 11 | 12 | \item{par}{either a parameter list, a string to specify a parameter file or NULL to load default parameters (see also \code{\link[=CM.par]{CM.par()}})} 13 | } 14 | \value{ 15 | returns the global data object containing data and parameters that will be passed to all main functions of \code{cmgo}. 16 | } 17 | \description{ 18 | Create the global data object with data and parameters (information on the global data object in section 19 | "General information on the global data object). Depending on the arguments passed to 20 | \code{CM.ini()}, the data are either created from input files, a work space file or from a demo data set. 21 | The parameters are either created from defaults, from a parameter file 22 | or merged with a passed list of parameters. 23 | } 24 | \details{ 25 | \code{CM.ini()} returns a global data object based on the arguments passed to it. Initially, 26 | the function builds a parameter object. If you leave the \code{par} argument empty, the default configuration 27 | is loaded. You can also pass everything to \code{par} that is accepted by \code{\link[=CM.par]{CM.par()}} as 28 | this argument will be directly passed to this function (see the documentation of CM.par() for further information). 29 | Once the parameter object is built, the function will create the data object by the following rules (if one rule 30 | was successfull, the routine stops and returns the global data object): 31 | 32 | \enumerate{ 33 | 34 | \item If \code{$workspace.read} is \code{TRUE} (default) the function looks for an .RData user workspace 35 | named \code{$workspace.filename} (defaults to "./user_workspace.RData"). Note: there will be no such workspace file 36 | once you start a project, since it needs to be saved by the user with \code{\link[=CM.writeData]{CM.writeData()}}. 37 | If such a workspace file exists the global data object will be created from this source, otherwise the next source 38 | is tested. 39 | \item If data input files are available in the directory \code{$input.dir} (defaults to "./input") the function 40 | interates over all files in this directory and create the data object from this source (see section "Input data" below 41 | for further information on the data format). If this rule applies you will start with a clean data set, that 42 | contains nothing than the bank geometry and you will need to process the data from scratch. Otherwise the next source is tested. 43 | \item If \code{object} is a string, the function will check for a demo data set with the same name. Available demo data 44 | sets are \code{"demo"}, \code{"demo1"} and \code{"demo2"}. See section "Demo data sets" below. 45 | } 46 | } 47 | \section{General information on the global data object}{ 48 | 49 | All the data and parameters used in \code{cmgo} are stored in one variable of 50 | \href{http://www.r-tutor.com/r-introduction/list}{type list}: the global data object, 51 | in the following examples named \code{cmgo.obj}. Its structure is: 52 | \preformatted{cmgo.obj = list( 53 | data = list() # the data set(s), different surveys of the channel 54 | set1 = list(), # survey 1 55 | set2 = list() # survey 2 56 | # ... 57 | ), 58 | par = list() # all plotting and model parameters 59 | )} 60 | 61 | The global data object then has to be \strong{passed to} and is \strong{returned from} 62 | all main functions of the package as in 63 | 64 | \code{cmgo.obj = \link[=CM.generatePolygon]{CM.generatePolygon(cmgo.obj)}}\cr 65 | \code{cmgo.obj = \link[=CM.calculateCenterline]{CM.calculateCenterline(cmgo.obj)}}\cr 66 | \code{cmgo.obj = \link[=CM.processCenterline]{CM.processCenterline(cmgo.obj)}}\cr 67 | \code{\link[=CM.writeData]{CM.writeData(cmgo.obj)}}\cr 68 | \code{\link[=CM.plotPlanView]{CM.plotPlanView(cmgo.obj)}}\cr 69 | } 70 | 71 | \section{Input data}{ 72 | 73 | The package requires as \strong{input data} the bank points of a river in 2D- or 74 | 3D-coordinates along with the information of the side of the bank points 75 | (right or left), as for example: 76 | 77 | \code{Name POINT_X POINT_Y}\cr 78 | \code{right 401601.0819 3106437.335}\cr 79 | \code{right 401586.5327 3106406.896}\cr 80 | \code{right 401568.3238 3106383.586}\cr 81 | \code{right 401558.4961 3106364.129}\cr 82 | \code{...}\cr 83 | \code{left 401621.4337 3106431.134}\cr 84 | \code{left 401602.9913 3106405.991}\cr 85 | \code{left 401574.6073 3106352.232}\cr 86 | \code{left 401582.2671 3106323.134}\cr 87 | \code{...}\cr 88 | 89 | The data can be either collected during field 90 | surveys with GPS or total stations or through remote sensing techniques 91 | with further digitizing for example in a GIS. The input can be given in any ASCII 92 | table format. By default, the program expects tab-delimited columns of a table with one header 93 | line with the header names \strong{Names} (for the side) and \strong{POINT_X}/_Y/Z (the coordinates 94 | of the bank points) where the z component is optional. The expected column names and tab delimiters 95 | are set in the parameters (see documentation of \code{\link[=CM.par]{CM.par()}} for details). 96 | The order of the points can be either all right bank points first or all left bank points first but not mixed. 97 | 98 | The input file(s) have to be placed in the input directory specified in the parameters (defaults to "./input") 99 | and can have any file extension (.txt, .csv, etc.). The function \code{\link[=CM.ini]{CM.ini()}} will iterate 100 | over all files in that directory and create a data set for each file in the global data object of cmgo. 101 | } 102 | 103 | \section{Demo data sets}{ 104 | 105 | Four demo data sets are available, which contain a few kilometer long section of a channel. The data sets 106 | differ in the degree of data processing. The data set \strong{demo} only contains the channel bank points, thus 107 | contains a global data object how it looks directly after reading the input files (check 108 | structure with \code{str(cmgo.obj$data[[set]]$channel)}). The data set \strong{demo1} has passed the first steps 109 | of the processing: CM.generatePolygon() and CM.calculateCenterlin(). Thus, it contains successfully created 110 | centerlines (check structure with \code{str(cmgo.obj$data[[set]]$cl)}). The data set \strong{demo2} has gone through 111 | the full stack of processing of cmgo, e.g. CM.processCenterline() , and all metrics are calculated (check 112 | structure with \code{str(cmgo.obj$data[[set]]$metrics)}). Thus you can use this data set for testing the 113 | plotting functions CM.plotPlanView() and CM.plotWidth(). Note, that demo data set demo3 uses the standard 114 | mode for the calculation of the metrics (default) 115 | and not the reference centerline mode. To see the reference centerline mode in action use data set \strong{demo3}. In addition 116 | to the previously mentioned plotting functions, here also CM.plotMetrics() is available. 117 | } 118 | 119 | \examples{ 120 | # example 1: get data set from demo data 121 | cmgo.obj = CM.ini("demo") 122 | 123 | # example 2: get data set from input files 124 | par = CM.par() 125 | print(cmgo.obj$par$input.dir) 126 | par$input.dir = "custom_input_folder" 127 | #cmgo.obj = CM.ini(NULL, par) # works if 'custom_input_folder' contains file(s) 128 | 129 | # example 3: load existing workspace 130 | # (see CM.writeData() to learn how to write your workspace) 131 | cmgo.obj$par$workspace.filename = "custom_workspace.RData" 132 | #cmgo.obj = CM.ini(NULL, par) # works if 'custom_workspace.RData' exists 133 | 134 | } 135 | \author{ 136 | Antonius Golly 137 | } 138 | -------------------------------------------------------------------------------- /man/CM.par.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/CM.par.r 3 | \name{CM.par} 4 | \alias{CM.par} 5 | \title{Get the parameter object} 6 | \usage{ 7 | CM.par(par.set = NULL) 8 | } 9 | \arguments{ 10 | \item{par.set}{either NULL (default parameters are returned), of type string to specify a filename or of type list to specify parameters} 11 | } 12 | \value{ 13 | The resulting parameters list. 14 | } 15 | \description{ 16 | Create a parameter list containing all model and plotting parameters. Depending on the arguments passed to 17 | \code{CM.par()}, the parameter list is either created from the defaults or from a specified parameter file. 18 | } 19 | \details{ 20 | \code{CM.par()} creates or renews a parameter list based on the arguments passed to it. The list contains all 21 | model and plot parameters and is stored within the global data object, for example \code{cmgo.obj$par} 22 | (see \link[=cmgo]{package documentation}). Thus, the returned parameter object must be assigned to the global data 23 | object as in \code{cmgo.obj$par = CM.par()}. 24 | 25 | If you call \code{CM.par()} without arguments (example #1), the default parameter list 26 | is returned (see section "All default parameters and their defaults"). For larger projects, it can be desired to easily switch between 27 | parameter sets, for example to reproduce different plots. You can save these customized parameter sets in files 28 | (see section "Make a custom parameter file"). These files are loaded with \code{CM.par("path_to_parameter_file")} (example #2). The file is 29 | \strong{not required} to host \strong{all} parameters, since the list will be merged with the defaults on loading. That means, a parameter file 30 | has to host only those parameters differing from the defaults. As a third option, you can pass directly a list to 31 | \code{CM.par()} (example #3). The directly passed parameters will be merged with defaults, as well. 32 | } 33 | \section{All parameters and their defaults}{ 34 | 35 | The parameter list contains more than 50 parameters specifying the model and the plotting. 36 | All parameters can directly accessed via the global data object, for example 37 | \code{cmgo.obj$par$input.dir = "/my_folder"}. 38 | 39 | This is the full list with explanations: \preformatted{ 40 | 41 | # name of the parameter set 42 | name = "default", 43 | 44 | # workspace 45 | workspace.read = TRUE, # if [TRUE] it is tried to load the global data object from a workspace file in CM.ini() 46 | workspace.write = FALSE, # if [TRUE] a workspace with the global data object will be written in CM.writeData() 47 | workspace.replace = FALSE, # if [TRUE] a workspace will be replaced when existing in CM.writeData() 48 | workspace.filename = "user_workspace.RData", # the filename used in CM.ini() and CM.writeData() 49 | 50 | # input settings 51 | input.dir = "input", # the directory from which all input files will be read in by CM.ini() 52 | input.sep = "\t", # the column separator sign, e.g. ",", ";", "\t" (tab) passed to read.table (?read.table for more information) 53 | input.col.easting = "POINT_X", # the column name for the x-value 54 | input.col.northing = "POINT_Y", # s.a. 55 | input.col.elevation = "POINT_Z", # s.a. 56 | input.units = "m", # units of input coordinates (will be used for axis labels in plotting functions) 57 | input.col.bank = "Name", # the column name of the side (left/right bank) 58 | bank.code.left = "left", # the string code used for the left bank 59 | bank.code.right = "right", # the string code used for the right bank 60 | 61 | # output settings 62 | output.write = FALSE, # if [TRUE] output ASCII files will be written 63 | output.replace = FALSE, # if [TRUE] the output files are replaced when existing in CM.writeFiles() 64 | output.write.centerline = FALSE, # if [TRUE] the geometry of the centerline will be written in CM.writeFiles() 65 | output.write.metrics = TRUE, # if [TRUE] the calculated channel metrics will be written in CM.writeFiles() 66 | output.write.metrics.d = TRUE, # switch on/off the variable d.r and d.l (distances from centerline to banks) 67 | output.write.metrics.w = TRUE, # switch on/off the variable w (channel width) 68 | output.write.metrics.r = TRUE, # switch on/off the variable r.r and r.l (direction factor of d.r and d.l) 69 | output.write.metrics.diff = TRUE, # switch on/off the variable diff.r and diff.l (distances between two banks) 70 | 71 | output.dir = "output", 72 | output.sep = "\t", 73 | 74 | # enable/disable plots 75 | plot.polygoncheck = TRUE, # if [TRUE], a three-column plot is generated showing the entire river and both ends to rouhgly check the polygon consitency (see also CM.generatePolygon()) 76 | 77 | plot.planview = TRUE, # create a plan view overview plot 78 | plot.planview.secondary = TRUE, # in the plan view plot, add a secodary data set for comparison (will be displayed in dashed lines) 79 | plot.planview.bankpoints = FALSE, # in the plan view plot, add the bank points of a data set 80 | plot.planview.polygons = TRUE, # in the plan view plot, add the channel borders 81 | plot.planview.voronoi = FALSE, # in the plan view plot, add voronoi polygons in plan view plot 82 | plot.planview.cl.original = FALSE, # in the plan view plot, add the rough centerline (before smoothing) 83 | plot.planview.cl.smoothed = TRUE, # in the plan view plot, add the smoothed centerline 84 | plot.planview.cl.tx = FALSE, # in the plan view plot, add a label with the number next to the centerline points 85 | plot.planview.transects = FALSE, # in the plan view plot, add transects (perpendiculars to centerline) 86 | plot.planview.transects.len = 20, # give the length of transects in the unit of the input coordinates 87 | plot.planview.dist2banks = TRUE, # in the plan view plot, add transect segments from centerline to the banks (left and right) 88 | plot.planview.grid = TRUE, # in the plan view plot, add a grid in the background 89 | plot.planview.grid.dist = 20, # the distance of the grid lines in the unit of the input coordinates 90 | plot.planview.legend = TRUE, # in the plan view plot, add a legend 91 | plot.planview.scalebar = TRUE, # in the plan view plot, add a scalebar (width of one plot.planview.grid.dist) 92 | 93 | # plot options 94 | plot.zoom = TRUE, # if [TRUE] the plan view plot is zoomed in (see also CM.plotPlanView()) 95 | plot.zoom.extent.length = 140, # zoom window extent for the plan view plot in the unit of the input coordinates 96 | plot.zoom.extent = "e1", # applied zoom window name (see also CM.plotPlanView()) 97 | plot.zoom.extents = list( # presets (customizable list) of zoom windows 98 | e1 = c(400480, 3103130), 99 | e2 = c(399445, 3096220), 100 | e3 = c(401623, 3105925) 101 | ), 102 | plot.cl.range = "cl1", # applied zoom cl range (see also CM.plotPlanView) 103 | plot.cl.ranges = list( # presets (customizable list) of cl ranges 104 | cl1 = c(1235, 1260) 105 | ), 106 | plot.cl.range.use.reference = TRUE, # determines whether to look for reference centerline [TRUE] or current centerline when centering around cl.range 107 | plot.to.file = FALSE, # if [TRUE] all plots will be copied to file devices 108 | plot.to.pdf = TRUE, # if [TRUE] the plot will be saved as pdf 109 | plot.to.png = TRUE, # if [TRUE] the plot will be saved as png 110 | plot.index = 0, # numbering for filenames (see also CM.plotPlanView()) 111 | plot.directory = "plots/", # directory for saving plots if plot.to.file = TRUE 112 | plot.filename = "documentation", # plot file name 113 | 114 | # model parameters 115 | force.calc.voronoi = FALSE, # if [TRUE] the voronoi polygons are always re-calculated and never taken from cache 116 | force.calc.cl = FALSE, # if [TRUE] the centerline is always re-calculated and never taken from cache 117 | bank.interpolate = TRUE, # if [TRUE] the provided bank points are linearly interpolated to generate a denser polygon (see CM.generatePolygon()) 118 | bank.interpolate.max.dist = 6, # if bank.interpolate is [TRUE] this is the minimum distance all bank points will have 119 | bank.filter3.max.it = 12, # number of the maximum iterations for filter 3 to prevent the program to run infinitely 120 | centerline.smoothing.width = 7, # smoothing window width of mean filter in number of observations (see CM.calculateCenterline()) 121 | transects.span = 3, # span of centerline points used for calculating the transects (see CM.processCenterline()) 122 | centerline.bin.length = 5, # for simplifying the centerline give the spacing in the unit of the input coordinates (see CM.reduceCenterline()) 123 | centerline.use.reference = FALSE, # sets method for calculating distance centerline to banks, if [FALSE] (default) each river profile will be compared to its own centerline, if [TRUE] the centerline of centerline.reference will be taken (see CM.processCenterline()) 124 | centerline.reference = "set1", # sets the reference data set if centerline.use.reference is [TRUE] 125 | calculate.metrics = TRUE, # if [TRUE] all centerline metrics are calculated (see CM.processCenterline()) 126 | force.calc.metrics = FALSE, # if [TRUE] the metrics are always re-calculated and never taken from cache 127 | } 128 | } 129 | 130 | \section{Make a custom parameter file}{ 131 | 132 | Create an empty .r-file with the following code:\preformatted{ 133 | par = list( 134 | plot.to.file = TRUE, 135 | other_par = "value" 136 | # other_par = "other value" 137 | ) 138 | } 139 | A full list of available parameters can be found in the paragraph "All parameters and their defaults" above. In a parameter file you 140 | don't have to specify \strong{all} parameters. Just list parameters that you like to differ from the defaults. The parameter object that 141 | will be created by CM.par() if you specify a file name will be merged with the defaults, where specified parameters overwrite the defaults. 142 | } 143 | 144 | \examples{ 145 | # instantiate your global data object first, for example with CM.ini() 146 | cmgo.obj = list() 147 | 148 | # example #1: get the default parameters 149 | cmgo.obj$par = CM.par() 150 | 151 | # example #2: get parameters from a configuration file (see also "Make a custom parameter file") 152 | #cmgo.obj$par = CM.par("par/custom_parameters.r")#' 153 | 154 | # example 3: get modified default parameters 155 | cmgo.obj$par = CM.par(list( 156 | plot.to.file = TRUE, 157 | plot.directory = "/my_figures" 158 | )) 159 | 160 | } 161 | \author{ 162 | Antonius Golly 163 | } 164 | -------------------------------------------------------------------------------- /man/CM.plotMetrics.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/CM.plotMetrics.r 3 | \name{CM.plotMetrics} 4 | \alias{CM.plotMetrics} 5 | \title{Plot changes of the banks (erosion and aggradation)} 6 | \usage{ 7 | CM.plotMetrics(cmgo.obj, set = "set1", cl = NULL, d = NULL) 8 | } 9 | \arguments{ 10 | \item{cmgo.obj}{the global object of type list containing data and parameters created with \code{\link[=CM.ini]{CM.ini()}}} 11 | 12 | \item{set}{the reference data set} 13 | 14 | \item{cl}{the range of centerline points to be plotted, if NULL (default) the full channel length will be plotted, if 15 | a vector of two elements is provided (e.g. c(200, 500)) this cl range is plotted, if a string is provided (e.g. "cl1"), 16 | the range defined in \code{par$plot.cl.ranges$cl1} will be plotted} 17 | 18 | \item{d}{the distance range of the centerline downstream to be plotted, NULL (default) cl defintions are taken, if a 19 | single value (e.g. d=500) is given 50 m around this distance is plotted, if a vector with two elements is given (e.g. 20 | c(280, 620)) this distance range will be plotted} 21 | } 22 | \value{ 23 | desc 24 | } 25 | \description{ 26 | If multiple channel surveys are present (time series analyses) and the reference centerline mode is 27 | used, this function allows to plot the shift of the banks (bank erosion and aggradation) along the channel. 28 | } 29 | \details{ 30 | \code{CM.plotMetrics()} allows to plot the position of banks with regard to the centerline in downstream 31 | direction. If only one survey is present, the plot will only show the distance of the right and left bank 32 | to the centerline over the centerline distance (downstream length of the channel). If multiple surveys of a 33 | channel exists (time series analyses) the differences of the channel banks can be calculated if a reference 34 | centerline is used (reference centerline mode). The differences (bank ersosion and aggradation) are plotted 35 | with this function. 36 | 37 | Without passing something to the function, the banks of the whole channel are plotted. To specify a region 38 | use the \code{cl} and \code{d} parameters. See the parameter definition and the example section for details. 39 | } 40 | \examples{ 41 | 42 | # open demo 43 | cmgo.obj = CM.ini("demo3") 44 | 45 | # example 1: plot the distance of channel banks to centerline 46 | CM.plotMetrics(cmgo.obj) 47 | 48 | # example 2: plot the change of the channel banks (aggradation/erosion) 49 | CM.plotMetrics(cmgo.obj, set="set2") 50 | 51 | # example 3: plot only a range 52 | CM.plotMetrics(cmgo.obj, set="set2", cl=c(800, 850)) 53 | CM.plotPlanView(cmgo.obj, set="set2", cl=c(800, 850)) # compare with plan view map 54 | 55 | } 56 | \author{ 57 | Antonius Golly 58 | } 59 | -------------------------------------------------------------------------------- /man/CM.plotPlanView.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/CM.plotPlanView.r 3 | \name{CM.plotPlanView} 4 | \alias{CM.plotPlanView} 5 | \title{Plot a map of the channel} 6 | \usage{ 7 | CM.plotPlanView( 8 | cmgo.obj, 9 | set = "set1", 10 | title = NULL, 11 | set.compare = NULL, 12 | extent = NULL, 13 | zoom = FALSE, 14 | zoom.length = NULL, 15 | cl = NULL, 16 | error = NULL, 17 | error.type = "errors.filter2", 18 | x = NULL, 19 | y = NULL 20 | ) 21 | } 22 | \arguments{ 23 | \item{cmgo.obj}{the global object of type list containing data and parameters created with \code{\link[=CM.ini]{CM.ini()}}} 24 | 25 | \item{set}{the data set to be plotted, "set1" if not specified. See documentation of CM.ini() to learn about data sets.} 26 | 27 | \item{title}{a title printed above the plot, if not specified a title will be composed from the enabled plot elements} 28 | 29 | \item{set.compare}{a second data set to be plotted in light color for comparison} 30 | 31 | \item{extent}{a string defining the plotting extent of the map (specifying an object of the list in par$plot.zoom.extents) or NULL (the default extent of par$plot.zoom.extent is taken)} 32 | 33 | \item{zoom}{defines if plot is zoomed (TRUE) or not (FALSE). In case of NULL (default) the value of par$plot.zoom is taken} 34 | 35 | \item{zoom.length}{a number defining the zoom length} 36 | 37 | \item{cl}{the centerline point or points with should be centered} 38 | 39 | \item{error}{an integer between 1 and (see Details for further information)} 40 | 41 | \item{error.type}{a string specifying which errors should be investigated ("errors.filter2", "errors.filter2.first" or "errors.sort")} 42 | 43 | \item{x}{an x-coordinate where the map is centered at} 44 | 45 | \item{y}{an y-coordinate where the map is centered at} 46 | } 47 | \value{ 48 | a list of applied plot parameters (this is useful for plotting the same extent in CM.plotMetrics()) 49 | } 50 | \description{ 51 | Create a plan view map of the channel and various elements that can be switched on and off (banks, centerline, transects, 52 | grid, legend, etc.). 53 | } 54 | \details{ 55 | \code{CM.plotPlanView()} creates a plan view plot. To specify the map extent (plot region) multiple settings exist. 56 | The map extent is the range of x and y coordinates shown on the map, speaking in R terms the xlim and ylim parameters of the plot function. 57 | In \code{CM.plotPlanView()} the map extent is defined by a center coordinate (x and one y coordinate where the plot is centered at), and a zoom length. You have multiple 58 | ways to determine the center coordinate: pre-defined extent, cl, error and direct x/y coordinates (see descriptions in the parameters). 59 | This list also represents the priority, meaning, the pre-defined extent indicates the lowest priority and x/y coordinates the highest if more than one 60 | parameter is set. The zoom length can be given via the global parameter object or directly with the parameter zoom. 61 | 62 | You can enable/disable the following plotting elements via the paramtere object:\preformatted{ 63 | plot.planview = TRUE, # plot an plan view overview plot 64 | plot.planview.secondary = TRUE, # plot a secondary channel polygon to the plot (for comparison of data sets) 65 | plot.planview.bank.points = TRUE, # plot channel bank points 66 | plot.planview.polygon = TRUE, # plot channel bank polygon 67 | plot.planview.voronoi = TRUE, # plot voronoi polygons in plan view plot 68 | plot.planview.cl.original = FALSE, # plot centerline in plan view plot 69 | plot.planview.cl.smoothed = TRUE, # plot centerline in plan view plot 70 | plot.planview.cl.tx = FALSE, # plot a label next to the centerline points 71 | plot.planview.transects = FALSE, # plot transects 72 | plot.planview.transects.len = 20, # the length of transects 73 | plot.planview.dist2banks = TRUE, # plot transect segments from bank to bank 74 | plot.planview.grid = TRUE, # plot a grid in the background of the plan view plot 75 | plot.planview.grid.dist = 20, # the distance of the grid lines 76 | plot.planview.legend = TRUE, # plot a legend 77 | plot.planview.scalebar = TRUE, # plot a scalebar 78 | } 79 | } 80 | \examples{ 81 | # get demo data (find instructions on how to use own data in the documentation of CM.ini()) 82 | cmgo.obj = CM.ini("demo2") 83 | 84 | # example 1: overview plot 85 | CM.plotPlanView(cmgo.obj) 86 | 87 | } 88 | \author{ 89 | Antonius Golly 90 | } 91 | -------------------------------------------------------------------------------- /man/CM.plotWidth.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/CM.plotWidth.r 3 | \name{CM.plotWidth} 4 | \alias{CM.plotWidth} 5 | \title{Plot channel width} 6 | \usage{ 7 | CM.plotWidth(cmgo.obj, set = "set1", set.compare = NULL, cl = NULL, d = NULL) 8 | } 9 | \arguments{ 10 | \item{cmgo.obj}{the global object of type list containing data and parameters created with \code{\link[=CM.ini]{CM.ini()}}} 11 | 12 | \item{set}{the primary data set to plot ("set1" by default)} 13 | 14 | \item{set.compare}{the secondary data set to plot (optional)} 15 | 16 | \item{cl}{the range of centerline points to be plotted, if NULL (default) the full channel length will be plotted, if 17 | a vector of two elements is provided (e.g. c(200, 500)) this cl range is plotted, if a string is provided (e.g. "cl1"), 18 | the range defined in \code{par$plot.cl.ranges$cl1} will be plotted} 19 | 20 | \item{d}{the distance range of the centerline downstream to be plotted, NULL (default) cl defintions are taken, if a 21 | single value (e.g. d=500) is given 50m around this distance is plotted, if a vector with two elements is given (e.g. 22 | c(280, 620)) this distance range will be plotted} 23 | } 24 | \value{ 25 | desc 26 | } 27 | \description{ 28 | Plot the channel width of the whole channel (default) or for a portion (use \code{cl} argument). The function can 29 | also compare two data sets if they have the same reference centerline. 30 | } 31 | \details{ 32 | If more than one data set is defined in the global data object, of 33 | 34 | Details 35 | } 36 | \examples{ 37 | 38 | # open demo 39 | cmgo.obj = CM.ini("demo2") 40 | 41 | # example 1: plot channel width of whole channel 42 | CM.plotWidth(cmgo.obj) 43 | 44 | # example 2: plot channel width of a defined range (centerline points) 45 | CM.plotWidth(cmgo.obj, cl=c(800, 1000)) 46 | 47 | # example 2: plot channel width of a defined range (distance downstream) 48 | CM.plotWidth(cmgo.obj, d=c(200, 600)) 49 | 50 | } 51 | \author{ 52 | Antonius Golly 53 | } 54 | -------------------------------------------------------------------------------- /man/CM.processCenterline.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/CM.processCenterline.r 3 | \name{CM.processCenterline} 4 | \alias{CM.processCenterline} 5 | \title{Process the centerline} 6 | \usage{ 7 | CM.processCenterline(cmgo.obj, set = NULL) 8 | } 9 | \arguments{ 10 | \item{cmgo.obj}{the global object of type list containing data and parameters created with \code{\link[=CM.ini]{CM.ini()}}} 11 | 12 | \item{set}{an optional argument for processing a specific data set, if \code{NULL} all available data sets are used} 13 | } 14 | \value{ 15 | returns the global data object extended by the centerline data \code{$metrics} for the respective data set 16 | } 17 | \description{ 18 | Derive width, slope and further principle channel metrics for the channel centerline previously created. 19 | } 20 | \details{ 21 | \code{CM.processCenterline()} calculate the channel metrics (Fig. 9) based on the centerline previously calculated. 22 | It does that by first deriving channel transects. The transects are lines perpendicular to a group of centerline points 23 | where the size of that group is defined by the parameter \code{transects.span}. By default this span 24 | equals three which means for each group of three centerline points a line is created through the outer points of 25 | that group to which the perpendicular -- the transect -- is calculated (see Fig. 8b). In the final step the intersections of the 26 | transects with the banks are calculated (Fig. 8c). 27 | 28 | \if{html}{\figure{08-processing.png}{options: width="800px" alt="Figure: processing"}} 29 | \if{latex}{\figure{08-processing.pdf}{options: width=9cm}} 30 | \emph{Figure 8: A visualization of the transect calculation. a) the channel centerline, b) for each 31 | group of \code{n} points (in the example n=3) a line is fitted through the outer points (black line). 32 | The perpendicular to this line is the transect. c) the vectors from each centerline point to the left 33 | and to the right bank are calculated and stored separately.} 34 | 35 | When the transects cross the banks multiple times, the minimum distance is taken. In addition to the width, 36 | the distances of the centerline points to the banks is stored sepearately for the left and the right bank. This 37 | is particularly of importance when using multiple time series of channel profiles. See paragraph in 38 | the (see \link[=cmgo]{paragraph "Time series analyses" of package documentation}. 39 | 40 | The function returns the global data object extended by the following variables (length equals number 41 | of points of the reference centerline): \preformatted{ 42 | $metrics$tr # linear equations of the transects 43 | $metrics$cp.r # coordinates of crossing points transects / right bank 44 | $metrics$cp.l # coordinates of crossing points transects / left bank 45 | $metrics$d.r # distance of reference centerline point / right bank 46 | $metrics$d.l # distance of reference centerline point / left bank 47 | $metrics$w # channel width 48 | $metrics$r.r # direction value: -1 for right, +1 for left to the centerline 49 | $metrics$r.l # direction value: -1 for right, +1 for left to the centerline 50 | $metrics$diff.r # difference between right bank point of actual time series and right bank point of reference series 51 | $metrics$diff.l # difference between left bank point of actual time series and left bank point of reference series 52 | } 53 | If you calculate channel metrics for one channel survey, the right bank is always to the right side of the centerline and 54 | the left bank always left to the centerline. Thus, the values of \code{r.r} are all -1 and the values of \code{r.l} all +1. However, 55 | when using a reference centerline to compare different channel surveys, these values can be required. If for example 56 | you examine the bank metrics for a reference centerline that is very different to the actual survey, the centerline 57 | is not necessarily between the two banks. This can happen when a massive shift of the channel bed occurred (see Fig. 9). 58 | For further calculations consider then the sign of the \code{r.r} and \code{r.l} values! 59 | } 60 | \examples{ 61 | # get demo data (find instructions on how to use own data in the documentation of CM.ini()) 62 | cmgo.obj = CM.ini("demo1") 63 | 64 | # calculate channel metrics from centerline 65 | cmgo.obj = CM.processCenterline(cmgo.obj) 66 | 67 | } 68 | \author{ 69 | Antonius Golly 70 | } 71 | -------------------------------------------------------------------------------- /man/CM.resampleCenterline.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/CM.resampleCenterline.r 3 | \name{CM.resampleCenterline} 4 | \alias{CM.resampleCenterline} 5 | \title{Resample centerline points} 6 | \usage{ 7 | CM.resampleCenterline(cmgo.obj, set = NULL) 8 | } 9 | \arguments{ 10 | \item{cmgo.obj}{the global object of type list containing data and parameters created with \code{\link[=CM.ini]{CM.ini()}}} 11 | 12 | \item{set}{an optional argument for processing a specific data set, if \code{NULL} all available data sets are used} 13 | } 14 | \value{ 15 | the global data object 16 | } 17 | \description{ 18 | Create an equally spaced centerline with a given interval length. 19 | } 20 | \details{ 21 | The spatial resolution of the centerline depends on the spatial resolution of the bank points which is 22 | directly dependent on the parameter par$polygon.bank.interpolate.max.dist. A small interpolation distance is necessary for complex 23 | bed shapes. However, for further metric analyes a large number of centerline points is not necessary. Since they can introduce 24 | high computational costs during further calculation you can resample the centerline intervals with this function CM.resampleCenterline(). 25 | decreasing the resolution to a given value. This will have slight impact on the length of the centerline. Since you are losing 26 | detail a coarser interval will decrease the length of the centerline. 27 | } 28 | \examples{ 29 | 30 | # get the demo data set 31 | cmgo.obj = CM.ini("demo2") 32 | 33 | # resample centerline resolution 34 | cmgo.obj = CM.resampleCenterline(cmgo.obj) 35 | 36 | } 37 | \author{ 38 | Antonius Golly 39 | } 40 | -------------------------------------------------------------------------------- /man/CM.run.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/CM.run.r 3 | \name{CM.run} 4 | \alias{CM.run} 5 | \title{Run the full stack of the main cmgo functions} 6 | \usage{ 7 | CM.run(object = NULL, par = NULL) 8 | } 9 | \arguments{ 10 | \item{object}{Possible values include \code{NULL} and the global data object.} 11 | 12 | \item{par}{Possible values include \code{NULL}, filename or list of parameters. If \code{par} is not specified or 13 | NULL the default parameters are used (see documentation of CM.par() to learn about the default parameters). If \code{par} 14 | is a filename CM.ini() will try to open that file and look for a list \code{par} in that file. In case of success the parameters 15 | from that file are loaded and merged with the default parameters. Merging means, not all parameters have to be defined in the parameter 16 | file. Parameters that are not defined are taken from the default. In case \code{par} is a list, the default parameters are merged with this 17 | list. That means, if the actual parameters are handed over to CM.ini() - e.g. \code{global_data_object$par} - the parameters will be passed 18 | through.} 19 | } 20 | \value{ 21 | The global data object containing data ($data) and parameters ($par). The global data object must be passed to all main functions of \code{cmgo}. 22 | } 23 | \description{ 24 | This function is a wrapper function for the main functions of the package \code{cmgo}. With no parameters 25 | passed, it initializes the global data object containing the demo data set and the default parameters. 26 | It returns the global data object - as all main function do - which can be used for further execution 27 | of the program. If your global data object already exists, you can pass this to \code{CM.run()} to execute 28 | all main functions at once. Alternatively, you can call \code{CM.run()} with a parameter object or a file 29 | name of a parameter configuration (see \code{\link[=CM.par]{CM.par()}} for further information.) 30 | } 31 | \details{ 32 | CM.run represents a wrapper function of the main \code{cmgo} functions with the following code: 33 | \preformatted{ 34 | CM.ini() 35 | CM.generatePolygon() 36 | CM.calculateCenterline() 37 | CM.processCenterline() 38 | CM.writeData() 39 | CM.plotPlanView() 40 | } 41 | 42 | You can use \code{CM.run()} either for demo purposes (just call CM.run() without parameters) or to start 43 | a new project from scratch. To do this, make sure you have read about the input data preparation in the 44 | documentation of \code{\link[=CM.ini]{CM.ini()}}. If you are familiar with the input data preparation 45 | just call CM.run() while you place your valid input files to the specified input directory (defaults to \code{"./input"}). 46 | } 47 | \examples{ 48 | 49 | # example 1: open with demo data and default parameters 50 | cmgo.obj = CM.run() 51 | 52 | # example 2: re-create global data object with updated parameters 53 | #parameter_file = "par/new_config.r" # specify an existing parameter file 54 | parameter_file = NULL 55 | cmgo.obj = CM.run(cmgo.obj, parameter_file) 56 | 57 | } 58 | \author{ 59 | Antonius Golly 60 | } 61 | -------------------------------------------------------------------------------- /man/CM.writeData.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/CM.writeData.r 3 | \name{CM.writeData} 4 | \alias{CM.writeData} 5 | \title{Write data} 6 | \usage{ 7 | CM.writeData(cmgo.obj) 8 | } 9 | \arguments{ 10 | \item{cmgo.obj}{the global object of type list containing data and parameters created with \code{\link[=CM.ini]{CM.ini()}}} 11 | } 12 | \value{ 13 | This file function does not return any value. 14 | } 15 | \description{ 16 | Write output files with channel metrics and the current workspace. 17 | } 18 | \details{ 19 | \code{CM.writeData()} allows you to write the results to output files and to an R workspace file. 20 | The outputs written depend on the settings in the parameter object. If \code{cmgo.obj$par$workspace.write = TRUE} 21 | (default is FALSE) a workspace file is written containing the global data object. The 22 | filename is defined in \code{cmgo.obj$par$workspace.filename}. Further, ASCII tables can be written 23 | containing the centerline geometry and the calculated metrics. If \code{cmgo.obj$par$output.write = TRUE} 24 | (default is FALSE) an output file for each data set is written to the output folder specified 25 | in \code{cmgo.obj$par$output.dir}. The file names are the same as the input filenames with the 26 | prefixes cl_* and metrics_*. All parameters regarding the output generation are listed in \code{\link[=CM.par]{CM.par()}}. 27 | } 28 | \examples{ 29 | # get demo data (find instructions on how to use own data in the documentation of CM.ini()) 30 | cmgo.obj = CM.ini("demo2") 31 | 32 | # example 1: write workspace 33 | cmgo.obj$par$workspace.write = TRUE 34 | CM.writeData(cmgo.obj) 35 | 36 | # example 2: write output files 37 | cmgo.obj$par$output.write = TRUE 38 | cmgo.obj$par$output.write.centerline = TRUE 39 | cmgo.obj$par$output.write.metrics = TRUE 40 | cmgo.obj$par$output.dir = "custom_output_folder" 41 | cmgo.obj$par$workspace.write = FALSE 42 | 43 | CM.writeData(cmgo.obj) 44 | 45 | } 46 | \author{ 47 | Antonius Golly 48 | } 49 | -------------------------------------------------------------------------------- /man/cmgo.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/cmgo-package.r 3 | \docType{package} 4 | \name{cmgo} 5 | \alias{cmgo} 6 | \title{Deriving basic channel metrics from bank and long-profile geometry} 7 | \description{ 8 | Principle channel metrics, as for example \strong{channel width or gradient}, 9 | convey immanent information that can be exploited for geomorphic research. 10 | For example, a snap-shot of the current local channel geometry can provide 11 | an integrated picture of the processes leading to its formation, if examined 12 | in a statistically sound manner. Repeated surveys, 13 | as time-series of channel gradients, can reveal local erosional characteristics 14 | that sharpen our understanding of the underlying processes and facilitate, 15 | inspire and motivate further research. However, these geometrical metrics 16 | are not directly available. Typically, the measurable quantities are limited 17 | to the position of features, such as the channel banks (or water surface) or 18 | the water flow path (thalweg) in two- or three-dimensional coordinates. This package 19 | derives with a scale-free approach principle 20 | channel metrics, as channel width and slope. It does that by first generating a 21 | reference line in the middle of the channel (centerline) based on which then the 22 | channel width is calculated. It also allows for analyzing the evolution of channel 23 | metrics over time if multiple surveys are provided. Furthermore, secondary spatial information (as for example the 24 | occurrence of knickpoints, the abundance of certain species, etc.) can be projected 25 | to the reference line allowing for a spatial correlation of different variables. 26 | } 27 | \section{Getting started}{ 28 | 29 | To start a new project you will need to go through the full stack of the main functions 30 | of this package \code{cmgo}. To do this read the instructions under \strong{Run cmgo}. However, 31 | if you just want a quick demo run just write \code{\link[=CM.run]{CM.run()}} into the console and execute. 32 | } 33 | 34 | \section{General information on the global data object}{ 35 | 36 | All the data and parameters used in \code{cmgo} are stored in one variable of 37 | \href{http://www.r-tutor.com/r-introduction/list}{type list}: the global data object, 38 | in the following examples named \code{cmgo.obj}. Its structure is: 39 | \preformatted{cmgo.obj = list( 40 | data = list() # the data set(s), different surveys of the channel 41 | set1 = list(), # survey 1 42 | set2 = list() # survey 2 43 | # ... 44 | ), 45 | par = list() # all plotting and model parameters 46 | )} 47 | 48 | The global data object then has to be \strong{passed to} and is \strong{returned from} 49 | all main functions of the package as in 50 | 51 | \code{cmgo.obj = \link[=CM.generatePolygon]{CM.generatePolygon(cmgo.obj)}}\cr 52 | \code{cmgo.obj = \link[=CM.calculateCenterline]{CM.calculateCenterline(cmgo.obj)}}\cr 53 | \code{cmgo.obj = \link[=CM.processCenterline]{CM.processCenterline(cmgo.obj)}}\cr 54 | \code{\link[=CM.writeData]{CM.writeData(cmgo.obj)}}\cr 55 | \code{\link[=CM.plotPlanView]{CM.plotPlanView(cmgo.obj)}}\cr 56 | 57 | 58 | The global data object is \strong{initialized} with \code{cmgo.obj = CM.ini()} where 59 | \code{\link[=CM.ini]{CM.ini()}} will either create the object from input files, from a previously 60 | saved user workspace or from a demo data set. See the documentation of \code{\link[=CM.ini]{CM.ini()}} 61 | for detailed information on how to create the object. 62 | } 63 | 64 | \section{Parameters}{ 65 | 66 | The parameters are stored in the global data object, for example \code{cmgo.obj$par}. They 67 | can always be accessed or edited directly by e.g. \preformatted{obj$par$plot.planview = TRUE} 68 | Alternatively, users can load custom parameters from files previously created (e.g. to save 69 | project settings or reproduce certain plots). Parameter files are loaded with \preformatted{cmgo.obj$par = CM.par("custom_par_list.r")} 70 | 71 | 72 | See the documentation of \code{\link[=CM.par]{CM.par()}} for detailed information on how to load parameters. 73 | } 74 | 75 | \section{Work flow}{ 76 | 77 | The program can be divided into three main parts which you will go through if you start a project: 78 | \strong{1. initialization} (loading data and parameters), 79 | \strong{2. data processing} (calculating channel metrics) and 80 | \strong{3. review results} (plotting or writing results to file). 81 | The initialization covers the loading of the parameters in \code{\link[=CM.par]{CM.par()}} and loading of 82 | the data in \code{\link[=CM.ini]{CM.ini()}}. See their documentation for details. The work flow of 83 | the data processing is shown in the plan view plots below. 84 | 85 | \if{html}{\figure{01-processing.png}{options: width="800px" alt="Figure: processing"}} 86 | \if{latex}{\figure{01-processing.pdf}{options: width=9cm}} 87 | \emph{Figure 1: A visualization of the work flow of the package, a) data input, b) polygon generation, 88 | c-e) centerline generation, f) transect generation, g) channel width calculation.} 89 | 90 | Channel bank points (Fig. 1a) represent the required input data for the package. The algorithm 91 | then creates a polygon from these points (Fig. 1b) where the points are linearly interpolated 92 | to increase their spatial resolution. The maximum distance the points have is defined by the parameter 93 | \code{bank.interpolate.max.dist}. From these points Voronoi polygons are calculated (Fig. 1c). 94 | Voronoi polygons around points denote the areas within which all points are closest to that point. 95 | In Fig. 1c you can already notice a centerline evolving in the middle of the channel polygon. Fig. 1d shows 96 | the segments that represent the centerline filtered by the algorithm. These centerline segments will be 97 | connected to one consistent line and get smoothed (Fig. 1e). The degree of smoothing can be adjusted 98 | through the parameter \code{centerline.smoothing.width} (defaults to the same value as 99 | \code{bank.interpolate.max.dist}). This centerline represents the reference of the river, for which 100 | length, local width and slope are calculated next. Note, that the length of the centerline depends on 101 | the smoothing in 1e). The pros and cons of the smoothing are explained in the documentation of the function 102 | \code{CM.calculateCenterline()}. To derive the local channel width, transects are calculated perpendicular 103 | to portions of the centerline (Fig. 1f). The transects are lines perpendicular to a group of centerline points 104 | where the size of that group is defined by the parameter \code{transects.span}. See 105 | \code{\link[=CM.processCenterline]{CM.processCenterline()}} for detailed information on how the transects 106 | are generated. In the final step the intersections of the 107 | transects with the banks are calculated (Fig. 1g). The distance of the 108 | centerline point to the bank is stored sepearately for the left and the right bank. When the transects 109 | cross the banks multiple times, the minimum distance is taken. 110 | 111 | The described algorithm is hosted in the following functions: 112 | \itemize{ 113 | \item load data points in \code{\link[=CM.ini]{CM.ini()}}, step \strong{a} 114 | \item generate a polygon from bank points in \code{\link[=CM.generatePolygon]{CM.generatePolygon()}}, step \strong{b} 115 | \item calculate centerlin from the polygon in \code{\link[=CM.calculateCenterline]{CM.calculateCenterline()}}, steps \strong{c-e} 116 | \item process the centerline in \code{\link[=CM.processCenterline]{CM.processCenterline()}}, steps \strong{f-g} 117 | } 118 | } 119 | 120 | \section{Run cmgo}{ 121 | 122 | The main functions of cmgo (described in \strong{Work flow}) should be exectued in this order: \preformatted{ 123 | cmgo.obj = CM.ini(cmgo.obj, par="par/my_parameters.r") # read data, optional: path to a parameter file, alternatively leave empty to use defaults 124 | cmgo.obj = CM.generatePolygon(cmgo.obj) # generate polygon 125 | cmgo.obj = CM.calculateCenterline(cmgo.obj) # get centerline (calculate or load) 126 | cmgo.obj = CM.processCenterline(cmgo.obj) # process centerline (calculate width) 127 | CM.plotPlanView(cmgo.obj) # plot results 128 | CM.plotMetrics(cmgo.obj) # plot channel width and bank retreat 129 | CM.writeData(cmgo.obj) # data to workspace and export data to csv-files (see par)#' 130 | } 131 | 132 | If the generated polygon from CM.generatePolygon() has more than 10,000 vertices, the execution time can be extensive. 133 | Thus, CM.calculateCenterline(), as the other main CM functions, has a chaching mechanism of the data. If you call 134 | the function when the resulting data already exists, the data will not be processed. You will have to explicitly force the generation of the data. 135 | When you change a parameter regarding the generation of the polygon (see CM.generatePolygon()) the program will 136 | detect this change and will calculate the centerline without forcing it. 137 | } 138 | 139 | \section{Time series analyses}{ 140 | 141 | The package cmgo can handle time series of channel geometries and offers the opportunity 142 | to compare them. To do this, simply put the an input file for each data set in the input directory 143 | (see \code{\link[=CM.ini]{CM.ini()}}). The function will create a data object for each file in the 144 | global data object under, \code{cmgo.obj$data$set1}, \code{cmgo.obj$data$set2}, \code{cmgo.obj$data$set3}, etc. 145 | All functions will iterate over the data sets automatically. 146 | 147 | If you want to address via a variable use \code{cmgo.obj$data[[set]]}, where is a string of the data set, 148 | e.g. \code{"set1"}. The order of data sets will be determined by the filenames. So, make sure to name the files 149 | accordingly, e.g. \code{"channelsurvey_a.csv"},\code{"channelsurvey_b.csv"}. The mapping of the filenames to 150 | data sets will be printed to the console. Also, you can view the file names belonging to a data set with 151 | \code{print(cmgo.obj$data[[set]]$filename)}. 152 | 153 | \strong{Reference centerline}\cr 154 | The channel metrics are calculated based on a centerline. Normally, for a river plan geometry one centerline exists 155 | and this is the basis for the metrics. However, when there are multiple time lines two options exist. 156 | Metrics are either calculated for each channel geometry individually. This way you have the most accurate 157 | representation of the channel metrics for that channel observation. For example, channel width is most 158 | accurately measured. However, different time series of observations are difficult to compare since the basis 159 | for the calculations -- the centerlines -- differ. Thus, when comparing time series, a second approach exists 160 | where you can determine a reference centerline for all metrics calculations. To do this set: \preformatted{ 161 | cmgo.obj$par$centerline.use.reference = TRUE 162 | cmgo.obj$par$centerline.reference = "set1" 163 | } 164 | Now, all metrics for the different bank surveys will be calculated based on the centerline 165 | of the data set "set1". Use this option only if your bank surveys differ only slightly. Otherwise, the 166 | calculated channel metrics might not be representative (see Fig. 10). 167 | 168 | \if{html}{\figure{10-documentation.png}{options: width="800px" alt="Figure: reference centerline"}} 169 | \if{latex}{\figure{10-documentation.png}{options: width=6cm}} 170 | \emph{Figure 10: For channel geometries that differ drastically, the usage of a reference centerline 171 | is not advised. The centerline of a data set (blue line) is not useful for calculating the metrics 172 | of the dashed channel geometry.} 173 | } 174 | 175 | \section{Technical fails and how to prevent them}{ 176 | 177 | All parameters are stored in the global data object (see the section 'Global data object') under the sub-list 178 | $par. For example, if your global data object is named \code{obj} the parameter \code{$plot.planview} is 179 | accessible by \code{obj$par$transects.span}. The available parameters of the model are described in 180 | the documentation of the function \code{\link[=CM.par]{CM.par()}}. Here we only describe a few cases why editing the 181 | default parameters can be desired. 182 | 183 | There are certain geometrical cases in which the algorithm can fail with the default parametrization. 184 | To prevent this a wise parametrization of the model is required. The program will inform you during runtime 185 | if the generation of the centerline fails and will offer you ways to elaborate the issue. The main reason for 186 | failure occurs if the resolution of channel bank points (controlled via \code{$bank.interpolate.max.dist}) 187 | is relatively low compared to the channel width. The following image illustrates the problem: 188 | 189 | \if{html}{\figure{02-gap.png}{options: width="500px" alt="Figure: Gap in Centerline"}} 190 | \if{latex}{\figure{02-gap.png}{options: width=6cm}} 191 | \emph{Figure 2: A gap in the centerline occurs since the spacing of the bank points was too high.} 192 | 193 | Apparently, the centerline segments are too scraggy and do not lie entirely within the bank polygons. Since 194 | the filter mechanism (step \strong{c-d}) checks for segments within the polygon first, this will create a gap 195 | in the centerline. The program will not be able to fill this gap automatically. Thus, if you experience problems 196 | with the calculation of the centerline consider to increase the spatial resolution of bank points. The following 197 | example illustrates how this fixes the problem. 198 | 199 | \if{html}{\figure{03-sep-spacing.png}{options: width="500px" alt="Figure: fix"}} 200 | \if{latex}{\figure{03-sep-spacing.png}{options: width=6cm}} 201 | \emph{Figure 3: The same location of the channel with two different bank point spacings.} 202 | 203 | Another problem can arise from an unsuitable settings of the span for the calculation of the 204 | transects (step \strong{f}). The transects are perpendicular to a line that goes through the outer points 205 | of a group of \code{n} points of the centerline. This \code{n} equals 3 by default (parameter 206 | \code{$transects.span}). The following plan view plot illustrates to what misinterpretation of the channel width 207 | can lead: 208 | 209 | \if{html}{\figure{04-transect-span.png}{options: width="500px" alt="span_issues"}} 210 | \if{latex}{\figure{04-transect-span.png}{options: width=6cm}} 211 | \emph{Figure 4, left: the transects (perpendiculars to the centerline) do not intersect 212 | with banks properly, thus channel width is overrepresented. Right: an increased transect span fixes the problem 213 | and channel width is now identified correctly.} 214 | 215 | It can be seen that one of the red transects does not touch the left bank of the channel, thus leading to 216 | an overestimated channel width at this location. To prevent this, you can increase the span of the transect 217 | calculation. 218 | } 219 | 220 | -------------------------------------------------------------------------------- /man/demo.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/demo.r 3 | \docType{data} 4 | \name{demo} 5 | \alias{demo} 6 | \title{Raw input demo data set to run the full stack of cmgo functions. 7 | Contains a list with sublists $par and $data.} 8 | \format{ 9 | An object of class \code{list} of length 2. 10 | } 11 | \usage{ 12 | demo 13 | } 14 | \description{ 15 | Raw input demo data set to run the full stack of cmgo functions. 16 | Contains a list with sublists $par and $data. 17 | } 18 | \keyword{datasets} 19 | -------------------------------------------------------------------------------- /man/demo1.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/demo1.r 3 | \docType{data} 4 | \name{demo1} 5 | \alias{demo1} 6 | \title{Half processed demo data set to run test centerline processing of cmgo. The data set already contains a centerline. 7 | Contains a list with sublists $par and $data.} 8 | \format{ 9 | An object of class \code{list} of length 2. 10 | } 11 | \usage{ 12 | demo1 13 | } 14 | \description{ 15 | Half processed demo data set to run test centerline processing of cmgo. The data set already contains a centerline. 16 | Contains a list with sublists $par and $data. 17 | } 18 | \keyword{datasets} 19 | -------------------------------------------------------------------------------- /man/demo2.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/demo2.r 3 | \docType{data} 4 | \name{demo2} 5 | \alias{demo2} 6 | \title{Fully processed demo data set to run test the output and plotting functions of cmgo. 7 | Contains a list with sublists $par and $data.} 8 | \format{ 9 | An object of class \code{list} of length 2. 10 | } 11 | \usage{ 12 | demo2 13 | } 14 | \description{ 15 | Fully processed demo data set to run test the output and plotting functions of cmgo. 16 | Contains a list with sublists $par and $data. 17 | } 18 | \keyword{datasets} 19 | -------------------------------------------------------------------------------- /man/demo3.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/demo3.r 3 | \docType{data} 4 | \name{demo3} 5 | \alias{demo3} 6 | \title{Fully processed demo data set to run test the output and plotting functions of cmgo. 7 | In contrast to demo data set 2 this data set uses the reference centerline mode. 8 | Contains a list with sublists $par and $data.} 9 | \format{ 10 | An object of class \code{list} of length 2. 11 | } 12 | \usage{ 13 | demo3 14 | } 15 | \description{ 16 | Fully processed demo data set to run test the output and plotting functions of cmgo. 17 | In contrast to demo data set 2 this data set uses the reference centerline mode. 18 | Contains a list with sublists $par and $data. 19 | } 20 | \keyword{datasets} 21 | -------------------------------------------------------------------------------- /man/figures/01-processing.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntoniusGolly/cmgo/abce48b13cfeaa2c0e991ff02650aa569f5527b4/man/figures/01-processing.pdf -------------------------------------------------------------------------------- /man/figures/01-processing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntoniusGolly/cmgo/abce48b13cfeaa2c0e991ff02650aa569f5527b4/man/figures/01-processing.png -------------------------------------------------------------------------------- /man/figures/02-gap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntoniusGolly/cmgo/abce48b13cfeaa2c0e991ff02650aa569f5527b4/man/figures/02-gap.png -------------------------------------------------------------------------------- /man/figures/03-sep-spacing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntoniusGolly/cmgo/abce48b13cfeaa2c0e991ff02650aa569f5527b4/man/figures/03-sep-spacing.png -------------------------------------------------------------------------------- /man/figures/04-transect-span.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntoniusGolly/cmgo/abce48b13cfeaa2c0e991ff02650aa569f5527b4/man/figures/04-transect-span.png -------------------------------------------------------------------------------- /man/figures/06-processing.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntoniusGolly/cmgo/abce48b13cfeaa2c0e991ff02650aa569f5527b4/man/figures/06-processing.pdf -------------------------------------------------------------------------------- /man/figures/06-processing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntoniusGolly/cmgo/abce48b13cfeaa2c0e991ff02650aa569f5527b4/man/figures/06-processing.png -------------------------------------------------------------------------------- /man/figures/07-filtering.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntoniusGolly/cmgo/abce48b13cfeaa2c0e991ff02650aa569f5527b4/man/figures/07-filtering.pdf -------------------------------------------------------------------------------- /man/figures/07-filtering.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntoniusGolly/cmgo/abce48b13cfeaa2c0e991ff02650aa569f5527b4/man/figures/07-filtering.png -------------------------------------------------------------------------------- /man/figures/08-processing.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntoniusGolly/cmgo/abce48b13cfeaa2c0e991ff02650aa569f5527b4/man/figures/08-processing.pdf -------------------------------------------------------------------------------- /man/figures/08-processing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntoniusGolly/cmgo/abce48b13cfeaa2c0e991ff02650aa569f5527b4/man/figures/08-processing.png -------------------------------------------------------------------------------- /man/figures/09_original_and_smoothed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntoniusGolly/cmgo/abce48b13cfeaa2c0e991ff02650aa569f5527b4/man/figures/09_original_and_smoothed.png -------------------------------------------------------------------------------- /man/figures/10-documentation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntoniusGolly/cmgo/abce48b13cfeaa2c0e991ff02650aa569f5527b4/man/figures/10-documentation.png -------------------------------------------------------------------------------- /man/figures/10_documentation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntoniusGolly/cmgo/abce48b13cfeaa2c0e991ff02650aa569f5527b4/man/figures/10_documentation.png -------------------------------------------------------------------------------- /man/figures/10b_documentation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntoniusGolly/cmgo/abce48b13cfeaa2c0e991ff02650aa569f5527b4/man/figures/10b_documentation.png -------------------------------------------------------------------------------- /man/figures/11_documentation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntoniusGolly/cmgo/abce48b13cfeaa2c0e991ff02650aa569f5527b4/man/figures/11_documentation.png -------------------------------------------------------------------------------- /man/figures/basins.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntoniusGolly/cmgo/abce48b13cfeaa2c0e991ff02650aa569f5527b4/man/figures/basins.png -------------------------------------------------------------------------------- /man/figures/plotCheckPolygon.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntoniusGolly/cmgo/abce48b13cfeaa2c0e991ff02650aa569f5527b4/man/figures/plotCheckPolygon.pdf -------------------------------------------------------------------------------- /man/figures/plotCheckPolygon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AntoniusGolly/cmgo/abce48b13cfeaa2c0e991ff02650aa569f5527b4/man/figures/plotCheckPolygon.png --------------------------------------------------------------------------------