1

Using lidR 3.1.3, I made a user-defined function for catalog_apply() to process a LAScatalog following this, but a it raises the following error :

 Erreur : pas de méthode pour 'filter_poly' applicable pour un objet de classe "c('LAScluster', 'Spatial')"

Here's the working code. Error appears when plan(multisession) is inserted.

library(lidR)
library(future)
library(sf)

filter_poly = function(las, ...)
{
  UseMethod("filter_poly", las)
}

filter_poly.LAS = function(las, polygons_shp, buffer, outClass)
{
  poly_buff = st_buffer(st_read(polygons_shp, quiet = TRUE), dist = buffer, endCapStyle = 'SQUARE', joinStyle = 'MITRE', mitreLimit = 3)
  las <- merge_spatial(las, poly_buff, "inpoly")
  las <- filter_poi(las, inpoly == FALSE)
  return(las)
}

filter_poly.LAScluster = function(las, polygons_shp, buffer, outClass)
{
  # The function is automatically fed with LAScluster objects
  # Here the input 'las' will a LAScluster
  
  las <- readLAS(las)                          # Read the LAScluster
  if (is.empty(las))
    return(NULL)              # Exit early (see documentation)
  
  las <- filter_poly(las, polygons_shp, buffer, outClass)      # Filter shp
  las <- filter_poi(las, buffer == 0)           # Don't forget to remove the buffer
  
  return(las)                                  # Return the filtered point cloud
}

filter_poly.LAScatalog  = function(las, polygons_shp, buffer, outClass)
{
  opt_select(las) <-  "*"         # Do not respect the select argument by overwriting it
  
  options <- list(
    need_output_file = TRUE,    # Throw an error if no output template is provided
    need_buffer = FALSE,         # Throw an error if buffer is 0
    automerge = TRUE)           # Automatically merge the output list (here into a LAScatalog)
  
  output <- catalog_apply(las, filter_poly, polygons_shp, buffer, outClass)
  return(output)
}

poly_file = "Z:/TRASH/polygons.shp"
buffer = 10
polyClass = 24

ctg <- readLAScatalog("Z:/TRASH/")
plot(ctg)
opt_output_files(ctg) <- paste0("Z:/TRASH/{ORIGINALFILENAME}_filtered")
opt_laz_compression(ctg) <- TRUE

output <- filter_poly(ctg, polygons_shp = poly_file, buffer = buffer, outClass = polyClass)

1 Answer 1

0

The problem is that in parallel we need to export every needed objects to each worker. This is done automatically except in some cases where the internal method used to detect what is needed misses some objects. This is the case with generics methods. The solution was used to be easy

plan(multissssion, globals = objects_needed)

but this not longer works because it seems that future has a new behaviour that forbids to do that (I just discovered it). Thus the easiest solution I can see is to explicitly call each method so the internal functions detect better the objects that are needed

# in filter_poly.LAScluster
las <- filter_poly.LAS(las, polygons_shp, buffer, outClass)

# in filter_poly.LAScatalog
output <- catalog_apply(las, filter_poly.LAScluster, polygons_shp, buffer, outClass)

For the sake of completeness and for future readers we can also use an internal dispatch to get rid of the issue.

filter_poly = function(las, polygons_shp, buffer, outClass)
{
  if (is(las, "LAS"))  {
    poly_buff = st_buffer(st_read(polygons_shp, quiet = TRUE), dist = buffer, endCapStyle = 'SQUARE', joinStyle = 'MITRE', mitreLimit = 3)
    las <- merge_spatial(las, poly_buff, "inpoly")
    las <- filter_poi(las, inpoly == FALSE)
    return(las)
  }
  
  if (is(las, "LAScluster")) {
    las <- readLAS(las)
    if (is.empty(las)) return(NULL) 
    las <- filter_poly(las, polygons_shp, buffer, outClass)
    #las <- filter_poi(las, buffer == 0)
    return(las)    
  }
  
  if (is(las, "LAScatalog")) {
    opt_select(las) <-  "*"
    opt_buffer(las) <- 0
    options <- list(
      need_output_file = TRUE,
      need_buffer = FALSE,
      automerge = TRUE)
    output <- catalog_apply(las, filter_poly, polygons_shp, buffer, outClass, .options = options)
    return(output)
  }
  
  stop("Invalid input")
}

Considering it is no longer possible to export manually missing objects (as far as I know) I guess this syntax should be preferred.

Edit: in your specific case the buffer is not needed

1
  • Hi JRR, thanks for the clear answer! Perfect.
    – juu
    Commented Mar 18, 2021 at 8:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.