ign-pdal-tools 1.7.10__tar.gz → 1.7.11__tar.gz

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.
Files changed (34) hide show
  1. {ign_pdal_tools-1.7.10 → ign_pdal_tools-1.7.11}/PKG-INFO +1 -1
  2. {ign_pdal_tools-1.7.10 → ign_pdal_tools-1.7.11}/ign_pdal_tools.egg-info/PKG-INFO +1 -1
  3. {ign_pdal_tools-1.7.10 → ign_pdal_tools-1.7.11}/pdaltools/_version.py +1 -1
  4. {ign_pdal_tools-1.7.10 → ign_pdal_tools-1.7.11}/pdaltools/add_points_in_pointcloud.py +20 -22
  5. {ign_pdal_tools-1.7.10 → ign_pdal_tools-1.7.11}/test/test_add_points_in_pointcloud.py +36 -0
  6. {ign_pdal_tools-1.7.10 → ign_pdal_tools-1.7.11}/LICENSE.md +0 -0
  7. {ign_pdal_tools-1.7.10 → ign_pdal_tools-1.7.11}/README.md +0 -0
  8. {ign_pdal_tools-1.7.10 → ign_pdal_tools-1.7.11}/ign_pdal_tools.egg-info/SOURCES.txt +0 -0
  9. {ign_pdal_tools-1.7.10 → ign_pdal_tools-1.7.11}/ign_pdal_tools.egg-info/dependency_links.txt +0 -0
  10. {ign_pdal_tools-1.7.10 → ign_pdal_tools-1.7.11}/ign_pdal_tools.egg-info/top_level.txt +0 -0
  11. {ign_pdal_tools-1.7.10 → ign_pdal_tools-1.7.11}/pdaltools/add_points_in_las.py +0 -0
  12. {ign_pdal_tools-1.7.10 → ign_pdal_tools-1.7.11}/pdaltools/color.py +0 -0
  13. {ign_pdal_tools-1.7.10 → ign_pdal_tools-1.7.11}/pdaltools/las_add_buffer.py +0 -0
  14. {ign_pdal_tools-1.7.10 → ign_pdal_tools-1.7.11}/pdaltools/las_clip.py +0 -0
  15. {ign_pdal_tools-1.7.10 → ign_pdal_tools-1.7.11}/pdaltools/las_info.py +0 -0
  16. {ign_pdal_tools-1.7.10 → ign_pdal_tools-1.7.11}/pdaltools/las_merge.py +0 -0
  17. {ign_pdal_tools-1.7.10 → ign_pdal_tools-1.7.11}/pdaltools/las_remove_dimensions.py +0 -0
  18. {ign_pdal_tools-1.7.10 → ign_pdal_tools-1.7.11}/pdaltools/pcd_info.py +0 -0
  19. {ign_pdal_tools-1.7.10 → ign_pdal_tools-1.7.11}/pdaltools/replace_attribute_in_las.py +0 -0
  20. {ign_pdal_tools-1.7.10 → ign_pdal_tools-1.7.11}/pdaltools/standardize_format.py +0 -0
  21. {ign_pdal_tools-1.7.10 → ign_pdal_tools-1.7.11}/pdaltools/unlock_file.py +0 -0
  22. {ign_pdal_tools-1.7.10 → ign_pdal_tools-1.7.11}/pyproject.toml +0 -0
  23. {ign_pdal_tools-1.7.10 → ign_pdal_tools-1.7.11}/setup.cfg +0 -0
  24. {ign_pdal_tools-1.7.10 → ign_pdal_tools-1.7.11}/test/test_add_points_in_las.py +0 -0
  25. {ign_pdal_tools-1.7.10 → ign_pdal_tools-1.7.11}/test/test_color.py +0 -0
  26. {ign_pdal_tools-1.7.10 → ign_pdal_tools-1.7.11}/test/test_las_add_buffer.py +0 -0
  27. {ign_pdal_tools-1.7.10 → ign_pdal_tools-1.7.11}/test/test_las_clip.py +0 -0
  28. {ign_pdal_tools-1.7.10 → ign_pdal_tools-1.7.11}/test/test_las_info.py +0 -0
  29. {ign_pdal_tools-1.7.10 → ign_pdal_tools-1.7.11}/test/test_las_merge.py +0 -0
  30. {ign_pdal_tools-1.7.10 → ign_pdal_tools-1.7.11}/test/test_las_remove_dimensions.py +0 -0
  31. {ign_pdal_tools-1.7.10 → ign_pdal_tools-1.7.11}/test/test_pcd_info.py +0 -0
  32. {ign_pdal_tools-1.7.10 → ign_pdal_tools-1.7.11}/test/test_replace_attribute_in_las.py +0 -0
  33. {ign_pdal_tools-1.7.10 → ign_pdal_tools-1.7.11}/test/test_standardize_format.py +0 -0
  34. {ign_pdal_tools-1.7.10 → ign_pdal_tools-1.7.11}/test/test_unlock.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ign-pdal-tools
3
- Version: 1.7.10
3
+ Version: 1.7.11
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,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ign-pdal-tools
3
- Version: 1.7.10
3
+ Version: 1.7.11
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,4 +1,4 @@
1
- __version__ = "1.7.10"
1
+ __version__ = "1.7.11"
2
2
 
3
3
 
