diff --git a/grass7/raster/r.in.pdal/r.in.pdal.html b/grass7/raster/r.in.pdal/r.in.pdal.html
index 7b036957b7..a29c41941d 100644
--- a/grass7/raster/r.in.pdal/r.in.pdal.html
+++ b/grass7/raster/r.in.pdal/r.in.pdal.html
@@ -36,6 +36,8 @@
NOTES
EXAMPLES
+Import LAS file using PDAL
+
Import of a LAS file using PDAL into a mapset in the sample NC SPM
location. The sample LAS file is available
here.
@@ -49,6 +51,10 @@ EXAMPLES
# scan extent (g.region style) and exit
r.in.pdal input=lidar_raleigh_nc_spm_height_feet.las output=lidar_raleigh -s -g
+# n=228500 s=215000.01 w=633370.82 e=645000 t=558.87 b=88.5
+
+# set computation region to this extent
+g.region n=228500 s=215000.01 w=633370.82 e=645000 -p
# import while aligning pixel geometry to existing "elevation" 10m res. raster map
# specifying EPSG manually because SRS information is missing in this LAS file
@@ -83,6 +89,35 @@ EXAMPLES
Figure: LiDAR cloud footprint
+Import LAZ file using PDAL docker
+Import of a LAZ file using PDAL docker into a mapset in the sample NC SPM
+location. The sample LAZ file is available
+here.
+
+
+# pulling official PDAL docker image
+docker pull pdal/pdal
+
+# using PDAL docker as command with mounted data volume
+# (caution: the LAZ file has to be stored in the mounted folder! (here: $(pwd)))
+export pdal_docker="docker run --rm -v $(pwd):/data -t pdal/pdal pdal"
+
+# scan extent and exit
+r.in.pdal input=/data/simple.laz output=lidar -s pdal_cmd="$pdal_docker"
+
+# scan extent (g.region style) and exit
+r.in.pdal input=/data/simple.laz output=lidar -s -g pdal_cmd="$pdal_docker"
+# n=853535.43 s=848899.7 w=635619.85 e=638982.55 t=586.38 b=406.59
+
+# set computation region to this extent
+g.region n=853535.43 s=848899.7 w=635619.85 e=638982.55 -p
+
+# import data
+r.in.pdal input=/data/simple.laz output=lidar_perc95 method=percentile pth=95 pdal_cmd="$pdal_docker"
+
+r.univar lidar_perc95
+
+
SEE ALSO
diff --git a/grass7/raster/r.in.pdal/r.in.pdal.py b/grass7/raster/r.in.pdal/r.in.pdal.py
index 04edf9f638..9a4a748253 100644
--- a/grass7/raster/r.in.pdal/r.in.pdal.py
+++ b/grass7/raster/r.in.pdal/r.in.pdal.py
@@ -129,6 +129,14 @@
#% required: no
#%end
+#%option
+#% key: pdal_cmd
+#% type: string
+#% description: Command for PDAL (e.g. if PDAL runs only in a docker)
+#% required: no
+#% answer: pdal
+#%end
+
#%flag
#% key: s
#% description: Scan data file for extent then exit
@@ -158,22 +166,26 @@ def footprint_to_vectormap(infile, footprint):
infile(string): Name of LAS input file
footprint(string): Footprint of the data as vector map
"""
- if not grass.find_program('pdal', 'info --boundary'):
+ if not grass.find_program(
+ options['pdal_cmd'].split(' ')[0], ' '.join(options['pdal_cmd'].split(' ')[1:])
+ + ' info --boundary'
+ ):
grass.fatal(_(
- "The pdal executable is not available."
- " Install PDAL or put the pdal executable on path."))
- command_fp = ['pdal', 'info', '--boundary', infile]
+ "The pdal executable is not available."
+ " Install PDAL or put the pdal executable on path."))
+ command_fp = options['pdal_cmd'].split(' ')
+ command_fp.extend(['info', '--boundary', infile])
tmp_fp = grass.tempfile()
if tmp_fp is None:
grass.fatal("Unable to create temporary files")
fh = open(tmp_fp, 'wb')
- p = grass.call(command_fp, stdout=fh)
- fh.close()
- if p != 0:
+ if grass.call(command_fp, stdout=fh) != 0:
+ fh.close()
# check to see if pdal info executed properly
os.remove(tmp_fp)
grass.fatal(_("pdal info broken..."))
-
+ else:
+ fh.close()
data = json.load(open(tmp_fp))
xy_in = ''
str1 = u'boundary'
@@ -186,10 +198,9 @@ def footprint_to_vectormap(infile, footprint):
except Exception:
coord_str = str(data[str1][str1])
coord = coord_str[coord_str.find('((') + 2:coord_str.find('))')]
- x_y = coord.split(', ')
+ x_y = coord.split(',')
for xy in x_y:
- xy_in += xy.replace(' ', ',') + '\n'
-
+ xy_in += xy.rstrip().replace(' ', ',') + '\n'
tmp_xy = grass.tempfile()
if tmp_xy is None:
grass.fatal("Unable to create temporary files")
@@ -285,31 +296,39 @@ def main():
# scan -s or shell_script_style -g:
if scan:
- if not grass.find_program('pdal', 'info --summary'):
+ if not grass.find_program(
+ options['pdal_cmd'].split(' ')[0], ' '.join(options['pdal_cmd'].split(' ')[1:])
+ + ' info --summary'
+ ):
grass.fatal(_(
"The pdal program is not in the path " +
"and executable. Please install first"))
- command_scan = ['pdal', 'info', '--summary', infile]
+ command_scan = options['pdal_cmd'].split(' ')
+ command_scan.extend(['info', '--summary', infile])
+
tmp_scan = grass.tempfile()
if tmp_scan is None:
grass.fatal("Unable to create temporary files")
fh = open(tmp_scan, 'wb')
- p = grass.call(command_scan, stdout=fh)
- fh.close()
summary = True
- if p != 0:
- command_scan = ['pdal', 'info', infile]
- fh = open(tmp_scan, 'wb')
- p = grass.call(command_scan, stdout=fh)
+ if grass.call(command_scan, stdout=fh) != 0:
fh.close()
+ command_scan = options['pdal_cmd'].split(' ')
+ command_scan.extend(['info', infile])
+ fh2 = open(tmp_scan, 'wb')
+ if grass.call(command_scan, stdout=fh2) != 0:
+ os.remove(tmp_scan)
+ grass.fatal(_(
+ "pdal cannot determine metadata " +
+ "for unsupported format of <%s>")
+ % infile)
+ fh2.close()
+ else:
+ fh2.close()
summary = False
- if p != 0:
- # check to see if pdal executed properly
- os.remove(tmp_scan)
- grass.fatal(_(
- "pdal cannot determine metadata " +
- "for unsupported format of <%s>")
- % infile)
+ else:
+ fh.close()
+
data = json.load(open(tmp_scan))
if summary:
str1 = u'summary'
@@ -414,9 +433,8 @@ def main():
quiet=True
)
grass.fatal(_("Format .%s is not supported.." % infile_format))
- tmp_file_json = grass.tempfile()
- if tmp_file_json is None:
- grass.fatal("Unable to create temporary files")
+ tmp_file_json = 'tmp_file_json_' + str(os.getpid())
+
data = {}
data['pipeline'] = []
data['pipeline'].append({'type': format_reader, 'filename': infile})
@@ -433,7 +451,17 @@ def main():
tmp_xyz = grass.tempfile()
if tmp_xyz is None:
grass.fatal("Unable to create temporary files")
- command_pdal1 = ['pdal', 'pipeline', '--input', tmp_file_json]
+ command_pdal1 = options['pdal_cmd'].split(' ')
+ if options['pdal_cmd'] != 'pdal':
+ v_index = None
+ cmd_entries = options['pdal_cmd'].split(' ')
+ for cmd_entry, num in zip(cmd_entries, range(len(cmd_entries))):
+ if cmd_entry == '-v':
+ v_index = num
+ break
+ mnt_vol = cmd_entries[v_index+1].split(':')[1]
+ tmp_file_json2 = os.path.join(mnt_vol, tmp_file_json)
+ command_pdal1.extend(['pipeline', '--input', tmp_file_json2])
command_pdal2 = ['r.in.xyz',
'input=' + tmp_xyz, 'output=' + outfile,
'skip=1', 'separator=comma', 'method=' + method]
@@ -452,14 +480,14 @@ def main():
command_pdal2.append('trim=' + trim)
fh = open(tmp_xyz, 'wb')
- p2 = grass.call(command_pdal1, stdout=fh)
- fh.close()
- if p2 != 0:
+ if grass.call(command_pdal1, stdout=fh) != 0:
+ fh.close()
# check to see if pdal pipeline executed properly
grass.fatal(_("pdal pipeline is broken..."))
+ else:
+ fh.close()
- p3 = grass.call(command_pdal2, stdout=outdev)
- if p3 != 0:
+ if grass.call(command_pdal2, stdout=outdev) != 0:
# check to see if r.in.xyz executed properly
os.remove(tmp_xyz)
grass.fatal(_("r.in.xyz is broken..."))