If you are viewing this file on CRAN, please check the latest news on GitHub where the formatting is also better
LASheader
has a new slot @EVLR
for the extended variable length records. print()
has been extended to display EVLR. While this change is compatible with rlas <= 1.3.9
it is only used with version of rlas >= 1.4.0
.lowest()
for decimate_points()
catalog_apply()
now works with cluster plan plan(cluster)
meaning that it can be used on HPC e.g. with MDPI. We took advantage of this bug to better detect the parallel strategy used and disable or not OpenMP. When lidR
is not able to figure out if the strategy involves multiple machines or multiple cores of a single machine, then a warning is thrown and OpenMP is disabled by security. The parallel evaluation strategy was no recognized and lidR does not know if OpenMP should be disabled. OpenMP has been disabled by security. Use options(lidR.check.nested.parallelism = FALSE) and set_lidr_threads() for a fine control of parallelism.
spTransform()
have for consequences to make the function failing with error: Non quantizable value outside the range of representable values of type 'int'
.projection()
when using an epsg code as input (projection(las) <- 12345
).readLAScatalog()
now reads the WKT CRS of LAS files format 1.4. To support both EPSG and WKT the table of attribute of a LAScatalog
now has a column named CRS
that replace former column EPSG
.print()
for a LAScatalog
now prints the CRS exactly like print
for LAS
.options(lidR.check.nested.parallelism = FALSE)
was missing. Information can now be found in ?lidR-package
and ?lidR-parallelism
catalog_apply()
if lidR.check.nested.parallelism = FALSE
it now respects the input of set_lidr_thread()
instead of the output of get_lidr_threads()
. For example if set_lidr_thread(0)
it now propagates the information 0 (all cores) instead of the output of get_lidr_thread()
which might be e.g. 4 on the master worker but might be different on the slave workers. Similarly set_lidr_thread(20)
will request 20 cores to the workers even if get_lidr_thread()
returns 4 on the local machine.set_lidr_thread()
accepts inputs < 1 such as 0.5 or 0.25 to mean ‘half’ or ‘quarter’ of available cores.grid_density()
now returns 0 for pixels with 0 points instead of NA
which make more sense and corresponds to what should be expected.The release of lidR
3.1.0 comes with major internal modifications enabling users to chose different kinds of spatial indexes to process the point-clouds, including Quadtrees and Octrees, plus others. Previous releases were optimized to process ALS data but were suboptimal for TLS data (for example) because the spatial index in use was specialized for ALS. With 3 new spatial indexes, version 3.1.0 brings the capability to process TLS (but not only) data more efficiently. For the time being, however, lidR
is still mainly focused on ALS and does not include many functions for TLS processing, but the existing functions that be used on all kinds of point-cloud, such as point_metrics()
, detect_shape()
, and classify_noise()
are already much faster for TLS data.
LAS
has a new slot @index
that registers the source of the point cloud (e.g. ALS, TLS, UAV, DAP) and the spatial index that must be used (e.g. grid partition, voxel partition, quadtree, octree). See help("lidR-spatial-index")
.read*LAS()
functions, such as readTLSLAS()
, which registers the point-cloud type and a default spatial index. Registering the correct point type improves the performance of some functions. This is particularly visible in functions that perform 3D knn searches, such as point_metrics()
. Computing point_metrics()
on a TLS point-cloud tagged as TLS is much faster than if it is not tagged. If performance is not improved in this release the future versions of the package may bring enhancements transparently.index()
and sensor()
to manually modify the spatial indexing-related information. help("lidR-spatial-index")
.inst/include
, meaning that other packages can link to lidR
to uses the spatial index at C++ level. The classes are not documented yet but the source code is simple and commented, and the lidR book contains (or will contain) a chapter on spatial indexing.lassomething()
) now triggers a message inviting users to move on the new namespace.LAS
object with LAS()
now triggers warnings with incorrectly quantized coordinates according to the information in the header.grid_terrain()
now has a parameter ...
after algorithm
that invalidates code that uses too many parameters without naming them. This no longer works:grid_terrain(las, 1, tin(), TRUE, TRUE, 8)
# Use instead
grid_terrain(las, 1, tin(), keep_lowest = TRUE, full_raster = TRUE, use_class = 8)
opt_cores()
and opt_cores<-()
are now defunct. These functions did not have any effect because they only throw a warning to alert about deprecation since v2.1.0 (July 2019).LAS*
classes have a new slot @index
(see above). This should not break anything expect when a LAS*
object is saved in an Rds
file and loaded as an R object instead of being read with readLAS
.classify_noise()
classify_noise()
to classify the outliers of a point-cloud according to ASPRS standardsor()
(statistical outlier removal) for noise classificationivf()
(isolated voxel filter) for noise classificationLAS
objects in lidR
closely respect the ASPRS standard. When modified manually by users, some inadequate practices may generate invalid LAS objects. We thus decided to export some internal functions to help in creating valid LAS objects and we modified the behavior of the [[<-
and $<-
operators to ensure that it is more difficult to create LAS
objects that are not ASPRS compliant.
las_quantize()
, quantize()
, is.quantized()
, count_not_quantized()
to ensure that coordinates are quantized according to the metadata in the header.las_update()
to update the header (bounding box, number of points, return count and so on) if a LAS object was modified outside a lidR
functions.[[<-
and $<-
operators. Values are quantized on-the-fly and the header is updated automatically when attributing new values to X
, Y
or Z
.las$X # Original values
#> [1] 0.755 0.286 0.100 0.954 0.416 0.455 0.971 0.584 0.962 0.762
las$X + 5/3 # Many decimals because 5/3 = 1.666666...
#> [1] 2.421667 1.952667 1.766667 2.620667 2.082667 2.121667 2.637667 2.250667 2.628667 2.428667
las$X <- las$X + 5/3 # Updates X with these numbers
las$X # Values were quantized (and header updated)
#> [1] 2.422 1.953 1.767 2.621 2.083 2.122 2.638 2.251 2.629 2.429
help("las_utilities")
.voxel_metrics()
gained a parameter all_voxels
to include “empty” voxels (i.e. those with 0 points) in the output #375.grid_terrain()
...
after algorithm
that invalidates code that uses too many parameters without naming them. This no longer works:grid_terrain(las, 1, tin(), TRUE, TRUE, 8)
# Use instead
grid_terrain(las, 1, tin(), keep_lowest = TRUE, full_raster = TRUE, use_class = 8)
is_concave
to compute a nicer DTM if the point-cloud boundaries are not convex #374clip_transect()
the polygon generated to extract the transect defined by points p1
, p2
was created by buffering the line p1-p2
with a SQUARE
cap style meaning that the transect was extended beyond points p1
, p2
. It now uses a FLAT
cap style meaning that the transect is no longer extended beyond the limits of the user input.segment_trees()
when using a raster-based algorithm, some points may have been misclassified as NAs at the edges of the point cloud instead of getting the correct tree ID found in the raster because of some edge effects. Now, all points are correctly classified and there are no longer false positive NAs.normalize_intensity()
was previously not working with a LAScatalog
. Now fixed. See #388grid_*()
functions when a RasterLayer
is given as layout, the computation was performed for all the cells no matter if the extent of the loaded point-cloud was much smaller than the raster. For large rasters this dramatically increased the workload with redundant computation and saturated the RAM to a point that the computation was no longer possible.track_sensor()
pulse IDs could be wrongly attributed for multi-beam sensors if the number of points is very low. See #392track_sensor()
, if thin_pulses_with_time = 0
a single pulse was loaded with a LAScatalog
. However it worked as expected with a LAS
object. This behavior has been fixed.future
and related to RNG.clip_*()
in a region with no points from a LAScatalog
+ an output file no longer fails. See #400.point_metrics()
clarifies how the user-defined function is fed and in which order the points are sorted.Wdegenerated
in grid_terrain()
and normalize_height()
was misleading. A wrong interpretation was that degenerated ground points were discarded from the dataset. The documentation now clarifies the text to avoid misinterpretation.LAScatalog-class
page of the manual.plot_dtm3d()
now enables pan by default, like plot()
for LAS
objects.track_sensor()
throws a new warning if a swath in the point cloud does not produce any sensor location. This addresses #391.readLAScatalog()
the documentation states that ...
is propagated to list.files()
, but the argument pattern
was actually hard coded internally and this prevents it being overwritten. When using readLAScatalog(..., pattern = "xxx")
this previously triggered an error, formal argument "pattern" matched by multiple actual arguments
. It now works. See #368.spTransform()
the reprojected point cloud now has quantized coordinates and is thus LAS compliant #369.RasterLayer
.classify_ground()
no longer erases the previous classification when no ground points were recorded but some points are classified with other classes.las_reoffset()
may not have caught extremely rare Z coordinate overflow when converting to integers.las_reoffset()
incorrectly converted decimal coordinates to integers using trunc
instead of round
.projection<-()
and crs<-()
properly attributes NA
CRS for LAS 1.4 objectsprint
the CRS of LAS
and LAScatalog
is no longer displayed as a proj4 string but uses the WTK string with sf
style display. E.g. NAD83 / UTM zone 17N
is displayed instead of +proj=utm +zone=17 +datum=NAD83 +units=m +no_defs
. This is part of the migration toward WTK instead of proj4.lidR
now explicitly depends on rgdal >= 1.5.8
.grid_canopy()
now rounds the values of the pixels for not outputing pixels that with an irrelevant number of decimal digits.epsg()
now throws a warning if the LAS is in format 1.4 and CRS is stored as WKT.projection()<-
supports crs
from sf
and numeric values for espg code: projection(las) <- 26918
.spTransform()
it is now possible to use a parameter scale
to change the scale factor after reprojection. This is useful for projecting from lon-lat data las2 = spTransform(las, crs, scale = 0.01)
.projection<-
of the current changes with CRS representation in the R spatial ecosystem.citation("lidR")
tin()
gains a parameter extrapolate
to control how the method treats interpolation of points outside the convex hull determined by ground points. This solves #356grid_terrain()
were incorrect especially the buffer that is required.Wing2015()
the mention about weak performance was removed since it was not longer true for a while.clip
{ORIGINALFILENAME}
as a template in clip_*()
.Rcpp
ahead of the release of Rcpp
. Thanks to @waltersom in #358grid_metrics()
and grid_canopy()
when processing a LAScatalog
the option to process by files without buffer and disabling the wall-to-wall guarantees (processing independant filles) is now repected. See also.grid_metrics()
NA pixels were zeroed. They are now properly initialized to NA.grid_terrain()
and normalize_height()
we introduced few releases ago an option use_class
but we did not removed an internal test consisting in failling in absance of point classified 2. This invalidated the possibility to use e.g. use_class = 1
in files that do not respect ASPRS standards #350.readLAS(filter = "-help")
was not working but was suggested in the documentation.Summary
In lidR version 3.0.0, 80% of the functions were renamed. Old functions were soft-deprecated, meaning that they still exist so version 3 is fully compatible with version 2, at least for 1 year. Users should start to use the new names. See ?lidR::deprecated
for the list of deprecated functions and their new names. The plan is to remove these functions in 1 year so they will progressively print a message, then throw a warning, then throw an error, after which they will be definitively removed.
Full explanation
At the very beginning of the development of lidR we started to name the functions that return a LAS object lassomething()
. At that point there were 5 functions and ~10 users. As lidR grew up, we kept going with this naming convention but now lidR is used worldwide and this naming convention now overlaps with the LAStools software suite created by Martin Isenburg. This creates confusion for users which is problematic both for Martin and for us. This situation is likely to get worse as more tools are released into LAStools. We discussed the issue with Martin Isenburg and we took the decision to rename the functions in the lidR package so that the overlaps in namespace will progressively disappear.
The new naming convention follows the currently trending verb_noun
syntax initiated by the tidyverse
. For example, lasnormalize()
becomes normalize_height()
, while lasground()
becomes classify_ground()
. The full list of changes can be found in ?lidR::deprecated
.
In efforts to avoid breaking users’ scripts version 3 is fully backwards-compatible. For example, the function lasground()
still exists and can be used without throwing a warning or error message. But this will progressively change with versions 3.1.0, 3.2.0 and 3.3.0. First a message will be displayed to invite users to change to using the new names, then a warning, then finally an error. After a year, maybe 18 months, the function will no longer exist. So users are invited to adopt the new naming convention as soon as possible.
readLAScatalog()
has new parameters to tune the processing options at read time without using the functions opt_*()
.
New function clip_transect()
to extract a transect between two points. The function has the capability to reorient the point cloud to put it on XZ coordinates and easily create some 2D rendering of the transects in e.g. ggplot2.
New function readMSLAS()
to read multisprectral data from 3 different files.
delineate_crowns()
(formerly named tree_hulls()
) now returns 3 metrics: XTOP
, YTOP
and ZTOP
, that contain the coordinates of the apices of the trees.
segment_trees()
(formerly named lastrees()
) and find_trees()
(formerly tree_detection()
) can now perform the computation on a LAScatalog
using two strategies to ensure that tree IDs are always unique on a coverage and that trees that belong on the edge of two tiles will independently get the same IDs.
point_metrics()
r
and given k
k
and given r
k
and r
givenxyz = FALSE
xyz = FALSE
the the output now contains a column (the first one) named pointID
that references the point of the original las object. See #325normalize_height()
(formerly named lasnormalize()
)
add_lasattribute
. If TRUE
the absolute elevation (above sea level) is retained as before, but the header is updated so the absolute elevation becomes an extrabyte attribute writable on a las file. Otherwise the information is discarded at write time.Wdegenerated
. If FALSE
the function does not warn about degenerated points. Degenerated points are removed anyway.New function find_localmaxima()
to find local maxima with different windows. This function is designed for programming purposes, not to find individual trees. This latter task is still performed by find_trees()
(formerly called tree_detection()
). Instead, find_localmaxima()
may help with finding other human-made structures.
Internal global variables were exported to help with ASPRS LAS classification standard. Instead of remembering the classification table of the specification it is now possible to use one of LASNONCLASSIFIED
, LASUNCLASSIFIED
, LASGROUND
, LASLOWVEGETATION
, LASMEDIUMVEGETATION
, LASHIGHVEGETATION
, LASBUILDING
, LASLOWPOINT
, LASKEYPOINT
, LASWATER
, LASRAIL
, LASROADSURFACE
, LASWIREGUARD
, LASWIRECONDUCTOR
, LASTRANSMISSIONTOWER
, LASBRIGDE
, LASNOISE
. e.g.:
The internal function catalog_makechunks()
has been exported. It is not actually intended to be used by regular users but might be useful in some specifc cases for debugging purposes.
lasmetrics()
, grid_metrics3d()
, grid_hexametrics()
were deprecated in previous versions. They are now defunct.
las_check()
(formerly named lascheck()
):
print = FALSE
.list
for further automatic processing/parsing. If print = TRUE
the list is returned invisibly so the former behavior looks the same.las_check(las, FALSE)
#> $warnings
#> [1] "1 points are duplicated and share XYZ coordinates with other points"
#> [2] "There were 1 degenerated ground points. Some X Y Z coordinates were repeated."
#> [3] "There were 1 degenerated ground points. Some X Y coordinates were repeated but with different Z coordinates."
#>
#> $errors
#> [1] "Invalid header: X scale factors should be factor ten of 0.1 or 0.5 or 0.25 not 0.123"
#> [2] "Invalid file: the data contains a 'gpstime' attribute but point data format is not set to 1, 3, 6, 7 or 8."
deep = TRUE
with a LAScatalog
only. In this case it performs a deep inspection of each file reading each point cloud.lidR
always ensures to return LAS
objects that are stricly valid with respect to ASPRS standard. If not valid this may lead to failure in lidR
because some functions, such as tin()
, dsmtin()
, pitfree()
work with the integer representation of the coordinates. This is why we introduced a quantization check in las_check()
.merge_spatial()
(formerly named lasmergespatial()
) now supports sf
POLYGON objects.
plot()
add
to overprint two point clouds with e.g. different color palettes #325.las = readLAS("classified.las")
nonveg = filter_poi(las, Classification != LASHIGHVEGETATION)
veg = filter_poi(las, Classification == LASHIGHVEGETATION)
x = plot(nonveg, color = "Classification")
plot(veg, add = x)
overlaps = TRUE
to highlight the overlaps.New function add_lasrgb()
to add RGB attributes. The function updates the header in such a way that the LAS object has a valid point format that supports RGB.
LAScatalog
processing engine
opt_merge(ctg) <- FALSE
to disable final merging and force the engine to return a listopt_independent_files(ctg) <- TRUE
to set adequate options to a collection of independent files, for example a set of circular ground inventory plots. It is equivalent to set no buffer, processing by file and no wall-to-wall guarantee.autoread = TRUE
in catalog_apply()
. Not actually intended to be used widely but might be convenient for some use cases.New function get_range()
.
knnidw()
gains an argument rmax
to set a maximum radius search in which to find the knn. This fixes computation time issues with non-convex point clouds.
track_sensor()
(formerly sensor_tracking()
)
writeLAS()
gains a parameter index = TRUE
to automatically write a lax file along with the las/laz file.
readLAS()
now warns when reading incompatible files. Point coordinates are recomputed on-the-fly as it has always been done but now the user is aware of potential problems or precision loss.
A new vignette named LAScatalog processing engine has been added and documents in-depth the catalog_apply()
engine of lidR.
In clip_*()
several lines of codes were removed because they were not used. We suspected these lines covered old cases from lidR v1.x.y that are no longer relevant. If a user encounters problems, please report.
The arguments select
and filter
from readLAS()
are not expected to be used with a LAScluster
when processing a LAScatalog
. The options are carried by the LAScatalog
itself with opt_select()
and opt_filter()
. If used, a warning is now thrown.
Enhancements made here and there to improve the support of the CRS when reading and checking a LAS file.
When processing by file with a raster output, automatic chunk extension to match with a raster resolution now performs a tighter extension.
Minor modification of print()
methods to enhance information displayed.
All algorithms such as tin()
, p2r()
, knnidw()
, li2012()
, and so on, now have the classes c("lidRAlgorithm", "something")
and a dedicated print function. The source code is no longer displayed when printing these objects
In grid_metrics()
the RasterBrick
is built much faster.
In delineate_crowns()
, formerly named tree_hull()
, when applied to a LAScatalog
the buffer was not properly removed. The polygons were simply clipped using the bounding box of the chunk. Now the trees that have an apex in the buffer are removed and the trees that have an apex outside the buffer are retained. Thus, when merging, everything is smooth and continuous.
catalog_retile()
returns a LAScatalog
with only the newly created files even if the folder contains other las files. It formerly read every las file in the folder leading to an invalid catalog if the folder already contained las files.
Previously in automatic filename generation the template YCENTER
was not actually recognized. However, XCENTER
was recognized but actually contained the value for YCENTER
. This was working for lasclip()
thanks to a previous fix but was still a problem in other functions when processing chunks.
Function wkt()
no longer masks the new function wkt()
in sp
.
merge_spatial()
(formerly named lasmergespatial()
) no longer fails with a LAS object containing a single point.
lidR v2.x.y changelog has been moved to NEWS_v2.md