4
4
  if __name__ == "__main__":
@@ -1,5 +1,5 @@
1
1
  import argparse
2
- import shutil
2
+ from shutil import copy2
3
3
 
4
4
  import geopandas as gpd
5
5
  import laspy
@@ -127,25 +127,22 @@ def add_points_to_las(
127
127
  crs (str): CRS of the data.
128
128
  virtual_points_classes (int): The classification value to assign to those virtual points (default: 66).
129
129
  """
130
-
131
130
  if input_points_with_z.empty:
132
131
  print(
133
132
  "No points to add. All points of the geojson file are outside the tile. Copying the input file to output"
134
133
  )
135
- shutil.copy(input_las, output_las)
136
-
137
134
  return
138
135
 
139
136
  # Extract XYZ coordinates and additional attribute (classification)
137
+ nb_points = len(input_points_with_z.geometry.x)
140
138
  x_coords = input_points_with_z.geometry.x
141
139
  y_coords = input_points_with_z.geometry.y
142
140
  z_coords = input_points_with_z.geometry.z
143
- classes = virtual_points_classes * np.ones(len(input_points_with_z.index))
141
+ classes = virtual_points_classes * np.ones(nb_points)
144
142
 
145
- with laspy.open(input_las, mode="r") as las:
146
- las_data = las.read()
143
+ # Open the input LAS file to check and possibly update the header of the output
144
+ with laspy.open(input_las) as las:
147
145
  header = las.header
148
-
149
146
  if not header:
150
147
  header = laspy.LasHeader(point_format=8, version="1.4")
151
148
  if crs:
@@ -155,20 +152,21 @@ def add_points_to_las(
155
152
  raise ValueError(f"Invalid CRS: {crs}")
156
153
  header.add_crs(crs_obj)
157
154
 
158
- # Append new points
159
- new_x = np.concatenate([las_data.x, x_coords])
160
- new_y = np.concatenate([las_data.y, y_coords])
161
- new_z = np.concatenate([las_data.z, z_coords])
162
- new_classes = np.concatenate([las_data.classification, classes])
163
-
164
- updated_las = laspy.LasData(header)
165
- updated_las.x = new_x
166
- updated_las.y = new_y
167
- updated_las.z = new_z
168
- updated_las.classification = new_classes
169
-
170
- with laspy.open(output_las, mode="w", header=header, do_compress=True) as writer:
171
- writer.write_points(updated_las.points)
155
+ # Copy data pointcloud
156
+ copy2(input_las, output_las)
157
+
158
+ # Add the new points with 3D points
159
+ nb_points = len(x_coords)
160
+ with laspy.open(output_las, mode="a", header=header) as output_las: # mode `a` for adding points
161
+ # create nb_points points with "0" everywhere
162
+ new_points = laspy.ScaleAwarePointRecord.zeros(nb_points, header=header) # use header for input_las
163
+ # then fill in the gaps (X, Y, Z an classification)
164
+ new_points.x = x_coords.astype(new_points.x.dtype)
165
+ new_points.y = y_coords.astype(new_points.y.dtype)
166
+ new_points.z = z_coords.astype(new_points.z.dtype)
167
+ new_points.classification = classes.astype(new_points.classification.dtype)
168
+
169
+ output_las.append_points(new_points)
172
170
 
173
171
 
174
172
  def line_to_multipoint(line, spacing: float, z_value: float = None):
@@ -3,6 +3,8 @@ import os
3
3
  from pathlib import Path
4
4
 
5
5
  import geopandas as gpd
6
+ import laspy
7
+ import numpy as np
6
8
  import pytest
7
9
  from shapely.geometry import LineString, MultiPoint, Point
8
10
 
@@ -98,6 +100,40 @@ def test_add_points_to_las(input_file, epsg, expected_nb_points):
98
100
  point_count = compute_count_one_file(OUTPUT_FILE)["68"]
99
101
  assert point_count == expected_nb_points # Add all points from geojson
100
102
 
103
+ # Read original and updated point clouds
104
+ original_las = laspy.read(input_file)
105
+ updated_las = laspy.read(OUTPUT_FILE)
106
+
107
+ original_count = len(original_las.points)
108
+ added_count = len(points)
109
+
110
+ # Check total point count
111
+ assert len(updated_las.points) == original_count + added_count
112
+
113
+ default_zero_fields = [
114
+ "gps_time",
115
+ "intensity",
116
+ "return_number",
117
+ "number_of_returns",
118
+ "scan_direction_flag",
119
+ "edge_of_flight_line",
120
+ "R",
121
+ "G",
122
+ "B",
123
+ ]
124
+ # Ensure original points retain their values (gps_tme, intensity, etc)
125
+ for field in default_zero_fields:
126
+ if hasattr(updated_las, field):
127
+ values = getattr(updated_las, field)
128
+ original_values = getattr(original_las, field)
129
+ assert np.all(values[:original_count] == original_values[:original_count])
130
+
131
+ # Ensure added points have zero values for gps_time, intensity, etc
132
+ for field in default_zero_fields:
133
+ if hasattr(updated_las, field):
134
+ values = getattr(updated_las, field)
135
+ assert np.all(values[original_count:] == 0)
136
+
101
137
 
102
138
  @pytest.mark.parametrize(
103
139
  "line, spacing, z_value, expected_points",