grid_*()
functions return consistently a RasterLayer
if there is a single layer. virtual raster mosaic were returned as RasterStack
no matter the number of layers.lasmergespatial()
wrongly copied shapefile attributes to each point when the paramter attribute
was the name of an attribute of the shapefile.laspulse()
, lasflightline()
, lasscanline()
were broken since v2.0.0.lasmergespatial()
and lasclip()
loose precision when extracting polygons due to missing digits in the WKT string used to rebuild the polygons at C++ level.catalog
has been slightly modified in prevision of the release of the package rlas 1.3.0
to preserve future compatibility. This is invisible for the users.lasnormalize
gained a parameter na.rm = TRUE
chunk_pattern = TRUE
: objet ‘ctg’ introuvable.tin()
and knnidw()
were inverted.keep_lowest
in grid_terrain
.> 2.0
are incompatible with versions 1.x.y
?The lidR package versions 1 were mainly built upon “personal R scripts” I wrote 3 years ago. These scripts were written for my own use at a time when the lidR package was much smaller (both in term of code and users). The lidR package became a relatively large framework built on top of an unstructured base so it became impossible to develop it further. Many features and functions were missing because the way lidR was built did not allow them to be written. The new release (lidR version 2) breaks the former code to build a more robust, more consistent and more scalable framework that is intended and expected to continue for years without the need to break anything more in the future.
Old binaries can still be found here for 6 months:
lidR as a GIS tool
lidR versions 1 was not a GIS tool. For example, rasterization functions such as grid_metrics()
or grid_canopy()
returned a data.frame
. Tree tops extraction with tree_detection()
also returned a data.frame
. Tree segmentation with lastrees()
accepted RasterLayer
or data.frame
as input in a very inconsistent way. Moreover, the CRS of the point cloud was useless and never propagated to the outputs because outputs were not spatial objects.
lidR version 2 consistently uses Raster*
and Spatial*
objects everywhere. Rasterization functions such as grid_metrics()
or grid_canopy()
return Raster*
objects. Tree tops extraction returns SpatialPointDataFrame
objects. Tree segmentation methods accept SpatialPointDataFrame
objects only in a consistent way across functions. The CRS of the point cloud is always propagated to the outputs. LAS
objects are Spatial
objects. LAScatalog
objects are SpatialPolygonDataFrame
objects. In short, lidR version 2 is now a GIS tool that is fully compatible with the R ecosystem.
No longer any update by reference
Several lidR functions used to update objects by reference. In lidR versions 1 the user wrote: lasnormalize(las)
instead of las2 <- lasnormalize(las1)
. This used to make sense in R < 3.1 but now the gain is no longer as relevant because R makes shallow copies instead of deep copies.
To simplfy, let’s assume that we have a 1 GB data.frame
that stores the point cloud. In R < 3.1 las2
was a copy of las1
i.e. las1
+ las2
= 2GB . This is why we made functions that worked by reference that implied no copy at all. This was memory optimized but not common or traditional in R. The question of memory optimization is now less relevant since R >= 3.1. In the previous example las2
is no longer a deep copy of las1
, but a shallow copy. Thus lidR now consistently uses the traditional syntax y <- f(x)
.
Algorithm dispatch
The frame of lidR versions 1 was designed at a time when there were fewer algorithms. The increasing number of algorithms led to inconsistent ways to dispatch algorithms. For example:
grid_canopy()
implemented one algorithm and a second function grid_tincanopy()
was created to implement another algorithm. With two functions the switch was possible by using two different names (algorithms dispatched by names).grid_tincanopy()
actually implemented two algorithms in one function. The switch was possible by changing the input parameters in the function (algorithm dispatched by input).lastrees()
had several variants that provided access to several algorithms: lastrees_li()
, lastrees_dalpontes()
, lastrees_watershed()
, and so on. With several functions the switch was possible by using several different names (algorithms dispatched by names).tree_detection
did not have several variants, thus it was impossible to introduce a new algorithm (no dispatch at all).lidR version 2 comes with a flexible and scalable dispatch method that unifies all the former functions. For example, grid_canopy()
is the only function to make a CHM. There is no longer the need for a second function grid_tincanopy()
. grid_canopy()
unifies the two functions by accepting as input an algorithm for a digital surface model:
The same idea drives several other functions including lastrees
, lassnags
, tree_detection
, grid_terrain
, lasnormalize
, and so on. Examples:
ttops = tree_detection(las, algo = lmf(5))
ttops = tree_detection(las, algo = lidRplugins::multichm(1,2))
lastrees(las, algo = li2012(1.5, 2))
lastrees(las, algo = watershed(chm))
lasnormalize(las, algo = tin())
lasnormalize(las, algo = knnidw(k = 10))
This allows lidR
to be extended with new algorithms without any restriction either in lidR or even from third-party tools. Also, how lidR functions are used is now more consistent across the package.
LAScatalog processing engine
lidR versions 1 was designed to run algorithms on medium-sized point clouds loaded in memory but not to run algorithms over a set of files covering wide areas. In addition, lidR 1 had a poorly and inconsistently designed engine to process catalogs of las files. For example:
LAScatalog
but not multipart-polygons or polygons with holes. This was only possible with LAS
objects i.e loaded in memory (inconsistent behaviors within a function).grid_metrics()
on a LAScatalog
i.e. over a wide area not loaded in memory, but not lasnormalize
, lasground
or tree_detection
(inconsistent behavior across the functions).lidR version 2 comes with a powerful and scalable catalog processing engine. Almost all the lidR functions can be used seamlessly with either LAS
or LAScatalog
objects. The following chunks of code are now possible:
ctg = catalog("folfer/to/las/file")
opt_output_file(ctg) <- "folder/to/normalized/las/files/{ORIGINALFILENAME}_normalized"
new_ctg = lasnormalize(ctg, algo = tin())
LAS class
LAS
class is now a Spatial
object or, more technically, it inherits a Spatial
object.Spatial
object, a LAS
object no longer has a @crs
slot. It has now a slot @proj4string
that is accessible with the functions raster::projection
or sp::proj4string
Spatial
object, a LAS
object inherits multiple functions from raster
and sp
, such $
and [[
accessors or raster::extent
, sp::bbox
, raster::projection
, and so on. However, the replacement method $<-
, [[<-
have restricted capabilities to ensure a LAS
object cannot be modified in a way that implies loosening the properties of the LAS specifications.LAS
objects with 0 points are now allowed. This has repercussions for several functions including lasfilter
, lasclip
, and readLAS
that do not return NULL
for empty data but a LAS
object with 0 points. This new behavior has been introduced to fix the old inconsistent behavior of functions that return either LAS
or NULL
objects. LAS
objects are always returned.LAScatalog class
LAScatalog
class is now a SpatialPolygonsDataFrame
or, more technically, it inherits a SpatialPolygonsDataFrame
.SpatialPolygonsDataFrame
object, a LAScatalog
no longer has a @crs
slot. It has now a slot @proj4string
that is accessible with the functions raster::projection
or sp::proj4string
.SpatialPolygonsDataFrame
a LAScatalog
can be plotted with sp::spplot()
.@cores
, @by_file
, @buffer
, and so on. They are replaced by more generic and scalable slots @processing_options
, @output_options
, @clustering_options
and @input_options
that are list of options classified by their main roles.by_file
, progress
, tiling_size
, buffer
were replaced by opt_chunk_size
, opt_chunk_buffer
, opt_progress
, and so on. These allow for a consistent set of functions that do not overlap with functions from raster
or sp
.sp
functions.readLAS
readLAS
no longer supports option PFC
. Users must use the functions laspulse
, lasflightlines
manually.lasclip
lasclip
now works both with a LAS
object and a LAScatalog
object in a seamless and consistent way. There are no longer any differences between the capabilities of the LAS
version or the LAScatalog
one.lasclip
support many geometries including multipart polygons and polygons with holes, both with a LAS
object and a LAScatalog
object.inside
has been removed for consistency because it cannot be safely supported both on LAS
and LAScatalog
.ofile
has been removed for consistency and this option in now managed by the LAScatalog
processing engine. For example, one can extract ground inventories and write them in laz
files automatically named after their center coordinates like this:ctg = catalog(folder)
output_files(ctg) <- "path/to/a/file_{XCENTER}_{YCENTER}"
laz_compression(ctg) <- TRUE
new_ctg = lasclipCircle(ctg, xc,yc, r)
lasclip
does not return NULL
anymore for empty queries but an empty LAS
object.lasclipRectangle
returns the same output both with a LAS
and a LAScatalog
. With a LAS
the rectangle is now closed on the bottom and the left and open on the right and the top.catalog_queries
catalog_queries
has been removed because it is superseded by lasclip
.lasnormalize
lasnormalize()
no longer updates the original object by reference.copy = TRUE
that is now meaningless.lasnormalize()
now relies on lidR algorithms dispatch (see also the main new features above).lasnormalize()
can be applied on a LAScatalog
to write a new normalized catalog using the catalog processing engine (see also the main new features above).lasclassify
lasclassify()
is now named lasmergespatial()
to free the name lasclassify
that should be reserved for other usage.lasmergespatial()
no longer updates the original object by reference.RasterLayer
, preserves the data type of the RasterLayer
. This also fixes the fact that lastrees()
used to classify the tree with double
instead of int
.tree_detection
tree_detection()
now relies on the new dispatch method (see also the main new features above).lmf
has user-defined variable-sized search windows and two possible search window shapes (square or disc).manual
algorithm for manual correction of tree detection.tree_detection
algorithms are seamlessly useable with a LAScatalog
object by using the catalog processing engine (see also the main new features above). Thus, the following just works:lmf
algorithm, when used with a RasterLayer
as input, expects parameters given in the units of the map and no longer in pixels.tree_detection()
function consistently returns a SpatialPointsDataFrame
whatever the algorithm.tree_detection()
function based on a CHM no longer support a lasmetric
object as input. Anyway, this class no longer exists.tree_metrics
tree_metrics()
returns a SpatialPointsDataFrame
.tree_metrics()
is seamlessly useable with a LAScatalog
using the catalog processing engine (see also the main new features above). Thus, this just works if the las file has extra bytes attributes that store the tree ids:lastrees
lastrees()
now relies on the new algorithms dispatch method (see also the main new features above).mcwatershed
algorithm that implements a marker-controlled watershed.grid_metrics
grid_metrics()
as well as other grid_*
functions consistently return a RasterLayer
or a RasterBrick
instead of a data.table
.splitlines
has been removed. grid_metrics()
used to return a data.table
because of the splitlines
option and lidR was built on top of that feature from the very beginning. Now lidR consistently usessp
and raster
and this option is no longer supported.grid_terrain
grid_terrain()
now relies on the new algorithms dispatch method (see also the main new features above).grid_terrain()
consistently returns a RasterLayer
instead of a data.table
, whatever the algorithm used.grid_canopy
grid_canopy()
now relies on the new algorithms dispatch method (see also the main new features above). It unifies the former functions grid_canopy()
and grid_tincanopy()
.grid_canopy()
consistently returns a RasterLayer
instead of a data.table
, whatever the algorithm used.grid_tincanopy
grid_tincanopy()
has been removed. Digital Surface Models are consistently driven by the function grid_canopy()
and the lidR algorithm dispatch engine. The algorithms that replaced grid_tincanopy()
are dsmtin
and pitfree
.grid_hexametrics
grid_metrics
, the parameter splitlines
has been removed.hexbin
object or a list of hexbin
objects and no longer data.table
objects.grid_catalog
grid_catalog()
has been removed. The new LAScatalog
processing engine means that this function is no longer useful.class lasmetrics
data.table
with a class lasmetrics
no longer exists. It has been consistently replaced by RasterLayer
and RasterBrick
everywhere.as.raster
no longer exists because it used to convert lasmetrics
into RasterLayer
and RasterStack
.as.spatial
no longer converts lasmetrics
to SpatialPixelsDataFrame
but still converts LAS
to SpatialPointsDataFrame
.plot.lasmetrics
has been removed obviously.lasroi
lasoi()
has been removed. It was not useful and ‘buggy’. It might be reintroduced later in lasclipManual
.lascolor
lascolor()
has been removed. It was one of the first functions of the package and is no longer useful because plot()
has enhanced capabilities.lasfilterdecimate
highest
available in lasfilterdecimate()
. This supersedes the function lasfiltersurfacepoints()
.lassnags
lassnags()
now relies on the new algorithms dispatch method (see also the main new features above).lasnsnags()
can be applied on a LAScatalog
to write a new catalog using the catalog processing engine (see also the main new features above).lidr_options
lidr_option()
has been removed. The options are now managed by regular R base options with function options()
. Available lidR options are named with the prefix lidR
.Example files
proj4string
.MixedConifers.laz
contains the segmented trees in extra bytes 0.plot
plot()
for LAS
objects supports RGB
as a color attribute.color
supports lazy evaluation. This syntax is correct: plot(las, color = Classification)
.clear_artifact = TRUE
shifts the point cloud to (0,0) and reduces the display artifact due to the use of floating point in rgl
.add_treetops3d
, add_dtm3d
and plot_dtm3d
add elements in the point cloud.trim
does not trim on a percentile of values but on the values themselves.Coordinate reference system
epsg()
.lastranform
that returns transformed coordinates of a LAS
object using the CRS argument.New functions
lasfilterduplicates
lascheck
lasvoxelize
point_in_polygon
algorithm relies on boost
and drastically simplifies the former code of lasmergespatial()
catalog_apply
on Windows.tree_hulls
that computes a convex or concave hull for each segmented tree.stop_early
that enables processing of an entire catalog or stops if an error occurs.catalog_retile
supersedes the function catalog_reshape
and performs the same task while adding much more functionality.LAScatalog
, error handling has been seriously improved. A process can now run until the end even with errors. In this case clusters with errors are skipped.LAScatalog
, the graphical progress now uses 3 colors. green: ok, red: error, gray: null.as.spatial()
for LAS
object preserves the CRS.plot.LAScatalog
always displays the catalog with mapview
by default even if the CRS is empty.lastrees_dalponte
the matching between the seeds and the canopy is more tolerant. Rasters can have different resolution and/or extent.lasground
uses (as an option) only the last and single returns to perform the segmentation.catalog()
displays a message when finding overlaps between files.LAScatalog
by cluster.lasscanline()
did not compute the scanline because the conditional statement that checked if the field was properly populated was incorrect.tree_detection
when used with a point cloud was not properly coded and tended to miss some trees.lasclip*
if ofile
was non empty, the function wrote properly the file but returned a non-expected error.future
and some function were missing. User supplied function is now manually analyzed.lasclip
was used with a SpatialPolygonDataFrame
.LAScatalog
was wrongly computed for non square tiles because of a bad copy/paste in the code.NULL
class objects returned by grid_*
functions when processing a LAScatalog
if the first cluster is empty.rumple_index
returns NA
if not computable.catalog_options()
is formally deprecated. Use LAScatalog
properties instead (see ?catalog
).magrittr
is no longer loaded with lidR
. Thus, piping operators are no longer usable by default. To use piping operators use library(magrittr)
.lassmooth
function. A point cloud-based smoothing function.lasfiltersurfacepoints
function to filter surface points.grid_catalog
function is a simplified and more powerful function like catalog_apply
but specifically dedicated to grid_*
outputs.lasadddata
, lasaddextrabyte
and lasaddextrabyte_manual
to add new data in a LAS
object.lasclip
can clip a SpatialPolygonsDataFrame
lasclipRectangle
and lasclipCircle
can clip multiple selections (non-documented feature).treeID
computed with lastrees_*
functions can now be written in a las/laz
file by default.LAScatalog
objects are processed with a single core by default.lasdecimate
is formally deprecated. Use lasfilterdecimate
grid_density
now returns both the point and the pulse density, where possible.P
is no longer set by default in readLAS
.lastrees
has been split into several pages.grid_metrics(lidar, stdmetrics_i(Intensity))
returned and empty data.table
raster::extract
function.area
from lidR
and from raster
.entropy
functionlasclassify
when using the shapefile table of attributes as data.field = NULL
in lasclassify
.NA
return in entropy when negative value are found.start
has been enabled in grid_metrics
with catalogs
.lasclip
and lasclip*
can extract from a catalog.lasclip
supports sp::Polygon
objects.lastrees
gains a new algorithm from Silva et al. (2016).lastrees
with the Li et al. (2012) algorithm gains a new parameter to prevent over-segmentation.lassnags
for classifying points as snag points or for segmenting snags.tree_detection
to detect individual trees. This feature has been extracted from lastrees
’s algorithms and it is now up to the users to use lidR
’s algos or other input sources.plot
supports natively the PointCloudViewer
package available on github.lasscanline
.lastrees
with the Li et al. (2012) algorithm is now 5-6 times faster and much more memory efficient.lastrees
with the Li et al. (2012) algorithm no longer sorts the original point cloud.lastrees
with the Dalponte et al (2016) algorithm is now computed in linear time and is therefore hundreds to millions times faster.catalog_reshape()
streams the data and uses virtually zero memory to run.grid_canopy()
has been rewritten entirely in C++ and is now 10 to 20 times faster both with the option subcircle
or without it.grid_canopy()
with the option subcircle
uses only 16 bytes of extra memory to run, while this feature previously required the equivalent of several copies of the point cloud (several hundreds of MB).as.raster()
is now three times faster.lasclassify
now uses a QuadTree and is therefore faster. This enables several algorithms to run faster, such as lastrees
with Silva’s algo.lasground
with the PMF algorithm now accepts user-defined sequences.lasground
with the PMF algorithm has simplified parameter names to make them easier to type and understand, and to prepare the package for new algorithms.lasground
documentation is more explicit about the actual algorithm used.lasground
now computes the windows size more closely in line with the original Zhang paper.lastrees
when used with raster-based methods now accepts a missing las object. In that case extra
is turned to true
.p
(for power) added to functions that enable spatial interpolation with IDW.This version is dedicated to extending functions and processes to entire catalogs in a continuous way. Major changes are:
catalog_apply
works. More powerful but no longer compatible with previous releasesCatalog
catalog_apply
has been entirely re-designed. It is more flexible, more user-friendly and enables loading of buffered data.catalog_queries
has now an argument ...
to pass any argument of readLAS
.catalog_queries
has now an argument buffer
to load extra buffered points around the region of interest.grid_metrics
accepts a catalog as input. It allows users to grid an entire catalog in a continuous way.grid_density
also inherits this new featuregrid_terrain
also inherits this new featuregrid_canopy
also inherits this new featuregrid_tincanopy
also inherits this new featuregrid_metrics
has now has an argument filter
for streaming filters when used with a catalogcatalog_reshape
lasnormalize
updates the point cloud by reference and avoids making deep copies. An option copy = TRUE
is available for compatibility with former versions.readLAS
arguments changed. The new syntax is simpler. The previous syntax is still supported.catalog_index
is no longer an exported function. It is now an internal function.plot.Catalog
accepts the usual plot
argumentscatalog_queries
and catalog_apply
do not expect a parameter mc.cores
. This is now driven by global options in catalog_options()
.grid_metrics
and lasmetrics
do not expect a parameter debug
. This is now driven by global options in lidr_options
.catalog
can build a catalog from a set of paths to files instead of a path to a folder.$
access to LAS attribute (incredibly slow)catalog_select
is more pleasant an more interactive to use.Catalog
class is now a S4 LAScatalog
classLAS
and LAScatalog
class gain a slot crs
automatically filled with a proj4 stringplot.LAScatalog
display a google map background if the catalog has a CRS.plot.LAScatalog
gains an argument y
to display a either a terrain, road, satellite map.lasarea
is deprecated. Use the more generic function area
writeLAS
for skipped fields when no field is skipped is now correct.grid_terrain
with delaunay allocates less memory, makes fewer deep copies and is 2 to 3 times fastergrid_terrain
with knnidw allocates less memory, makes fewer deep copies and is 2 to 3 times fasterlasnormalize
and lasclassify
no longer rely on raster::extract
but on internal fast_extract
, which is memory efficient and more than 15 times faster.catalog
enables a LAScatalog
to be built 8 times faster than previously.RANN
package using internal k-nearest neighbor search (2 to 3 times faster)tree_metrics
.stdtreemetrics
.grid_tincanopy()
gains a parameter subcircle
like grid_canopy()
rumple_index
for measuring roughness of a digital model (terrain or canopy)lidr_options()
grid_tincanopy
x > 0
was replaced by x >= 0
to avoid errors in the canopy height modelslastrees
Li et al. algorithm for tree segmentation is now ten to a thousand of times faster than in v1.2.0grid_terrain
, the interpolation is now done only within the convex hull of the point cloudgrid_tincanopy
makes the triangulation only for highest return per grid cell.grid_tincanopy
and grid_terrain
using Delaunay triangulation is now ten to a hundred times faster than in v1.2.0as.raster
now relies on sp
and is more flexibleas.raster
automatically returns a RasterStack
if no layer is provided.plot.lasmetrics
inherits as.raster
changes and can display a RasterStack
lasground
for ground segmentation.grid_tincanopy
. Canopy height model using Khosravipour et al. pit-free algorithm.grid_hexametrics
. Area-based approach in hexagonal cells.lasnormalize
allows for “non-discretized” normalization i.e interpolating each point instead of using a raster.lascheck
performs more tests to check if the header is in accordance with the data.gap_fraction_profile()
bug with negative values (thanks to Florian de Boissieu)stdmetric_i
stdmetric
stdmetric_z
when max(Z) = 0
grid_terrain
, forcing the lowest point to be retained is now an option keep_lowest = FALSE
lastree()
for individual tree segmentationreadLAS()
gains a parameter filter
from rlas (>= 1.1.0)
catalog_queries()
relies on rlas (>= 1.1.0)
. It saves a lot of memory, is 2 to 6 times faster and supports .lax files.colorPalette
parameter in plot.LAS()
now expects a list of colors instead of a function. Use height.colors(50)
instead of height.colors
LASheader
akima
is now called delaunay
because it corresponds to what is actually computed.akima
lost its parameter linear
.kriging
now performs a KNN kriging.catalog_queries()
lost the parameter ...
all the fields are loaded by default.lasterrain()
which was not consistent with other functions and not useful.Number of point records
and Number of nth return
.lasnormalize()
updates the header and returns warnings for some behaviorsThird submission
Second submission - rejected
First submission - rejected