ign-pdal-tools 1.10.0__py3-none-any.whl → 1.12.0__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.
- {ign_pdal_tools-1.10.0.dist-info → ign_pdal_tools-1.12.0.dist-info}/METADATA +1 -1
- ign_pdal_tools-1.12.0.dist-info/RECORD +20 -0
- {ign_pdal_tools-1.10.0.dist-info → ign_pdal_tools-1.12.0.dist-info}/WHEEL +1 -1
- pdaltools/_version.py +1 -1
- pdaltools/add_points_in_pointcloud.py +5 -5
- pdaltools/create_random_laz.py +146 -0
- pdaltools/las_comparison.py +105 -0
- pdaltools/las_rename_dimension.py +11 -11
- pdaltools/standardize_format.py +43 -13
- ign_pdal_tools-1.10.0.dist-info/RECORD +0 -18
- {ign_pdal_tools-1.10.0.dist-info → ign_pdal_tools-1.12.0.dist-info}/licenses/LICENSE.md +0 -0
- {ign_pdal_tools-1.10.0.dist-info → ign_pdal_tools-1.12.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
ign_pdal_tools-1.12.0.dist-info/licenses/LICENSE.md,sha256=iVzCFZTUXeiqP8bP474iuWZiWO_kDCD4SPh1Wiw125Y,1120
|
|
2
|
+
pdaltools/_version.py,sha256=uuG85nhWU5wpaYiHuTFYsaS18txZLNqRwMOK8z2G96k,75
|
|
3
|
+
pdaltools/add_points_in_pointcloud.py,sha256=6NclQeAFYyVz3kfJ114BEFKfM5nwWWC2c8iN4IpaPOc,12662
|
|
4
|
+
pdaltools/color.py,sha256=vJgpb8dOvT5rnq5NdVOaMdGc_pKL3damLy4HwGvigJQ,14472
|
|
5
|
+
pdaltools/create_random_laz.py,sha256=RxRzMGZ33xoomu4eh-cLSj4tj5Gy41rBzk08lAKHHzg,5726
|
|
6
|
+
pdaltools/las_add_buffer.py,sha256=rnFExAfi0KqlQpL4hDMh2aC08AcYdSHSB6WPG5RyFIc,11274
|
|
7
|
+
pdaltools/las_clip.py,sha256=GvEOYu8RXV68e35kU8i42GwSkbo4P9TvmS6rkrdPmFM,1034
|
|
8
|
+
pdaltools/las_comparison.py,sha256=pq0fa_kOkysPBBYNNcGg9FFyRLT6IANdPjaGwQALwVU,4193
|
|
9
|
+
pdaltools/las_info.py,sha256=lMKxKzsViptDENI1wOlANG4qOvdc19ixyasYKD-N1ck,9512
|
|
10
|
+
pdaltools/las_merge.py,sha256=tcFVueV9X9nNEaoAl5zCduY5DETlBg63MAgP2SuKiNo,4121
|
|
11
|
+
pdaltools/las_remove_dimensions.py,sha256=f8imGhN6LNTuQ1GMJQRzIIV3Wab_oRPOyEnKi1CgfiM,2318
|
|
12
|
+
pdaltools/las_rename_dimension.py,sha256=zXEKHyx1uQ3U0oZYo_BTnqbTHGSq5TIZHqZn_EPqNKQ,2576
|
|
13
|
+
pdaltools/pcd_info.py,sha256=NIAH5KGikVDQLlbCcw9FuaPqe20UZvRfkHsDZd5kmZA,3210
|
|
14
|
+
pdaltools/replace_attribute_in_las.py,sha256=po1F-fi8s7iilqKWaryW4JRbsmdMOUe0yGvG3AEKxtk,4771
|
|
15
|
+
pdaltools/standardize_format.py,sha256=Z09yhY_dRaX0uNO0K_Ml5ZD3XpVDv4Q2gIyZHXaplAQ,4849
|
|
16
|
+
pdaltools/unlock_file.py,sha256=G2odk0cpp_X9r49Y90oK88v3qlihaMfg6acwmWqblik,1958
|
|
17
|
+
ign_pdal_tools-1.12.0.dist-info/METADATA,sha256=UAKzHKeQ_jlZB_uwlRWWfeV2vJO1HVEXvIfMu7om554,5778
|
|
18
|
+
ign_pdal_tools-1.12.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
19
|
+
ign_pdal_tools-1.12.0.dist-info/top_level.txt,sha256=KvGW0ZzqQbhCKzB5_Tp_buWMZyIgiO2M2krWF_ecOZc,10
|
|
20
|
+
ign_pdal_tools-1.12.0.dist-info/RECORD,,
|
pdaltools/_version.py
CHANGED
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
import argparse
|
|
2
|
-
from shutil import copy2
|
|
3
2
|
import tempfile
|
|
3
|
+
from shutil import copy2
|
|
4
4
|
|
|
5
5
|
import geopandas as gpd
|
|
6
6
|
import laspy
|
|
7
7
|
import numpy as np
|
|
8
|
-
|
|
9
|
-
from pyproj.exceptions import CRSError
|
|
8
|
+
import pdal
|
|
10
9
|
from shapely.geometry import MultiPoint, Point, box
|
|
11
10
|
|
|
12
11
|
from pdaltools.las_info import get_epsg_from_las, get_tile_bbox
|
|
13
12
|
|
|
14
|
-
import pdal
|
|
15
|
-
|
|
16
13
|
|
|
17
14
|
def parse_args(argv=None):
|
|
18
15
|
parser = argparse.ArgumentParser("Add points from GeoJSON in LIDAR tile")
|
|
@@ -223,6 +220,9 @@ def generate_3d_points_from_lines(
|
|
|
223
220
|
and Z coordinates are not available in the geometry.
|
|
224
221
|
"""
|
|
225
222
|
# Check if altitude_column is provided and exists in the GeoDataFrame
|
|
223
|
+
if lines_gdf.empty:
|
|
224
|
+
return lines_gdf
|
|
225
|
+
|
|
226
226
|
if altitude_column and (altitude_column not in lines_gdf.columns):
|
|
227
227
|
raise ValueError("altitude_column must exist in the GeoDataFrame if provided.")
|
|
228
228
|
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import laspy
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
import sys
|
|
5
|
+
import argparse
|
|
6
|
+
import pdal
|
|
7
|
+
from pyproj import CRS
|
|
8
|
+
from typing import List, Tuple, Union
|
|
9
|
+
|
|
10
|
+
def create_random_laz(output_file: str, point_format: int = 3, num_points: int = 100, crs: int = 2154,
|
|
11
|
+
center: Tuple[float, float] = (650000, 6810000),
|
|
12
|
+
extra_dims: List[Tuple[str, str]] = [],
|
|
13
|
+
):
|
|
14
|
+
"""
|
|
15
|
+
Create a test LAZ file with EPSG code and additional dimensions.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
output_file: Path to save the LAZ file
|
|
19
|
+
point_format: Point format of the LAZ file (default: 3)
|
|
20
|
+
num_points: Number of points to generate
|
|
21
|
+
crs: EPSG code of the CRS (default: 2154)
|
|
22
|
+
center: Tuple of floats (x, y) of the center of the area to generate points in (default: (650000, 6810000) ; around Paris)
|
|
23
|
+
extra_dims: List of tuples (dimension_name, dimension_type) where type can be:
|
|
24
|
+
'float32', 'float64', 'int8', 'int16', 'int32', 'int64', 'uint8', 'uint16', 'uint32', 'uint64'
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
# Create a new point cloud
|
|
28
|
+
header = laspy.LasHeader(point_format=point_format, version="1.4")
|
|
29
|
+
|
|
30
|
+
# Map string types to numpy types
|
|
31
|
+
type_mapping = {
|
|
32
|
+
'float32': np.float32,
|
|
33
|
+
'float64': np.float64,
|
|
34
|
+
'int8': np.int8,
|
|
35
|
+
'int16': np.int16,
|
|
36
|
+
'int32': np.int32,
|
|
37
|
+
'int64': np.int64,
|
|
38
|
+
'uint8': np.uint8,
|
|
39
|
+
'uint16': np.uint16,
|
|
40
|
+
'uint32': np.uint32,
|
|
41
|
+
'uint64': np.uint64,
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
for dim_name, dim_type in extra_dims:
|
|
45
|
+
if dim_type not in type_mapping:
|
|
46
|
+
raise ValueError(f"Unsupported dimension type: {dim_type}. Supported types: {list(type_mapping.keys())}")
|
|
47
|
+
|
|
48
|
+
numpy_type = type_mapping[dim_type]
|
|
49
|
+
header.add_extra_dim(laspy.ExtraBytesParams(name=dim_name, type=numpy_type))
|
|
50
|
+
|
|
51
|
+
# Create point cloud
|
|
52
|
+
las = laspy.LasData(header)
|
|
53
|
+
las.header.add_crs(CRS.from_string(f"epsg:{crs}"))
|
|
54
|
+
|
|
55
|
+
# Generate random points in a small area
|
|
56
|
+
las.x = np.random.uniform(center[0] - 1000, center[0] + 1000, num_points)
|
|
57
|
+
las.y = np.random.uniform(center[1] - 1000, center[1] + 1000, num_points)
|
|
58
|
+
las.z = np.random.uniform(0, 200, num_points)
|
|
59
|
+
|
|
60
|
+
# Generate random intensity values
|
|
61
|
+
las.intensity = np.random.randint(0, 255, num_points)
|
|
62
|
+
|
|
63
|
+
# Generate random classification values
|
|
64
|
+
# 66 is the max value for classification of IGN LidarHD
|
|
65
|
+
# cf. https://geoservices.ign.fr/sites/default/files/2022-05/DT_LiDAR_HD_1-0.pdf
|
|
66
|
+
if point_format > 3:
|
|
67
|
+
num_classifications = 66
|
|
68
|
+
else:
|
|
69
|
+
num_classifications = 10
|
|
70
|
+
las.classification = np.random.randint(0, num_classifications, num_points)
|
|
71
|
+
|
|
72
|
+
# Generate random values for each extra dimension
|
|
73
|
+
for dim_name, dim_type in extra_dims:
|
|
74
|
+
numpy_type = type_mapping[dim_type]
|
|
75
|
+
|
|
76
|
+
# Generate appropriate random values based on the type
|
|
77
|
+
if numpy_type in [np.float32, np.float64]:
|
|
78
|
+
las[dim_name] = np.random.uniform(0, 10, num_points).astype(numpy_type)
|
|
79
|
+
elif numpy_type in [np.int8, np.int16, np.int32, np.int64]:
|
|
80
|
+
las[dim_name] = np.random.randint(-100, 100, num_points).astype(numpy_type)
|
|
81
|
+
elif numpy_type in [np.uint8, np.uint16, np.uint32, np.uint64]:
|
|
82
|
+
las[dim_name] = np.random.randint(0, 100, num_points).astype(numpy_type)
|
|
83
|
+
|
|
84
|
+
# Write to file
|
|
85
|
+
las.write(output_file)
|
|
86
|
+
dimensions = list(las.point_format.dimension_names)
|
|
87
|
+
return {
|
|
88
|
+
"output_file": output_file,
|
|
89
|
+
"num_points": num_points,
|
|
90
|
+
"dimensions": dimensions,
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def test_output_file(result : dict, output_file: str):
|
|
95
|
+
|
|
96
|
+
# Validate output file path
|
|
97
|
+
output_path = Path(output_file)
|
|
98
|
+
if not output_path.exists():
|
|
99
|
+
raise ValueError(f"Error: Output file {output_file} does not exist")
|
|
100
|
+
|
|
101
|
+
# Print results
|
|
102
|
+
print(f"Successfully created test LAZ file at {result['output_file']}")
|
|
103
|
+
print(f"Number of points: {result['num_points']}")
|
|
104
|
+
print(f"Dimensions available: {result['dimensions']}")
|
|
105
|
+
|
|
106
|
+
# Print available dimensions using PDAL
|
|
107
|
+
pipeline = pdal.Pipeline() | pdal.Reader.las(result['output_file'])
|
|
108
|
+
pipeline.execute()
|
|
109
|
+
points = pipeline.arrays[0]
|
|
110
|
+
dimensions = list(points.dtype.fields.keys())
|
|
111
|
+
print("\nAvailable dimensions in input file:")
|
|
112
|
+
for dim in dimensions:
|
|
113
|
+
print(f"- {dim}")
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def parse_args():
|
|
117
|
+
# Parse arguments (assuming argparse is used)
|
|
118
|
+
parser = argparse.ArgumentParser(description="Create a random LAZ file.")
|
|
119
|
+
parser.add_argument("--output_file", type=str, help="Path to save the LAZ file")
|
|
120
|
+
parser.add_argument("--point_format", type=int, default=3, help="Point format of the LAZ file")
|
|
121
|
+
parser.add_argument("--num_points", type=int, default=100, help="Number of points to generate")
|
|
122
|
+
parser.add_argument("--extra_dims", type=str, nargs="*", default=[], help="Extra dimensions in the format name:type")
|
|
123
|
+
parser.add_argument("--crs", type=int, default=2154, help="Projection code")
|
|
124
|
+
parser.add_argument("--center", type=str, default="650000,6810000", help="Center of the area to generate points in")
|
|
125
|
+
return parser.parse_args()
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def main():
|
|
129
|
+
|
|
130
|
+
# Parse arguments
|
|
131
|
+
args = parse_args()
|
|
132
|
+
|
|
133
|
+
# Parse extra dimensions
|
|
134
|
+
extra_dims = [tuple(dim.split(":")) for dim in args.extra_dims]
|
|
135
|
+
|
|
136
|
+
# Parse center
|
|
137
|
+
center = tuple(map(float, args.center.split(",")))
|
|
138
|
+
|
|
139
|
+
# Call create_random_laz
|
|
140
|
+
result = create_random_laz(args.output_file, args.point_format, args.num_points, args.crs, center, extra_dims)
|
|
141
|
+
|
|
142
|
+
# Test output file
|
|
143
|
+
test_output_file(result, args.output_file)
|
|
144
|
+
|
|
145
|
+
if __name__ == "__main__":
|
|
146
|
+
main()
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import laspy
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
import numpy as np
|
|
4
|
+
import argparse
|
|
5
|
+
|
|
6
|
+
def compare_las_dimensions(file1: Path, file2: Path, dimensions: list = None) -> bool:
|
|
7
|
+
"""
|
|
8
|
+
Compare specified dimensions between two LAS files.
|
|
9
|
+
If no dimensions are specified, compares all available dimensions.
|
|
10
|
+
Sorts points by x,y,z,gps_time coordinates before comparison to ensure point order consistency.
|
|
11
|
+
|
|
12
|
+
Args:
|
|
13
|
+
file1: Path to the first LAS file
|
|
14
|
+
file2: Path to the second LAS file
|
|
15
|
+
dimensions: List of dimension names to compare (optional)
|
|
16
|
+
|
|
17
|
+
Returns:
|
|
18
|
+
bool: True if all specified dimensions are identical, False otherwise
|
|
19
|
+
"""
|
|
20
|
+
try:
|
|
21
|
+
# Read both LAS files
|
|
22
|
+
las1 = laspy.read(file1)
|
|
23
|
+
las2 = laspy.read(file2)
|
|
24
|
+
|
|
25
|
+
# Check if files have the same number of points
|
|
26
|
+
if len(las1) != len(las2):
|
|
27
|
+
print(f"Files have different number of points: {len(las1)} vs {len(las2)}")
|
|
28
|
+
return False
|
|
29
|
+
|
|
30
|
+
# Sort points by x,y,z,gps_time coordinates
|
|
31
|
+
# Create sorting indices
|
|
32
|
+
sort_idx1 = np.lexsort((las1.z, las1.y, las1.x, las1.gps_time))
|
|
33
|
+
sort_idx2 = np.lexsort((las2.z, las2.y, las2.x, las2.gps_time))
|
|
34
|
+
|
|
35
|
+
# If no dimensions specified, compare all dimensions
|
|
36
|
+
dimensions_las1 = sorted(las1.point_format.dimension_names)
|
|
37
|
+
dimensions_las2 = sorted(las2.point_format.dimension_names)
|
|
38
|
+
|
|
39
|
+
if dimensions is None:
|
|
40
|
+
if dimensions_las1 != dimensions_las2:
|
|
41
|
+
print("Files have different dimensions")
|
|
42
|
+
return False
|
|
43
|
+
dimensions = dimensions_las1
|
|
44
|
+
else:
|
|
45
|
+
for dim in dimensions:
|
|
46
|
+
if dim not in dimensions_las1 or dim not in dimensions_las2:
|
|
47
|
+
print(f"Dimension '{dim}' is not found in one or both files. Available dimensions: {las1.point_format.dimension_names}")
|
|
48
|
+
return False
|
|
49
|
+
|
|
50
|
+
# Compare each dimension
|
|
51
|
+
for dim in dimensions:
|
|
52
|
+
try:
|
|
53
|
+
# Get sorted dimension arrays
|
|
54
|
+
dim1 = np.array(las1[dim])[sort_idx1]
|
|
55
|
+
dim2 = np.array(las2[dim])[sort_idx2]
|
|
56
|
+
|
|
57
|
+
# Compare dimensions
|
|
58
|
+
if not np.array_equal(dim1, dim2):
|
|
59
|
+
# Find differences
|
|
60
|
+
diff_indices = np.where(dim1 != dim2)[0]
|
|
61
|
+
print(f"Found {len(diff_indices)} points with different {dim}:")
|
|
62
|
+
for idx in diff_indices[:10]: # Show first 10 differences
|
|
63
|
+
print(f"Point {idx}: file1={dim1[idx]}, file2={dim2[idx]}")
|
|
64
|
+
if len(diff_indices) > 10:
|
|
65
|
+
print(f"... and {len(diff_indices) - 10} more differences")
|
|
66
|
+
return False
|
|
67
|
+
|
|
68
|
+
except KeyError:
|
|
69
|
+
print(f"Dimension '{dim}' not found in one or both files")
|
|
70
|
+
return False
|
|
71
|
+
|
|
72
|
+
return True
|
|
73
|
+
|
|
74
|
+
except laspy.errors.LaspyException as e:
|
|
75
|
+
print(f"LAS file error: {str(e)}")
|
|
76
|
+
return False
|
|
77
|
+
except FileNotFoundError as e:
|
|
78
|
+
print(f"File not found: {str(e)}")
|
|
79
|
+
return False
|
|
80
|
+
except ValueError as e:
|
|
81
|
+
print(f"Value error: {str(e)}")
|
|
82
|
+
return False
|
|
83
|
+
|
|
84
|
+
# Update main function to use the new compare function
|
|
85
|
+
def main():
|
|
86
|
+
parser = argparse.ArgumentParser(description='Compare dimensions between two LAS files')
|
|
87
|
+
parser.add_argument('file1', type=str, help='Path to first LAS file')
|
|
88
|
+
parser.add_argument('file2', type=str, help='Path to second LAS file')
|
|
89
|
+
parser.add_argument('--dimensions', nargs='*', help='List of dimensions to compare. If not specified, compares all dimensions.')
|
|
90
|
+
|
|
91
|
+
args = parser.parse_args()
|
|
92
|
+
|
|
93
|
+
file1 = Path(args.file1)
|
|
94
|
+
file2 = Path(args.file2)
|
|
95
|
+
|
|
96
|
+
if not file1.exists() or not file2.exists():
|
|
97
|
+
print("Error: One or both files do not exist")
|
|
98
|
+
exit(1)
|
|
99
|
+
|
|
100
|
+
result = compare_las_dimensions(file1, file2, args.dimensions)
|
|
101
|
+
print(f"Dimensions comparison result: {'identical' if result else 'different'}")
|
|
102
|
+
return result
|
|
103
|
+
|
|
104
|
+
if __name__ == "__main__":
|
|
105
|
+
main()
|
|
@@ -13,20 +13,20 @@ from pdaltools.las_remove_dimensions import remove_dimensions_from_points
|
|
|
13
13
|
|
|
14
14
|
def rename_dimension(input_file: str, output_file: str, old_dims: list[str], new_dims: list[str]):
|
|
15
15
|
"""
|
|
16
|
-
Rename one or multiple dimensions in a LAS file using PDAL.
|
|
16
|
+
Rename one or multiple dimensions in a LAS file using PDAL.
|
|
17
17
|
|
|
18
|
-
Args:
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
"""
|
|
18
|
+
Args:
|
|
19
|
+
input_file: Path to the input LAS file
|
|
20
|
+
output_file: Path to save the output LAS file
|
|
21
|
+
old_dims: List of names of dimensions to rename
|
|
22
|
+
new_dims: List of new names for the dimensions
|
|
23
|
+
"""
|
|
24
24
|
|
|
25
25
|
# Validate dimensions
|
|
26
26
|
if len(old_dims) != len(new_dims):
|
|
27
27
|
raise ValueError("Number of old dimensions must match number of new dimensions")
|
|
28
28
|
|
|
29
|
-
mandatory_dimensions = [
|
|
29
|
+
mandatory_dimensions = ["X", "Y", "Z", "x", "y", "z"]
|
|
30
30
|
for dim in new_dims:
|
|
31
31
|
if dim in mandatory_dimensions:
|
|
32
32
|
raise ValueError(f"New dimension {dim} cannot be a mandatory dimension (X,Y,Z,x,y,z)")
|
|
@@ -60,18 +60,18 @@ def main():
|
|
|
60
60
|
)
|
|
61
61
|
|
|
62
62
|
args = parser.parse_args()
|
|
63
|
-
|
|
63
|
+
|
|
64
64
|
# Validate input file
|
|
65
65
|
input_path = Path(args.input_file)
|
|
66
66
|
if not input_path.exists():
|
|
67
67
|
print(f"Error: Input file {args.input_file} does not exist", file=sys.stderr)
|
|
68
68
|
sys.exit(1)
|
|
69
|
-
|
|
69
|
+
|
|
70
70
|
# Validate output file
|
|
71
71
|
output_path = Path(args.output_file)
|
|
72
72
|
if output_path.exists():
|
|
73
73
|
print(f"Warning: Output file {args.output_file} already exists. It will be overwritten.")
|
|
74
|
-
|
|
74
|
+
|
|
75
75
|
rename_dimension(args.input_file, args.output_file, args.old_dims, args.new_dims)
|
|
76
76
|
|
|
77
77
|
|
pdaltools/standardize_format.py
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"""Re-write las file with expected format:
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
- laz version
|
|
3
|
+
- [TODO] nomenclature ???
|
|
4
|
+
- record format
|
|
5
|
+
- global encoding
|
|
6
|
+
- projection
|
|
7
|
+
- precision
|
|
8
|
+
- no extra-dims
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
11
|
import argparse
|
|
@@ -18,6 +18,7 @@ from typing import Dict, List
|
|
|
18
18
|
import pdal
|
|
19
19
|
|
|
20
20
|
from pdaltools.unlock_file import copy_and_hack_decorator
|
|
21
|
+
from pdaltools.las_rename_dimension import rename_dimension
|
|
21
22
|
|
|
22
23
|
# Standard parameters to pass to the pdal writer
|
|
23
24
|
STANDARD_PARAMETERS = dict(
|
|
@@ -60,6 +61,13 @@ def parse_args():
|
|
|
60
61
|
help="List of extra dims to keep in the output (default=[], use 'all' to keep all extra dims), "
|
|
61
62
|
"extra_dims must be specified with their type (see pdal.writers.las documentation, eg 'dim1=double')",
|
|
62
63
|
)
|
|
64
|
+
parser.add_argument(
|
|
65
|
+
"--rename_dims",
|
|
66
|
+
default=[],
|
|
67
|
+
nargs="*",
|
|
68
|
+
type=str,
|
|
69
|
+
help="Rename dimensions in pairs: --rename_dims old_name1 new_name1 old_name2 new_name2 ...",
|
|
70
|
+
)
|
|
63
71
|
return parser.parse_args()
|
|
64
72
|
|
|
65
73
|
|
|
@@ -73,11 +81,27 @@ def get_writer_parameters(new_parameters: Dict) -> Dict:
|
|
|
73
81
|
|
|
74
82
|
|
|
75
83
|
def rewrite_with_pdal(
|
|
76
|
-
input_file: str, output_file: str, params_from_parser: Dict, classes_to_remove: List = []
|
|
84
|
+
input_file: str, output_file: str, params_from_parser: Dict, classes_to_remove: List = [], rename_dims: List = []
|
|
77
85
|
) -> None:
|
|
78
86
|
params = get_writer_parameters(params_from_parser)
|
|
87
|
+
|
|
88
|
+
# Create temporary file for dimension renaming if needed
|
|
89
|
+
if rename_dims:
|
|
90
|
+
with tempfile.NamedTemporaryFile(suffix=".laz", delete=False) as tmp_file:
|
|
91
|
+
tmp_file_name = tmp_file.name
|
|
92
|
+
|
|
93
|
+
# Rename dimensions
|
|
94
|
+
old_dims = rename_dims[::2]
|
|
95
|
+
new_dims = rename_dims[1::2]
|
|
96
|
+
rename_dimension(input_file, tmp_file_name, old_dims, new_dims)
|
|
97
|
+
|
|
98
|
+
# Use renamed file as input
|
|
99
|
+
input_file = tmp_file_name
|
|
100
|
+
else:
|
|
101
|
+
tmp_file_name = input_file
|
|
102
|
+
|
|
79
103
|
pipeline = pdal.Pipeline()
|
|
80
|
-
pipeline |= pdal.Reader.las(
|
|
104
|
+
pipeline |= pdal.Reader.las(tmp_file_name)
|
|
81
105
|
if classes_to_remove:
|
|
82
106
|
expression = "&&".join([f"Classification != {c}" for c in classes_to_remove])
|
|
83
107
|
pipeline |= pdal.Filter.expression(expression=expression)
|
|
@@ -102,18 +126,24 @@ def exec_las2las(input_file: str, output_file: str):
|
|
|
102
126
|
|
|
103
127
|
|
|
104
128
|
@copy_and_hack_decorator
|
|
105
|
-
def standardize(
|
|
129
|
+
def standardize(
|
|
130
|
+
input_file: str, output_file: str, params_from_parser: Dict, class_points_removed: [], rename_dims: []
|
|
131
|
+
) -> None:
|
|
106
132
|
filename = os.path.basename(output_file)
|
|
107
133
|
with tempfile.NamedTemporaryFile(suffix=filename) as tmp:
|
|
108
|
-
rewrite_with_pdal(input_file, tmp.name, params_from_parser, class_points_removed)
|
|
134
|
+
rewrite_with_pdal(input_file, tmp.name, params_from_parser, class_points_removed, rename_dims)
|
|
109
135
|
exec_las2las(tmp.name, output_file)
|
|
110
136
|
|
|
111
137
|
|
|
112
|
-
|
|
138
|
+
def main():
|
|
113
139
|
args = parse_args()
|
|
114
140
|
params_from_parser = dict(
|
|
115
141
|
dataformat_id=args.record_format,
|
|
116
142
|
a_srs=args.projection,
|
|
117
143
|
extra_dims=args.extra_dims,
|
|
118
144
|
)
|
|
119
|
-
standardize(args.input_file, args.output_file, params_from_parser, args.class_points_removed)
|
|
145
|
+
standardize(args.input_file, args.output_file, params_from_parser, args.class_points_removed, args.rename_dims)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
if __name__ == "__main__":
|
|
149
|
+
main()
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
ign_pdal_tools-1.10.0.dist-info/licenses/LICENSE.md,sha256=iVzCFZTUXeiqP8bP474iuWZiWO_kDCD4SPh1Wiw125Y,1120
|
|
2
|
-
pdaltools/_version.py,sha256=P7Y6oBanMwNtN5HNsPQJszr9apg6shwS8QyOphkF_c0,75
|
|
3
|
-
pdaltools/add_points_in_pointcloud.py,sha256=13xl8tnoaW6FsRHBPa77-c6Olw8uUw2KBUGoz8JcbBg,12675
|
|
4
|
-
pdaltools/color.py,sha256=vJgpb8dOvT5rnq5NdVOaMdGc_pKL3damLy4HwGvigJQ,14472
|
|
5
|
-
pdaltools/las_add_buffer.py,sha256=rnFExAfi0KqlQpL4hDMh2aC08AcYdSHSB6WPG5RyFIc,11274
|
|
6
|
-
pdaltools/las_clip.py,sha256=GvEOYu8RXV68e35kU8i42GwSkbo4P9TvmS6rkrdPmFM,1034
|
|
7
|
-
pdaltools/las_info.py,sha256=lMKxKzsViptDENI1wOlANG4qOvdc19ixyasYKD-N1ck,9512
|
|
8
|
-
pdaltools/las_merge.py,sha256=tcFVueV9X9nNEaoAl5zCduY5DETlBg63MAgP2SuKiNo,4121
|
|
9
|
-
pdaltools/las_remove_dimensions.py,sha256=f8imGhN6LNTuQ1GMJQRzIIV3Wab_oRPOyEnKi1CgfiM,2318
|
|
10
|
-
pdaltools/las_rename_dimension.py,sha256=YSfxLspBPXvDklVztdPxQIK65FeDl7gEgQDWMWpXxm8,2560
|
|
11
|
-
pdaltools/pcd_info.py,sha256=NIAH5KGikVDQLlbCcw9FuaPqe20UZvRfkHsDZd5kmZA,3210
|
|
12
|
-
pdaltools/replace_attribute_in_las.py,sha256=po1F-fi8s7iilqKWaryW4JRbsmdMOUe0yGvG3AEKxtk,4771
|
|
13
|
-
pdaltools/standardize_format.py,sha256=gqm2GJbtDkT4k4oC_NX2LIPh9R2BLh4sMHLKYgfKrMc,3973
|
|
14
|
-
pdaltools/unlock_file.py,sha256=G2odk0cpp_X9r49Y90oK88v3qlihaMfg6acwmWqblik,1958
|
|
15
|
-
ign_pdal_tools-1.10.0.dist-info/METADATA,sha256=nHBXaDPf2WckwbwvyXJZUo0oCz9fgePfI3sfExF2tXw,5778
|
|
16
|
-
ign_pdal_tools-1.10.0.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
|
|
17
|
-
ign_pdal_tools-1.10.0.dist-info/top_level.txt,sha256=KvGW0ZzqQbhCKzB5_Tp_buWMZyIgiO2M2krWF_ecOZc,10
|
|
18
|
-
ign_pdal_tools-1.10.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|