ign-pdal-tools 1.15.4__py3-none-any.whl → 1.15.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ign-pdal-tools
3
- Version: 1.15.4
3
+ Version: 1.15.5
4
4
  Summary: Library for common LAS files manipulation with PDAL
5
5
  Author-email: Guillaume Liegard <guillaume.liegard@ign.fr>
6
6
  Description-Content-Type: text/markdown
@@ -1,5 +1,5 @@
1
- ign_pdal_tools-1.15.4.dist-info/licenses/LICENSE.md,sha256=iVzCFZTUXeiqP8bP474iuWZiWO_kDCD4SPh1Wiw125Y,1120
2
- pdaltools/_version.py,sha256=v1-P-Ov-24Bdx7-zaJ7QUAVXDpuCxPkaM1l4VOXLOSA,75
1
+ ign_pdal_tools-1.15.5.dist-info/licenses/LICENSE.md,sha256=iVzCFZTUXeiqP8bP474iuWZiWO_kDCD4SPh1Wiw125Y,1120
2
+ pdaltools/_version.py,sha256=PMKGb38n4U-Bt7iqMv25IaET5dM26eUnM9VEKomGNDI,75
3
3
  pdaltools/add_points_in_pointcloud.py,sha256=UJTwoOjC0WKnp_ynNHpwUh1fmbIgw7hq5xoNN8_FxQQ,12965
4
4
  pdaltools/color.py,sha256=s-_rmLK6fIK3UwkUzHVZPEkm6r1LliG5ftGr-jkqyjM,9549
5
5
  pdaltools/create_random_laz.py,sha256=XuHH4G8Nrs8DB-F8bkcIeto7JtmrlrNGF_R66oxGCbQ,6069
@@ -12,11 +12,11 @@ pdaltools/las_merge.py,sha256=tcFVueV9X9nNEaoAl5zCduY5DETlBg63MAgP2SuKiNo,4121
12
12
  pdaltools/las_remove_dimensions.py,sha256=f8imGhN6LNTuQ1GMJQRzIIV3Wab_oRPOyEnKi1CgfiM,2318
13
13
  pdaltools/las_rename_dimension.py,sha256=FEWIcq0ZZiv9xWbCLDRE9Hzb5K0YYfoi3Z8IZFEs-uU,2887
14
14
  pdaltools/pcd_info.py,sha256=NIAH5KGikVDQLlbCcw9FuaPqe20UZvRfkHsDZd5kmZA,3210
15
- pdaltools/replace_area_in_pointcloud.py,sha256=4JyWWDtPUqtzE3zMh7eHwjGAupLclvjxKg8ScgIC4-4,8714
15
+ pdaltools/replace_area_in_pointcloud.py,sha256=J3az8_Z7nNsGKqns9MNHrWRLc5yss7DKZvmYinlweEE,10539
16
16
  pdaltools/replace_attribute_in_las.py,sha256=MHpIizSupgWtbizteoRH8FKDE049hrAh4v_OhmRmSPU,4318
17
17
  pdaltools/standardize_format.py,sha256=I2oNiwhSMtr4e5ZK9qbB_yKmy3twOoO6QLiSFu4_AaI,3905
18
18
  pdaltools/unlock_file.py,sha256=G2odk0cpp_X9r49Y90oK88v3qlihaMfg6acwmWqblik,1958
19
- ign_pdal_tools-1.15.4.dist-info/METADATA,sha256=kBr1Y0CwOciH9Gjw4HxpYiYy5eQpcHqbSxQ_zXnZr3M,6146
20
- ign_pdal_tools-1.15.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
21
- ign_pdal_tools-1.15.4.dist-info/top_level.txt,sha256=KvGW0ZzqQbhCKzB5_Tp_buWMZyIgiO2M2krWF_ecOZc,10
22
- ign_pdal_tools-1.15.4.dist-info/RECORD,,
19
+ ign_pdal_tools-1.15.5.dist-info/METADATA,sha256=6L_lOss5aYUBg8p3MAZNH2_xyaZpwidS9yCms9CCzcA,6146
20
+ ign_pdal_tools-1.15.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
21
+ ign_pdal_tools-1.15.5.dist-info/top_level.txt,sha256=KvGW0ZzqQbhCKzB5_Tp_buWMZyIgiO2M2krWF_ecOZc,10
22
+ ign_pdal_tools-1.15.5.dist-info/RECORD,,
pdaltools/_version.py CHANGED
@@ -1,4 +1,4 @@
1
- __version__ = "1.15.4"
1
+ __version__ = "1.15.5"
2
2
 
3
3
 
4
4
  if __name__ == "__main__":
@@ -1,12 +1,22 @@
1
1
  import argparse
2
+ import os
3
+ import shutil
4
+ import tempfile
5
+ import time
2
6
  import warnings
3
7
 
8
+ import geopandas as gpd
4
9
  import numpy as np
5
10
  import pdal
6
11
  from numpy.lib import recfunctions as rfn
7
12
  from osgeo import gdal
13
+ from shapely.geometry import box
8
14
 
