11import argparse
22from shutil import copy2
3+ import tempfile
34
45import geopandas as gpd
56import laspy
1011
1112from pdaltools .las_info import get_epsg_from_las , get_tile_bbox
1213
14+ import pdal
15+
1316
1417def parse_args (argv = None ):
1518 parser = argparse .ArgumentParser ("Add points from GeoJSON in LIDAR tile" )
@@ -127,13 +130,12 @@ def add_points_to_las(
127130 crs (str): CRS of the data.
128131 virtual_points_classes (int): The classification value to assign to those virtual points (default: 66).
129132 """
130- # Copy data pointcloud
131- copy2 (input_las , output_las )
132133
133134 if input_points_with_z .empty :
134135 print (
135136 "No points to add. All points of the geojson file are outside the tile. Copying the input file to output"
136137 )
138+ copy2 (input_las , output_las )
137139 return
138140
139141 # Extract XYZ coordinates and additional attribute (classification)
@@ -148,24 +150,30 @@ def add_points_to_las(
148150 header = las .header
149151 if not header :
150152 header = laspy .LasHeader (point_format = 8 , version = "1.4" )
153+
154+ new_points = laspy .ScaleAwarePointRecord .zeros (nb_points , header = header ) # use header for input_las
155+ # then fill in the gaps (X, Y, Z an classification)
156+ new_points .x = x_coords .astype (new_points .x .dtype )
157+ new_points .y = y_coords .astype (new_points .y .dtype )
158+ new_points .z = z_coords .astype (new_points .z .dtype )
159+ new_points .classification = classes .astype (new_points .classification .dtype )
160+
161+ with tempfile .NamedTemporaryFile (suffix = "_new_points.las" ) as tmp :
162+ with laspy .open (tmp .name , mode = "w" , header = header ) as las_file :
163+ las_file .write_points (new_points )
164+
151165 if crs :
152- try :
153- crs_obj = CRS .from_user_input (crs ) # Convert to a pyproj.CRS object
154- except CRSError :
155- raise ValueError (f"Invalid CRS: { crs } " )
156- header .add_crs (crs_obj )
157-
158- # Add the new points with 3D points
159- with laspy .open (output_las , mode = "a" , header = header ) as output_las : # mode `a` for adding points
160- # create nb_points points with "0" everywhere
161- new_points = laspy .ScaleAwarePointRecord .zeros (nb_points , header = header ) # use header for input_las
162- # then fill in the gaps (X, Y, Z an classification)
163- new_points .x = x_coords .astype (new_points .x .dtype )
164- new_points .y = y_coords .astype (new_points .y .dtype )
165- new_points .z = z_coords .astype (new_points .z .dtype )
166- new_points .classification = classes .astype (new_points .classification .dtype )
167-
168- output_las .append_points (new_points )
166+ a_srs = crs
167+ else :
168+ a_srs = get_epsg_from_las (input_las )
169+
170+ # Use pdal to merge the new points with the existing points
171+ pipeline = pdal .Pipeline ()
172+ pipeline |= pdal .Reader .las (filename = input_las )
173+ pipeline |= pdal .Reader .las (filename = tmp .name )
174+ pipeline |= pdal .Filter .merge ()
175+ pipeline |= pdal .Writer .las (filename = output_las , forward = "all" , a_srs = a_srs )
176+ pipeline .execute ()
169177
170178
171179def line_to_multipoint (line , spacing : float , z_value : float = None ):
0 commit comments