ign-pdal-tools 1.7.5__py3-none-any.whl → 1.7.6__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
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: ign-pdal-tools
3
- Version: 1.7.5
3
+ Version: 1.7.6
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,6 @@
1
- pdaltools/_version.py,sha256=Jr3d2rnNzq-ZLSjZiEMdSSozTrU6AhKJLKOvXK3-0H0,74
1
+ pdaltools/_version.py,sha256=J51Tb9gFrrvFgU9fo3qbvKaTCWayFmNsRBrzb6HjUIM,74
2
2
  pdaltools/add_points_in_las.py,sha256=TGbt5JUkszjmbQiA2LCUntsjz6A8DHb7QPIXGDuEgWA,3643
3
+ pdaltools/add_points_in_pointcloud.py,sha256=W_b1eBjPPyUO20aHj8BkFgL0qNnkBs7qNnp1fGJ68JA,3725
3
4
  pdaltools/color.py,sha256=PSdtMMdsapOtgzojdnaKVx6IxbKOaN2xP9mScAbCGm0,8629
4
5
  pdaltools/las_add_buffer.py,sha256=sBpTywlfsHHS8KuCUa-eydB2hylshEvjrMQt5TrqXb8,11275
5
6
  pdaltools/las_clip.py,sha256=GvEOYu8RXV68e35kU8i42GwSkbo4P9TvmS6rkrdPmFM,1034
@@ -10,8 +11,8 @@ pdaltools/pcd_info.py,sha256=NIAH5KGikVDQLlbCcw9FuaPqe20UZvRfkHsDZd5kmZA,3210
10
11
  pdaltools/replace_attribute_in_las.py,sha256=po1F-fi8s7iilqKWaryW4JRbsmdMOUe0yGvG3AEKxtk,4771
11
12
  pdaltools/standardize_format.py,sha256=gqm2GJbtDkT4k4oC_NX2LIPh9R2BLh4sMHLKYgfKrMc,3973
12
13
  pdaltools/unlock_file.py,sha256=pIThdWMNkTph0xgJVVRaM1o9aUMQhM6804PscScB3JI,1963
