R/SecondTrailsOpening.R

Defines functions secondtrailsopening

Documented in secondtrailsopening

#' Secondary skidding trails layout
#'
#' @description Starting from the main skidding trails, draw secondary skidding
#'   trails on the zones accessible to the machines, allowing to collect the
#'   selected trees with the chosen machines ("winching" argument). The layout
#'   is optimised to reduce the distance covered while respecting topographical
#'   constraints and avoiding trees to protect.
#'
#' @param topography Digital terrain model (DTM) of the inventoried plot (LiDAR
#'  or SRTM) (\code{\link{DTMParacou}}) (RasterLayer **with a crs in UTM**)
#'
#' @param plotmask Inventoried plot mask
#' (SpatialPolygonsDataFrame **with a crs in UTM**)
#'
#' @param maintrails Main trails defined at the entire harvestable area (sf
#'   linestring **with a crs in UTM**)
#'
#' @param treeselectionoutputs A list with:
#' - your inventory with: "DistCriteria", "Slope", "SlopeCriteria",
#'    "LoggingStatus", "Selected", "Up", "VolumeCumSum",
#'     "ProbedHollowProba", "ProbedHollow" new columns
#'     (see the outputs metadata in the vignette).
#'
#' - the objective volume
#'
#' - 6 sets of spatial points:
#'   harvestable, selected, future and reserve, hollow and fuel wood trees
#'
#' @param harvestablepolygons Accessible zones of the inventoried plot
#'  (default: \code{\link{harvestableareadefinition}}) (sfc_MULTIPOLYGON)
#'
#' @param machinepolygons Accessible zones for machines of the inventoried plot
#'  (default: \code{\link{harvestableareadefinition}}) (sf polygons data.frame)
#'
#' @param maintrailsaccess Access point of maintrail for each PU (prospection
#'    unit) (sf or sfc)
#'
#' @param plotslope Slopes (in radians) of the inventoried plot (with a
#'  neighbourhood of 8 cells) (default:
#'  \code{\link{HarvestableAreaOutputsCable}})
#'  (RasterLayer **with a crs in UTM**)
#'
#'@param scenario Logging scenario among: "RIL1", "RIL2broken", "RIL2", "RIL3",
#'  "RIL3fuel", "RIL3fuelhollow" or "manual"(character) (see the
#'  vignette)
#'
#'@param winching
#' "0": no cable or grapple (trail to tree foot)
#' "1": only cable (default = 40m)
#' "2": grapple (default = 6m) + cable (grapple priority)
#' If grapple + cable (winching = "2") without fuel wood (fuel = "0")
#'  recovery of the tree foot with grapple if possible (respected grapple
#'  conditions) otherwise with cable with angle to the trail.
#'  Avoidance of future/reserves if chosen.
#'
#'@param fuel Fuel wood exploitation: no exploitation = "0", exploitation of
#'   damage and unused part of logged trees for fuel = "1", exploitation of
#'   hollow trees, damage and and unused part of the log for fuel = "2".
#'   If fuel wood harvesting is chosen, these trails are preliminary,
#'   and the trails will be adjusted after tree felling for fuel wood recovery.
#'   The mortality of the trails is therefore not recorded at this stage
#'
#'@param verbose Allow to provide messages from internal functions (boolean)
#'
#' @param advancedloggingparameters Other parameters of the logging simulator
#'   \code{\link{loggingparameters}} (list)
#'
#' @return A list with :
#' - *inventory*: Updated inventory
#'
#' - *SmoothedTrails*: Smoothed secondary trails (MULTIPOLYGON with crs)
#'
#' - *TrailsDensity*: Secondary trails density (in m/ha)
#'
#' - *TrailsIdentity*: Information on sections of the trails (matrix) with:
#'     - *LineID*:
#'     - *LoggedTrees*: idTree of trees reached by the trails
#'     - *TypeExpl*: type of winching
#'
#' - *MainTrailsAccess*: Random access point of main trail for each harvestable
#'   zone (sfc_POINT with crs)
#'
#' - *RawSecondTrails*: Non-smoothed secondary trails (SpatialLines with crs)
#'
#' - *CostRasterAgg*: The cost raster (RasterLayer  with crs)
#'
#' @importFrom sf st_cast st_as_sf st_as_sfc st_intersection st_union st_sample st_join
#'   st_buffer as_Spatial st_centroid st_set_precision st_make_valid st_set_agr
#'   st_geometry st_area st_is_empty st_set_crs st_crs sf_use_s2 st_geometry<-
#'   st_drop_geometry st_geometry_type
#'
#' @importFrom dplyr mutate row_number select as_tibble left_join if_else filter
#'   arrange desc distinct
#'
#' @importFrom raster raster extend extent focal res crs mask crop rasterize
#'   rasterToPoints rasterToPolygons rasterFromXYZ aggregate values ncell
#'   values<- adjacent resample ncol
#'
#' @importFrom dplyr select filter mutate
#' @importFrom tidyr unnest
#' @importFrom tibble add_column
#' @importFrom sp proj4string<- coordinates<-
#' @importFrom sf st_as_sf st_union st_distance st_crs
#' @importFrom lwgeom st_snap_to_grid
#' @importFrom smoothr smooth
#' @importFrom gdistance transition geoCorrection
#' @importFrom utils txtProgressBar setTxtProgressBar
#' @importFrom stats na.exclude
#'
#' @export
#'
#' @examples
#' set.seed(1)
#' data(Paracou6_2016)
#' data(DTMParacou)
#' data(PlotMask)
#' data(SpeciesCriteria)
#' data(HarvestableAreaOutputsCable)
#' data(MainTrails)
#'
#' scenario <- "manual"
#' winching <- "2"
#' objective <- 10
#' fuel <- "2"
#' diversification <- TRUE
#'
#' inventory <- addtreedim(cleaninventory(Paracou6_2016, PlotMask),
#' volumeparameters = ForestZoneVolumeParametersTable)
#'
#' treeselectionoutputs <- suppressWarnings(treeselection(inventory,
#'   topography = DTMParacou,
#'   speciescriteria = SpeciesCriteria,
#'   scenario = "manual", objective = objective,
#'   fuel = fuel,
#'   diversification = diversification,
#'   winching = winching,
#'   specieslax = FALSE, objectivelax = TRUE,
#'   harvestablearea = HarvestableAreaOutputsCable$HarvestableArea,
#'   plotslope = HarvestableAreaOutputsCable$PlotSlope,
#'   maintrails = MainTrails,
#'   harvestablepolygons = HarvestableAreaOutputsCable$HarvestablePolygons,
#'   advancedloggingparameters = loggingparameters()))
#'
#' \dontrun{
#' secondtrails <- secondtrailsopening(
#'   topography = DTMParacou,
#'   plotmask = PlotMask,
#'   maintrails = MainTrails,
#'   plotslope = HarvestableAreaOutputsCable$PlotSlope,
#'   harvestablepolygons = HarvestableAreaOutputsCable$HarvestablePolygons,
#'   machinepolygons = HarvestableAreaOutputsCable$MachinePolygons,
#'   treeselectionoutputs = treeselectionoutputs,
#'   scenario = "manual",
#'   winching = winching,
#'   fuel =  "0",
#'   advancedloggingparameters = loggingparameters())
#'   }
#'
#' data(SecondaryTrails)
#' library(ggplot2)
#' library(sf)
#'
#' NewInventory <- SecondaryTrails$inventory
#'
#'
#' Harvestable <- sf::st_as_sf(
#' dplyr::filter(NewInventory, LoggingStatus == "harvestable"),
#' coords = c("Xutm", "Yutm")) %>%
#' st_set_crs(st_crs(SecondaryTrails$MainTrailsAccess))
#'
#' HarvestableUp <- sf::st_as_sf(
#' dplyr::filter(NewInventory, LoggingStatus == "harvestableUp"),
#' coords = c("Xutm", "Yutm")) %>%
#' st_set_crs(st_crs(SecondaryTrails$MainTrailsAccess))
#'
#' Selected <- sf::st_as_sf(
#' dplyr::filter(NewInventory, Selected == "1"), coords = c("Xutm", "Yutm")) %>%
#' st_set_crs(st_crs(SecondaryTrails$MainTrailsAccess))
#'
#' Reserve <- sf::st_as_sf(
#' dplyr::filter(NewInventory, LoggingStatus == "reserve"),
#' coords = c("Xutm", "Yutm")) %>%
#' st_set_crs(st_crs(SecondaryTrails$MainTrailsAccess))
#'
#' Future <- sf::st_as_sf(
#' dplyr::filter(NewInventory, LoggingStatus == "future"),
#' coords = c("Xutm", "Yutm")) %>%
#' st_set_crs(st_crs(SecondaryTrails$MainTrailsAccess))
#'
#' ProbedHollow <- sf::st_as_sf(
#' dplyr::filter(NewInventory, ProbedHollow == "1"),
#'  coords = c("Xutm", "Yutm")) %>%
#' st_set_crs(st_crs(SecondaryTrails$MainTrailsAccess))
#'
#' VisibleDefect <- sf::st_as_sf(
#' dplyr::filter(NewInventory, VisibleDefect == "1"),
#'  coords = c("Xutm", "Yutm")) %>%
#' st_set_crs(st_crs(SecondaryTrails$MainTrailsAccess))
#'
#'
#' ggplot() +
#'   # Harvestable zones
#'   geom_sf(data = HarvestableAreaOutputsCable$HarvestablePolygons,
#'         fill = "olivedrab", alpha = 0.1) +
#'    geom_sf(data = HarvestableAreaOutputsCable$MachinePolygons,
#'         fill = "olivedrab", alpha = 0.5) +
#'   labs(alpha = "Harvestable") +
#'   labs(title = "Paracou P6 - secondary trails") +
#'
#'   geom_sf(data = VisibleDefect,
#'   aes(colour = "Visible defect"), show.legend = "point") +
#'   # geom_sf(data = Future,
#'   # aes(colour = "Future"), show.legend = "point", size = 4) +
#'   geom_sf(data = Reserve,
#'   aes(colour = "Reserve"), show.legend = "point", size = 4) +
#'   geom_sf(data = Harvestable,
#'   aes(colour = "Harvestable"), show.legend = "point", size = 4) +
#'   geom_sf(data = HarvestableUp,
#'   aes(colour = "HarvestableUp"), show.legend = "point", size = 4) +
#'   geom_sf(data = Selected,
#'   aes(colour = "Selected"), show.legend = "point") +
#'   geom_sf(data = ProbedHollow,
#'   aes(colour = "Probed hollow"), show.legend = "point") +
#'
#'   # 2ndary trails
#'     geom_sf(data = st_as_sf(SecondaryTrails$SmoothedTrails), col = "darkgreen") +
#'     geom_sf(data = st_as_sf(SecondaryTrails$MainTrailsAccess), col = "black") +
#'
#'     scale_colour_manual(values = c("Visible defect" = "pink",
#'    "Harvestable" = "skyblue", "HarvestableUp" = "blue", "Selected" = "red",
#'    "Future" = "orange", "Reserve" = "purple", "Probed hollow" = "forestgreen",
#'   "Second trails" = "darkgreen", "Harvestable area" = "olivedrab"))
#'
#' SecondaryTrails$TrailsIdentity
#'
secondtrailsopening <- function(
    topography,
    plotmask,
    maintrails,
    plotslope,
    harvestablepolygons,
    machinepolygons,
    maintrailsaccess = NULL,
    treeselectionoutputs,
    scenario,
    winching = NULL,
    fuel = NULL,
    verbose = FALSE,
    advancedloggingparameters = loggingparameters()
){


  # Arguments check

  if(!inherits(treeselectionoutputs, "list"))
    stop("The 'treeselectionoutputs' arguments of the 'secondtrailsopening'
         function must be list following treeselection output format")

  if(!inherits(plotmask, "SpatialPolygonsDataFrame"))
    stop("The 'plotmask' argument of the 'secondtrailsopening' function must be
         SpatialPolygonsDataFrame")

  # if(!any(unlist(lapply(list(maintrails), inherits, "sf" ))))
  #   stop("The 'maintrails' argument of the 'secondtrailsopening' function must be sf polygon")

  if(!inherits(topography, "RasterLayer"))
    stop("The 'topography' argument of the 'secondtrailsopening' function must
         be RasterLayer")

  if(sf::st_is_empty(treeselectionoutputs$SelectedTreesPoints)[1]) {
    stop("The 'treeselectionoutputs' argument does not contain any selected
         tree.")
  }

  # Options
  options("rgdal_show_exportToProj4_warnings"="none") # to avoid gdal warnings
  # gc() # remove intermediary files (to avoid gdal warnings)

  # Global Variables
  slope <- x <- y <- Harvestable <- idTree <- ID <- type <- ptAcc <- . <- NULL
  EstCost <- n.overlaps <- TypeAcc <- IDpts <- Logged <- AccessPolygons <- NULL
  Selected <- DeathCause <- ID_Acc <- isEmpty <- gprlAcc <- cblAcc <- NULL
  ID.y <- IdMachineZone <- IdMachineZone.y <- IdMachineZone.x <- LineID <- LoggedTrees <- TypeExpl <- NULL

  #### Redefinition of the parameters according to the chosen scenario ####
  scenariosparameters <- scenariosparameters(scenario = scenario, winching = winching, fuel = fuel)
  WinchingInit <- scenariosparameters$winching
  winching <- WinchingInit
  fuel <- scenariosparameters$fuel

  ##################################

  suppressMessages(sf_use_s2(FALSE)) # to deal with actual unresolved s2 issues in sf ("Spherical geometry (s2) switched off")

  CostMatrix <- advancedloggingparameters$CostMatrix

  factagg <-  floor(advancedloggingparameters$SlopeDistance/res(topography)[1])

  advancedloggingparameters$CableLength <- advancedloggingparameters$CableLength + factagg

  # Transformation of the DTM so that the maintrails are outside the plot


  DTMExtExtended <- raster::extend(topography, c(2*factagg,2*factagg)) # extend the extent

  fill.boundaries <- function(x) {
    center = 0.5 + (factagg*factagg/2)
    if( is.na(x)[center] ) {
      return( round(mean(x, na.rm=T),5) )
    } else {
      return( x[center] )
    }
  }

  DTMExtended <- raster::focal(DTMExtExtended,
                               matrix(1,factagg,factagg),
                               fun=fill.boundaries,
                               na.rm=F, pad=T)

  for (iterExt in 1:5) {
    DTMExtended <- raster::focal(DTMExtended,
                                 matrix(1,factagg,factagg),
                                 fun=fill.boundaries,
                                 na.rm=F, pad=T)
  }

  # Generate accessible area from HarvestablePolygones and winching choice

  AccessPolygons <- machinepolygons

  maintrailsRed <- maintrails %>% st_as_sfc() %>%
    st_cast("POLYGON") %>% st_buffer(-factagg) %>%
    st_cast("LINESTRING") %>% st_buffer(factagg+0.5)

  #-------------------------------------------

  if (!is.null(maintrailsaccess)) {

    AccessMainTrails <- AccessPolygons  %>% st_union() %>%
      st_cast("POLYGON", warn = FALSE) %>%
      st_as_sf() %>% st_join(maintrailsaccess) %>%
      select(ID)

    PartMainTrails <- st_intersection(st_geometry(maintrailsRed),
                                      st_geometry(AccessMainTrails)) %>%
      st_union(by_feature = T) %>% st_as_sf() %>%
      filter(st_geometry_type(.) %in% c("POLYGON","MULTIPOLYGON") ) %>%
      st_cast("MULTIPOLYGON", warn = FALSE)  %>% # "In st_cast.MULTIPOLYGON(X[[i]], ...) : polygon from first part only"
      st_as_sf() %>%
      st_set_agr(value = "constant") %>%
      st_join(AccessMainTrails)%>%
      st_make_valid()

    PartMainTrails <- PartMainTrails %>%
      arrange(desc(st_area(PartMainTrails))) %>%
      filter(duplicated(PartMainTrails$ID) == FALSE)

    AccessPointAll <- maintrailsaccess
  }else{


    accesspts <- genaccesspts(topography = topography,
                              machinepolygons = machinepolygons,
                              maintrails = maintrails,
                              advancedloggingparameters = advancedloggingparameters)

    PartMainTrails <- accesspts$PartMainTrails


    # Generate point access in the intersections between accessible area and maintrails (ID = accessible area index)
    AccessPointAll <- accesspts$AccessPointAll

    AccessMainTrails <- AccessPolygons  %>% st_union() %>%
      st_cast("POLYGON", warn = FALSE) %>%
      st_as_sf() %>% st_join(accesspts$AccessPointAll) %>%
      select(ID)


  }

  #-------------------------------------------


  # Generate Cost raster --> cf CostMatrix
  CostRaster <- raster(extent(DTMExtended),resolution = res(DTMExtended), crs = crs(DTMExtended))
  values(CostRaster) <- CostMatrix[[2]][[1]]$CostValue

  #Generate weight according to slope conditions
  # RastersToPoints

  plotslopePoint <- as_tibble(rasterToPoints(plotslope))

  CostRasterPoint <- as_tibble(rasterToPoints(CostRaster))

  # left join par x et y
  plotTib <-
    left_join(plotslopePoint, CostRasterPoint, by = c('x', 'y'))

  CostSlopeRaster <- plotTib %>%
    mutate(Harvestable = if_else(
      slope <= atan(CostMatrix[[1]][[1]]$Slope/100),
      true = CostMatrix[[1]][[1]]$Cost,
      false = if_else(
        slope <= atan(CostMatrix[[1]][[2]]$Slope/100),
        true = CostMatrix[[1]][[2]]$Cost,
        false = if_else(
          slope <= atan(CostMatrix[[1]][[3]]$Slope/100),
          true = CostMatrix[[1]][[3]]$Cost,
          false = if_else(
            slope <= atan(CostMatrix[[1]][[4]]$Slope/100),
            true = CostMatrix[[1]][[4]]$Cost,
            false = if_else(
              slope <= atan(CostMatrix[[1]][[5]]$Slope/100),
              true = CostMatrix[[1]][[5]]$Cost,
              false = CostMatrix[[1]][[6]]$Cost)
          )
        )
      )
    )) %>% dplyr::select(x,y,Harvestable)

  CostRaster <- rasterFromXYZ(CostSlopeRaster, crs = crs(DTMExtended)) # Update weights from plotTib tibble

  #Aggregation each raster to selected resolution
  CostRasterMean <- aggregate(CostRaster, fact=factagg, fun=mean)

  DTMmean <- aggregate(DTMExtended, fact=factagg, fun=mean)

  plotmaskagg <- rasterToPolygons(DTMmean, dissolve=T) %>%  st_as_sf() %>%  st_union() %>%  as_Spatial()

  #Generate protection buffer for Big Trees (dist : ScndTrailWidth/2 + 2 m)

  BigTreesRaster <- raster(extent(DTMmean),resolution = res(DTMmean), crs = crs(DTMmean))
  values(BigTreesRaster) <- 0
  BigTreesRaster <- rasterize(x = as_Spatial(treeselectionoutputs$BigTreesPoints %>%
                                               st_buffer(dist = advancedloggingparameters$ScndTrailWidth/2 + 2) ),
                              y = BigTreesRaster,
                              field = CostMatrix[[2]][[3]]$CostValue,
                              update = TRUE)
  BigTreesRaster <- crop(BigTreesRaster, CostRasterMean)
  BigTreesRaster <- mask(BigTreesRaster, plotmaskagg)

  #Generate protection buffer for Reserve Trees (dist : ScndTrailWidth/2 + 2 m)

  ReserveRaster <- raster(extent(DTMmean),resolution = res(DTMmean), crs = crs(DTMmean))
  values(ReserveRaster) <- 0
  ReserveRaster <- rasterize(x = as_Spatial(treeselectionoutputs$HarvestableTreesPoints %>%
                                              st_buffer(dist = advancedloggingparameters$ScndTrailWidth/2 + 2) ),
                             y = ReserveRaster,
                             field = CostMatrix[[2]][[4]]$CostValue,
                             update = TRUE)
  ReserveRaster <- crop(ReserveRaster, CostRasterMean)
  ReserveRaster <- mask(ReserveRaster, plotmaskagg)

  #Generate protection buffer for Futures Trees (dist : ScndTrailWidth/2 + 2 m)
  FutureRaster <- raster(extent(DTMmean),resolution = res(DTMmean), crs = crs(DTMmean))
  values(FutureRaster ) <- 0
  FutureRaster  <- rasterize(x = as_Spatial(treeselectionoutputs$HarvestableTreesPoints %>%
                                              st_buffer(dist =  advancedloggingparameters$ScndTrailWidth/2 +2) ),
                             y = FutureRaster  ,
                             field = CostMatrix[[2]][[5]]$CostValue,
                             update = TRUE)
  FutureRaster  <- crop(FutureRaster, CostRasterMean)
  FutureRaster  <- mask(FutureRaster, plotmaskagg)

  #Update Cost Raster with protection buffers

  #Generate protection buffer for selected Trees (dist : ScndTrailWidth/2 + 2 m)
  SelectedRaster <- raster(extent(DTMmean),resolution = res(DTMmean), crs = crs(DTMmean))
  values(SelectedRaster ) <- 0
  SelectedRaster  <- rasterize(x = as_Spatial(treeselectionoutputs$SelectedTreesPoints %>%
                                                st_buffer(dist = 2) ),
                               y = SelectedRaster,
                               field = CostMatrix[[2]][[3]]$CostValue/2,
                               update = TRUE)
  SelectedRaster <- crop(SelectedRaster, CostRasterMean)
  SelectedRaster <- mask(SelectedRaster, plotmaskagg)

  #Update Cost Raster with protection buffers

  CostRasterMean <- CostRasterMean + BigTreesRaster + ReserveRaster + FutureRaster + SelectedRaster



  #Generate maintrail intersection cost raster
  CostRasterMean <- rasterize(x = as_Spatial(AccessPointAll %>% st_buffer(dist = advancedloggingparameters$ScndTrailWidth+2)),
                              y = CostRasterMean ,
                              field = CostMatrix[[2]][[6]]$CostValue,
                              update = TRUE)

  #Generate Slope accessibility for grapple machine
  if (winching == "2") {

    plotslopePointGrpl <- as_tibble(rasterToPoints(plotslope))

    CostRasterPointGrpl <- as_tibble(rasterToPoints(CostRaster))

    # left join par x et y
    plotTibGrpl <-
      left_join(plotslopePointGrpl, CostRasterPointGrpl, by = c('x', 'y'))

    CostSlopeRasterGrpl <- plotTibGrpl %>%
      mutate(Harvestable = if_else(
        slope <= atan(advancedloggingparameters$GrappleMaxslope/100),
        true = 0,
        false = Inf
      )) %>% dplyr::select(x,y,Harvestable)

    CostRasterGrpl <- rasterFromXYZ(CostSlopeRasterGrpl, crs = crs(CostRasterMean))

    PolygonGrpl <- rasterToPolygons(x = CostRasterGrpl,
                                    n = 8,
                                    dissolve = TRUE)

    CostRasterMeanGrpl <- rasterize(x = PolygonGrpl[PolygonGrpl$Harvestable == Inf,],
                                    y = CostRasterMean ,
                                    field = Inf,
                                    update = TRUE)

    CostRasterMeanGrpl <- rasterize(x = as_Spatial(AccessPointAll %>% st_buffer(dist = advancedloggingparameters$ScndTrailWidth+2)),
                                    y = CostRasterMeanGrpl ,
                                    field = CostMatrix[[2]][[6]]$CostValue,
                                    update = TRUE)


    #Generate accessible weights raster
    AccessRaster <- raster(extent(CostRaster),resolution = res(CostRaster), crs = crs(CostRaster))
    values(AccessRaster) <- CostMatrix[[2]][[2]]$CostValue

    AccessRaster <- rasterize(x = as_Spatial(machinepolygons %>% st_buffer(dist = factagg)),
                              y = AccessRaster ,
                              field = 1,
                              update = TRUE)

    AccessRaster <- aggregate(AccessRaster,fact=factagg, fun=min)
    AccessRaster <- crop(AccessRaster,  CostRasterMeanGrpl)
    AccessRaster <- mask(AccessRaster,  plotmaskagg)


    #Update Cost Raster with accessible weights raster

    CostRasterMeanGrpl <- CostRasterMeanGrpl * AccessRaster


  }

  #Generate accessible weights raster
  AccessRaster <- raster(extent(CostRaster),resolution = res(CostRaster), crs = crs(CostRaster))
  values(AccessRaster) <- CostMatrix[[2]][[2]]$CostValue

  AccessRaster <- rasterize(x = as_Spatial(machinepolygons %>% st_buffer(dist = factagg)),
                            y = AccessRaster ,
                            field = 1,
                            update = TRUE)
  AccessRaster <- aggregate(AccessRaster,fact=factagg, fun=min)
  AccessRaster <- crop(AccessRaster,  CostRasterMean)
  AccessRaster <- mask(AccessRaster,plotmaskagg)


  #Update Cost Raster with accessible weights raster

  CostRasterMean <- CostRasterMean * AccessRaster


  pathLines <- list() #Initialize storage pathlines
  Lines <- list() #Initialize storage logged trees
  k <- 1 #Initialize pathlines index
  l <- 1 #Initialize lines index

  #Generate appropriate selected trees points format


  ptsAllinit <- treeselectionoutputs$SelectedTreesPoints %>%
    dplyr::select(idTree) %>%
    st_cast("POINT", warn = FALSE) %>%
    mutate(ID = NA) %>%
    mutate(type = "Tree") %>%
    st_set_crs(st_crs(AccessPointAll)) %>%
    st_join(AccessMainTrails %>% st_buffer(dist =  max((advancedloggingparameters$ScndTrailWidth/2),factagg)) %>%
              mutate(ID_Acc = ID) %>% dplyr::select(-ID)) %>%
    dplyr::select(ID,ID_Acc,type,idTree)

  ptsAllNA <- ptsAllinit %>%
    filter(is.na(ID_Acc)) %>%
    mutate(ID_Acc = AccessMainTrails$ID[c(max.col(-st_distance(ptsAllinit %>%
                                                                 filter(is.na(ID_Acc)),AccessMainTrails)))])

  ptsAllNotNA <- ptsAllinit %>%
    filter(!is.na(ID_Acc))
  ptsAll <- rbind(ptsAllNotNA,ptsAllNA)

  # Reassign Selected Tree values (= BigTrees) to the aggregated Cost raster
  CostRasterMean <- rasterize(x = as_Spatial(ptsAll %>% st_buffer(dist = factagg)),
                              y = CostRasterMean ,
                              field = CostMatrix[[2]][[3]]$CostValue,
                              update = TRUE)
  if (winching == "2") {
    # Reassign Selected Tree values (= BigTrees) to the aggregated Cost raster (Grpl)
    CostRasterMeanGrpl <- rasterize(x = as_Spatial(ptsAll %>%
                                                     st_buffer(dist = factagg)),
                                    y = CostRasterMeanGrpl ,
                                    field = CostMatrix[[2]][[3]]$CostValue,
                                    update = TRUE)

    CostRasterMeanGrpl <- crop(CostRasterMeanGrpl,  CostRasterMean)
    CostRasterMeanGrpl <- mask(CostRasterMeanGrpl,  plotmaskagg)
  }

  #Generate maintrail intersection cost raster
  CostRasterMean <- rasterize(x = as_Spatial(AccessPointAll %>% st_buffer(dist = 3*factagg)),
                              y = CostRasterMean ,
                              field = CostMatrix[[2]][[6]]$CostValue,
                              update = TRUE)

  CostRasterMean <- crop(CostRasterMean,DTMmean)
  CostRasterMean <- mask(CostRasterMean,plotmaskagg)

  DTMmean <- crop(DTMmean,CostRasterMean)
  DTMmean <- mask(DTMmean,plotmaskagg)
  #Compute conductance raster
  CondSurf <- 1/CostRasterMean

  ########### Compute slope criteria transition graph ###############


  if (winching == "2") {
    #Compute adjacent transition layer according to slope conditions (winching = "2")
    SlopeCondGrpl <- sloperdcond(topography = DTMmean,
                                 advancedloggingparameters = advancedloggingparameters,
                                 grapple = TRUE)
  }
  #Compute adjacent transition layer according to slope conditions (winching = "1")
  SlopeCond <- sloperdcond(topography = DTMmean,advancedloggingparameters = advancedloggingparameters)

  ########### Compute LCP algorithm ###############

  for(ID_Access in unique(ptsAll$ID_Acc)) { # ici

    winching <- WinchingInit
    pts <- ptsAll %>%
      filter(ID_Acc == ID_Access) %>% dplyr::mutate(ID = ID_Access) %>%
      dplyr::select(-ID_Acc) %>%
      dplyr::distinct()

    AccessPoint <- AccessPointAll %>%
      filter(ID == ID_Access)

    pathLinesWIP <- c()

    ki <- 1



    if (winching == "0") {
      # winching 0 #########

      #Update Cost Raster with accessible weights raster

      CostRasterMean <- CostRasterMean * AccessRaster
      CondSurf <- 1/CostRasterMean

      pts <- st_set_crs(pts, st_crs(AccessPoint))# set crs

      pts <- rbind(AccessPoint %>%
                     mutate(type = "Access") %>%
                     mutate(IPpts = paste0("A.",row_number())),
                   pts %>%
                     mutate(IPpts = paste0("T.",idTree)))



      PointAcc <- pts %>%
        filter(type == "Access") %>%
        mutate(EstCost = NA)



      #Compute Cost between points and Access points
      CostDistEst <- adjtopolcp(costSurface = CondSurf,
                                topography = DTMmean ,
                                pts = as_Spatial(pts),
                                slopeRdCond = SlopeCond,
                                paths = FALSE) [,1:dim(AccessPoint)[1]]
      CostDistEst <- CostDistEst[(length(PointAcc$ID)+1):length(CostDistEst)[1]]

      CostDistEst <- matrix(CostDistEst,ncol = length(PointAcc$ID) )

      #Attribute a least cost point access to each points
      PointTree <- pts %>% filter(type == "Tree") %>%
        mutate(ptAcc = max.col(-CostDistEst))

      PointTree$ID <- as.factor(PointTree$ptAcc)
      levels(PointTree$ID) <- as.character(AccessPoint$ID)

      pts <- rbind(AccessPoint %>%
                     mutate(type = "Access") %>%
                     mutate(ptAcc = row_number()) %>%
                     mutate(IPpts = paste0("A.",row_number())),
                   PointTree %>%
                     mutate(IPpts = paste0("T.",idTree)))


      PointAcc <- pts %>%
        filter(type == "Access") %>%
        mutate(EstCost = NA)

      #Attribute a least cost point access to each points
      PointTree <- pts %>% filter(type == "Tree") %>%
        mutate(ptAcc = max.col(-CostDistEst))
      if (length(PointAcc$ID) == 1) {
        PointTree <- PointTree %>% mutate(EstCost = CostDistEst)
      }else{PointTree <- PointTree %>% mutate(EstCost = apply(CostDistEst,1, min))}
      selectedPoints <- rbind(PointAcc,PointTree)

      accessPtId <- 1

      TmpSelectedPts <- selectedPoints %>%
        filter(ptAcc == accessPtId)

      TmpAccPts <- TmpSelectedPts %>%
        filter(type == "Access")

      #Select Costliest selected tree
      TmpTreePts <- TmpSelectedPts %>%
        filter(type == "Tree") %>%
        arrange(desc(EstCost))

      if (dim(TmpTreePts)[1] != 0) {
        for (TreeId in 1:dim(TmpTreePts)[1]){

          #Compute Least cost path polygons to the WIP selected tree
          TmpPtsWIP <- rbind(TmpAccPts,TmpTreePts[TreeId,])
          TmpPathWIP <-  adjtopolcp(costSurface = CondSurf,topography = DTMmean , pts = TmpPtsWIP %>% as_Spatial(),
                                    slopeRdCond = SlopeCond,paths = TRUE)
          if (TmpPathWIP[[1]][1,2] == 0) {
            #Update Cost raster with LCP second trail
            CostRasterMean  <- rasterize(x = TmpTreePts[TreeId,] ,
                                         y = CostRasterMean  ,
                                         field = CostMatrix[[2]][[7]]$CostValue,update =  TRUE)
          }else{
            #Update Cost raster with LCP second trail
            CostRasterMean  <- rasterize(x = TmpPathWIP[[2]] ,
                                         y = CostRasterMean  ,
                                         field = CostMatrix[[2]][[7]]$CostValue,update =  TRUE)
          }

          CondSurf <- 1/CostRasterMean

          #Store pathline
          pathLines[[k]] <- TmpPathWIP[[2]]
          pathLines[[k]]@lines[[1]]@ID <- paste("Path", TmpPtsWIP$idTree[2], sep = ".")

          Lines[[k]] <- list("LineID" = k,"LoggedTrees" = TmpPtsWIP$idTree[2],"TypeExpl" = "FoT")

          k <- k +1

        }
      }

    }else{
      # winching 1/2 #########

      # Select intersection points from buffer polygons


      PointAcc <- AccessPoint %>% #def Access Point
        mutate(type = "Access") %>%
        mutate(IDpts = paste0("A.",row_number())) %>%
        mutate(n.overlaps = NA, origins = NA) %>%
        dplyr::select(-ID)

      TreePts <- pts %>% filter(type == "Tree")

      if (winching == "2") {
        ptsGrpl <- TreePts %>% #def Grpl point
          st_buffer(dist = advancedloggingparameters$GrappleLength) %>%
          st_snap_to_grid(size = .2) %>% # avoid GEOS error (st-intersection issue)
          #st_set_precision(1) %>%
          st_temporaryintersection(topography = topography,
                                   plotmask = plotmask,
                                   advancedloggingparameters = advancedloggingparameters) %>%
          st_make_valid() %>%
          mutate(type = "Inter") %>%
          dplyr::select(-ID)


        for (OriginI in 1:length(ptsGrpl$origins)) {
          for (OriginJ in 1:length(ptsGrpl$origins[[OriginI]])) {
            IndexPts <- ptsGrpl$origins[[OriginI]][OriginJ]
            ptsGrpl$origins[[OriginI]][OriginJ] <- TreePts$idTree[IndexPts]
          }
        }

        ptsGrpl$isEmpty <- FALSE


        for (h in 1:dim(ptsGrpl)[1]) {
          if (ptsGrpl[h,] %>% st_intersects(AccessMainTrails %>%
                                            filter(ID == ID_Access),sparse = FALSE) == FALSE) {
            ptsGrpl$isEmpty[h] <- TRUE
          }else{
            suppressWarnings(st_geometry(ptsGrpl[h,]) <- st_geometry(ptsGrpl[h,] %>% st_intersection(AccessMainTrails %>%
                                                                                                       filter(ID == ID_Access))))
          }

        }

        #Filter polygons which intersect accessible area to second trails

        ptsGrpl<- st_set_crs(ptsGrpl,st_crs(AccessPolygons)) # set crs from AccessPolygons

        ptsGrpl <- ptsGrpl %>%
          filter(isEmpty == FALSE) %>%
          dplyr::select(-isEmpty) %>%
          mutate(IDpts = paste0("I.", row_number()))

        ptsWIP <- ptsGrpl %>% #def Grpl point as WIP point
          st_set_agr("constant") %>%
          st_centroid()


        ptsCbl <- TreePts %>% #def cbl polygons
          st_buffer(dist = advancedloggingparameters$CableLength) %>%
          st_snap_to_grid(size = 1) %>%# avoid GEOS error (st-intersection issue)
          st_set_precision(1) %>%
          st_temporaryintersection(topography = topography,
                                   plotmask = plotmask,
                                   advancedloggingparameters = advancedloggingparameters) %>%
          st_make_valid() %>%
          mutate(type = "Inter")%>%
          dplyr::select(-ID)



        for (OriginI in 1:length(ptsCbl$origins)) {
          for (OriginJ in 1:length(ptsCbl$origins[[OriginI]])) {
            IndexPts <- ptsCbl$origins[[OriginI]][OriginJ]
            ptsCbl$origins[[OriginI]][OriginJ] <- TreePts$idTree[IndexPts]
          }
        }


        ptsCbl$isEmpty <- FALSE


        for (h in 1:dim(ptsCbl)[1]) {
          if (ptsCbl[h,] %>% st_intersects(AccessMainTrails %>%
                                           filter(ID == ID_Access),sparse = FALSE) == FALSE) {
            ptsCbl$isEmpty[h] <- TRUE
          }else{
            suppressWarnings(st_geometry(ptsCbl[h,]) <- st_geometry(ptsCbl[h,] %>%
                                                                      st_intersection(AccessMainTrails %>%
                                                                                        filter(ID == ID_Access))))
          }

        }


        ptsCbl <- st_set_crs(ptsCbl,st_crs(AccessPolygons)) #set crs from AccessPolygons

        ptsCbl <- ptsCbl %>% filter(isEmpty == FALSE) %>% dplyr::select(-isEmpty) %>%
          mutate(IDpts = paste0("I.",row_number())) #Filter polygons which intersect accessible area to second trails



        ptsWIPCbl <- ptsCbl %>%#Convert polygons to centroid
          st_set_agr("constant") %>%
          st_centroid()


        ptsWIP <- ptsWIP %>%
          arrange(desc(n.overlaps))

        RemainTree <- max(length(unique(unlist(ptsWIP$origins))),length(unique(unlist(ptsWIPCbl$origins))))


        #Select adjacent grpl graph
        SlopeCondRd <- SlopeCondGrpl

      }else{


        ptsCbl <- TreePts %>% #def cbl point
          st_buffer(dist = advancedloggingparameters$CableLength) %>%
          st_snap_to_grid(size = 1) %>% # avoid GEOS error (st-intersection issue)
          st_set_precision(1) %>%
          st_temporaryintersection(topography = topography,
                                   plotmask = plotmask,
                                   advancedloggingparameters = advancedloggingparameters) %>%
          st_make_valid() %>%
          mutate(IDpts = paste0("I.",row_number())) %>%
          mutate(type =  "Inter") %>% dplyr::select(-ID)


        ptsCbl <- st_set_crs(ptsCbl,st_crs(AccessPolygons)) #set crs from AccessPolygons

        for (OriginI in 1:length(ptsCbl$origins)) {
          for (OriginJ in 1:length(ptsCbl$origins[[OriginI]])) {
            IndexPts <- ptsCbl$origins[[OriginI]][OriginJ]
            ptsCbl$origins[[OriginI]][OriginJ] <- TreePts$idTree[IndexPts]
          }
        }

        ptsCbl$isEmpty <- FALSE


        for (h in 1:dim(ptsCbl)[1]) {
          if (st_geometry(ptsCbl[h,]) %>% st_intersects(AccessMainTrails %>%
                                                        filter(ID == ID_Access),sparse = FALSE) == FALSE) {
            ptsCbl$isEmpty[h] <- TRUE
          }else{
            suppressWarnings(st_geometry(ptsCbl[h,]) <- st_geometry(ptsCbl[h,] %>%
                                                                      st_intersection(AccessMainTrails %>%
                                                                                        filter(ID == ID_Access))))
            ptsCbl$isEmpty[h] <- FALSE
          }
        }


        ptsWIP <-  ptsCbl %>% filter(isEmpty == FALSE) %>%
          dplyr::select(-isEmpty) %>% #def cbl point as WIP point
          st_set_agr("constant") %>%
          st_centroid()

        ptsWIP <- ptsWIP %>%  #filter cbl intersection centroid point out plot
          filter(st_intersects(st_geometry(ptsWIP),
                               st_geometry(plotmask %>% st_as_sf()),
                               sparse = FALSE)) %>%
          arrange(desc(n.overlaps))

        RemainTree <- length(unique(ptsWIP$idTree))

        #Select adjacent cbl graph
        SlopeCondRd <- SlopeCond

      }


      #Define a switch from grapple accessible tree exploitation to cable exploitation

      if (winching == "2") {
        WinchingSwitch <- FALSE
      }else{
        WinchingSwitch <- TRUE
      }



      steps <- 0

      RemainTreeInit <- RemainTree


      #Loop over possible intersection
      while (RemainTree !=0L &  steps < 5*RemainTreeInit) {

        steps <- steps +1


        if (verbose) {
          print(RemainTree)
        }


        #Switch from grpl to cbl exploitation when grapple accessible tree != 0
        Grpl2CblFlag <- FALSE

        if (length(unique(unlist(ptsWIP$origins))) == 0 & WinchingSwitch == FALSE & winching == "2") {
          winching <- "1"
          ptsWIP <- ptsWIPCbl
          WinchingSwitch <- TRUE
        }



        ptsWIPmax <- rbind(PointAcc,ptsWIP %>%
                             filter(st_intersects(.,st_geometry(plotmask %>%
                                                                  st_as_sf()),sparse = FALSE)) %>%
                             filter(n.overlaps == max(ptsWIP$n.overlaps))) %>%
          mutate(TypeAcc = NA) %>%
          mutate(EstCost = NA)  %>%
          mutate(ptsAcc = NA)


        ptsTreeWIP <-  rbind(PointAcc,TreePts %>%
                               mutate(n.overlaps = NA, origins = idTree,IDpts = NA) %>%
                               dplyr::select(-ID)) %>%
          mutate(TypeAcc = NA) %>%
          mutate(EstCost = NA)  %>%
          mutate(ptsAcc = NA)

        if (ki == 1 ) {
          if (winching == "2") {
            ptsDirAcc <- ptsTreeWIP %>%
              mutate(gprlAcc  = c(FALSE,as.numeric(st_distance(ptsTreeWIP)[2:dim(ptsTreeWIP)[1],1]) < advancedloggingparameters$GrappleLength)) %>%
              filter(gprlAcc == TRUE | type == "Access") %>%
              dplyr::select(-gprlAcc)
            TmpTypeAcc <- "Grpl"

          }else{
            ptsDirAcc <- ptsTreeWIP %>%
              mutate(cblAcc  = c(FALSE,as.numeric(st_distance(ptsTreeWIP)[2:dim(ptsTreeWIP)[1],1]) < advancedloggingparameters$CableLength)) %>%
              filter(cblAcc == TRUE | type == "Access") %>%
              dplyr::select(-cblAcc)
            TmpTypeAcc <- "Cbl"
          }
        }else{

          # Set pathsWIP CRS
          pathsWIP <- st_set_crs(pathsWIP, st_crs(PointAcc))

          if (winching == "2") {

            ptsDirAcc <- ptsTreeWIP %>%
              mutate(gprlAcc  = c(FALSE,as.numeric(st_distance(ptsTreeWIP,st_union(pathsWIP %>%
                                                                                     st_buffer(dist = advancedloggingparameters$MaxMainTrailWidth/2) %>%
                                                                                     st_make_valid() %>%
                                                                                     st_union(),PointAcc %>%
                                                                                     st_buffer(dist = advancedloggingparameters$MaxMainTrailWidth/2) %>%
                                                                                     st_make_valid() %>%
                                                                                     st_union()))[2:dim(ptsTreeWIP)[1],1]) < advancedloggingparameters$GrappleLength)) %>%
              filter(gprlAcc == TRUE | type == "Access") %>%
              dplyr::select(-gprlAcc)

            TmpTypeAcc <- "Grpl"

          }else{
            ptsDirAcc <- ptsTreeWIP %>%  mutate(cblAcc  = c(FALSE,as.numeric(st_distance(ptsTreeWIP,st_union(pathsWIP %>% st_buffer(dist = advancedloggingparameters$MaxMainTrailWidth/2)  %>% st_make_valid() %>%
                                                                                                               st_union(),PointAcc %>% st_buffer(dist = advancedloggingparameters$MaxMainTrailWidth/2)  %>% st_make_valid() %>%
                                                                                                               st_union()))[2:dim(ptsTreeWIP)[1],1]) < advancedloggingparameters$CableLength)) %>%
              filter(cblAcc == TRUE | type == "Access") %>% dplyr::select(-cblAcc)

            TmpTypeAcc <- "Cbl"
          }
        }



        if (dim(ptsDirAcc)[1] > 1) {

          PointTreeWIP <- ptsDirAcc %>% filter(type == "Tree")

          if (verbose){
            print(paste0("LoggedTrees : ",PointTreeWIP$origins[[1]]))
          }

          Lines[[l]] <- list("LineID" = NA,"LoggedTrees" = PointTreeWIP$origins, "TypeExpl" = TmpTypeAcc,"IdMachineZone" = ID_Access)


          l <- l+1

        }else{



          #Compute Cost between points and Access points in cbl exploitation
          CostDistEstCbl <- adjtopolcp(costSurface = CondSurf,
                                       topography = DTMmean ,
                                       pts = ptsWIPmax %>%
                                         as_Spatial(),
                                       slopeRdCond = SlopeCond,
                                       paths = FALSE) [,1]

          CostDistEstCbl <- CostDistEstCbl[(length(PointAcc$ID)+1):length(CostDistEstCbl)[1]]

          CostDistEstCbl <- matrix(CostDistEstCbl,ncol = length(PointAcc$ID) )

          #Attribute a least cost point access to each points
          PointTree <- ptsWIPmax %>% filter(type != "Access" ) %>%
            mutate(ptAccCbl = max.col(- CostDistEstCbl,ties.method = "first")) %>%
            mutate(EstCostCbl = CostDistEstCbl)


          if (winching == "2") {

            CondSurfGrpl <- 1/CostRasterMeanGrpl

            #Compute Cost between points and Access points in grpl exploitation
            CostDistEstGrpl <- adjtopolcp(costSurface = CondSurfGrpl,
                                          topography = DTMmean ,
                                          pts = ptsWIPmax %>%
                                            as_Spatial(),
                                          slopeRdCond = SlopeCondGrpl,
                                          paths = FALSE) [,1:length(PointAcc$ID)]

            CostDistEstGrpl <- CostDistEstGrpl[(length(PointAcc$ID)+1):length(CostDistEstGrpl)[1]]
            CostDistEstGrpl <- matrix(CostDistEstGrpl,ncol = length(PointAcc$ID) )


            #Attribute a least cost point access to each points
            PointTree <- PointTree %>%
              mutate(ptAccGpl = max.col(-matrix(CostDistEstGrpl,ncol = length(PointAcc$ID) ),ties.method = "first")) %>%
              mutate(EstCostGrpl = CostDistEstGrpl)

            #Prioritize grpl exploitation if possible
            CostDistEstGrpl[CostDistEstGrpl != Inf] <- 0
            CostDistEstGrpl[CostDistEstGrpl == Inf] <- 1

            for (j in 1:length(CostDistEstGrpl)) {
              PointTree[j,"TypeAcc"] <-  as.character(prod(CostDistEstGrpl[j,]))
            }
            PointTree$TypeAcc[PointTree$TypeAcc == "0"] <- "Grpl"
            PointTree$TypeAcc[PointTree$TypeAcc == "1"] <- "Cbl"

            PointTree$ptsAcc[PointTree$TypeAcc == "Grpl"] <- PointTree$ptAccGpl[PointTree$TypeAcc == "Grpl"]
            PointTree$ptsAcc[PointTree$TypeAcc != "Grpl"] <- PointTree$ptAccCbl[PointTree$TypeAcc != "Grpl"]

            PointTree$EstCost[PointTree$TypeAcc == "Grpl"] <- PointTree$EstCostGrpl[PointTree$TypeAcc == "Grpl"]
            PointTree$EstCost[PointTree$TypeAcc != "Grpl"] <- PointTree$EstCostCbl[PointTree$TypeAcc != "Grpl"]


            PointTree <- PointTree %>% arrange(desc(TypeAcc),EstCost)




            #Define WIP point according to possible exploitation type
            if (PointTree$TypeAcc[1] == "Grpl") {
              #Reconstruct access points + selected tree in grpl exploitation
              TmpPtsWIP <- ptsGrpl %>%
                filter(IDpts == PointTree$IDpts[1])  %>%
                st_union() %>%
                st_cast("POINT", warn = FALSE) %>%
                st_as_sf() %>%
                mutate(type = "Overlay") %>%
                mutate(ptsAcc = PointTree$ptsAcc[1]) %>%
                mutate(IDpts = PointTree$IDpts[1]) %>%
                mutate(origins = PointTree$origins[1])%>%
                mutate(n.overlaps = PointTree$n.overlaps[1])

              TmpTypeAcc <- "Grpl"

              #Select adjacent grpl graph
              SlopeCondRd <- SlopeCondGrpl

            }else{
              #if the selected point is not a grpl accessible point BUT not all grpl accessible point are done

              #Shift to cbl exploitation
              Grpl2CblFlag <- TRUE


              #Reconstruct access points + selected tree in cbl exploitation
              TmpPtsWIP <- ptsCbl %>%
                filter(IDpts == PointTree$IDpts[1])  %>%
                st_union() %>%
                st_cast("POINT", warn = FALSE) %>%
                st_as_sf() %>%
                mutate(type = "Overlay") %>%
                mutate(ptsAcc = PointTree$ptsAcc[1]) %>%
                mutate(IDpts = PointTree$IDpts[1]) %>%
                mutate(origins = PointTree$origins[1])%>%
                mutate(n.overlaps = PointTree$n.overlaps[1])

              #Select adjacent cbl graph
              SlopeCondRd <- SlopeCond

              TmpTypeAcc <- "Cbl"
            }

          }else{

            #Reconstruct access points + selected tree in cbl exploitation
            TmpPtsWIP <- ptsCbl %>%
              filter(IDpts == PointTree$IDpts[1])  %>%
              st_union() %>%
              st_cast("POINT", warn = FALSE) %>%
              st_as_sf() %>%
              mutate(type = "Overlay") %>%
              mutate(ptsAcc = PointTree$ptsAcc[1]) %>%
              mutate(IDpts = PointTree$IDpts[1]) %>%
              mutate(origins = PointTree$origins[1]) %>%
              mutate(n.overlaps = PointTree$n.overlaps[1])



            #Select adjacent cbl graph
            SlopeCondRd <- SlopeCond

            TmpTypeAcc <- "Cbl"

          }

          #filter WIP points in accessible scd trail area
          # TmpPtsWIP <- st_set_crs(TmpPtsWIP,st_crs(ptsCbl)) # set crs from ptsCbl

          TmpPtsWIP <- TmpPtsWIP %>%
            filter(st_intersects(
              st_geometry(TmpPtsWIP),st_geometry(AccessPolygons %>%
                                                   st_union()),sparse = FALSE))


          #Reconstruct access points + selected points
          TmpPtsWIP <- rbind( PointAcc %>%
                                st_union() %>%
                                st_cast("POINT", warn = FALSE)%>%
                                st_as_sf() %>%
                                mutate(type = "Access") %>%
                                mutate(ptsAcc = NA ) %>%
                                mutate(IDpts = NA) %>%
                                mutate(origins = NA)%>%
                                mutate(n.overlaps = NA),TmpPtsWIP)


          #Compute Cost between all points and Access points

          CostDistEstWIP <-  adjtopolcp(costSurface = CondSurf,topography = DTMmean , pts = TmpPtsWIP %>% as_Spatial(),
                                        slopeRdCond = SlopeCondRd,paths = FALSE)[,1]


          CostDistEstWIP <- CostDistEstWIP[(length(PointAcc$ID)+1):length(CostDistEstWIP)[1]]

          CostDistEstWIP <- matrix(CostDistEstWIP, ncol = length(PointAcc$ID))

          PointTreeWIP <- TmpPtsWIP %>%
            filter(type == "Overlay") %>%
            mutate(EstCost = CostDistEstWIP) %>%
            arrange(EstCost)




          TmpPtsWIP <- rbind(TmpPtsWIP %>% filter(type == "Access") %>%
                               mutate(EstCost = NA),PointTreeWIP[1,])

          TmpPathWIP <- adjtopolcp(costSurface = CondSurf,topography = DTMmean , pts = TmpPtsWIP %>% as_Spatial(),
                                   slopeRdCond = SlopeCondRd,paths = FALSE)

          TmpPathWIPCost <- TmpPathWIP[1:length(PointAcc$ID),length(PointAcc$ID)+1]

          LCPathWIP <- max.col(t(-TmpPathWIPCost))

          TmpPtsWIP <- rbind(TmpPtsWIP[LCPathWIP,],PointTreeWIP[1,])

          TmpPathWIP <- adjtopolcp(costSurface = CondSurf,topography = DTMmean , pts = TmpPtsWIP %>% as_Spatial(),
                                   slopeRdCond = SlopeCondRd,paths = TRUE)

          if (TmpPathWIP[[1]][2,1] != 0) {

            if (TmpTypeAcc == "Grpl") {
              CostRasterMean  <- rasterize(x = TmpPathWIP[[2]] ,
                                           y = CostRasterMean  ,
                                           field = CostMatrix[[2]][[7]]$CostValue,update =  TRUE)
              CostRasterMeanGrpl  <- rasterize(x = TmpPathWIP[[2]] ,
                                               y = CostRasterMeanGrpl  ,
                                               field = CostMatrix[[2]][[7]]$CostValue,update =  TRUE)
            }else{
              CostRasterMean  <- rasterize(x = TmpPathWIP[[2]] ,
                                           y = CostRasterMean  ,
                                           field = CostMatrix[[2]][[7]]$CostValue,update =  TRUE)
            }

          }

          pathLines[[k]] <- TmpPathWIP[[2]]
          pathLines[[k]]@lines[[1]]@ID <- paste("Path",
                                                "A",
                                                LCPathWIP,
                                                "NTree",
                                                length(PointTreeWIP$origins[[1]]),
                                                "T",
                                                paste(as.character(unlist(PointTreeWIP$origins[[1]])),
                                                      collapse='-'),
                                                sep = ".")

          Lines[[l]] <- list("LineID" = k,"LoggedTrees" = PointTreeWIP$origins[[1]], "TypeExpl" = TmpTypeAcc,"IdMachineZone" = ID_Access)

          k <- k +1
          l <- l+1



          pathLinesWIP[[ki]] <- TmpPathWIP[[2]]

          pathLinesWIP[[ki]]@lines[[1]]@ID <- paste("Path",
                                                    "A",
                                                    LCPathWIP,
                                                    "NTree",
                                                    length(PointTreeWIP$origins[[1]]),
                                                    "T",
                                                    paste(as.character(unlist(PointTreeWIP$origins[[1]])),
                                                          collapse='-'),
                                                    sep = ".")

          ki <- ki +1

          pathsWIP <- do.call(rbind, pathLinesWIP)


          pathsWIP <- pathsWIP %>% st_as_sf() %>% st_make_valid() %>%
            filter(!st_is_empty(pathsWIP %>%
                                  st_as_sf())) %>%
            filter(st_geometry_type(.) %in% c("LINESTRING"))


          if(dim(pathsWIP)[1]>0){

            pathsWIP <- pathsWIP$geometry %>% as_Spatial()

            if ( length(pathsWIP)==1) {

              pathsWIP <- pathsWIP %>% st_as_sf() %>%
                st_buffer(dist = advancedloggingparameters$ScndTrailWidth/2)  %>% st_make_valid() %>%
                st_union()

            }else{

              pathsWIP <-  smoothtrails(paths = pathsWIP ,
                                        plotmask = plotmask,
                                        verbose = FALSE,
                                        advancedloggingparameters = advancedloggingparameters)$SmoothedTrails %>%
                st_union()
            }



          }else{

            pathsWIP <- pathsWIP %>% st_union()
          }



        }


        TreePts$Logged<- FALSE



        for (j in 1:dim(TreePts)[1]) {
          TreePts$Logged[j] <- any(PointTreeWIP$origins[[1]] %in% TreePts$idTree[j])
        }


        TreePts <- TreePts %>%
          filter(Logged == FALSE) %>%
          dplyr::select(-Logged)

        if (dim(TreePts)[1]> 0) {



          if (winching == "2") {
            ptsGrpl <- TreePts %>% #def Grpl point
              st_buffer(dist = advancedloggingparameters$GrappleLength) %>%
              st_snap_to_grid(size = .2) %>% # avoid GEOS error (st-intersection issue)
              #st_set_precision(1) %>%
              st_temporaryintersection(topography = topography,
                                       plotmask = plotmask,
                                       advancedloggingparameters = advancedloggingparameters) %>%
              st_make_valid() %>%
              mutate(type = "Inter") %>%
              dplyr::select(-ID)


            for (OriginI in 1:length(ptsGrpl$origins)) {
              for (OriginJ in 1:length(ptsGrpl$origins[[OriginI]])) {
                IndexPts <- ptsGrpl$origins[[OriginI]][OriginJ]
                ptsGrpl$origins[[OriginI]][OriginJ] <- TreePts$idTree[IndexPts]
              }
            }

            ptsGrpl$isEmpty <- FALSE


            for (h in 1:dim(ptsGrpl)[1]) {
              if (ptsGrpl[h,] %>%
                  st_intersects(AccessMainTrails %>%
                                filter(ID == ID_Access),sparse = FALSE) == FALSE) {
                ptsGrpl$isEmpty[h] <- TRUE
              }else{
                suppressWarnings(st_geometry(ptsGrpl[h,]) <- st_geometry(ptsGrpl[h,] %>%
                                                                           st_intersection(AccessMainTrails %>%
                                                                                             filter(ID == ID_Access))))
              }

            }

            #Filter polygons which intersect accessible area to second trails

            ptsGrpl<- st_set_crs(ptsGrpl,st_crs(AccessPolygons)) # set crs from AccessPolygons

            ptsGrpl <- ptsGrpl %>%
              filter(isEmpty == FALSE) %>%
              dplyr::select(-isEmpty) %>%
              mutate(IDpts = paste0("I.", row_number()))

            ptsWIP <- ptsGrpl %>% #def Grpl point as WIP point
              st_set_agr("constant") %>%
              st_centroid()


            ptsCbl <- TreePts %>% #def cbl polygons
              st_buffer(dist = advancedloggingparameters$CableLength) %>%
              st_snap_to_grid(size = 1) %>%# avoid GEOS error (st-intersection issue)
              st_set_precision(1) %>%
              st_temporaryintersection(topography = topography,
                                       plotmask = plotmask,
                                       advancedloggingparameters = advancedloggingparameters) %>%
              st_make_valid() %>%
              mutate(type = "Inter")%>%
              dplyr::select(-ID)



            for (OriginI in 1:length(ptsCbl$origins)) {
              for (OriginJ in 1:length(ptsCbl$origins[[OriginI]])) {
                IndexPts <- ptsCbl$origins[[OriginI]][OriginJ]
                ptsCbl$origins[[OriginI]][OriginJ] <- TreePts$idTree[IndexPts]
              }
            }


            ptsCbl$isEmpty <- FALSE



            for (h in 1:dim(ptsCbl)[1]) {
              if (ptsCbl[h,] %>%
                  st_intersects(st_geometry(AccessMainTrails %>%
                                            filter(ID == ID_Access) %>%
                                            st_union()),sparse = FALSE) == FALSE) {
                ptsCbl$isEmpty[h] <- TRUE
              }else{
                suppressWarnings(st_geometry(ptsCbl[h,]) <- st_geometry(ptsCbl[h,] %>%
                                                                          st_intersection(st_geometry(AccessMainTrails %>%
                                                                                                        filter(ID == ID_Access)))))
              }

            }


            ptsCbl <- st_set_crs(ptsCbl,st_crs(AccessPolygons)) #set crs from AccessPolygons

            ptsCbl <- ptsCbl %>%
              filter(isEmpty == FALSE) %>%
              dplyr::select(-isEmpty) %>%
              mutate(IDpts = paste0("I.",row_number())) #Filter polygons which intersect accessible area to second trails



            ptsWIPCbl <- ptsCbl %>%#Convert polygons to centroid
              st_set_agr("constant") %>%
              st_centroid()


            ptsWIP <- ptsWIP %>%
              arrange(desc(n.overlaps))

            #Select adjacent grpl graph
            SlopeCondRd <- SlopeCondGrpl

          }else{


            ptsCbl <- TreePts %>% #def cbl point
              st_buffer(dist = advancedloggingparameters$CableLength) %>%
              st_snap_to_grid(size = 1) %>% # avoid GEOS error (st-intersection issue)
              st_set_precision(1) %>%
              st_temporaryintersection(topography = topography,
                                       plotmask = plotmask,
                                       advancedloggingparameters = advancedloggingparameters) %>%
              st_make_valid() %>%
              mutate(IDpts = paste0("I.",row_number())) %>%
              mutate(type =  "Inter") %>% dplyr::select(-ID)


            ptsCbl <- st_set_crs(ptsCbl,st_crs(AccessPolygons)) #set crs from AccessPolygons

            for (OriginI in 1:length(ptsCbl$origins)) {
              for (OriginJ in 1:length(ptsCbl$origins[[OriginI]])) {
                IndexPts <- ptsCbl$origins[[OriginI]][OriginJ]
                ptsCbl$origins[[OriginI]][OriginJ] <- TreePts$idTree[IndexPts]
              }
            }

            ptsCbl$isEmpty <- FALSE


            for (h in 1:dim(ptsCbl)[1]) {
              if (ptsCbl[h,] %>%
                  st_intersects(AccessMainTrails %>%
                                filter(ID == ID_Access),sparse = FALSE) == FALSE) {
                ptsCbl$isEmpty[h] <- TRUE
              }else{
                suppressWarnings(st_geometry(ptsCbl[h,]) <- st_geometry(ptsCbl[h,] %>%
                                                                          st_intersection(AccessMainTrails %>%
                                                                                            filter(ID == ID_Access))))
              }

            }



            ptsWIP <-  ptsCbl %>%
              filter(isEmpty == FALSE) %>%
              dplyr::select(-isEmpty) %>%#def cbl point as WIP point
              st_set_agr("constant") %>%
              st_centroid()

            ptsWIP <- ptsWIP %>%  #filter cbl intersection centroid point out plot
              filter(st_intersects(st_geometry(ptsWIP),
                                   st_geometry(plotmask %>% st_as_sf()),
                                   sparse = FALSE)) %>%
              arrange(desc(n.overlaps))



            #Select adjacent cbl graph
            SlopeCondRd <- SlopeCond

          }

        }

        RemainTree <- dim(TreePts)[1]

      }


      if (RemainTree > 0L){
        stop("Failed to compute 2nd trails")
      }
    }


  }




  MainTrailsAccess <- AccessPointAll %>%
    st_set_crs(st_crs(topography))

  inventory <- treeselectionoutputs$inventory

  # initial inventory
  inventory0 <- inventory

  lines <- do.call(rbind, Lines)

  # WinchingMachine info in the inventory
  TrailsIdentity_df <- as.data.frame(lines) %>%
    unnest(cols = c(LineID, LoggedTrees, TypeExpl, IdMachineZone)) #  unnesting flattens it back out into regular columns


  TrailsIdentity_df <- TrailsIdentity_df %>%
    dplyr::select(LoggedTrees, TypeExpl, IdMachineZone) %>%
    rename(idTree = LoggedTrees) %>%
    rename(WinchingMachine = TypeExpl) %>%
    unique()

  if(any(duplicated(TrailsIdentity_df$idTree))) # trees logged several times?
    stop("Error: duplicated tree in logged trees")


  inventory <- inventory %>%
    left_join(TrailsIdentity_df, by = "idTree")


  paths <- do.call(rbind, pathLines)
  paths <- paths %>% st_as_sf() %>% st_make_valid() %>%
    filter(!st_is_empty(paths %>% st_as_sf())) %>%
    filter(st_geometry_type(.) %in% c("LINESTRING"))

  if (dim(paths)[1]>0) {

    paths <- paths$geometry %>%  as_Spatial()

    if ( length(paths)==1) {

      SmoothedTrails <- paths %>% st_as_sf() %>%
        st_buffer(dist = advancedloggingparameters$ScndTrailWidth/2)  %>% st_make_valid() %>%
        st_union()%>% st_set_crs(st_crs(topography))

      TrailsDensity <- (SmoothedTrails  %>%
                          st_intersection(plotmask %>% st_as_sf()) %>%
                          st_area / advancedloggingparameters$ScndTrailWidth)/(plotmask %>% st_as_sf() %>% st_area() /10000)
    }else{
      secondtrails <- smoothtrails(paths,
                                   plotmask,
                                   verbose = verbose,
                                   advancedloggingparameters = advancedloggingparameters)

      SmoothedTrails <- secondtrails$SmoothedTrails %>% st_set_crs(st_crs(topography))

      TrailsDensity <- secondtrails$TrailsDensity
    }
    #
    #
    # # Records the dead trees

    if(fuel == "0"){

      if (!("DeathCause" %in% names(inventory))){
        inventory <- inventory %>%
          add_column(DeathCause = NA) # if "DeathCause" column doesnt exist create it
      }

      DeadTrees <- suppressWarnings(st_intersection(
        st_make_valid(st_set_crs(st_as_sf(inventory, coords = c("Xutm", "Yutm")), st_crs(topography))),
        st_make_valid(st_as_sf(SmoothedTrails) %>% st_union()) # "make valid" to avoid self-intersection
      )) %>%
        add_column(DeadTrees = "1") %>%
        dplyr::select(idTree, DeadTrees) %>% st_drop_geometry() # remove geometry column (sf to data.frame)
      DeadTrees <- unique(DeadTrees)

      inventory <- inventory %>%
        left_join(DeadTrees, by = "idTree") %>%
        mutate(DeathCause = ifelse(is.na(DeathCause) & Selected != "1" & DeadTrees == "1",
                                   "2ndtrail", DeathCause)) %>%  # Damage trees
        dplyr::select(-DeadTrees)

    }

  }else{
    paths <- NULL
    SmoothedTrails <- MainTrailsAccess %>% st_union() %>%
      st_buffer(dist = advancedloggingparameters$MaxMainTrailWidth/2) %>% st_set_crs(st_crs(topography))
    TrailsDensity <- 0

    if(fuel == "0"){

      if (!("DeathCause" %in% names(inventory))){
        inventory <- inventory %>%
          add_column(DeathCause = NA) # if "DeathCause" column doesnt exist create it
      }

      DeadTrees <- suppressWarnings(sf::st_intersection(
        sf::st_make_valid(st_set_crs(st_as_sf(inventory, coords = c("Xutm", "Yutm")), st_crs(topography))),
        sf::st_make_valid(st_as_sf(SmoothedTrails) %>% st_union()) # "make valid" to avoid self-intersection
      )) %>%
        add_column(DeadTrees = "1") %>%
        dplyr::select(idTree, DeadTrees) %>% st_drop_geometry()
      DeadTrees <- unique(DeadTrees)

      inventory <- inventory %>%
        left_join(DeadTrees, by = "idTree") %>%
        mutate(DeathCause = ifelse(is.na(DeathCause) & Selected != "1" & DeadTrees == "1",
                                   "2ndtrail", DeathCause)) %>%  # Damage trees
        dplyr::select(-DeadTrees)
    }
  }

  if(nrow(inventory) != nrow(inventory0))
    stop("The number of rows between the input inventory and the output inventory
         of the function secondtrailsopening() is not the same.The function must be corrected.")

  # OUTPUTS

  if (WinchingInit == "2") {
    secondtrails <- list("inventory" =  inventory,
                         "SmoothedTrails" =  SmoothedTrails,
                         "TrailsDensity" =  TrailsDensity,
                         "TrailsIdentity" = lines,        # "LineID","LoggedTrees", "TypeExpl"
                         "MainTrailsAccess" = MainTrailsAccess,
                         "RawSecondTrails" = paths,
                         "CostRasterAgg" = list("CostRasterMean" = CostRasterMean,"CostRasterMeanGrpl" = CostRasterMeanGrpl))
  }else{
    secondtrails <- list("inventory" =  inventory,
                         "SmoothedTrails" =  SmoothedTrails,
                         "TrailsDensity" =  TrailsDensity,
                         "TrailsIdentity" = lines,        # "LineID","LoggedTrees", "TypeExpl"
                         "MainTrailsAccess" = MainTrailsAccess,
                         "RawSecondTrails" = paths,
                         "CostRasterAgg" = list("CostRasterMean" = CostRasterMean,"CostRasterMeanGrpl" = NULL))
  }



  return(secondtrails)

}
VincyaneBadouard/LoggingLab documentation built on Oct. 16, 2024, 9:42 p.m.