9
- from pdaltools.las_info import get_writer_parameters_from_reader_metadata
15
+ from pdaltools.las_info import (
16
+ get_bounds_from_header_info,
17
+ get_writer_parameters_from_reader_metadata,
18
+ las_info_metadata,
19
+ )
10
20
 
11
21
 
12
22
  def argument_parser():
@@ -139,6 +149,18 @@ def pipeline_read_from_DSM(dsm, ground_mask, classification):
139
149
  return pipeline
140
150
 
141
151
 
152
+ def clip_area(area_input, area_output, las_file):
153
+ start = time.time()
154
+ gdf = gpd.read_file(area_input)
155
+ minx, maxx, miny, maxy = get_bounds_from_header_info(las_info_metadata(las_file))
156
+ selection = gdf[gdf.intersects(box(minx, miny, maxx, maxy))]
157
+ num_polygon = len(selection)
158
+ selection.to_file(area_output)
159
+ end = time.time()
160
+ print(f"Create replacement area cropped: {num_polygon} polygons in {end-start:.2f} seconds")
161
+ return num_polygon
162
+
163
+
142
164
  def replace_area(
143
165
  target_cloud, pipeline_source, replacement_area, output_cloud, source_pdal_filter="", target_pdal_filter=""
144
166
  ):
@@ -147,6 +169,24 @@ def replace_area(
147
169
  print("output cloud: ", output_cloud)
148
170
  print("source pdal filter: ", source_pdal_filter)
149
171
  print("target pdal filter: ", target_pdal_filter)
172
+
173
+ start = time.time()
174
+ tmpdir = tempfile.mkdtemp()
175
+ replacement_name, ext = os.path.splitext(os.path.basename(replacement_area))
176
+ las_name, _ = os.path.splitext(os.path.basename(target_cloud))
177
+ replacement_area_crop = os.path.join(tmpdir, f"{replacement_name}_{las_name}{ext}")
178
+ print("replacement area crop: ", replacement_area_crop)
179
+
180
+ num_polygon = clip_area(replacement_area, replacement_area_crop, target_cloud)
181
+ if num_polygon == 0:
182
+ print("No polygon inside target cloud, output file is target cloud. We copy target in output.")
183
+
184
+ shutil.copy2(src=target_cloud, dst=output_cloud)
185
+ end = time.time()
186
+ print("all steps done in ", f"{end-start:.2f}", " seconds")
187
+ return
188
+
189
+ replacement_area = replacement_area_crop
150
190
  crops = []
151
191
  # pipeline to read target_cloud and remove points inside the polygon
152
192
  pipeline_target = pdal.Pipeline()
@@ -160,7 +200,9 @@ def replace_area(
160
200
  # Keep only points out of the area
161
201
  pipeline_target |= pdal.Filter.expression(expression="geometryFid==-1", tag="A")
162
202
  target_count = pipeline_target.execute()
163
- print("Step 1: target count: ", target_count)
203
+
204
+ t1 = time.time()
205
+ print(f"Step 1: target count: {target_count} points in {t1-start:.2f} seconds")
164
206
 
165
207
  # get input dimensions dtype from target
166
208
  if pipeline_target.arrays:
@@ -171,7 +213,10 @@ def replace_area(
171
213
  pipeline_target2 |= pdal.Reader.las(filename=target_cloud)
172
214
  pipeline_target2.execute()
173
215
  input_dim_dtype = pipeline_target2.arrays[0].dtype
216
+ t1_bis = time.time()
217
+ print(f"Step 1-bis: re-read to have dimensions: {t1_bis-t1:.2f} seconds")
174
218
 
219
+ t2 = time.time()
175
220
  # get input dimensions names
176
221
  input_dimensions = list(input_dim_dtype.fields.keys())
177
222
 
@@ -179,7 +224,7 @@ def replace_area(
179
224
  output_dimensions = [dim for dim in input_dimensions if dim not in "geometryFid"]
180
225
 
181
226
  # add target to the result after keeping only the expected dimensions
182
- if pipeline_target.arrays:
227
+ if target_count:
183
228
  target_cloud_pruned = pipeline_target.arrays[0][output_dimensions]
184
229
  crops.append(target_cloud_pruned)
185
230
 
@@ -192,7 +237,9 @@ def replace_area(
192
237
  # Keep only points in the area
193
238
  pipeline_source |= pdal.Filter.expression(expression="geometryFid>=0", tag="B")
194
239
  source_count = pipeline_source.execute()
195
- print("Step 2: source count: ", source_count)
240
+
241
+ t3 = time.time()
242
+ print(f"Step 2: source count: {source_count} points in {t3-t2:.2f} seconds")
196
243
 
197
244
  # add source to the result
198
245
  if source_count:
@@ -221,7 +268,11 @@ def replace_area(
221
268
 
222
269
  writer_params = get_writer_params(target_cloud)
223
270
  pipeline |= pdal.Writer.las(filename=output_cloud, **writer_params)
224
- pipeline.execute()
271
+ points = pipeline.execute()
272
+
273
+ end = time.time()
274
+ print(f"Step 3: merge: { points }, points in {end-t3:.2f} seconds")
275
+ print("all steps done in ", f"{end-start:.2f}", " seconds")
225
276
 
226
277
 
227
278
  if __name__ == "__main__":