13
- ign_pdal_tools-1.7.5.dist-info/LICENSE.md,sha256=iVzCFZTUXeiqP8bP474iuWZiWO_kDCD4SPh1Wiw125Y,1120
14
- ign_pdal_tools-1.7.5.dist-info/METADATA,sha256=EqDhgZ2NEpoOr7Whk2RefX9emt_M05l7MGotTplcgkE,5722
15
- ign_pdal_tools-1.7.5.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
16
- ign_pdal_tools-1.7.5.dist-info/top_level.txt,sha256=KvGW0ZzqQbhCKzB5_Tp_buWMZyIgiO2M2krWF_ecOZc,10
17
- ign_pdal_tools-1.7.5.dist-info/RECORD,,
14
+ ign_pdal_tools-1.7.6.dist-info/LICENSE.md,sha256=iVzCFZTUXeiqP8bP474iuWZiWO_kDCD4SPh1Wiw125Y,1120
15
+ ign_pdal_tools-1.7.6.dist-info/METADATA,sha256=CwwZbRIegxl51Mi-0WP2_UEmARo7IBVdJf1eRxxT2bM,5722
16
+ ign_pdal_tools-1.7.6.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
17
+ ign_pdal_tools-1.7.6.dist-info/top_level.txt,sha256=KvGW0ZzqQbhCKzB5_Tp_buWMZyIgiO2M2krWF_ecOZc,10
18
+ ign_pdal_tools-1.7.6.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.6.0)
2
+ Generator: setuptools (75.8.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
pdaltools/_version.py CHANGED
@@ -1,4 +1,4 @@
1
- __version__ = "1.7.5"
1
+ __version__ = "1.7.6"
2
2
 
3
3
 
4
4
  if __name__ == "__main__":
@@ -0,0 +1,102 @@
1
+ import geopandas as gpd
2
+ import laspy
3
+ import numpy as np
4
+ from shapely.geometry import box
5
+
6
+ from pdaltools.las_info import get_tile_origin_using_header_info
7
+
8
+
9
+ def get_tile_bbox(input_las, tile_width=1000) -> tuple:
10
+ """
11
+ Get the theoretical bounding box (xmin, ymin, xmax, ymax) of a LIDAR tile
12
+ using its origin and the predefined tile width.
13
+
14
+ Args:
15
+ input_las (str): Path to the LIDAR `.las/.laz` file.
16
+ tile_width (int): Width of the tile in meters (default: 1000).
17
+
18
+ Returns:
19
+ tuple: Bounding box as (xmin, ymin, xmax, ymax).
20
+ """
21
+ origin_x, origin_y = get_tile_origin_using_header_info(input_las)
22
+ bbox = (origin_x, origin_y - tile_width, origin_x + tile_width, origin_y)
23
+ return bbox
24
+
25
+
26
+ def clip_3d_points_to_tile(input_points: str, input_las: str, crs: str) -> gpd.GeoDataFrame:
27
+ """
28
+ Add points from a GeoJSON file in the LIDAR's tile.
29
+
30
+ Args:
31
+ input_points (str): Path to the input GeoJSON file with 3D points.
32
+ input_las (str): Path to the LIDAR `.las/.laz` file.
33
+ crs (str): CRS of the data, e.g., 'EPSG:2154'.
34
+
35
+ Return:
36
+ gpd.GeoDataFrame: Points 2d with "Z" value
37
+ """
38
+ # Compute the bounding box of the LIDAR tile
39
+ tile_bbox = get_tile_bbox(input_las)
40
+
41
+ # Read the input GeoJSON with 3D points
42
+ points_gdf = gpd.read_file(input_points)
43
+
44
+ # Ensure the CRS matches
45
+ if crs:
46
+ points_gdf = points_gdf.to_crs(crs)
47
+
48
+ # Create a polygon from the bounding box
49
+ bbox_polygon = box(*tile_bbox)
50
+
51
+ # Clip the points to the bounding box
52
+ clipped_points = points_gdf[points_gdf.intersects(bbox_polygon)].copy()
53
+
54
+ return clipped_points
55
+
56
+
57
+ def add_points_to_las(
58
+ input_points_with_z: gpd.GeoDataFrame, input_las: str, output_las: str, virtual_points_classes=66
59
+ ):
60
+ """Add points (3D points in LAZ format) by LIDAR tiles (tiling file)
61
+
62
+ Args:
63
+ input_points_with_z(gpd.GeoDataFrame): geometry columns (2D points) as encoded to WKT.
64
+ input_las (str): Path to the LIDAR tiles (LAZ).
65
+ output_las (str): Path to save the updated LIDAR file (LAS/LAZ format).
66
+ virtual_points_classes (int): The classification value to assign to those virtual points (default: 66).
67
+ """
68
+ # Check if input points are empty
69
+ if input_points_with_z.empty:
70
+ raise ValueError("No points to add. The input GeoDataFrame is empty.")
71
+
72
+ # Extract XYZ coordinates and additional attribute (classification)
73
+ x_coords = input_points_with_z.geometry.x
74
+ y_coords = input_points_with_z.geometry.y
75
+ z_coords = input_points_with_z.RecupZ
76
+ classes = virtual_points_classes * np.ones(len(input_points_with_z.index))
77
+
78
+ # Read the existing LIDAR file
79
+ with laspy.open(input_las, mode="r") as las:
80
+ las_data = las.read()
81
+ header = las.header
82
+
83
+ # Create a new header if the original header is missing or invalid
84
+ if header is None:
85
+ header = laspy.LasHeader(point_format=6, version="1.4") # Example format and version
86
+
87
+ # Append the clipped points to the existing LIDAR data
88
+ new_x = np.concatenate([las_data.x, x_coords])
89
+ new_y = np.concatenate([las_data.y, y_coords])
90
+ new_z = np.concatenate([las_data.z, z_coords])
91
+ new_classes = np.concatenate([las_data.classification, classes])
92
+
93
+ # Create a new LAS file with updated data
94
+ updated_las = laspy.LasData(header)
95
+ updated_las.x = new_x
96
+ updated_las.y = new_y
97
+ updated_las.z = new_z
98
+ updated_las.classification = new_classes
99
+
100
+ # Write the updated LAS file
101
+ with laspy.open(output_las, mode="w", header=header, do_compress=True) as writer:
102
+ writer.write_points(updated_las.points)