#' R function for calculating accumulated anisotropic slope-dependant cost of movement across the terrain and least-cost paths from a point origin
#'
#' The function provides the facility to calculate the anisotropic accumulated cost of movement around a starting location and to optionally calculate least-cost path(s) toward
#' one or multiple destinations. It implements different cost estimations related to human movement across the landscape.
#' The function takes as input a Digital Terrain Model ('RasterLayer' class) and a point feature ('SpatialPointsDataFrame' class), the latter representing
#' the starting location, i.e. the location from which the accumulated cost is calculated. Besides citing this package,
#' you may want to refer to the following journal article, where an earlier version of the
#' package is described: \strong{Alberti (2019) <doi:10.1016/j.softx.2019.100331>}.\cr
#' Visit this \href{https://drive.google.com/file/d/1gLDrkZFh1b_glzCEqKdkPrer72JJ9Ffa/view?usp=sharing}{LINK} to access the package's vignette.\cr
#'
#' If the parameter \code{destin} is fed with a dataset representing destination location(s) ('SpatialPointsDataFrame' class), the function also calculates
#' least-cost path(s) plotted on the input DTM; the length of each path is saved under the variable 'length' stored in the 'LCPs' dataset ('SpatialLines' class) returned by the function.
#' In the produced plot, the red dot(s) representing the destination location(s) are labelled with numeric values representing
#' the cost value at the location(s). \cr
#'
#' The cost value is also appended to the updated destination locations dataset returned by the function, which
#' stores a new variable labelled \code{cost}. If the cost is expressed in terms of walking time, the labels accompaining each destinaton location will
#' express time in sexagesimal numbers (hours, minutes, seconds). In this case, the variable 'cost' appended to the returned destination location datset
#' will store the time figures in decimal numbers, while another variable named \code{cost_hms} will store the corresponding value in sexagesimal numbers.
#' When interpreting the time values stored in the \code{cost} variable, the user may want to bear in mind the selected time unit (see right below).\cr
#'
#' When using cost functions expressing cost in terms of time, the time unit can be selected by the user setting the \code{time} parameter to \code{h} (hours) or to \code{m} (minutes).\cr
#'
#' In general, the user can also select which type of visualization the function has to produce; this is achieved setting the \code{outp} parameter to either \code{r} (=raster)
#' or to \code{c} (=contours). The former will produce a raster with a colour scale and contour lines representing the accumulated cost surface; the latter parameter will only
#' produce contour lines.\cr
#'
#' The contour lines' interval is set using the \code{breaks} parameter; if no value is passed to the parameter, the interval will be set by default to
#' 1/10 of the range of values of the accumulated cost surface.\cr
#'
#' It is worth reminding the user(s) that all the input layers (i.e., DTM, start location, and destination locations) must use the same projected coordinate system.\cr
#'
#'
#' \strong{Cost surface calculation}:\cr
#' for the cost-surface and LCPs calculation, \code{movecost()} builds on functions from Jacob van Etten's
#' \href{https://cran.r-project.org/package=gdistance}{gdistance} package.
#' Under the hood, \code{movecost()} calculates the slope as rise over run, following the procedure described
#' by van Etten, "R Package gdistance: Distances and Routes on Geographical Grids" in Journal of Statistical Software 76(13), 2017, pp. 14-15.
#' The number of directions in which cells are connected in the cost calculation can be set to 4 (rook's case), 8 (queen's case), or
#' 16 (knight and one-cell queen moves) using the \code{move} parameter (see 'Arguments').\cr
#'
#'
#' \strong{Inhibition of movement (barrier)}:\cr
#' areas where the movement is inhibited can be fed into the analysis via the \code{barrier} parameter; SpatialLineDataFrame or SpatialPolygonDataFrame can be used.
#' The barrier is assigned a conductance value of 0 (i.e., movement is inhibited) by default, but the user can assign any other value via the
#' \code{field} parameter. Internally, the barrier creation rests on the internal \code{create_barrier_cs} function, which relies on the same function
#' out of an earlier version of the \emph{leastcostpath} package.\cr
#'
#' To test this facility, consider the following example:\cr
#'
#' First, we use in-built data to come up with a linear feature (i.e., a LCP) that we will later use as barrier:\cr
#'
#' result1 <- movecost(volc, destin.loc[1,], destin.loc[4,])\cr
#'
#' After, we calculate the LCP between two other locations, first not using any barrier (result2), then using the mentioned LCP (from result1)
#' as a barrier (result3):\cr
#'
#' result2 <- movecost(volc, destin.loc[3,], destin.loc[6,], move=8)\cr
#' result3 <- movecost(volc, destin.loc[3,], destin.loc[6,], barrier=result1$LCPs, plot.barrier=TRUE, move=8)\cr
#'
#' As apparent by comparing result2 to result3, when the barrier is used (result3), the LCP does not cross the barrier but is "forced"
#' to make a long detour. In result3, the barrier is plotted as a blue line. \strong{Note} that the \code{move} parameter has been set to 8; if set to 16, the LCP will be "able" to jump the barrier.\cr
#'
#'
#' \strong{DTM featuring irregular margins}:\cr
#' if the input DTM features irregular margins, e.g a coastline with gulfs and/or inlets where cells corresponding to the sea are given NoData,
#' the user is to set the \code{irregular.dtm} parameter to TRUE; this will prevent the LCPs to cross the sea. Internally, what \code{movecost()} does is
#' to generate a polygon vector layer from the DTM and to use the polygon as a mask to create a Transitional Layer via the
#' internal \code{create_barrier_cs} function, which relies on the same function out of an earlier version from the \emph{leastcostpath} package.
#' In the mask Transitional Layer those parts corresponding to the terrain are given a conductance value equal to 1, while everything else (i.e., the parts corresponding to the sea)
#' are given 0 conductance. The mask Transitional Layer is then internally multiplied by the conductance transitional layer representing the cost of movement
#' (according to the user-selected function). This will set to 0 the conductance values of those parts of the study area that do not correspond to the terrain,
#' while keeping unaltered the conductance of those parts that do coincide with the terrain.\cr
#'
#' As a case in point, let's consider the two following examples (using some in-build datasets):\cr
#'
#' resultA <- movecost(malta_dtm_40, origin=springs[5,], destin=springs[15,], irregular.dtm=FALSE, oneplot=FALSE)\cr
#'
#' resultB <- movecost(malta_dtm_40, origin=springs[5,], destin=springs[15,], irregular.dtm=TRUE, oneplot=FALSE)\cr
#'
#' As you can see, in the first case, the LCP between the two locations cross the sea, while in the second case the LCP follows
#' the coastline. One can also appreciate the difference between the two returned conductance transitional layers:\cr
#'
#' raster::plot(raster::raster(resultA$conductance))\cr
#'
#' raster::plot(raster::raster(resultB$conductance))\cr
#'
#' It is apparent that in the second layer the sea area has been given 0 conductance, while keeping the rest unchanged. If the input DTM does not feature
#' irregular margins (like, for instance, the built-in \code{volc} DTM), the user may safely leave the \code{irregular.dtm} parameter set to FALSE
#' (which is the default value).\cr
#'
#'
#' \strong{Acquiring online elevation data}:\cr
#' if a DTM is not provided,\code{movecost()}' will download elevation data from online sources.
#' Elevation data will be acquired for the area enclosed  by the  polygon supplied by the \code{studyplot} parameter (SpatialPolygonDataFrame class).
#' To tap online elevation data, \code{movecost()}' internally builds on the
#' \code{\link[elevatr]{get_elev_raster}} function from the \emph{elevatr} package.\cr
#'
#' The zoom level of the downloaded DTM (i.e., its resolution) is controlled by the parameter \code{z}, which is
#' set to 9 by default (a trade off between resolution and download time).\cr
#'
#' To test this facility, the user may want to try the following code, that will generate a least-cost surface and least-cost paths
#' in an area close the Mount Etna (Sicily, Italy), whose elevation data are acquired online; the start and end locations, and the
#' polygon defining the study area, are provided in this same package:\cr
#'
#' result <- movecost(origin=Etna_start_location, destin=Etna_end_location, studyplot=Etna_boundary) \cr
#'
#' The LCPs back to the origin can be calculated and plotted setting the parameter 'return.base' to TRUE:\cr
#'
#' result <- movecost(origin=Etna_start_location, destin=Etna_end_location, studyplot=Etna_boundary, return.base=TRUE) \cr
#'
#' To know more about what elevation data are tapped from online
#' sources, visit: https://cran.r-project.org/web/packages/elevatr/vignettes/introduction_to_elevatr.html. \cr
#'
#' For more information about the elevation data resolution per zoom level, visit
#' https://github.com/tilezen/joerd/blob/master/docs/data-sources.md#what-is-the-ground-resolution.\cr
#'
#' To know what is sourced at what zoom level, visit
#' https://github.com/tilezen/joerd/blob/master/docs/data-sources.md#what-is-sourced-at-what-zooms. \cr
#'
#'
#' \strong{Terrain slope and cognitive slope}:\cr
#' when it comes to the terrain slope, the function provides the facility to use the so-called 'cognitive slope',
#' following Pingel TJ (2013), Modeling Slope as a Contributor to Route Selection in Mountainous Areas, in Cartography and Geographic Information Science, 37(2), 137-148.
#' According to Pingel, "Humans tend to overestimate geographic slopes by a surprisingly high margin...This analysis indicates downhill slopes are overestimated
#' at approximately 2.3 times the vertical, while uphill slopes are overestimated at 2 times the vertical.". As a result,
#' if the parameter \code{cogn.slp} is set to \code{TRUE}, positive slope values are preliminarily multiplied by 1.99, while negative slope values are multiplied by 2.31.
#'
#'
#' \strong{Topographic (surface) distance}:\cr
#' by default, \code{movecost()} calculates cost based on planar distance, which is the horizontal distance
#' between cell centres as projected onto a flat plane. This approach ignores the additional distance
#' incurred when traversing sloped terrain. When the parameter \code{topo.dist} is set to \code{TRUE},
#' the function accounts for the actual surface distance travelled over the terrain.\cr
#'
#' The surface distance correction is calculated as: surface distance = planar distance * sqrt(1 + slope^2),
#' where slope is expressed as rise/run (gradient). For example, on a 30% slope the surface distance
#' increases by approximately 4.4%, while on a 50% slope it increases by approximately 11.8%.\cr
#'
#' \strong{Applicability to different cost functions}:\cr
#' while the \code{topo.dist} parameter can be used with any cost function, its methodological
#' appropriateness varies:\cr
#' \itemize{
#'   \item \strong{Recommended} for time-based hiking functions (\code{t}, \code{tofp}, \code{mp},
#'   \code{icmonp}, \code{icmoffp}, \code{icfonp}, \code{icfoffp}, \code{gkrs}, \code{r}, \code{ks},
#'   \code{ug}, \code{ma}, \code{alb}, \code{trp}): walking time logically depends on the actual
#'   distance travelled over the terrain surface, making the correction clearly appropriate.
#'   \item \strong{Use with caution} for metabolic energy expenditure functions (\code{p}, \code{pcf},
#'   \code{vl}, \code{m}, \code{hrz}, \code{ls}, \code{a}, \code{h}): these equations were typically
#'   derived from empirical studies that measured distance as planar (horizontal) distance. Applying
#'   surface distance correction changes the model's original basis and may or may not improve accuracy.
#'   Users should consider whether the original studies accounted for surface distance in their derivations.
#'   \item \strong{Context-dependent} for abstract cost functions (\code{ree}, \code{b}, \code{e}, \code{wcs}):
#'   these are theoretical constructs where appropriateness depends on whether the user conceptualises
#'   cost as relating to actual surface traversal or to horizontal displacement.
#' }
#'
#' In general, \code{topo.dist=TRUE} is most beneficial for analyses in mountainous or highly dissected
#' terrain where slopes frequently exceed 20-30%. In gently undulating landscapes, the
#' differences between planar and surface distance are negligible.\cr
#'
#'
#' \strong{Terrain factor (N)}:\cr
#' virtually all the implemented cost functions (with few exceptions) can take into account a 'terrain factor' (\code{N} parameter; 1 by default), which
#' represents the easiness/difficulty of moving on different terrain types. According to the type of terrain, the energy spent when walking
#' increases. The same holds true for time, which increases because on a loose terrain (for instance) the walking speed decreases.
#' While a terrain factor is 'natively' part of the Van Leusen's, Pandolf et al.'s, and Bellavia's cost function,
#' it has been integrated into the other cost functions as well (when/if relevant).\cr
#'
#' Note that the terrain factor has NOT been implemented in the Alberti's, Tobler's off-path, and Irmischer-Clarke's off-path cost function.
#' As for the latter two, they already natively feature a terrain factor. Therefore, it has been implemented only in their on-path version.
#' Needless to say, if we use a terrain factor of 1.67 with the Tobler's (on-path) hiking function, the results
#' will be equal to those obtained using the Tobler's off-path function (the reciprocal of 1.67, i.e. 0.60, is in fact
#' natively used by the Tobler's function for off-path hiking). In fact, compare the results of the following two runs
#' of  \code{movecost()} (using in-built datasets):\cr
#'
#' result1 <- movecost(dtm=volc, origin=volc.loc, destin=destin.loc, breaks=0.05, funct="t", N=1.67)\cr
#' result2 <- movecost(dtm=volc, origin=volc.loc, destin=destin.loc, breaks=0.05, funct="tofp")\cr
#'
#' The user may want to refer to the following \strong{list of terrain factors}, which is based on the data collected in Herzog, I. (2020).
#' Spatial Analysis Based on Cost Functions. In Gillings M, Haciguzeller P, Lock G (eds), "Archaeological Spatial Analysis. A Methodological Guide.",
#' Routledge: New York, 340 (with previous references). The list is divided into two sections (a and b), the first reporting the terrain
#' factors to be used for cost functions measuring time, the second for functions measuring cost other than time:\cr
#'
#' (a)\cr
#' \itemize{
#'   \item Blacktop roads, improved dirt paths, cement = 1.00
#'   \item Lawn grass = 1.03
#'   \item Loose beach sand = 1.19
#'   \item Disturbed ground (former stone quarry) = 1.24
#'   \item Horse riding path, flat trails and meadows = 1.25
#'   \item Tall grassland (with thistle and nettles) = 1.35
#'   \item Open space above the treeline (i.e., 2000 m asl) = 1.50
#'   \item Bad trails, stony outcrops and river beds = 1.67
#'   \item Off-paths = 1.67
#'   \item Bog = 1.79
#'   \item Off-path areas below the treeline (pastures, forests, heathland) = 2.00
#'   \item Rock = 2.50
#'   \item Swamp, water course = 5.00
#' }
#'
#' (b)\cr
#' \itemize{
#'   \item Asphalt/blacktop = 1.00
#'   \item Dirt road or grass = 1.10
#'   \item Hard-surface road = 1.20
#'   \item Light brush = 1.20
#'   \item Ploughed field = 1.30 or 1.50
#'   \item Heavy brush = 1.50
#'   \item Hard-packed snow = 1.60
#'   \item Swampy bog = 1.80
#'   \item Sand dunes = 1.80
#'   \item Loose sand = 2.10
#' }
#'
#'
#'
#' \strong{Implemented cost functions}:\cr
#' note that in what follows \strong{x[adj]} stands for slope as rise/run calculated for adjacent cells:\cr
#'
#' \strong{Tobler's hiking function (on-path) (speed in kmh)}:\cr
#'
#' \eqn{ (6 * exp(-3.5 * abs(x[adj] + 0.05))) * (1/N) }\cr
#'
#'
#' \strong{Tobler's hiking function (off-path) (speed in kmh)}:\cr
#'
#' \eqn{(6 * exp(-3.5 * abs(x[adj] + 0.05))) * 0.6}\cr
#'
#' as per Tobler's indication, the off-path walking speed is reduced by 0.6.\cr
#'
#'
#' \strong{Marquez-Perez et al.'s modified Tobler hiking function (speed in kmh)}:\cr
#'
#' \eqn{ (4.8 * exp(-5.3 * abs((x[adj] * 0.7) + 0.03))) * (1/N) }\cr
#'
#' modified version of the Tobler's hiking function as proposed by Joaquin Marquez-Parez, Ismael Vallejo-Villalta & Jose I. Alvarez-Francoso (2017), "Estimated travel time for walking trails in natural areas",
#' Geografisk Tidsskrift-Danish Journal of Geography, 117:1, 53-62, DOI: 10.1080/00167223.2017.1316212.\cr
#'
#'
#' \strong{Irmischer-Clarke's modified Tobler hiking function (male, on-path; speed in kmh)}:\cr
#'
#' \eqn{ ((0.11 + exp(-(abs(x[adj])*100 + 5)^2 / (2 * 30^2))) * 3.6) * (1/N) }\cr
#'
#' modified version of the Tobler's function as proposed for (male) on-path hiking by Irmischer, I. J., & Clarke, K. C. (2018). Measuring and modeling the speed of human navigation.
#' Cartography and Geographic Information Science, 45(2), 177-186. https://doi.org/10.1080/15230406.2017.1292150.
#' It is interesting to note that the hiking speed predicted by this and by the other functions proposed by the authors is slower than the one
#' modelled by Tobler's hiking function. This is attributed to the cognition involved in wayfinding
#', such as map reading, analyzing the terrain, decision making, determining routes, etc.
#' \strong{Note}: all the all the Irmischer-Clarke's functions originally express speed in m/s; they have been reshaped (multiplied by 3.6) to turn m/s into km/h for consistency
#' with the other Tobler-related cost functions; slope is in percent.\cr
#'
#'\strong{Irmischer-Clarke's modified Tobler hiking function (male, off-path; speed in kmh)}:\cr
#'
#' \eqn{(0.11 + 0.67 * exp(-(abs(x[adj])*100 + 2)^2 / (2 * 30)^2)) * 3.6}\cr
#'
#' \strong{Irmischer-Clarke's modified Tobler hiking function (female, on-path; speed in kmh)}:\cr
#'
#' \eqn{ ((0.95 * (0.11 + exp(-(abs(x[adj]) * 100 + 5)^2/(2 * 30^2)))) * 3.6) * (1/N) }\cr
#'
#' \strong{Irmischer-Clarke's modified Tobler hiking function (female, off-path; speed in kmh)}:\cr
#'
#' \eqn{(0.95 * (0.11 + 0.67 * exp(-(abs(x[adj]) * 100 + 2)^2/(2 * 30^2)))) * 3.6}\cr
#'
#'
#'\strong{Uriarte Gonzalez's walking-time cost function}:\cr
#'
#' \eqn{ 1 / ((0.0277 * (abs(x[adj])*100) + 0.6115) * N) }\cr
#'
#' proposed by Uriarte Gonzalez;
#' \strong{see}: Chapa Brunet, T., Garcia, J., Mayoral Herrera, V., & Uriarte Gonzalez, A. (2008). GIS landscape models for the study of preindustrial settlement patterns in Mediterranean areas.
#' In Geoinformation Technologies for Geo-Cultural Landscapes (pp. 255-273). CRC Press. https://doi.org/10.1201/9780203881613.ch12.\cr
#' The cost function originally expresses walking time in seconds; for the purpose of its implementation in this function, it is the reciprocal of time (1/T) that is used in order to eventually get
#' T/1. Unlike in the original cost function, here the pixel resolution is not taken into account since 'gdistance' takes care of the cells' dimension
#' when calculating accumulated costs.\cr
#'
#'
#'
#' \strong{Marin Arroyo's walking-time cost function}:\cr
#'
#' \eqn{ ifelse((abs(x[adj])*100) < 0, 1 / ((0.6 * ((abs(x[adj])*100)/23+1))*N), 1 / ((0.6 * ((abs(x[adj])*100)/11+1))*N)) }\cr
#'
#' used by Marin Arroyo A.B. (2009), The use of optimal foraging theory to estimate Late Glacial site catchments areas from a central place:
#' the case of eastern Cantabria, Span, in Journal of Anthropological Archaeology 28, 27-36.
#' The cost function originally expresses walking time in seconds; here it is the reciprocal of time (1/T) that is used in order to eventually get
#' T/1. Slope is in percent. Note: unlike in the original equation, here d (distance travelled in meter) is not taken into account since 'gdistance'
#' takes care of the cells' dimension when calculating accumulated costs.\cr
#'
#'
#'
#'\strong{Alberti's Tobler hiking function modified for pastoral foraging excursions (speed in kmh)}:\cr
#'
#' \eqn{(6 * exp(-3.5 * abs(x[adj] + 0.05))) * 0.25}\cr
#'
#' proposed by Gianmarco Alberti;
#' \strong{see}: \href{https://www.um.edu.mt/library/oar/bitstream/123456789/64172/1/Chapter_9_Locating_potential_pastoral_foraging_routes.pdf}{Locating potential pastoral foraging routes in Malta through the use of a Geographic Information System}.
#' The Tobler's function has been rescaled to fit animal walking speed during foraging excursions. The distribution of the latter, as empirical data show, turns out to be right-skewed
#' and to vary along a continuum. It ranges from very low speed values (corresponding to slow grazing activities grazing while walking) to comparatively higher values
#' (up to about 4.0 km/h) corresponding to travels without grazing (directional travel toward feeding stations).
#' The function consider 1.5 km/h as the average flock speed, which roughly corresponds to the average speed recorded in some studies, and
#' can be considered the typical speed of flocks during excursions in which grazing takes place while walking  (typical form of grazing in most situations).
#' Tobler's hiking function has been rescaled by a factor of 0.25 to represent the walking pace of a flock instead of humans.
#' The factor corresponds to the ratio between the flock average speed (1.5 km/h) and the maximum human walking speed (about 6.0 km/h) on a favourable slope.\cr
#'
#'
#'
#' \strong{Garmy, Kaddouri, Rozenblat, and Schneider's hiking function (speed in kmh)}:\cr
#'
#' \eqn{ (4 * exp(-0.008 * ((atan(abs(x[adj]))*180/pi)^2))) * (1/N) }\cr
#'
#' slope in degrees;
#' \strong{see}: Herzog, I. (2020). Spatial Analysis Based on Cost Functions. In Gillings M, Haciguzeller P, Lock G (eds), "Archaeological Spatial Analysis. A Methodological Guide.",
#' Routledge: New York, 333-358 (with previous references).\cr
#'
#'
#'
#' \strong{Rees' hiking function (speed in kmh)}:\cr
#'
#' \eqn{ ((1 / (0.75 + 0.09 * abs(x[adj]) + 14.6 * (abs(x[adj]))^2)) * 3.6) * (1/N) }\cr
#'
#' Rees' slope-dependant cost function; it is originally expressed in terms of time (1/v in Rees' publication);
#' here it is the reciprocal of time (i.e. speed) that is used in order to eventually get the reciprocal of speed (i.e. time).
#' Slope is dealt with here as originally expressed in Rees' publication (i.e. rise over run). The speed, which is originally expressed in m/s,
#' has been here transposed to kmh (i.e., multiplied by 3.6) for consistency with other hiking functions.\cr
#' For this cost function \strong{see}: Rees, WG (2004). Least-cost paths in mountainous terrain.
#' Computers & Geosciences, 30(3), 203-209. See also: Campbell MJ, Dennison PE, Butler BW, Page WG (2019). Using crowdsourced
#' fitness tracker data to model the relationship between slope and travel rates. Applied Geography 106, 93-107 (with previous references).\cr
#'
#'
#'
#'\strong{Kondo-Seino's modified Tobler hiking function (speed in kmh)}:\cr
#'
#' \eqn{ ifelse(abs(x[adj]) >= -0.07, (5.1 * exp(-2.25 * abs(x[adj] + 0.07))) * (1/N), (5.1 * exp(-1.5 * abs(x[adj] + 0.07)))) * (1/N) }\cr
#'
#' Kondo-Seino's modified Tobler hiking function; it expresses walking speed in Kmh; slope as rise/run;
#' \strong{see} Kondo Y., Seino Y. (2010). GPS-aided Walking Experiments and Data-driven Travel Cost Modelingon the Historical Road of Nakasendo-Kisoji
#' (Central Highland Japan), in: Frischer B., Webb Crawford J., Koller D. (eds.), Making History Interactive.
#' Computer Applications and Quantitative Methods in Archaeology (CAA). Proceedings of the 37th International Conference, Williamsburg, Virginia, United States of America,
#' March 22-26 (BAR International Series S2079). Archaeopress, Oxford, 158-165.\cr
#'
#'
#'
#' \strong{Tripcevich hiking function (speed in kmh)}:\cr
#'
#' \eqn{ ((4.028*46^2)/(((atan(abs(x[adj]))*180/pi)+4.127)^2+46^2))*(1/N) }\cr
#'
#' Tripcevich's hiking function; it expresses walking speed in Kmh; slope is originally expressed in degrees;
#' \strong{see} Tripcevich N (2008). Estimating Llama caravan travel speeds: ethno-archaeological fieldwork with a Peruvian salt caravan.
#' Trabajo presentado el la inauguracionn del Centre for Spatial Studies, University of California, Santa Barbara.
#' See also: Lucero G, Marsh EJ, Castro S (2014), Rutas prehistoricas en lo NO de San Juan: una propuesta macroregional desde los sistemas
#' de information geografica, in Cortegoso V, Duran V, Gasco Alejandra (eds), Arqueologia de ambientes de altura de Mendoza y San
#' Juan (Argentina), EDIUNC, pp. 275-305.\cr
#'
#'
#'
#' \strong{Wheeled-vehicle critical slope cost function}:\cr
#'
#' \eqn{ 1 / ((1 + ((abs(x[adj])*100) / sl.crit)^2) * N) }\cr
#'
#' where \eqn{sl.crit} (=critical slope, in percent) is "the transition where switchbacks become more effective than direct uphill or downhill paths" and typically is in the range 8-16;
#' \strong{see} Herzog, I. (2016). Potential and Limits of Optimal Path Analysis. In A. Bevan & M. Lake (Eds.), Computational Approaches to Archaeological Spaces (pp. 179-211). New York: Routledge. \cr
#'
#'
#'
#'\strong{Relative energetic expenditure cost function}:\cr
#'
#' \eqn{ 1 / ((tan((atan(abs(x[adj]))*180/pi)*pi/180) / tan (1*pi/180)) * N) }\cr
#'
#' slope-based cost function expressing change in potential energy expenditure;
#' \strong{see} Conolly, J., & Lake, M. (2006). Geographic Information Systems in Archaeology. Cambridge: Cambridge University Press, p. 220;
#' \strong{see also} Newhard, J. M. L., Levine, N. S., & Phebus, A. D. (2014). The development of integrated terrestrial and marine pathways in the Argo-Saronic region, Greece. Cartography and Geographic Information Science, 41(4), 379-390, with references to studies that use this
#' function; \strong{see also} ten Bruggencate, R. E., Stup, J. P., Milne, S. B., Stenton, D. R., Park, R. W., & Fayek, M. (2016). A human-centered GIS approach to modeling mobility on southern Baffin Island, Nunavut,
#' Canada. Journal of Field Archaeology, 41(6), 684-698. https://doi.org/10.1080/00934690.2016.1234897.\cr
#'
#'
#'
#' \strong{Bellavia's cost function}:\cr
#'
#' \eqn{1 / (N * ((atan(abs(x[adj]))*180/pi)+1))}\cr
#'
#' proposed by G. Bellavia, it measures abstract cost. Slope in degrees; N is a terrain factor (see above).
#' \strong{See}: Herzog I. (2020). Spatial Analysis Based on Cost Functions. In Gillings M, Haciguzeller P, Lock G (eds), "Archaeological Spatial Analysis. A Methodological Guide.",
#' Routledge: New York, 333-358 (with previous references).\cr
#'
#'
#'
#' \strong{Eastman's cost function}:\cr
#'
#' \eqn{ 1 / ((0.031*(atan(abs(x[adj]))*180/pi)^2-0.025*(atan(abs(x[adj]))*180/pi)+1)*N) }\cr
#'
#' proposed by J.R. Eastman, it measures abstract cost; slope in degrees.
#' \strong{See}: Vaissie E., Mobility of Paleolithic Populations: Biomechanical Considerations and Spatiotemporal Modelling,
#' in PaleoAnthropology 2021 (1): 120-144 (with previous reference to Eastman 1999).\cr
#'
#'
#'
#' \strong{Pandolf et al.'s metabolic energy expenditure cost function (in Watts)}:\cr
#'
#' \eqn{ 1 / ((1.5 * W + 2.0 * (W + L) * (L / W)^2 + N * (W + L) * (1.5 * (V^2) + 0.35 * V * (abs(x[adj])*100)))*N) }\cr
#'
#' where \eqn{W} is the walker's body weight (Kg), \eqn{L} is the carried load (in Kg), \eqn{V} is the velocity in m/s, \eqn{N} is a coefficient representing ease of movement on the terrain (see above).
#' \strong{Note} that if \eqn{V} is set to 0 by the user, it is internally worked out on the basis of the Tobler function for on-path hiking; therefore, \eqn{V} will not be
#' considered constant throughout the analysed area, but will vary as function of the slope.
#'
#' For this cost function, \strong{see} Pandolf, K. B., Givoni, B., & Goldman, R. F. (1977). Predicting energy expenditure with loads while standing or walking very slowly. Journal of Applied Physiology,
#' 43(4), 577-581. https://doi.org/10.1152/jappl.1977.43.4.577.\cr
#'
#' For the use of this cost function in a case study, \strong{see} Rademaker, K., Reid, D. A., & Bromley, G. R. M. (2012). Connecting the Dots: Least Cost Analysis, Paleogeography, and
#' the Search for Paleoindian Sites in Southern Highland Peru. In White D.A. & Surface-Evans S.L. (Eds.), Least Cost Analysis of Social Landscapes. Archaeological Case Studies (pp. 32-45).
#' University of Utah Press; \strong{see also} Herzog, I. (2013). Least-cost Paths - Some Methodological Issues, Internet Archaeology 36 (http://intarch.ac.uk/journal/issue36/index.html) with references.
#' For the idea of using an hiking function inside an energetic cost function, \strong{see} for instance White D.A., Prehistoric Trail Networks of the Western Papaguarie.
#' A Multifaceted Least Cost Graph Theory Analysis. In White D.A. & Surface-Evans S.L. (Eds.), Least Cost Analysis of Social Landscapes. Archaeological Case Studies (pp. 188-206).
#' University of Utah Press.\cr
#'
#' \strong{Note}: in the returned charts, the cost is transposed from Watts to Megawatts (see, e.g., Rademaker et al 2012 cited above).\cr
#'
#'
#'
#' \strong{Pandolf et al.'s metabolic energy expenditure cost function with correction factor for downhill movements (in Watts)}:\cr
#'
#' \eqn{ ifelse(abs(x[adj])*100 > 0 , 1 / (1.5 * W + 2.0 * (W+L) * (L/W)^2 + N * (W+L) * (1.5 * V^2 + 0.35 * V * (abs(x[adj])*100))),
#' 1 / ((1.5 * W + 2.0 * (W+L) * (L/W)^2 + N * (W+L) * (1.5 * V^2 + 0.35 * V * (abs(x[adj])*100))) - (N * ((abs(x[adj])*100) * (W+L) * V/3.5) - ((W+L) * ((abs(x[adj])*100)+6)^2/W) + (25-V^2)))) }\cr
#'
#' for the parameters \eqn{W}, \eqn{L}, \eqn{V}, and \eqn{N}, see above. If \eqn{V} is set to 0 by the user, it is internally worked out on the basis of the Tobler function for on-path hiking; therefore, \eqn{V} will not be
#' considered constant throughout the analysed area, but will vary as function of the slope.
#' For the correction factor applied to the Pandolf et al.'s cost function, \strong{see} Yokota M., Berglund L.G., Santee W.R., Buller M.J., Hoyt R.W. (2004),
#' Predicting Individual Physiological Responsed During Marksmanship Field Training Using an Updates Scenario-J Model. U.S. Army Research Institute of Environmental Medicine
#' Technical Report T04-09. For an archaeological application of the Pandol et al's cost function with correction factor, \strong{see} White D.A., Prehistoric Trail Networks of the Western Papaguarie.
#' A Multifaceted Least Cost Graph Theory Analysis. In White D.A. & Surface-Evans S.L. (Eds.), Least Cost Analysis of Social Landscapes. Archaeological Case Studies (pp. 188-206).
#' University of Utah Press.\cr
#'
#' \strong{Note}: in the returned charts, the cost is transposed from Watts to Megawatts (see, e.g., Rademaker et al 2012 cited above).\cr
#'
#'
#'
#' \strong{Minetti et al.'s metabolic energy cost function (in J/(kg*m))}:\cr
#'
#' \eqn{ 1 / (((280.5 * abs(x[adj])^5) - (58.7 * abs(x[adj])^4) - (76.8 * abs(x[adj])^3) + (51.9 * abs(x[adj])^2) + (19.6 * abs(x[adj])) + 2.5) * N) }\cr
#'
#' \strong{see} Minetti A.E., Moia C., Roi G.S., Susta D., Ferretti G. (2002), Enery cost of walking and running at extreme uphilland downhill slopes,
#' in Journal of Applied Physiology 93, 1039-1046. \strong{Note} that this equation is valid for slopes in the range -0.5/0.5; outside this range,
#' the function's output becomes counterintuitive, as noted in Paez et al. in Journal of Transport Geography 82 (2020) and Herzog I. (2013), Theory and practice
#' of cost functions, in Contreras F., Farjas M., Melero F.J. (eds), "Fusion of cultures. Proceedings of the 38th annual conference on computer
#' applications and quantitative methods in archaeology". BAR IS, 2494, 375-382. Oxford: Archaeopress. In the latter work, Herzog proposes to
#' replace Minetti et al.'s equation with its 6th degrees polynomial approximation (see the Herzog's metabolic cost function below).\cr
#'
#'
#'
#' \strong{Herzog's metabolic cost function in J/(kg*m)}:\cr
#'
#' \eqn{1 / (((1337.8 * abs(x[adj])^6) + (278.19 * abs(x[adj])^5) - (517.39 * abs(x[adj])^4) - (78.199 * abs(x[adj])^3) + (93.419 * abs(x[adj])^2) + (19.825 * abs(x[adj])) + 1.64) * N)  }\cr
#'
#' \strong{see} Herzog, I. (2016). Potential and Limits of Optimal Path Analysis. In A. Bevan & M. Lake (Eds.), Computational Approaches to Archaeological Spaces (pp. 179-211). New York: Routledge.
#' Herzog suggests to use this as a 6th degree polynomial approximation of the Minetti et al's cost function (see above).\cr
#'
#'
#'
#' \strong{Van Leusen's metabolic energy expenditure cost function (in Watts)}:\cr
#'
#' \eqn{ 1 / ((1.5 * W + 2.0 * (W + L) * (L / W)^2 + N * (W + L) * (1.5 * (V^2) + 0.35 * V * ((abs(x[adj])*100) + 10)))*N) }\cr
#'
#' which modifies the Pandolf et al.'s equation; \strong{see} Van Leusen, P. M. (2002). Pattern to process: methodological investigations into the formation and interpretation of spatial patterns in archaeological landscapes. University of Groningen.
#' \strong{Note} that, as per Herzog, I. (2013). Least-cost Paths - Some Methodological Issues, Internet Archaeology 36 (http://intarch.ac.uk/journal/issue36/index.html) and
#' unlike Van Leusen (2002), in the above equation slope is expressed in percent and speed in m/s; also, in the last bit of the equantion, 10 replaces
#' the value of 6 used by Van Leusen (as per Herzog 2013).\cr
#' As explained above, if \eqn{V} is set to 0 by the user, it is internally worked out on the basis of the Tobler function for on-path hiking; therefore, \eqn{V} will not be considered constant
#' throughout the analysed area, but will vary as function of the slope.\cr
#'
#' \strong{Note}: in the returned charts, the cost is transposed from Watts to Megawatts.\cr
#'
#'
#'
#' \strong{Llobera-Sluckin's metabolic energy expenditure cost function (in KJ/m)}:\cr
#'
#' \eqn{ 1 / ((2.635 + (17.37 * abs(x[adj])) + (42.37 * abs(x[adj])^2) - (21.43 * abs(x[adj])^3) + (14.93 * abs(x[adj])^4)) * N)  }\cr
#'
#' for which \strong{see} Llobera M.-Sluckin T.J. (2007). Zigzagging: Theoretical insights on climbing strategies, Journal of Theoretical Biology 249, 206-217.\cr
#'
#'
#'
#' \strong{Ardigo et al.'s metabolic energy expenditure cost function (in J/(kg*m))}:\cr
#'
#' \eqn{ 1 / ((1.866 * exp(4.911*abs(x[adj])) * V^2 - 3.773 * exp(3.416*abs(x[adj])) * V + (45.71*abs(x[adj]^2) + 18.90*abs(x[adj])) + 4.456) * N) }\cr
#'
#' \strong{see} Ardigo L.P., Saibene F., Minetti A.E. (2003), The optimal locomotion on gradients: walking, running or cycling?, in
#' Eur J Appl Physiol 90, 365-371. If \eqn{V} is set to 0 by the user, it is internally worked out on the basis of the Tobler function for on-path hiking; therefore,
#' \eqn{V} will not be considered constant throughout the analysed area, but will vary as function of the slope.\cr
#'
#'
#'
#' \strong{Hare's metabolic energy expenditure cost function (in cal/km)}:\cr
#'
#' \eqn{ 1 / ((48+30/(1/(6 * exp(-3.5 * abs(x[adj] + 0.05)))))*N) }\cr
#'
#' \strong{see} Hare T.S., Using Measures of Cost Distance in the Estimation of Polity Bounrdaries in the Post Classic
#' Yautepec valley, Mexico, in Journal of Archaeological Science 31 (2004). Energetic expenditure is expressed in calories per km; walking speed
#' is internally worked out from the DTM using the on-path Tobler's hiking function, which is expressed as its reciprocal; walking speed in km/h as per original Tobler's equation
#' and as requested by Hare's function.\cr
#'
#'
#'
#' \strong{Note} that the walking-speed-related cost functions listed above are used as they are, while the other functions are reciprocated.
#' This is done since "gdistance works with conductivity rather than the more usual approach using costs"; therefore
#' "we need inverse cost functions" (Nakoinz-Knitter (2016). "Modelling Human Behaviour in Landscapes". New York: Springer, p. 183).
#'  As a consequence, if we want to estimate time, we have to use the walking-speed functions as they are since the final accumulated values will correspond to the
#'  reciprocal of speed, i.e. pace. In the other cases, we have to use 1/cost-function to eventually get cost-function/1.\cr
#'
#'
#'
#' @param dtm Digital Terrain Model (RasterLayer class); if not provided, elevation data will be acquired online for the area enclosed by the 'studyplot' parameter (see Details).
#' @param origin location from which the cost surface is calculated (SpatialPointsDataFrame class).
#' @param destin location(s) to which least-cost path(s) is calculated (SpatialPointsDataFrame class).
#' @param studyplot polygon (SpatialPolygonDataFrame class) representing the study area for which online elevation data are acquired (see Details); NULL is default.
#' @param barrier area where the movement is inhibited (SpatialLineDataFrame or SpatialPolygonDataFrame class).
#' @param plot.barrier TRUE or FALSE (default) if the user wants or does not want the barrier to be plotted (in blue).
#' @param irregular.dtm TRUE or FALSE (default) if the input DTM features irregular margins (Details).
#' @param funct cost function to be used:\cr
#'
#' \strong{-functions expressing cost as walking time-}\cr
#' \strong{t} (default) uses the on-path Tobler's hiking function;\cr
#' \strong{tofp} uses the off-path Tobler's hiking function;\cr
#' \strong{mp} uses the Marquez-Perez et al.'s modified Tobler's function;\cr
#' \strong{icmonp} uses the Irmischer-Clarke's hiking function (male, on-path);\cr
#' \strong{icmoffp} uses the Irmischer-Clarke's hiking function (male, off-path);\cr
#' \strong{icfonp} uses the Irmischer-Clarke's hiking function (female, on-path);\cr
#' \strong{icfoffp} uses the Irmischer-Clarke's hiking function (female, off-path);\cr
#' \strong{ug} uses the Uriarte Gonzalez's walking-time cost function;\cr
#' \strong{ma} uses the Marin Arroyo's walking-time cost function;\cr
#' \strong{alb} uses the Alberti's Tobler hiking function modified for pastoral foraging excursions;\cr
#' \strong{gkrs} uses the Garmy, Kaddouri, Rozenblat, and Schneider's hiking function;\cr
#' \strong{r} uses the Rees' hiking function;\cr
#' \strong{ks} uses the Kondo-Seino's hiking function;\cr
#' \strong{trp} uses the Tripcevich's hiking function;\cr
#'
#' \strong{-functions for wheeled-vehicles-}\cr
#' \strong{wcs} uses the wheeled-vehicle critical slope cost function;\cr
#'
#' \strong{-functions expressing abstract cost-}\cr
#' \strong{ree} uses the relative energetic expenditure cost function;\cr
#' \strong{b} uses the Bellavia's cost function;\cr
#' \strong{e} uses the Eastman's cost function;\cr
#'
#' \strong{-functions expressing cost as metabolic energy expenditure-}\cr
#' \strong{p} uses the Pandolf et al.'s metabolic energy expenditure cost function;\cr
#' \strong{pcf} uses the Pandolf et al.'s cost function with correction factor for downhill movements;\cr
#' \strong{m} uses the Minetti et al.'s metabolic energy expenditure cost function;\cr
#' \strong{hrz} uses the Herzog's metabolic energy expenditure cost function;\cr
#' \strong{vl} uses the Van Leusen's metabolic energy expenditure cost function;\cr
#' \strong{ls} uses the Llobera-Sluckin's metabolic energy expenditure cost function;\cr
#' \strong{a} uses the Ardigo et al.'s metabolic energy expenditure cost function;\cr
#' \strong{h} uses the Hare's metabolic energy expenditure cost function (for all the mentioned cost functions, see Details).\cr
#' @param time time-unit expressed by the accumulated raster and by the isolines if Tobler's and other time-related cost functions are used; 'h' for hour, 'm' for minutes.
#' @param outp type of output: 'raster' or 'contours' (see Details).
#' @param move number of directions in which cells are connected: 4 (rook's case), 8 (queen's case), 16 (knight and one-cell queen moves; default).
#' @param field value assigned to the cells coinciding with the barrier (0 by default).
#' @param cogn.slp  TRUE or FALSE (default) if the user wants or does not want the 'cognitive slope' to be used in place of the real slope (see Details).
#' @param topo.dist TRUE or FALSE (default) if the user wants the cost calculation to use topographic (surface) distance rather than planar distance. When TRUE, distances are corrected by the factor sqrt(1 + slope^2), accounting for the actual terrain surface. This is recommended for accurate walking-time estimates in rugged terrain (see Details).
#' @param sl.crit critical slope (in percent), typically in the range 8-16 (10 by default) (used by the wheeled-vehicle cost function; see Details).
#' @param W walker's body weight (in Kg; 70 by default; used by the Pandolf's and Van Leusen's cost function; see Details).
#' @param L carried load weight (in Kg; 0 by default; used by the Pandolf's and Van Leusen's cost function; see Details).
#' @param N coefficient representing ease of movement (1 by default) (see Details).
#' @param V speed in m/s (1.2 by default) (used by the Pandolf et al.'s, Pandolf et al.s with correction factor, Van Leusen's, and Ardigo et al.'s cost function; if set to 0, it is internally worked out on the basis of Tobler on-path hiking function; see Details).
#' @param z zoom level for the elevation data downloaded from online sources (0 to 15; 9 by default) (see Details and \code{\link[elevatr]{get_elev_raster}}).
#' @param return.base TRUE or FALSE (default) if the user wants or does not want the least-cost paths back to the origin to be calculated and plotted (as dashed lines).
#' @param rb.lty line type used to represent the least-cost paths back to the origin in the returned plot (2 by default; dashed line; see 'lty' parameter in \code{\link[graphics]{par}}).
#' @param breaks contour interval; if no value is supplied, the interval is set by default to 1/10 of the range of values of the accumulated cost surface.
#' @param cont.lab if set to TRUE (default) display the labels of the contours over the accumulated cost surface.
#' @param destin.lab if set to TRUE (default) display the label(s) indicating the cost at the destination location(s).
#' @param cex.breaks set the size of the cost labels used in the contour plot (0.6 by default).
#' @param cex.lcp.lab set the size of the labels used in least-cost path(s) plot (0.6 by default).
#' @param graph.out TRUE (default) or FALSE if the user wants or does not want a graphical output to be generated.
#' @param transp set the transparency of the slopeshade raster that is plotted over the rendered plots (0.5 by default).
#' @param oneplot TRUE (default) or FALSE if the user wants or does not want the plots displayed in a single window.
#' @param export TRUE or FALSE (default) if the user wants or does not want the outputs to be exported; if TRUE, the DTM, the cost-surface, and the accumulated cost surface are
#' exported as a GeoTiff file, while the isolines, the least-cost path(s), and a copy of the input destination locations (storing the cost measured at each location)
#' are exported as shapefile; all the exported files (excluding the DTM) will bear a suffix corresponding to the cost function selected by the user.
#' Note that the DTM is exported only if it was not provided by the user and downloaded by the function from online sources.
#'
#' @return The function returns a list storing the following components
#' \itemize{
##'  \item dtm: Digital Terrain Model ('RasterLayer' class)
##'  \item cost.surface: raster representing the cost-surface ('RasterLayer' class)
##'  \item accumulated.cost.raster: raster representing the accumualted cost ('RasterLayer' class)
##'  \item isolines: contour lines derived from the accumulated cost surface ('SpatialLinesDataFrame' class)
##'  \item LCPs: estimated least-cost paths ('SpatialLinesDataFrame' class)
##'  \item LCPs.back: estimated least-cost paths back to the origin ('SpatialLinesDataFrame' class)
##'  \item LCPs$length: length of each least-cost path (units depend on the unit used in the input DTM)
##'  \item LCPs.back$length: length of each least-cost path back to the origin (units depend on the unit used in the input DTM)
##'  \item dest.loc.w.cost: copy of the input destination location(s) dataset with a new variable ('cost') added; if
##'  the cost is expressed in terms of time, the 'cost' variable will store the time values in decimal numbers, while another variable named
##'  'cost_hms' will store the time values in sexagesimmal numbers (hours, minutes, seconds)
##'  \item conductance: conductance 'Transitional Layer', returned because internally used by the \code{movenetw()} function
##' }
##'
##'
#' @keywords movecost
#' @export
#' @importFrom raster ncell mask crop raster terrain focal
#' @importFrom terra writeVector vect
#' @importFrom elevatr get_elev_raster
#' @importFrom chron times
#' @importFrom grDevices terrain.colors topo.colors grey
#' @importFrom graphics layout par
#' @importFrom terra as.polygons
#' @importFrom stats na.omit
#' @importFrom sf st_length st_as_sf
#'
#'
#' @examples
#' # load a sample Digital Terrain Model
#' data(volc)
#'
#' # load a sample start location on the above DTM
#' data(volc.loc)
#'
#' # load the sample destination locations on the above DTM
#' data(destin.loc)
#'
#' # calculate walking-time isochrones based on the on-path Tobler's hiking function (default),
#' # setting the time unit to hours and the isochrones interval to 0.05 hour;
#' # also, since destination locations are provided,
#' # least-cost paths from the origin to the destination locations will be calculated
#' # and plotted; 8-directions move is used
#'
#' result <- movecost(dtm=volc, origin=volc.loc, destin=destin.loc, move=8, breaks=0.05)
#'
#'
#' # same as above, but using the Irmischer-Clarke's hiking function (male, on-path)
#'
#' result <- movecost(dtm=volc, origin=volc.loc, destin=destin.loc, funct="icmonp",
#' move=8, breaks=0.05)
#'
#'
#' # same as above, but using the 'cognitive slope'
#'
#' result <- movecost(dtm=volc, origin=volc.loc, destin=destin.loc, funct="icmonp",
#' move=8, breaks=0.05, cogn.slp=TRUE)
#'
#'
#' # calculate accumulated cost surface and the least-cost path between the
#' # origin and one destination, and also calculate the LCP back to the origin
#'
#' results <- movecost(dtm=volc, origin=volc.loc, destin=destin.loc[2,], move=8, return.base = TRUE)
#'
#'
#' @seealso \code{\link[elevatr]{get_elev_raster}}, \code{\link{movecorr}}, \code{\link{movebound}}, \code{\link{movealloc}},  \code{\link{movecomp}}, \code{\link{movenetw}}, \code{\link{moverank}}
#'
#'
movecost <- function (dtm=NULL, origin, destin=NULL, studyplot=NULL, barrier=NULL, plot.barrier=FALSE, irregular.dtm=FALSE, funct="t", time="h", outp="r", move=16, field=0, cogn.slp=FALSE, topo.dist=FALSE, sl.crit=10, W=70, L=0, N=1, V=1.2, z=9, return.base=FALSE, rb.lty=2, breaks=NULL, cont.lab=TRUE, destin.lab=TRUE, cex.breaks=0.6, cex.lcp.lab=0.6, graph.out=TRUE, transp=0.5, oneplot=TRUE, export=FALSE){

  #deactivate the warning messages because a warning that can be safely ignored will be produced by the procedure
  #used to get slope as rise over run
  options(warn = -1)

  #if no dtm is provided
  if (is.null(dtm)==TRUE) {
    #get the elvation data using the elevatr's get_elev_raster() function, using the studyplot dataset (SpatialPolygonDataFrame)
    #to select the area whose elevation data are to be downloaded;
    #z sets the resolution of the elevation datataset
    elev.data <- elevatr::get_elev_raster(studyplot, z = z, verbose=FALSE, override_size_check = TRUE)
    #crop the elevation dataset to the exact boundary of the studyplot dataset
    dtm <- raster::crop(elev.data, studyplot)
  }

  #calculate the altitudinal difference between adjacent cells
  altDiff <- function(x){x[2] - x[1]}
  hd <- gdistance::transition(dtm, altDiff, directions=move, symm=FALSE)

  #use the geoCorrection function to divide the altitudinal difference by the distance between cells
  #so getting slope as rise over run
  slope <- gdistance::geoCorrection(hd)

  #if 'cogn.slp' is set to TRUE, positive slope values (ie. up-hill movement) multiplied by 1.99
  # and negative slope values (ie. down-hill movement) multiplied by 2.31
  if (cogn.slp==TRUE) {
    slope@transitionMatrix@x <- ifelse(slope@transitionMatrix@x > 0, slope@transitionMatrix@x * 1.99, slope@transitionMatrix@x * 2.31)
  }

  #if 'topo.dist' is TRUE, compute the surface distance correction factor
  #surface_distance = planar_distance * sqrt(1 + slope^2)
  #this correction factor will be applied later to adjust conductance values
  if (topo.dist==TRUE) {
    #compute correction factor: sqrt(1 + slope^2)
    #since slope is rise/run, this gives us the ratio of surface distance to planar distance
    surf_corr <- slope
    surf_corr@transitionMatrix@x <- sqrt(1 + slope@transitionMatrix@x^2)
  }

  #define different types of cost functions and set the appropriate text to be used for subsequent plotting
  if (funct=="t") {
    #Tobler's hiking function; kmh
    cost_function <- function(x){ (6 * exp(-3.5 * abs(x[adj] + 0.05))) * (1/N) }

    #set the labels to be used within the returned plot
    main.title <- paste0("Walking-time isochrones (in ", time, ") around origin")
    sub.title <- paste0("Walking-time based on the Tobler's on-path hiking function \nterrain factor N=", N)
    legend.cost <- paste0("walking-time (", time,")")
    sub.title.lcp.plot <- paste0("LCP(s) and walking-time distance(s) based on the Tobler's on-path hiking function \nterrain factor N=", N, "\nblack dot=start location\n red dot(s)=destination location(s)")
  }

  if (funct=="tofp") {
    #Tobler's hiking function off-path routes; kmh
    #note that the multiplier 0.6 suggested by Tobler is meant to reduce the off-path walking speed
    cost_function <- function(x){(6 * exp(-3.5 * abs(x[adj] + 0.05))) * 0.6}

    #set the labels to be used within the returned plot
    main.title <- paste0("Walking-time isochrones (in ", time, ") around origin")
    sub.title <- "Walking-time based on the Tobler's off-path hiking function"
    legend.cost <- paste0("walking-time (", time,")")
    sub.title.lcp.plot <- paste0("LCP(s) and walking-time distance(s) based on the Tobler's off-path hiking function \nblack dot=start location\n red dot(s)=destination location(s)")
  }

  if(funct=="mp") {
    #Marquez-Perez et al.'s modified Tobler hiking function; kmh
    cost_function <- function(x){ (4.8 * exp(-5.3 * abs((x[adj] * 0.7) + 0.03))) * (1/N) }

    #set the labels to be used within the returned plot
    main.title <- paste0("Walking-time isochrones (in ", time, ") around origin")
    sub.title <- paste0("Walking-time based on the Marquez-Perez et al.'s modified Tobler hiking function \n terrain factor N=", N)
    legend.cost <- paste0("walking-time (", time,")")
    sub.title.lcp.plot <- paste0("LCP(s) and walking-time distance(s) based on the Marquez-Perez et al.'s modified Tobler hiking function \n terrain factor N=", N, "\nblack dot=start location\n red dot(s)=destination location(s)")
  }

  if(funct=="alb") {
    #Alberti's modified Tobler hiking function, adapted for animal foraging excursions
    cost_function <- function(x){(6 * exp(-3.5 * abs(x[adj] + 0.05))) * 0.25}

    #set the labels to be used within the returned plot
    main.title <- paste0("Walking-time isochrones (in ", time, ") around origin")
    sub.title <- "Walking-time based on the Alberti's modified Tobler hiking function"
    legend.cost <- paste0("walking-time (", time,")")
    sub.title.lcp.plot <- paste0("LCP(s) and walking-time distance(s) based on the Alberti's modified Tobler hiking function \nblack dot=start location\n red dot(s)=destination location(s)")
  }

  if(funct=="icmonp") {
    #Irmischer-Clarke's modified Tobler hiking function; originally in m/s (male, on-path);
    # the formula is reshaped (multiplied by 3.6) below to turn it into kmh for consistency with the other Tobler-related cost functions;
    # Slope in percent.
    cost_function <- function(x){ ((0.11 + exp(-(abs(x[adj])*100 + 5)^2 / (2 * 30^2))) * 3.6) * (1/N) }

    #set the labels to be used within the returned plot
    main.title <- paste0("Walking-time isochrones (in ", time, ") around origin")
    sub.title <- paste0("Walking-time based on the (male, on-path) Irmischer-Clarke's hiking function \n terrain factor N=", N)
    legend.cost <- paste0("walking-time (", time,")")
    sub.title.lcp.plot <- paste0("LCP(s) and walking-time distance(s) based on the (male, on-path) Irmischer-Clarke's hiking function \n terrain factor N=", N, "\nblack dot=start location\n red dot(s)=destination location(s)")
  }

  if(funct=="icmoffp") {
    #Irmischer-Clarke's modified Tobler hiking function; originally in m/s (male, off-path);
    # the formula is reshaped (multiplied by 3.6) below to turn it into kmh for consistency with the other Tobler-related cost functions;
    # Slope in percent.
    cost_function <- function(x){ (0.11 + 0.67 * exp(-(abs(x[adj])*100 + 2)^2 / (2 * 30^2))) * 3.6 }

    #set the labels to be used within the returned plot
    main.title <- paste0("Walking-time isochrones (in ", time, ") around origin")
    sub.title <- "Walking-time based on the (male, off-path) Irmischer-Clarke's hiking function"
    legend.cost <- paste0("walking-time (", time,")")
    sub.title.lcp.plot <- paste0("LCP(s) and walking-time distance(s) based on the (male, off-path) Irmischer-Clarke's hiking function \nblack dot=start location\n red dot(s)=destination location(s)")
  }

  if(funct=="icfonp") {
    #Irmischer-Clarke's modified Tobler hiking function; originally in m/s (female, on-path);
    # the formula is reshaped (multiplied by 3.6) below to turn it into kmh for consistency with the other Tobler-related cost functions;
    # Slope in percent.
    cost_function <- function(x){ ((0.95 * (0.11 + exp(-(abs(x[adj]) * 100 + 5)^2/(2 * 30^2)))) * 3.6) * (1/N) }

    #set the labels to be used within the returned plot
    main.title <- paste0("Walking-time isochrones (in ", time, ") around origin")
    sub.title <- paste0("Walking-time based on the (female, on-path) Irmischer-Clarke's hiking function \n terrain factor N=", N)
    legend.cost <- paste0("walking-time (", time,")")
    sub.title.lcp.plot <- paste0("LCP(s) and walking-time distance(s) based on the (female, on-path) Irmischer-Clarke's hiking function \n terrain factor N=", N, "\nblack dot=start location\n red dot(s)=destination location(s)")
  }

  if(funct=="icfoffp") {
    #Irmischer-Clarke's modified Tobler hiking function; originally in m/s (female, off-path);
    # the formula is reshaped (multiplied by 3.6) below to turn it into kmh for consistency with the other Tobler-related cost functions;
    # Slope in percent.
    cost_function <- function(x){ (0.95 * (0.11 + 0.67 * exp(-(abs(x[adj]) * 100 + 2)^2/(2 * 30^2)))) * 3.6 }

    #set the labels to be used within the returned plot
    main.title <- paste0("Walking-time isochrones (in ", time, ") around origin")
    sub.title <- "Walking-time based on the (female, off-path) Irmischer-Clarke's hiking function"
    legend.cost <- paste0("walking-time (", time,")")
    sub.title.lcp.plot <- paste0("LCP(s) and walking-time distance(s) based on the (female, off-path) Irmischer-Clarke's hiking function \nblack dot=start location\n red dot(s)=destination location(s)")
  }

  if(funct=="gkrs") {
    #Garmy, Kaddouri, Rozenblat, Schneider's slope-dependant hiking function; speed in kmh;
    #slope is originally in degrees; (atan(abs(x[adj]))*180/pi) turns rise/run into degrees
    cost_function <- function(x){ (4 * exp(-0.008 * ((atan(abs(x[adj]))*180/pi)^2))) * (1/N) }

    #set the labels to be used within the returned plot
    main.title <- paste0("Walking-time isochrones (in ", time, ") around origin")
    sub.title <- paste0("Walking-time based on the Garmy et al.'s hiking function \n terrain factor N=", N)
    legend.cost <- paste0("walking-time (", time,")")
    sub.title.lcp.plot <- paste0("LCP(s) and walking-time distance(s) based on the Garmy et al.'s hiking function \n terrain factor N=", N, "\nblack dot=start location\n red dot(s)=destination location(s)")
  }

  if(funct=="ug") {
    #Antonio Uriarte Gonzalez's slope-dependant walking-time cost function;
    # the cost function is originally expressed in seconds; here it is the reciprocal of time (1/T) that is used in order to eventually get
    #T/1. Slope is in percent.
    #Note: unlike the original formula, here the pixel resolution is not taken into account since 'gdistance' takes care of the cells' dimension
    #when calculating accumulated costs.
    cost_function <- function(x){ 1 / ((0.0277 * (abs(x[adj])*100) + 0.6115) * N) }

    #set the labels to be used within the returned plot
    main.title <- paste0("Walking-time isochrones (in ", time, ") around origin")
    sub.title <- paste0("Walking-time based on the Uriarte Gonzalez's hiking function \n terrain factor N=", N)
    legend.cost <- paste0("walking-time (", time,")")
    sub.title.lcp.plot <- paste0("LCP(s) and walking-time distance(s) based on the Uriarte Gonzalez's hiking function \n terrain factor N=", N, "\nblack dot=start location\n red dot(s)=destination location(s)")
  }

  if(funct=="r") {
    #Rees' slope-dependant walking-time cost function;
    #the cost function is originally expressed in terms of time (1/v in Rees' publication);
    #here it is the reciprocal of time (i.e. speed) that is used in order to eventually get
    #the reciprocal of speed (i.e. time). Slope is as originally expressed in Rees' publication (i.e. rise over run);
    #the speed is originally expressed in m/s, so here has been transposed to kmh (i.e., multiplied by 3.6)
    cost_function <- function(x){ ((1 / (0.75 + 0.09 * abs(x[adj]) + 14.6 * (abs(x[adj]))^2)) * 3.6) * (1/N) }

    #set the labels to be used within the returned plot
    main.title <- paste0("Walking-time isochrones (in ", time, ") around origin")
    sub.title <- paste0("Walking-time based on the Rees' hiking function \n terrain factor N=", N)
    legend.cost <- paste0("walking-time (", time,")")
    sub.title.lcp.plot <- paste0("LCP(s) and walking-time distance(s) based on the Rees' hiking function \n terrain factor N=", N, "\nblack dot=start location\n red dot(s)=destination location(s)")
  }

  if(funct=="ks") {
    #Kondo-Saino's modifier Tobler's hiking function.
    #It expresses walking speed in KmH; slope is rise/run.
    cost_function <- function(x){ ifelse(abs(x[adj]) >= -0.07, (5.1 * exp(-2.25 * abs(x[adj] + 0.07))) * (1/N), (5.1 * exp(-1.5 * abs(x[adj] + 0.07)))) * (1/N) }

    #set the labels to be used within the returned plot
    main.title <- paste0("Walking-time isochrones (in ", time, ") around origin")
    sub.title <- paste0("Walking-time based on the Kondo-Seino's hiking function \n terrain factor N=", N)
    legend.cost <- paste0("walking-time (", time,")")
    sub.title.lcp.plot <- paste0("LCP(s) and walking-time distance(s) based on the  Kondo-Seino's hiking function \n terrain factor N=", N, "\nblack dot=start location\n red dot(s)=destination location(s)")
  }

  if(funct=="ree") {
    #relative energetic expenditure;
    # to calculate tangent of degrees (as requested by the cost function) we must first convert degrees to radians by multypling by pi/180;
    #(atan(abs(x[adj]))*180/pi) turns rise/run into degrees, which are then converted into radians before calculating the tangent
    cost_function <- function(x){ 1 / ((tan((atan(abs(x[adj]))*180/pi)*pi/180) / tan (1*pi/180)) * N) }

    #set the labels to be used within the returned plot
    main.title <- "Accumulated cost isolines around origin"
    sub.title <- paste0("Cost based on the relative energetic expenditure cost function \n terrain factor N=", N)
    legend.cost <- "cost"
    sub.title.lcp.plot <- paste0("LCP(s) and cost distance(s) based on the slope-based relative energetic expenditure cost function \n terrain factor N=", N, "\nblack dot=start location\n red dot(s)=destination location(s)")
  }

  if(funct=="hrz") {
    #Herzog metabolic cost function in J/(kg*m);
    #rise/run is requested by the cost function
    cost_function <- function(x){ 1 / (((1337.8 * abs(x[adj])^6) + (278.19 * abs(x[adj])^5) - (517.39 * abs(x[adj])^4) - (78.199 * abs(x[adj])^3) + (93.419 * abs(x[adj])^2) + (19.825 * abs(x[adj])) + 1.64) * N) }

    #set the labels to be used within the returned plot
    main.title <- "Accumulated cost isolines around origin"
    sub.title <- paste0("Cost based on the Herzog's metabolic cost function \n cost in J / (Kg*m) \n terrain factor N=", N)
    legend.cost <- "metabolic cost J / (Kg*m)"
    sub.title.lcp.plot <- paste0("LCP(s) and cost distance(s) based on the Herzog's metabolic cost function \ncost in J / (Kg*m); terrain factor N=", N, "\nblack dot=start location\n red dot(s)=destination location(s)")
  }

  if(funct=="wcs") {
    #wheeled-vehicle critical slope cost function; the slope is expressed in percent
    cost_function <- function(x){ 1 / ((1 + ((abs(x[adj])*100) / sl.crit)^2) * N) }

    #set the labels to be used within the returned plot
    main.title <- "Accumulated cost isolines around origin"
    sub.title <- paste0("Cost based on the wheeled-vehicle critical slope cost function \ncritical slope set to ", sl.crit, " percent \n terrain factor N=", N)
    legend.cost <- "cost"
    sub.title.lcp.plot <- paste0("LCP(s) and cost distance(s) based on the wheeled-vehicle critical slope cost function \ncritical slope set to ", sl.crit, " percent; terrain factor N=", N, "\nblack dot=start location\n red dot(s)=destination location(s)")
  }

  if(funct=="vl") {
    #Van Leusen's metabolic energy expenditure cost function
    #note: V is velocity in m/s; the slope is in percent
    #if V is set to 0 by the user, it is worked out from the DTM using the on-path Tobler hiking function
    #which is expressed as its reciprocal and is multiplied by 0.278 to turn kmh to m/s
    if (V==0) {
      cost_function <- function(x){ 1 / ((1.5 * W + 2.0 * (W + L) * (L / W)^2 + N * (W + L) * (1.5 * ((1 / ((6 * exp(-3.5 * abs(x[adj] + 0.05))) * 0.278))^2) + 0.35 * (1 / ((6 * exp(-3.5 * abs(x[adj] + 0.05))) * 0.278)) * ((abs(x[adj])*100) + 10)))*N) }
    } else {
      cost_function <- function(x){ 1 / ((1.5 * W + 2.0 * (W + L) * (L / W)^2 + N * (W + L) * (1.5 * (V^2) + 0.35 * V * ((abs(x[adj])*100) + 10)))*N) }
    }

    #set the labels to be used within the returned plot
    main.title <- "Accumulated cost isolines around origin"
    legend.cost <- "energy expenditure cost (Megawatts)"
    if (V==0) {
      sub.title <- paste0("Cost based on the Van Leusen's metabolic energy expenditure cost function \nparameters: W: ", W, "; L: ", L, "; N: ", N, "; V is based on the Tobler on-path hiking function")
      sub.title.lcp.plot <- paste0("LCP(s) and cost distance(s) based on the Van Leusen's metabolic energy expenditure cost function \n cost in Megawatts; parameters: W: ", W, "; L: ", L, "; N: ", N, "; V is based on the Tobler on-path hiking function \nblack dot=start location\n red dot(s)=destination location(s)")
    } else {
      sub.title <- paste0("Cost based on the Van Leusen's metabolic energy expenditure cost function \nparameters: W: ", W, "; L: ", L, "; N: ", N, "; V: ", V)
      sub.title.lcp.plot <- paste0("LCP(s) and cost distance(s) based on the Van Leusen's metabolic energy expenditure cost function \n cost in Megawatts; parameters: W: ", W, "; L: ", L, "; N: ", N, "; V: ", V, "\nblack dot=start location\n red dot(s)=destination location(s)")
    }
  }

  if(funct=="p") {
    #Pandolf et al.'s metabolic energy expenditure cost function
    #note: V is velocity in m/s; the slope is expressed in percent
    #if V is set to 0 by the user, it is worked out from the DTM using the on-path Tobler hiking function
    #which is expressed as its reciprocal and is multiplied by 0.278 to turn kmh to m/s
    if (V==0) {
      cost_function <- function(x){ 1 / ((1.5 * W + 2.0 * (W + L) * (L / W)^2 + N * (W + L) * (1.5 * ((1 / ((6 * exp(-3.5 * abs(x[adj] + 0.05))) * 0.278))^2) + 0.35 * (1 / ((6 * exp(-3.5 * abs(x[adj] + 0.05))) * 0.278)) * (abs(x[adj])*100)))*N) }
    } else {
      cost_function <- function(x){ 1 / ((1.5 * W + 2.0 * (W + L) * (L / W)^2 + N * (W + L) * (1.5 * (V^2) + 0.35 * V * (abs(x[adj])*100)))*N) }
    }

    #set the labels to be used within the returned plot
    main.title <- "Accumulated cost isolines around origin"
    legend.cost <- "energy expenditure cost (Megawatts)"
    if (V==0) {
      sub.title <- paste0("Cost based on the Pandolf et al.'s metabolic energy expenditure cost function \nparameters: W: ", W, "; L: ", L, "; N: ", N, "; V is based on the Tobler on-path hiking function")
      sub.title.lcp.plot <- paste0("LCP(s) and cost distance(s) based on the Pandolf et al.'s metabolic energy expenditure cost function \n cost in Megawatts; parameters: W: ", W, "; L: ", L, "; N: ", N, "; V is based on the Tobler on-path hiking function \nblack dot=start location\n red dot(s)=destination location(s)")
    } else {
      sub.title <- paste0("Cost based on the Pandolf et al.'s metabolic energy expenditure cost function \nparameters: W: ", W, "; L: ", L, "; N: ", N, "; V: ", V)
      sub.title.lcp.plot <- paste0("LCP(s) and cost distance(s) based on the Pandolf et al.'s metabolic energy expenditure cost function \n cost in Megawatts; parameters: W: ", W, "; L: ", L, "; N: ", N, "; V: ", V, "\nblack dot=start location\n red dot(s)=destination location(s)")
    }
  }

  if(funct=="pcf") {
    #Pandolf et al.'s metabolic energy expenditure cost function with CORRECTION FACTOR
    #note: V is velocity in m/s; the slope is expressed in percent
    #if V is set to 0 by the user, it is worked out from the DTM using the on-path Tobler hiking function
    #which is expressed as its reciprocal and is multiplied by 0.278 to turn kmh to m/s
    if (V==0) {
      cost_function <- function(x){ ifelse(abs(x[adj])*100 > 0 , 1 / (1.5 * W + 2.0 * (W+L) * (L/W)^2 + N * (W+L) * (1.5 * (1 / ((6 * exp(-3.5 * abs(x[adj] + 0.05))) * 0.278))^2 + 0.35 * (1 / ((6 * exp(-3.5 * abs(x[adj] + 0.05))) * 0.278)) * (abs(x[adj])*100))),
                                           1 / ((1.5 * W + 2.0 * (W+L) * (L/W)^2 + N * (W+L) * (1.5 * (1 / ((6 * exp(-3.5 * abs(x[adj] + 0.05))) * 0.278))^2 + 0.35 * (1 / ((6 * exp(-3.5 * abs(x[adj] + 0.05))) * 0.278)) * (abs(x[adj])*100))) - (N * ((abs(x[adj])*100) * (W+L) * (1 / ((6 * exp(-3.5 * abs(x[adj] + 0.05))) * 0.278))/3.5) - ((W+L) * ((abs(x[adj])*100)+6)^2/W) + (25-(1 / ((6 * exp(-3.5 * abs(x[adj] + 0.05))) * 0.278))^2)))) }
    } else {
      cost_function <- function(x){ ifelse(abs(x[adj])*100 > 0 , 1 / (1.5 * W + 2.0 * (W+L) * (L/W)^2 + N * (W+L) * (1.5 * V^2 + 0.35 * V * (abs(x[adj])*100))),
                                           1 / ((1.5 * W + 2.0 * (W+L) * (L/W)^2 + N * (W+L) * (1.5 * V^2 + 0.35 * V * (abs(x[adj])*100))) - (N * ((abs(x[adj])*100) * (W+L) * V/3.5) - ((W+L) * ((abs(x[adj])*100)+6)^2/W) + (25-V^2)))) }
    }

    #set the labels to be used within the returned plot
    main.title <- "Accumulated cost isolines around origin"
    legend.cost <- "energy expenditure cost (Megawatts)"
    if (V==0) {
      sub.title <- paste0("Cost based on the Pandolf et al.'s metabolic energy expenditure cost function with correction factor \nparameters: W: ", W, "; L: ", L, "; N: ", N, "; V is based on the Tobler on-path hiking function")
      sub.title.lcp.plot <- paste0("LCP(s) and cost distance(s) based on the Pandolf et al.'s metabolic energy expenditure cost function (with correction factor) \n cost in Megawatts; parameters: W: ", W, "; L: ", L, "; N: ", N, "; V is based on the Tobler on-path hiking function \nblack dot=start location\n red dot(s)=destination location(s)")
    } else {
      sub.title <- paste0("Cost based on the Pandolf et al.'s metabolic energy expenditure cost function with correction factor \nparameters: W: ", W, "; L: ", L, "; N: ", N, "; V: ", V)
      sub.title.lcp.plot <- paste0("LCP(s) and cost distance(s) based on the Pandolf et al.'s metabolic energy expenditure cost function with correction factor \n cost in Megawatts; parameters: W: ", W, "; L: ", L, "; N: ", N, "; V: ", V, "\nblack dot=start location\n red dot(s)=destination location(s)")
    }
  }

  if(funct=="ls") {
    #Llobera-Sluckin's metabolic energy expenditure cost function (in KJ/m)
    cost_function <- function(x){ 1 / ((2.635 + (17.37 * abs(x[adj])) + (42.37 * abs(x[adj])^2) - (21.43 * abs(x[adj])^3) + (14.93 * abs(x[adj])^4)) * N) }

    #set the labels to be used within the returned plot
    main.title <- "Accumulated cost isolines around origin"
    sub.title <- paste0("Cost based on the Llobera-Sluckin's metabolic energy expenditure cost function \n terrain factor N=", N)
    legend.cost <- "energy expenditure cost (KJ/m)"
    sub.title.lcp.plot <- paste0("LCP(s) and cost distance(s) based on the Llobera-Sluckin's metabolic energy expenditure cost function \n cost in KJ/m; terrain factor N=", N, "\nblack dot=start location\n red dot(s)=destination location(s)")
  }

  if(funct=="b") {
    #Bellavia 2002's cost function; it measures abstract cost;
    #slope is originally in degrees; (atan(abs(x[adj]))*180/pi) turns rise/run into degrees
    cost_function <- function(x){ 1 / (((atan(abs(x[adj]))*180/pi)+1) * N) }

    #set the labels to be used within the returned plot
    main.title <- "Accumulated cost isolines around origin"
    sub.title <- paste0("Cost based on the Bellavia's cost function \n terrain factor N=", N)
    legend.cost <- "cost"
    sub.title.lcp.plot <- paste0("LCP(s) and cost distance(s) based on the Bellavia's cost function \n terrain factor N=", N, "\nblack dot=start location\n red dot(s)=destination location(s)")
  }

  if(funct=="m") {
    #Minetti et al.'s cost function
    #slope as gradient (i.e., rise/run); cost in J/(kg*m)
    cost_function <- function(x){ 1 / (((280.5 * abs(x[adj])^5) - (58.7 * abs(x[adj])^4) - (76.8 * abs(x[adj])^3) + (51.9 * abs(x[adj])^2) + (19.6 * abs(x[adj])) + 2.5) * N) }

    #set the labels to be used within the returned plot
    main.title <- "Accumulated cost isolines around origin"
    sub.title <- paste0("Cost based on the Minetti et al.'s metabolic cost function \n cost in J / (Kg*m) \n terrain factor N=", N)
    legend.cost <- "metabolic cost J / (Kg*m)"
    sub.title.lcp.plot <- paste0("LCP(s) and cost distance(s) based on the Minetti et al.'s metabolic cost function \ncost in J / (Kg*m); terrain factor N=", N, "\nblack dot=start location\n red dot(s)=destination location(s)")
  }

  if(funct=="ma") {
    #Marin Arroyo's slope-dependant walking-time cost function;
    #the cost function is originally expressed in seconds; here it is the reciprocal of time (1/T) that is used in order to eventually get
    #T/1. Slope is in percent.
    #Note: unlike the original formula, here d (distance travelled in meter) is not taken into account since 'gdistance' takes care of the cells' dimension
    #when calculating accumulated costs.
    cost_function <- function(x){ ifelse((abs(x[adj])*100) < 0, 1 / ((0.6 * ((abs(x[adj])*100)/23+1))*N), 1 / ((0.6 * ((abs(x[adj])*100)/11+1))*N)) }

    #set the labels to be used within the returned plot
    main.title <- paste0("Walking-time isochrones (in ", time, ") around origin")
    sub.title <- paste0("Walking-time based on the Marin Arroyo's hiking function \n terrain factor N=", N)
    legend.cost <- paste0("walking-time (", time,")")
    sub.title.lcp.plot <- paste0("LCP(s) and walking-time distance(s) based on the Marin Arroyo's hiking function \n terrain factor N=", N, "\nblack dot=start location\n red dot(s)=destination location(s)")
  }

  if(funct=="a") {
    #Ardigo et al's energy cost function; slope as rise/run (gradient)
    #cost in J/(kg*m)
    #if V is set to 0 by the user, it is worked out from the DTM using the on-path Tobler hiking function
    #which is expressed as its reciprocal and is multiplied by 0.278 to turn kmh to m/s
    if (V==0) {
      cost_function <- function(x){ 1 / ((1.866 * exp(4.911*abs(x[adj])) * (1 / ((6 * exp(-3.5 * abs(x[adj] + 0.05))) * 0.278))^2 - 3.773 * exp(3.416*abs(x[adj])) * (1 / ((6 * exp(-3.5 * abs(x[adj] + 0.05))) * 0.278)) + (45.71*abs(x[adj]^2) + 18.90*abs(x[adj])) + 4.456) * N) }
    } else {
      cost_function <- function(x){ 1 / ((1.866 * exp(4.911*abs(x[adj])) * V^2 - 3.773 * exp(3.416*abs(x[adj])) * V + (45.71*abs(x[adj]^2) + 18.90*abs(x[adj])) + 4.456) * N) }
    }

    #set the labels to be used within the returned plot
    main.title <- "Accumulated cost isolines around origin"
    legend.cost <- "metabolic cost J / (Kg*m)"
    if (V==0) {
      sub.title <- paste0("Cost based on the Ardigo et al.'s metabolic cost function \n cost in J / (Kg*m) \nparameters: N=", N, "; V is based on the Tobler on-path hiking function")
      sub.title.lcp.plot <- paste0("LCP(s) and cost distance(s) based on the Ardigo et al.'s metabolic cost function \ncost in J / (Kg*m); parameters: N=", N, "; V is based on the Tobler on-path hiking function \nblack dot=start location\n red dot(s)=destination location(s)")
    } else {
      sub.title <- paste0("Cost based on the Ardigo et al.'s metabolic cost function \n cost in J / (Kg*m) \nparameters: N=", N, "; V=", V)
      sub.title.lcp.plot <- paste0("LCP(s) and cost distance(s) based on the Ardigo et al.'s metabolic cost function \ncost in J / (Kg*m); parameters: N=", N, "; V=", V, "\nblack dot=start location\n red dot(s)=destination location(s)")
    }
  }

  if(funct=="h") {
    #energetic expenditure in calories per km, following Hare 2004;
    #walking speed is worked out from the DTM using the on-path Tobler hiking function,
    #which is expressed as its reciprocal; speed in km/h as per original Tobler's function and as requested by Hare's function
    cost_function <- function(x){ 1 / ((48+30/(1/(6 * exp(-3.5 * abs(x[adj] + 0.05)))))*N) }

    #set the labels to be used within the returned plot
    main.title <- "Accumulated cost isolines around origin"
    sub.title <- paste0("Cost based on the Hare's metabolic cost function \n cost in cal/km \n terrain factor N=", N)
    legend.cost <- "metabolic cost cal/km"
    sub.title.lcp.plot <- paste0("LCP(s) and cost distance(s) based on the Hare's metabolic cost function \ncost in cal/km; terrain factor N=", N, "\nblack dot=start location\n red dot(s)=destination location(s)")
  }

  if(funct=="e") {
    #Eastman's cost function; it measures abstract cost;
    #slope is originally in degrees; (atan(abs(x[adj]))*180/pi) turns rise/run into degrees
    cost_function <- function(x){ 1 / ((0.031 * (atan(abs(x[adj]))*180/pi)^2 - 0.025 * (atan(abs(x[adj]))*180/pi) + 1)*N) }

    #set the labels to be used within the returned plot
    main.title <- "Accumulated cost isolines around origin"
    sub.title <- paste0("Cost based on the Eastman's cost function \n terrain factor N=", N)
    legend.cost <- "cost"
    sub.title.lcp.plot <- paste0("LCP(s) and cost distance(s) based on the Eastman's cost function \n terrain factor N=", N, "\nblack dot=start location\n red dot(s)=destination location(s)")
  }

  if(funct=="trp") {
    #Tripcevich's slope-dependant hiking function; speed in kmh;
    #slope is originally in degrees; (atan(abs(x[adj]))*180/pi) turns rise/run into degrees
    cost_function <- function(x){((4.028*46^2)/(((atan(abs(x[adj]))*180/pi)+4.127)^2+46^2))*(1/N) }

    #set the labels to be used within the returned plot
    main.title <- paste0("Walking-time isochrones (in ", time, ") around origin")
    sub.title <- paste0("Walking-time based on the Tripcevich's hiking function \n terrain factor N=", N)
    legend.cost <- paste0("walking-time (", time,")")
    sub.title.lcp.plot <- paste0("LCP(s) and walking-time distance(s) based on the Tripcevich's hiking function \n terrain factor N=", N, "\nblack dot=start location\n red dot(s)=destination location(s)")
  }

  #cost calculation for walking-speed-based cost functions
  if (funct=="t" | funct=="tofp" | funct=="mp" | funct=="icmonp" | funct=="icmoffp" | funct=="icfonp" | funct=="icfoffp" | funct=="alb" | funct=="gkrs" | funct=="r" | funct=="ks" | funct=="trp") {

    #restrict the speed calculation to adjacent cells by creating an index for adjacent cells (adj) with the function 'adjacent'
    adj <- raster::adjacent(dtm, cells=1:raster::ncell(dtm), pairs=TRUE, directions=move)

    speed <- slope

    #apply the cost function to the adjacent cells of the speed dataset, which is equal to the slope dataset as per previous step
    speed[adj] <- cost_function(slope)

    #turn the walking speed from kmh to ms (0.278=1000/3600)
    speed <- speed * 0.278

    #correct the speed values taking into account the distance between cell centers
    Conductance <- gdistance::geoCorrection(speed)

    #if 'topo.dist' is TRUE, adjust conductance to account for surface (topographic) distance
    #for speed-based functions: conductance represents speed (distance/time)
    #when using surface distance, the actual distance travelled is longer by factor sqrt(1+slope^2)
    #therefore, effective speed (surface_distance/time) requires dividing by the correction factor
    #since gdistance uses conductance (higher = easier movement), we divide by surf_corr
    if (topo.dist==TRUE) {
      Conductance@transitionMatrix@x <- Conductance@transitionMatrix@x / surf_corr@transitionMatrix@x
    }

    if (irregular.dtm==TRUE) {
      dtm.copy <- dtm

      #substitute the values of the copy with a single value, omitting the NA cells
      dtm.copy[na.omit(dtm.copy)] <- 1

      #run a 3x3 mean filter to remove possible in-land NoData value because they would prevent the subsequent
      #step from running
      dtm.copy <- raster::focal(dtm.copy, w=matrix(1/9,nrow=3,ncol=3))

      #convert the modified dtm copy to a polygon ignoring the NA cells and dissolving cells with the same
      #attribute (that is all, since we changed all the values to 1) into a single polygon;
      #as(dtm.copy, "SpatRaster") is needed because 'terra::as.polygons()' requires a SpatRaster layer (not Raster)
      mask.polyg <- terra::as.polygons(as(dtm.copy, "SpatRaster"), dissolve=TRUE)

      #turn the SpatVector format (returned by terra::as.polygons()) into a SpatialPolygonDataFrame that will be fed into
      #create_barrier_cs
      mask.polyg<-as(mask.polyg, "Spatial")

      #create a Transitional Layer where the masked area is given 1, while the other parts are given 0;
      #thus all which is not terrain will be given 0 conductance
      mask.TL <- create_barrier_cs(dtm.copy, mask.polyg, neighbours = move, field=1, background = 0)

      #use map algebra to "combine" the two Transitional Layers
      Conductance <- Conductance*mask.TL
    }

    #if the 'barrier' parameter in not NULL...
    if (is.null(barrier)==FALSE) {
      #...create a barrier transitional layers via the 'create_barrier_cs' function
      barrier.TL <- create_barrier_cs(dtm, barrier, neighbours=move, field=field)
      #use map algebra to "incorporate" the barrier to the conductance layer
      Conductance <- Conductance*barrier.TL
    }

    #cost-surface raster to be exported (the division turns ms back to kmh)
    cost.surface.to.export <- raster::raster(speed) / 0.278
  }

  #cost calculation for OTHER TYPES of cost functions;
  #NOTE the Uriarte Gonzalez's and Marin Arroyo's slope-dependant walking-time cost function are in this group since (unlike the above functions)
  #they expresses cost as time NOT speed
  if (funct=="ree" | funct=="hrz" | funct=="wcs" | funct=="vl" | funct=="p" | funct=="ug" | funct=="ls" | funct=="b" | funct=="m" | funct=="ma" | funct=="a" | funct=="pcf" | funct=="h" | funct=="e") {

    #restrict the cost calculation to adjacent cells by creating an index for adjacent cells (adj) with the function 'adjacent'
    adj <- raster::adjacent(dtm, cells=1:raster::ncell(dtm), pairs=TRUE, directions=move)

    cost <- slope

    #apply the cost function to the adjacent cells of the cost dataset, which is equal to the slope dataset as per previous step
    cost[adj] <- cost_function(slope)

    #correct the cost values taking into account the distance between cell centers
    Conductance <- gdistance::geoCorrection(cost)

    #if 'topo.dist' is TRUE, adjust conductance to account for surface (topographic) distance
    #for cost functions expressed as 1/cost: conductance is the reciprocal of cost
    #when using surface distance, the distance component increases by factor sqrt(1+slope^2)
    #since these functions use 1/cost and gdistance accumulates 1/conductance,
    #we divide conductance by surf_corr (which increases the accumulated cost appropriately)
    if (topo.dist==TRUE) {
      Conductance@transitionMatrix@x <- Conductance@transitionMatrix@x / surf_corr@transitionMatrix@x
    }

    if (irregular.dtm==TRUE) {
      dtm.copy <- dtm

      #substitute the values of the copy with a single value, omitting the NA cells
      dtm.copy[na.omit(dtm.copy)] <- 1

      #run a 3x3 mean filter to remove possible in-land NoData value because they would prevent the following
      #step from running
      dtm.copy <- raster::focal(dtm.copy, w=matrix(1/9,nrow=3,ncol=3))

      #convert the modified dtm copy to a polygon ignoring the NA cells and dissolving cells with the same
      #attribute (that is all, since we changed all the values to 1) into a single polygon;
      #as(dtm.copy, "SpatRaster") is needed because 'terra::as.polygons()' requires a SpatRaster layer (not Raster)
      mask.polyg <- terra::as.polygons(as(dtm.copy, "SpatRaster"), dissolve=TRUE)

      #turn the SpatVector format (returned by terra::as.polygons()) into a SpatialPolygonDataFrame that will be fed into
      #create_barrier_cs
      mask.polyg<-as(mask.polyg, "Spatial")

      #create a Transitional Layer where the masked area is given 1, while the other parts are given 0;
      #thus all which is not terrain will be given 0 conductance
      mask.TL <- create_barrier_cs(dtm.copy, mask.polyg, neighbours = move, field=1, background = 0)

      #use map algebra to "combine" the two Transitional Layers
      Conductance <- Conductance*mask.TL
    }

    #if the 'barrier' parameter in not NULL...
    if (is.null(barrier)==FALSE) {
      #...create a barrier transitional layers via the 'create_barrier_cs' function
      barrier.TL <- create_barrier_cs(dtm, barrier, neighbours=move, field=field)
      #use map algebra to "incorporate" the barrier to the conductance layer
      Conductance <- Conductance*barrier.TL
    }

    #cost-surface raster to be exported
    cost.surface.to.export <- raster::raster(cost)
  }

  #accumulate the cost outwards from the origin
  accum_final <- gdistance::accCost(Conductance, sp::coordinates(origin))

  #if user select the Tobler's, the modified Tobler's, the Irmischer-Clarke's,
  #the Uriarte Gonzalez's, the Alberti's function, or other speed-related functions, turn seconds into the user-defined time-scale
  if (funct=="t" | funct=="tofp" | funct=="mp" | funct=="icmonp" | funct=="icmoffp" | funct=="icfonp" | funct=="icfoffp" | funct=="ug" | funct=="alb" | funct=="gkrs" | funct=="r" | funct=="ks" | funct=="ma" | funct=="trp"){
    if (time=="h") {
      #turn seconds into hours
      accum_final <- accum_final / 3600
    } else {
      #turn seconds into minutes
      accum_final <- accum_final / 60
    }
  }

  #if user select the Val Leusen's, the Pandolf et al.'s, or the Pandolf et al.'s with correction factor function,
  #turn the cost from Watts to Megawatts
  if (funct=="vl" | funct=="p" | funct=="pcf") {
    accum_final <- accum_final / 1000000
  }

  #if no break value is entered, set the breaks to one tenth of the range of the values of the final accumulated cost surface
  if(is.null(breaks)==TRUE){
    #exclude the inf values from the calculation
    breaks <- round((max(accum_final[][is.finite(accum_final[])]) - min(accum_final[][is.finite(accum_final[])])) / 10,2)
  }

  #crop the final accumulated dataset to the extent of the input dtm so that NA cell (e.g., cells corresponding to the sea)
  #can be excluded
  accum_final <- raster::mask(accum_final, dtm)

  #set the break values for the isolines, again excluding inf values
  levels <- seq(min(accum_final[][is.finite(accum_final[])]), max(accum_final[][is.finite(accum_final[])]), breaks)

  if (graph.out==TRUE) {

    #produce the ingredient for the slopeshade raster
    #to be used in both the rendered plots
    slope <- raster::terrain(dtm, opt = "slope")

    #conditionally set the layout in just one visualization
    if(is.null(destin)==FALSE & oneplot==TRUE){
      m <- rbind(c(1,2))
      layout(m)
    }

    #produce the output
    if (outp=="r") {
      #produce a raster with contours
      raster::plot(accum_final,
                   main=main.title,
                   sub=sub.title,
                   cex.main=0.95,
                   cex.sub=0.75,
                   legend.lab=legend.cost,
                   col = topo.colors(255))

      #add the slopeshade
      raster::plot(slope,
                   col = rev(grey(0:100/100)),
                   legend = FALSE,
                   alpha=transp,
                   add=TRUE)

      #add the contours
      raster::contour(accum_final,
                      add=TRUE,
                      levels=levels,
                      labcex=cex.breaks,
                      drawlabels = cont.lab)

      #add the origin
      raster:: plot(origin,
                    pch=20,
                    add=TRUE)

    } else {
      #only produce contours
      raster::contour(accum_final,
                      levels=levels,
                      main=main.title,
                      sub=sub.title,
                      cex.main=0.95,
                      cex.sub=0.75,
                      labcex=cex.breaks,
                      drawlabels = cont.lab)

      #add the origin
      raster::plot(origin,
                   pch=20,
                   add=TRUE)
    }

  }

  #calculate and store the contours as a SpatialLinesDataFrame
  isolines <- raster::rasterToContour(accum_final, levels=levels)


  #if 'destin' is NOT NULL, calculate the least-cost path(s) from the origin to the destination(s);
  #the 'Conductance' transitional layer is used
  if(is.null(destin)==FALSE){
    #calculate the least-cost path(s)
    sPath <- gdistance::shortestPath(Conductance, sp::coordinates(origin), sp::coordinates(destin), output="SpatialLines")

    sPath.back <- NULL

    #if 'return.base' is set to TRUE
    if(return.base==TRUE){
      #create an empty list to store the LCPs back to the origin
      sPath.back <- list()
      #loop through the destinations, for each calculate the LCPs to the origin, and store those in the
      #previously created list
      for(i in 1:length(destin)) {
        sPath.back[[i]]<- gdistance::shortestPath(Conductance, sp::coordinates(destin[i,]), sp::coordinates(origin), output="SpatialLines")
      }
      #merge the individual LCPs
      sPath.back <- base::do.call(rbind, sPath.back)
    }


    if (graph.out==TRUE) {
      #plot the dtm
      raster::plot(dtm, main="Digital Terrain Model with Least-cost Path(s)",
                   sub=sub.title.lcp.plot,
                   cex.main=0.90,
                   cex.sub=0.7,
                   legend.lab="Elevation (masl)")

      #add the slopeshade
      raster::plot(slope,
                   col = rev(grey(0:100/100)),
                   legend = FALSE,
                   alpha=transp,
                   add=TRUE)

      #add the origin
      raster::plot(origin, add=TRUE, pch=20)

      #add the LCPs
      raster::plot(sPath, add=TRUE)

      #if 'return.base' is set to TRUE, plot the LCPs back to the origin
      if(return.base==TRUE){
        for(i in 1:length(destin)) {
          raster::plot(sPath.back, lty=rb.lty, add=TRUE)
        }
      }

      #add the destination(s)
      raster::plot(destin,
                   add=TRUE,
                   pch=20,
                   col="red")

      #if the barrier is provided AND if plot.barrier is TRUE, add the barrier
      if(is.null(barrier)==FALSE & plot.barrier==TRUE) {
        raster::plot(barrier, col="blue", add=TRUE)
      }
    }

    #calculate the length of the least-cost paths and store the values by appending them to a new variable of the sPath object
    sPath$length <- sf::st_length(st_as_sf(sPath), by_element=TRUE)

    #same as above if the LCPs back to the origin had been calculated
    if(return.base==TRUE){
      sPath.back$length <- sf::st_length(st_as_sf(sPath.back), by_element=TRUE)
    }

    #extract the cost from the accum_final to the destination location(s), appending the data to a new column
    destin$cost <- raster::extract(accum_final, destin)

    #if user select the Tobler's, the modified Tobler's, the Irmischer-Clarke's,
    #the Uriarte Gonzalez's, the Alberti's function, or other functions producing time cost...
    if (funct=="t" | funct=="tofp" | funct=="mp" | funct=="icmonp" | funct=="icmoffp" | funct=="icfonp" | funct=="icfoffp" | funct=="ug" | funct=="alb" | funct=="gkrs" | funct=="r" | funct=="ks" | funct=="ma" | funct=="trp"){
      #create a new columns in the 'destin' layer to store decimal hours turned into sessagesimal format
      if (time=="h") {
        destin$cost_hms <- as.character(chron::times(destin$cost / 24))
      } else {
        destin$cost_hms <- as.character(chron::times(destin$cost / (24*60)))
      }
    }

    if (graph.out==TRUE) {
      #if destin.lab is TRUE...
      if(destin.lab==TRUE){
        #if the dataset 'destin' contains the column "cost_hms" (as per the above step),
        #use that column to get the points' labels (this means that cost-functions that produced
        #walking time distance have been used)
        if(is.null(destin$cost_hms)==FALSE){
          raster::text(sp::coordinates(destin),
                       labels=destin$cost_hms,
                       pos = 4,
                       cex=cex.lcp.lab)
        } else {
          #otherwise (i.e., in case energy cost function has been used), use the "cost" column;
          #notice that in case of cost function returning time, the cost is still stored in the
          #"cost" column, but is the time in sessagesimal that will be used for plotting, not in decimal;
          #decimal time has been nonetheless stored
          raster::text(sp::coordinates(destin),
                       labels=round(destin$cost,2),
                       pos = 4,
                       cex=cex.lcp.lab)
        }
      }
    }

    #if export is TRUE, export the LPCs and the destinatin locations with cost as a shapefile
    if(export==TRUE){
      terra::writeVector(vect(sPath), filename=paste0("LCPs_", funct), filetype="ESRI Shapefile")
      terra::writeVector(vect(destin), filename=paste0("dest_loc_w_cost_", funct), filetype="ESRI Shapefile")
      #same as above if the LCPs back to the origin had been calculated
      if(return.base==TRUE){
        terra::writeVector(vect(sPath.back), filename=paste0("LCPs_back_", funct), filetype="ESRI Shapefile")
      }
    }

  } else {
    sPath=NULL
    sPath.back=NULL
    dest.loc.w.cost=NULL
  }

  #if export is TRUE, export the cost-surface and the accumulated cost surface as a raster file,
  #the isolines as a shapefile
  if(export==TRUE){
    raster::writeRaster(accum_final, paste0("accum_cost_surf_", funct), format="GTiff")
    raster::writeRaster(cost.surface.to.export, paste0("cost_surf_", funct), format="GTiff")
    terra::writeVector(vect(isolines), filename=paste0("isolines_", funct), filetype="ESRI Shapefile")
  }

  #if no DTM was provided (i.e., if 'studyplot' is not NULL), export the downloaded DTM as a raster file
  if(export==TRUE & is.null(studyplot)==FALSE){
    raster::writeRaster(dtm, "dtm", format="GTiff")
  }

  if (graph.out==TRUE) {
    #restore the original graphical device's settings if previously modified
    if(is.null(destin)==FALSE & oneplot==TRUE){
      par(mfrow = c(1,1))
    }
  }

  #restore the advice for error messages on the R console, which has been deactivated
  #at the beginning of function
  options(warn = 1)

  #store the results in a list
  results <- list("dtm"=dtm,
                  "cost.surface"=cost.surface.to.export,
                  "accumulated.cost.raster"=accum_final,
                  "isolines" = isolines,
                  "LCPs"=sPath,
                  "LCPs.back"=sPath.back,
                  "dest.loc.w.cost"=destin,
                  "conductance"=Conductance)
}
