v2.0.0
lidR v2.0.0 (Release date: 2019-01-02)
Why versions > 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:
Overview of the main visible changes
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 functiongrid_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:
chm = grid_canopy(las, res = 1, algo = pitfree())
chm = grid_canopy(las, res = 1, algo = p2r(0.2))
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:
- It was possible to extract a polygon of points from a
LAScatalog
but not multipart-polygons or polygons with holes. This was only possible withLAS
objects i.e loaded in memory (inconsistent behaviors within a function). - It was possible to run
grid_metrics()
on aLAScatalog
i.e. over a wide area not loaded in memory, but notlasnormalize
,lasground
ortree_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())
Complete description of visible changes
LAS class
- Change: the
LAS
class is now aSpatial
object or, more technically, it inherits aSpatial
object. - Change: being a
Spatial
object, aLAS
object no longer has a@crs
slot. It has now a slot@proj4string
that is accessible with the functionsraster::projection
orsp::proj4string
- New: being a
Spatial
object, aLAS
object inherits multiple functions fromraster
andsp
, such$
and[[
accessors orraster::extent
,sp::bbox
,raster::projection
, and so on. However, the replacement method$<-
,[[<-
have restricted capabilities to ensure aLAS
object cannot be modified in a way that implies loosening the properties of the LAS specifications. - New: empty
LAS
objects with 0 points are now allowed. This has repercussions for several functions includinglasfilter
,lasclip
, andreadLAS
that do not returnNULL
for empty data but aLAS
object with 0 points. This new behavior has been introduced to fix the old inconsistent behavior of functions that return eitherLAS
orNULL
objects.LAS
objects are always returned.
LAScatalog class
- Change: the
LAScatalog
class is now aSpatialPolygonsDataFrame
or, more technically, it inherits aSpatialPolygonsDataFrame
. - Change: being a
SpatialPolygonsDataFrame
object, aLAScatalog
no longer has a@crs
slot. It has now a slot@proj4string
that is accessible with the functionsraster::projection
orsp::proj4string
. - Change: being a
SpatialPolygonsDataFrame
aLAScatalog
can be plotted withsp::spplot()
. - Change: there are no longer any slots
@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. - Change: documentation has been entirely rewritten to explain the whole potential of the class.
- Change: functions
by_file
,progress
,tiling_size
,buffer
were replaced byopt_chunk_size
,opt_chunk_buffer
,opt_progress
, and so on. These allow for a consistent set of functions that do not overlap with functions fromraster
orsp
. - Change: standard column names were renamed to make syntactically-valid names and for compatibility with
sp
functions.
readLAS
- Change:
readLAS
no longer supports optionPFC
. Users must use the functionslaspulse
,lasflightlines
manually.
lasclip
- New:
lasclip
now works both with aLAS
object and aLAScatalog
object in a seamless and consistent way. There are no longer any differences between the capabilities of theLAS
version or theLAScatalog
one. - New:
lasclip
support many geometries including multipart polygons and polygons with holes, both with aLAS
object and aLAScatalog
object. - Change: The option
inside
has been removed for consistency because it cannot be safely supported both onLAS
andLAScatalog
. - Change: The option
ofile
has been removed for consistency and this option in now managed by theLAScatalog
processing engine. For example, one can extract ground inventories and write them inlaz
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)
- Change: documentation has been reviewed and extended
- Change:
lasclip
does not returnNULL
anymore for empty queries but an emptyLAS
object. - Fix:
lasclipRectangle
returns the same output both with aLAS
and aLAScatalog
. With aLAS
the rectangle is now closed on the bottom and the left and open on the right and the top.
catalog_queries
- Change:
catalog_queries
has been removed because it is superseded bylasclip
.
lasnormalize
- Change:
lasnormalize()
no longer updates the original object by reference. - Change: remove the old option
copy = TRUE
that is now meaningless. - Change:
lasnormalize()
now relies on lidR algorithms dispatch (see also the main new features above). - New:
lasnormalize()
can be applied on aLAScatalog
to write a new normalized catalog using the catalog processing engine (see also the main new features above).
lasclassify
- Change:
lasclassify()
is now namedlasmergespatial()
to free the namelasclassify
that should be reserved for other usage. - Change:
lasmergespatial()
no longer updates the original object by reference. - Fix: the classification, when made with a
RasterLayer
, preserves the data type of theRasterLayer
. This also fixes the fact thatlastrees()
used to classify the tree withdouble
instead ofint
.
tree_detection
- Change:
tree_detection()
now relies on the new dispatch method (see also the main new features above). - New: algorithm
lmf
has user-defined variable-sized search windows and two possible search window shapes (square or disc). - New: introduction of the
manual
algorithm for manual correction of tree detection. - New:
tree_detection
algorithms are seamlessly useable with aLAScatalog
object by using the catalog processing engine (see also the main new features above). Thus, the following just works:
ctg <- catalog(folder)
ttop <- tree_detection(ctg, lmf(5))
- Change: the
lmf
algorithm, when used with aRasterLayer
as input, expects parameters given in the units of the map and no longer in pixels. - Change:
tree_detection()
function consistently returns aSpatialPointsDataFrame
whatever the algorithm. - Change:
tree_detection()
function based on a CHM no longer support alasmetric
object as input. Anyway, this class no longer exists.
tree_metrics
- Change:
tree_metrics()
returns aSpatialPointsDataFrame
. - Change:
tree_metrics()
is seamlessly useable with aLAScatalog
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:
ctg <- catalog(folder)
metrics <- tree_metrics(ctg, list(`Mean I` = mean(Intensity)))
lastrees
- Change:
lastrees()
now relies on the new algorithms dispatch method (see also the main new features above). - New: introduction of the
mcwatershed
algorithm that implements a marker-controlled watershed.
grid_metrics
- Change:
grid_metrics()
as well as othergrid_*
functions consistently return aRasterLayer
or aRasterBrick
instead of adata.table
. - Change: option
splitlines
has been removed.grid_metrics()
used to return adata.table
because of thesplitlines
option and lidR was built on top of that feature from the very beginning. Now lidR consistently usessp
andraster
and this option is no longer supported.
grid_terrain
- Change:
grid_terrain()
now relies on the new algorithms dispatch method (see also the main new features above). - Change:
grid_terrain()
consistently returns aRasterLayer
instead of adata.table
, whatever the algorithm used.
grid_canopy
- Change:
grid_canopy()
now relies on the new algorithms dispatch method (see also the main new features above). It unifies the former functionsgrid_canopy()
andgrid_tincanopy()
. - Change:
grid_canopy()
consistently returns aRasterLayer
instead of adata.table
, whatever the algorithm used. - Fix: the pitfree algorithm fails if a layer contains only 1 or 2 points.
- Fix: the p2r algorithm is five times faster with the subcircle tweak.
grid_tincanopy
- Change:
grid_tincanopy()
has been removed. Digital Surface Models are consistently driven by the functiongrid_canopy()
and the lidR algorithm dispatch engine. The algorithms that replacedgrid_tincanopy()
aredsmtin
andpitfree
.
grid_hexametrics
- Change: as for
grid_metrics
, the parametersplitlines
has been removed. - Change: the function returns a
hexbin
object or a list ofhexbin
objects and no longerdata.table
objects.
grid_catalog
- Change:
grid_catalog()
has been removed. The newLAScatalog
processing engine means that this function is no longer useful.
class lasmetrics
data.table
with a classlasmetrics
no longer exists. It has been consistently replaced byRasterLayer
andRasterBrick
everywhere.as.raster
no longer exists because it used to convertlasmetrics
intoRasterLayer
andRasterStack
.as.spatial
no longer convertslasmetrics
toSpatialPixelsDataFrame
but still convertsLAS
toSpatialPointsDataFrame
.plot.lasmetrics
has been removed obviously.
lasroi
- Change:
lasoi()
has been removed. It was not useful and 'buggy'. It might be reintroduced later inlasclipManual
.
lascolor
- Change:
lascolor()
has been removed. It was one of the first functions of the package and is no longer useful becauseplot()
has enhanced capabilities.
lasfilterdecimate
- Change: now relies on the new algorithms dispatch method (see also the main new features above).
- New: introduction of the algorithm
highest
available inlasfilterdecimate()
. This supersedes the functionlasfiltersurfacepoints()
.
lassnags
- Change:
lassnags()
now relies on the new algorithms dispatch method (see also the main new features above). - New:
lasnsnags()
can be applied on aLAScatalog
to write a new catalog using the catalog processing engine (see also the main new features above).
lidr_options
- Change:
lidr_option()
has been removed. The options are now managed by regular R base options with functionoptions()
. Available lidR options are named with the prefixlidR
.
Example files
- New: the three example files are now georeferenced with an EPSG code that is read and converted to a
proj4string
. - New: the example file
MixedConifers.laz
contains the segmented trees in extra bytes 0.
plot
- New:
plot()
forLAS
objects supportsRGB
as a color attribute. - New: option
color
supports lazy evaluation. This syntax is correct:plot(las, color = Classification)
. - New: option
clear_artifact = TRUE
shifts the point cloud to (0,0) and reduces the display artifact due to the use of floating point inrgl
. - New: new functions
add_treetops3d
,add_dtm3d
andplot_dtm3d
add elements in the point cloud. - Change:
trim
does not trim on a percentile of values but on the values themselves.
Coordinate reference system
- New: coordinate reference system is supported everywhere and can be written in las files. See function
epsg()
. - New: function
lastranform
that returns transformed coordinates of aLAS
object using the CRS argument.
New functions
- New: function
lasfilterduplicates
- New: function
lascheck
- New: function
lasvoxelize
Other changes that are not directly visible
- Change: the code that drives the
point_in_polygon
algorithm relies onboost
and drastically simplifies the former code oflasmergespatial()
- Change: many memory optimizations