ign-pdal-tools 1.11.1__tar.gz → 1.12.0__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.
- {ign_pdal_tools-1.11.1 → ign_pdal_tools-1.12.0}/PKG-INFO +1 -1
- {ign_pdal_tools-1.11.1 → ign_pdal_tools-1.12.0}/ign_pdal_tools.egg-info/PKG-INFO +1 -1
- {ign_pdal_tools-1.11.1 → ign_pdal_tools-1.12.0}/ign_pdal_tools.egg-info/SOURCES.txt +4 -0
- {ign_pdal_tools-1.11.1 → ign_pdal_tools-1.12.0}/pdaltools/_version.py +1 -1
- {ign_pdal_tools-1.11.1 → ign_pdal_tools-1.12.0}/pdaltools/add_points_in_pointcloud.py +5 -5
- ign_pdal_tools-1.12.0/pdaltools/create_random_laz.py +146 -0
- ign_pdal_tools-1.12.0/pdaltools/las_comparison.py +105 -0
- {ign_pdal_tools-1.11.1 → ign_pdal_tools-1.12.0}/test/test_add_points_in_pointcloud.py +22 -4
- ign_pdal_tools-1.12.0/test/test_create_random_laz.py +174 -0
- ign_pdal_tools-1.12.0/test/test_las_comparison.py +275 -0
- {ign_pdal_tools-1.11.1 → ign_pdal_tools-1.12.0}/LICENSE.md +0 -0
- {ign_pdal_tools-1.11.1 → ign_pdal_tools-1.12.0}/README.md +0 -0
- {ign_pdal_tools-1.11.1 → ign_pdal_tools-1.12.0}/ign_pdal_tools.egg-info/dependency_links.txt +0 -0
- {ign_pdal_tools-1.11.1 → ign_pdal_tools-1.12.0}/ign_pdal_tools.egg-info/top_level.txt +0 -0
- {ign_pdal_tools-1.11.1 → ign_pdal_tools-1.12.0}/pdaltools/color.py +0 -0
- {ign_pdal_tools-1.11.1 → ign_pdal_tools-1.12.0}/pdaltools/las_add_buffer.py +0 -0
- {ign_pdal_tools-1.11.1 → ign_pdal_tools-1.12.0}/pdaltools/las_clip.py +0 -0
- {ign_pdal_tools-1.11.1 → ign_pdal_tools-1.12.0}/pdaltools/las_info.py +0 -0
- {ign_pdal_tools-1.11.1 → ign_pdal_tools-1.12.0}/pdaltools/las_merge.py +0 -0
- {ign_pdal_tools-1.11.1 → ign_pdal_tools-1.12.0}/pdaltools/las_remove_dimensions.py +0 -0
- {ign_pdal_tools-1.11.1 → ign_pdal_tools-1.12.0}/pdaltools/las_rename_dimension.py +0 -0
- {ign_pdal_tools-1.11.1 → ign_pdal_tools-1.12.0}/pdaltools/pcd_info.py +0 -0
- {ign_pdal_tools-1.11.1 → ign_pdal_tools-1.12.0}/pdaltools/replace_attribute_in_las.py +0 -0
- {ign_pdal_tools-1.11.1 → ign_pdal_tools-1.12.0}/pdaltools/standardize_format.py +0 -0
- {ign_pdal_tools-1.11.1 → ign_pdal_tools-1.12.0}/pdaltools/unlock_file.py +0 -0
- {ign_pdal_tools-1.11.1 → ign_pdal_tools-1.12.0}/pyproject.toml +0 -0
- {ign_pdal_tools-1.11.1 → ign_pdal_tools-1.12.0}/setup.cfg +0 -0
- {ign_pdal_tools-1.11.1 → ign_pdal_tools-1.12.0}/test/test_color.py +0 -0
- {ign_pdal_tools-1.11.1 → ign_pdal_tools-1.12.0}/test/test_las_add_buffer.py +0 -0
- {ign_pdal_tools-1.11.1 → ign_pdal_tools-1.12.0}/test/test_las_clip.py +0 -0
- {ign_pdal_tools-1.11.1 → ign_pdal_tools-1.12.0}/test/test_las_info.py +0 -0
- {ign_pdal_tools-1.11.1 → ign_pdal_tools-1.12.0}/test/test_las_merge.py +0 -0
- {ign_pdal_tools-1.11.1 → ign_pdal_tools-1.12.0}/test/test_las_remove_dimensions.py +0 -0
- {ign_pdal_tools-1.11.1 → ign_pdal_tools-1.12.0}/test/test_las_rename_dimension.py +0 -0
- {ign_pdal_tools-1.11.1 → ign_pdal_tools-1.12.0}/test/test_pcd_info.py +0 -0
- {ign_pdal_tools-1.11.1 → ign_pdal_tools-1.12.0}/test/test_pdal_custom.py +0 -0
- {ign_pdal_tools-1.11.1 → ign_pdal_tools-1.12.0}/test/test_replace_attribute_in_las.py +0 -0
- {ign_pdal_tools-1.11.1 → ign_pdal_tools-1.12.0}/test/test_standardize_format.py +0 -0
- {ign_pdal_tools-1.11.1 → ign_pdal_tools-1.12.0}/test/test_unlock.py +0 -0
|
@@ -8,8 +8,10 @@ ign_pdal_tools.egg-info/top_level.txt
|
|
|
8
8
|
pdaltools/_version.py
|
|
9
9
|
pdaltools/add_points_in_pointcloud.py
|
|
10
10
|
pdaltools/color.py
|
|
11
|
+
pdaltools/create_random_laz.py
|
|
11
12
|
pdaltools/las_add_buffer.py
|
|
12
13
|
pdaltools/las_clip.py
|
|
14
|
+
pdaltools/las_comparison.py
|
|
13
15
|
pdaltools/las_info.py
|
|
14
16
|
pdaltools/las_merge.py
|
|
15
17
|
pdaltools/las_remove_dimensions.py
|
|
@@ -20,8 +22,10 @@ pdaltools/standardize_format.py
|
|
|
20
22
|
pdaltools/unlock_file.py
|
|
21
23
|
test/test_add_points_in_pointcloud.py
|
|
22
24
|
test/test_color.py
|
|
25
|
+
test/test_create_random_laz.py
|
|
23
26
|
test/test_las_add_buffer.py
|
|
24
27
|
test/test_las_clip.py
|
|
28
|
+
test/test_las_comparison.py
|
|
25
29
|
test/test_las_info.py
|
|
26
30
|
test/test_las_merge.py
|
|
27
31
|
test/test_las_remove_dimensions.py
|
|
@@ -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()
|
|
@@ -220,6 +220,16 @@ def test_line_to_multipoint(line, spacing, z_value, expected_points):
|
|
|
220
220
|
Point(10, 10, 6.0),
|
|
221
221
|
],
|
|
222
222
|
),
|
|
223
|
+
# Test case for empty lines
|
|
224
|
+
(
|
|
225
|
+
gpd.GeoDataFrame(
|
|
226
|
+
{"geometry": [], "RecupZ": []},
|
|
227
|
+
crs="EPSG:2154",
|
|
228
|
+
),
|
|
229
|
+
2.5,
|
|
230
|
+
"RecupZ",
|
|
231
|
+
[],
|
|
232
|
+
),
|
|
223
233
|
],
|
|
224
234
|
)
|
|
225
235
|
def test_generate_3d_points_from_lines(lines_gdf, spacing, altitude_column, expected_points):
|
|
@@ -251,7 +261,7 @@ def test_generate_3d_points_from_lines(lines_gdf, spacing, altitude_column, expe
|
|
|
251
261
|
678,
|
|
252
262
|
0.25,
|
|
253
263
|
"RecupZ",
|
|
254
|
-
), # should add only
|
|
264
|
+
), # should add only lines (.shp) within tile extend
|
|
255
265
|
(INPUT_PCD, INPUT_LIGNES_SHAPE, None, 678, 0.25, "RecupZ"), # Should work with or with an input epsg
|
|
256
266
|
(
|
|
257
267
|
INPUT_PCD,
|
|
@@ -261,6 +271,14 @@ def test_generate_3d_points_from_lines(lines_gdf, spacing, altitude_column, expe
|
|
|
261
271
|
0.25,
|
|
262
272
|
None,
|
|
263
273
|
), # Should work with or without an input epsg and without altitude_column
|
|
274
|
+
(
|
|
275
|
+
INPUT_PCD_CROPPED,
|
|
276
|
+
INPUT_LIGNES_3D_GEOJSON,
|
|
277
|
+
None,
|
|
278
|
+
0,
|
|
279
|
+
0.25,
|
|
280
|
+
None,
|
|
281
|
+
), # Should work with lines and add no points if there is no geometry in the tile extent
|
|
264
282
|
],
|
|
265
283
|
)
|
|
266
284
|
def test_add_points_from_geometry_to_las(input_file, input_points, epsg, expected_nb_points, spacing, altitude_column):
|
|
@@ -272,11 +290,11 @@ def test_add_points_from_geometry_to_las(input_file, input_points, epsg, expecte
|
|
|
272
290
|
input_points, input_file, OUTPUT_FILE, 68, epsg, 1000, spacing, altitude_column
|
|
273
291
|
)
|
|
274
292
|
assert Path(OUTPUT_FILE).exists() # check output exists
|
|
275
|
-
|
|
293
|
+
|
|
276
294
|
# Read input and output files to compare headers
|
|
277
295
|
input_las = laspy.read(input_file)
|
|
278
296
|
output_las = laspy.read(OUTPUT_FILE)
|
|
279
|
-
|
|
297
|
+
|
|
280
298
|
# Compare headers
|
|
281
299
|
assert input_las.header.version == output_las.header.version
|
|
282
300
|
assert input_las.header.system_identifier == output_las.header.system_identifier
|
|
@@ -287,7 +305,7 @@ def test_add_points_from_geometry_to_las(input_file, input_points, epsg, expecte
|
|
|
287
305
|
assert np.array_equal(input_las.header.scales, output_las.header.scales)
|
|
288
306
|
assert np.array_equal(input_las.header.offsets, output_las.header.offsets)
|
|
289
307
|
assert input_las.header.vlrs[0].string == output_las.header.vlrs[0].string
|
|
290
|
-
|
|
308
|
+
|
|
291
309
|
point_count = compute_count_one_file(OUTPUT_FILE)["68"]
|
|
292
310
|
assert point_count == expected_nb_points # Add all points from geojson
|
|
293
311
|
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import tempfile
|
|
3
|
+
import pytest
|
|
4
|
+
import numpy as np
|
|
5
|
+
import laspy
|
|
6
|
+
import sys
|
|
7
|
+
|
|
8
|
+
from pdaltools.create_random_laz import create_random_laz, main
|
|
9
|
+
|
|
10
|
+
TEST_PATH = os.path.dirname(os.path.abspath(__file__))
|
|
11
|
+
TMP_PATH = os.path.join(TEST_PATH, "tmp")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def setup_module(module):
|
|
15
|
+
try:
|
|
16
|
+
os.makedirs(TMP_PATH, exist_ok=True)
|
|
17
|
+
except FileNotFoundError:
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def test_create_random_laz_basic():
|
|
22
|
+
"""Test basic functionality without extra dimensions"""
|
|
23
|
+
output_file = os.path.join(TMP_PATH, "test_basic.laz")
|
|
24
|
+
create_random_laz(output_file=output_file, num_points=50)
|
|
25
|
+
|
|
26
|
+
# Check file exists
|
|
27
|
+
assert os.path.isfile(output_file)
|
|
28
|
+
|
|
29
|
+
# Check file can be read
|
|
30
|
+
with laspy.open(output_file) as las_file:
|
|
31
|
+
las = las_file.read()
|
|
32
|
+
assert len(las.points) == 50
|
|
33
|
+
assert "X" in las.point_format.dimension_names
|
|
34
|
+
assert "Y" in las.point_format.dimension_names
|
|
35
|
+
assert "Z" in las.point_format.dimension_names
|
|
36
|
+
assert "intensity" in las.point_format.dimension_names
|
|
37
|
+
assert "classification" in las.point_format.dimension_names
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_create_random_laz_invalid_type():
|
|
41
|
+
"""Test error handling for invalid dimension type"""
|
|
42
|
+
output_file = os.path.join(TMP_PATH, "test_invalid_type.laz")
|
|
43
|
+
extra_dims = [("height", "invalid_type")]
|
|
44
|
+
|
|
45
|
+
with pytest.raises(ValueError):
|
|
46
|
+
create_random_laz(output_file=output_file, num_points=50, point_format=3, extra_dims=extra_dims)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def test_create_random_point_format():
|
|
50
|
+
"""Test that the point format is set correctly"""
|
|
51
|
+
output_file = os.path.join(TMP_PATH, "test_point_format.laz")
|
|
52
|
+
create_random_laz(output_file=output_file, point_format=6, num_points=50)
|
|
53
|
+
|
|
54
|
+
with laspy.open(output_file) as las_file:
|
|
55
|
+
las = las_file.read()
|
|
56
|
+
assert las.header.point_format.id == 6
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def test_create_random_laz_no_extra_dims():
|
|
60
|
+
"""Test that the output file is created correctly when no extra dimensions are provided"""
|
|
61
|
+
output_file = os.path.join(TMP_PATH, "test_no_extra_dims.laz")
|
|
62
|
+
create_random_laz(output_file, num_points=50)
|
|
63
|
+
|
|
64
|
+
with laspy.open(output_file) as las_file:
|
|
65
|
+
las = las_file.read()
|
|
66
|
+
assert len(las.points) == 50
|
|
67
|
+
assert "X" in las.point_format.dimension_names
|
|
68
|
+
assert "Y" in las.point_format.dimension_names
|
|
69
|
+
assert "Z" in las.point_format.dimension_names
|
|
70
|
+
assert "intensity" in las.point_format.dimension_names
|
|
71
|
+
assert "classification" in las.point_format.dimension_names
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def test_create_random_laz_crs_and_center():
|
|
75
|
+
"""Test that the CRS is set correctly"""
|
|
76
|
+
output_file = os.path.join(TMP_PATH, "test_crs.laz")
|
|
77
|
+
create_random_laz(output_file, num_points=50, crs=2153, center=(650000, 6810000))
|
|
78
|
+
|
|
79
|
+
with laspy.open(output_file) as las_file:
|
|
80
|
+
las = las_file.read()
|
|
81
|
+
epsg = las.header.parse_crs().to_epsg()
|
|
82
|
+
assert epsg == 2153
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def test_create_random_laz_all_types():
|
|
86
|
+
"""Test all supported dimension types"""
|
|
87
|
+
output_file = os.path.join(TMP_PATH, "test_all_types.laz")
|
|
88
|
+
extra_dims = [
|
|
89
|
+
("float32_dim", "float32"),
|
|
90
|
+
("float64_dim", "float64"),
|
|
91
|
+
("int8_dim", "int8"),
|
|
92
|
+
("int16_dim", "int16"),
|
|
93
|
+
("int32_dim", "int32"),
|
|
94
|
+
("int64_dim", "int64"),
|
|
95
|
+
("uint8_dim", "uint8"),
|
|
96
|
+
("uint16_dim", "uint16"),
|
|
97
|
+
("uint32_dim", "uint32"),
|
|
98
|
+
("uint64_dim", "uint64"),
|
|
99
|
+
]
|
|
100
|
+
|
|
101
|
+
create_random_laz(output_file, num_points=25, extra_dims=extra_dims)
|
|
102
|
+
|
|
103
|
+
# Check file exists
|
|
104
|
+
assert os.path.isfile(output_file)
|
|
105
|
+
|
|
106
|
+
# Check file can be read and has correct dimensions
|
|
107
|
+
with laspy.open(output_file) as las_file:
|
|
108
|
+
las = las_file.read()
|
|
109
|
+
assert len(las.points) == 25
|
|
110
|
+
|
|
111
|
+
# Check that all extra dimensions exist
|
|
112
|
+
for dim_name, _ in extra_dims:
|
|
113
|
+
assert dim_name in las.point_format.dimension_names
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def test_create_random_laz_data_ranges():
|
|
117
|
+
"""Test that generated data is within expected ranges for different types"""
|
|
118
|
+
output_file = os.path.join(TMP_PATH, "test_data_ranges.laz")
|
|
119
|
+
extra_dims = [
|
|
120
|
+
("float_dim", "float32"),
|
|
121
|
+
("int_dim", "int32"),
|
|
122
|
+
("uint_dim", "uint8"),
|
|
123
|
+
]
|
|
124
|
+
|
|
125
|
+
create_random_laz(output_file, num_points=1000, extra_dims=extra_dims)
|
|
126
|
+
|
|
127
|
+
with laspy.open(output_file) as las_file:
|
|
128
|
+
las = las_file.read()
|
|
129
|
+
|
|
130
|
+
# Check float data is in expected range (0-10)
|
|
131
|
+
assert np.all(las.float_dim >= 0)
|
|
132
|
+
assert np.all(las.float_dim <= 10)
|
|
133
|
+
|
|
134
|
+
# Check int data is in expected range (-100 to 100)
|
|
135
|
+
assert np.all(las.int_dim >= -100)
|
|
136
|
+
assert np.all(las.int_dim <= 100)
|
|
137
|
+
|
|
138
|
+
# Check uint data is in expected range (0 to 100)
|
|
139
|
+
assert np.all(las.uint_dim >= 0)
|
|
140
|
+
assert np.all(las.uint_dim <= 100)
|
|
141
|
+
|
|
142
|
+
def test_main():
|
|
143
|
+
"""Test the main function"""
|
|
144
|
+
output_file = os.path.join(TMP_PATH, "test_main.laz")
|
|
145
|
+
|
|
146
|
+
original_argv = sys.argv
|
|
147
|
+
|
|
148
|
+
try:
|
|
149
|
+
# Set up mock command-line arguments
|
|
150
|
+
sys.argv = [
|
|
151
|
+
"create_random_laz",
|
|
152
|
+
"--output_file", output_file,
|
|
153
|
+
"--point_format", "3",
|
|
154
|
+
"--num_points", "50",
|
|
155
|
+
"--crs", "2154",
|
|
156
|
+
"--center", "650000,6810000",
|
|
157
|
+
"--extra_dims", "height:float32",
|
|
158
|
+
]
|
|
159
|
+
|
|
160
|
+
# Run main function
|
|
161
|
+
main()
|
|
162
|
+
|
|
163
|
+
# Verify output file exists
|
|
164
|
+
assert os.path.isfile(output_file)
|
|
165
|
+
|
|
166
|
+
# Verify points count is reduced
|
|
167
|
+
with laspy.open(output_file) as las_file:
|
|
168
|
+
las = las_file.read()
|
|
169
|
+
assert len(las.points) == 50
|
|
170
|
+
assert "height" in las.point_format.dimension_names
|
|
171
|
+
|
|
172
|
+
finally:
|
|
173
|
+
# Restore original sys.argv
|
|
174
|
+
sys.argv = original_argv
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
import tempfile
|
|
3
|
+
import numpy as np
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
import laspy
|
|
6
|
+
from pdaltools.las_comparison import compare_las_dimensions, main
|
|
7
|
+
from typing import Tuple
|
|
8
|
+
|
|
9
|
+
def create_test_las_file(x: np.ndarray, y: np.ndarray, z: np.ndarray, dimensions: dict = None) -> Path:
|
|
10
|
+
"""Helper function to create a test LAS file with specified dimensions"""
|
|
11
|
+
with tempfile.NamedTemporaryFile(suffix='.las', delete=False) as temp:
|
|
12
|
+
las = laspy.create(point_format=3, file_version="1.4")
|
|
13
|
+
|
|
14
|
+
# Use provided dimensions or create default ones
|
|
15
|
+
if dimensions is None:
|
|
16
|
+
dimensions = {
|
|
17
|
+
'classification': np.random.randint(0, 10, len(x)),
|
|
18
|
+
'intensity': np.random.randint(0, 255, len(x)),
|
|
19
|
+
'return_number': np.random.randint(1, 5, len(x))
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
las.x = x
|
|
23
|
+
las.y = y
|
|
24
|
+
las.z = z
|
|
25
|
+
|
|
26
|
+
# Set all specified dimensions
|
|
27
|
+
for dim_name, dim_data in dimensions.items():
|
|
28
|
+
setattr(las, dim_name, dim_data)
|
|
29
|
+
|
|
30
|
+
las.write(temp.name)
|
|
31
|
+
return Path(temp.name)
|
|
32
|
+
|
|
33
|
+
def get_random_points(points: int) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
|
|
34
|
+
x = np.random.rand(points) * 1000
|
|
35
|
+
y = np.random.rand(points) * 1000
|
|
36
|
+
z = np.random.rand(points) * 100
|
|
37
|
+
return x, y, z
|
|
38
|
+
|
|
39
|
+
def test_identical_dimensions():
|
|
40
|
+
"""Test that identical dimensions return True"""
|
|
41
|
+
points = 10
|
|
42
|
+
x, y, z = get_random_points(points)
|
|
43
|
+
dimensions = {
|
|
44
|
+
'classification': np.random.randint(0, 10, points),
|
|
45
|
+
'intensity': np.random.randint(0, 255, points),
|
|
46
|
+
'return_number': np.random.randint(1, 5, points)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
file1 = create_test_las_file(x, y, z, dimensions)
|
|
50
|
+
file2 = create_test_las_file(x, y, z, dimensions)
|
|
51
|
+
|
|
52
|
+
try:
|
|
53
|
+
# Test with specific dimensions
|
|
54
|
+
result = compare_las_dimensions(file1, file2, ['classification', 'intensity'])
|
|
55
|
+
assert result is True, "Files with identical dimensions should return True"
|
|
56
|
+
|
|
57
|
+
# Test with identical files
|
|
58
|
+
result = compare_las_dimensions(file1, file2)
|
|
59
|
+
assert result is True, "Files with identical dimensions should return True"
|
|
60
|
+
finally:
|
|
61
|
+
# Clean up
|
|
62
|
+
file1.unlink()
|
|
63
|
+
file2.unlink()
|
|
64
|
+
|
|
65
|
+
def test_identical_dimensions_not_sorted():
|
|
66
|
+
"""Test that identical dimensions return True"""
|
|
67
|
+
points = 10
|
|
68
|
+
x, y, z = get_random_points(points)
|
|
69
|
+
dimensions = {
|
|
70
|
+
'classification': np.random.randint(0, 10, points),
|
|
71
|
+
'intensity': np.random.randint(0, 255, points),
|
|
72
|
+
'return_number': np.random.randint(1, 5, points)
|
|
73
|
+
}
|
|
74
|
+
dimensions2 = {
|
|
75
|
+
'classification': dimensions['classification'][::-1],
|
|
76
|
+
'intensity': dimensions['intensity'][::-1],
|
|
77
|
+
'return_number': dimensions['return_number'][::-1]
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
file1 = create_test_las_file(x, y, z, dimensions)
|
|
81
|
+
file2 = create_test_las_file(x[::-1], y[::-1], z[::-1], dimensions2)
|
|
82
|
+
|
|
83
|
+
try:
|
|
84
|
+
# Test with specific dimensions
|
|
85
|
+
result = compare_las_dimensions(file1, file2, ['classification', 'intensity'])
|
|
86
|
+
assert result is True, "Files with identical dimensions should return True"
|
|
87
|
+
|
|
88
|
+
# Test with identical files
|
|
89
|
+
result = compare_las_dimensions(file1, file2)
|
|
90
|
+
assert result is True, "Files with identical dimensions should return True"
|
|
91
|
+
finally:
|
|
92
|
+
# Clean up
|
|
93
|
+
file1.unlink()
|
|
94
|
+
file2.unlink()
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def test_different_dimensions_random():
|
|
98
|
+
"""Test that files with random dimensions return False"""
|
|
99
|
+
points = 100
|
|
100
|
+
x, y, z = get_random_points(points)
|
|
101
|
+
|
|
102
|
+
# Create file1 with random dimensions
|
|
103
|
+
dimensions1 = {
|
|
104
|
+
'classification': np.random.randint(0, 10, points),
|
|
105
|
+
'intensity': np.random.randint(0, 255, points),
|
|
106
|
+
'return_number': np.random.randint(1, 5, points)
|
|
107
|
+
}
|
|
108
|
+
file1 = create_test_las_file(x, y, z, dimensions1)
|
|
109
|
+
|
|
110
|
+
# Create file2 with different dimensions
|
|
111
|
+
dimensions2 = {
|
|
112
|
+
'classification': np.random.randint(0, 10, points), # Different classification
|
|
113
|
+
'intensity': dimensions1['intensity'], # Same intensity
|
|
114
|
+
'return_number': dimensions1['return_number'] # Same return_number
|
|
115
|
+
}
|
|
116
|
+
file2 = create_test_las_file(x, y, z, dimensions2)
|
|
117
|
+
|
|
118
|
+
try:
|
|
119
|
+
# Test full comparison (should be different)
|
|
120
|
+
result = compare_las_dimensions(file1, file2)
|
|
121
|
+
assert result is False, "Files with different classification should return False"
|
|
122
|
+
|
|
123
|
+
# Test specific dimensions (should be identical)
|
|
124
|
+
result = compare_las_dimensions(file1, file2, ['intensity', 'return_number'])
|
|
125
|
+
assert result is True, "Files with identical intensity and return_number should return True"
|
|
126
|
+
finally:
|
|
127
|
+
# Clean up
|
|
128
|
+
file1.unlink()
|
|
129
|
+
file2.unlink()
|
|
130
|
+
|
|
131
|
+
def test_different_number_of_points():
|
|
132
|
+
"""Test that files with different number of points return False"""
|
|
133
|
+
points = 100
|
|
134
|
+
x1, y1, z1 = get_random_points(points)
|
|
135
|
+
x2, y2, z2 = get_random_points(points + 1)
|
|
136
|
+
file1 = create_test_las_file(x1, y1, z1)
|
|
137
|
+
file2 = create_test_las_file(x2, y2, z2)
|
|
138
|
+
|
|
139
|
+
try:
|
|
140
|
+
result = compare_las_dimensions(file1, file2)
|
|
141
|
+
assert result is False, "Files with different number of points should return False"
|
|
142
|
+
finally:
|
|
143
|
+
# Clean up
|
|
144
|
+
file1.unlink()
|
|
145
|
+
file2.unlink()
|
|
146
|
+
|
|
147
|
+
def test_different_dimensions_number():
|
|
148
|
+
"""Test that files with different number of dimensions return False"""
|
|
149
|
+
points = 100
|
|
150
|
+
x, y, z = get_random_points(points)
|
|
151
|
+
|
|
152
|
+
# Create file1 with random dimensions
|
|
153
|
+
dimensions1 = {
|
|
154
|
+
'classification': np.random.randint(0, 10, points),
|
|
155
|
+
'intensity': np.random.randint(0, 255, points),
|
|
156
|
+
'return_number': np.random.randint(1, 5, points)
|
|
157
|
+
}
|
|
158
|
+
file1 = create_test_las_file(x, y, z, dimensions1)
|
|
159
|
+
|
|
160
|
+
# Create file2 only 2 dimensions
|
|
161
|
+
dimensions2 = {
|
|
162
|
+
'classification': np.random.randint(0, 10, points), # Different classification
|
|
163
|
+
'intensity': dimensions1['intensity'], # Same intensity
|
|
164
|
+
}
|
|
165
|
+
file2 = create_test_las_file(x, y, z, dimensions2)
|
|
166
|
+
|
|
167
|
+
try:
|
|
168
|
+
# Test full comparison (should be different)
|
|
169
|
+
result = compare_las_dimensions(file1, file2)
|
|
170
|
+
assert result is False, "Files with different dimensions should return False"
|
|
171
|
+
finally:
|
|
172
|
+
# Clean up
|
|
173
|
+
file1.unlink()
|
|
174
|
+
file2.unlink()
|
|
175
|
+
|
|
176
|
+
def test_one_empty_file():
|
|
177
|
+
"""Test that one empty file returns False"""
|
|
178
|
+
points = 100
|
|
179
|
+
x = np.random.rand(points) * 1000
|
|
180
|
+
y = np.random.rand(points) * 1000
|
|
181
|
+
z = np.random.rand(points) * 100
|
|
182
|
+
file1 = create_test_las_file(x, y, z)
|
|
183
|
+
file2 = create_test_las_file(np.array([]), np.array([]), np.array([]))
|
|
184
|
+
|
|
185
|
+
try:
|
|
186
|
+
result = compare_las_dimensions(file1, file2)
|
|
187
|
+
assert result is False, "One empty file should return False"
|
|
188
|
+
finally:
|
|
189
|
+
# Clean up
|
|
190
|
+
file1.unlink()
|
|
191
|
+
file2.unlink()
|
|
192
|
+
|
|
193
|
+
def test_both_empty_files():
|
|
194
|
+
"""Test that two empty files return True"""
|
|
195
|
+
file1 = create_test_las_file(np.array([]), np.array([]), np.array([]))
|
|
196
|
+
file2 = create_test_las_file(np.array([]), np.array([]), np.array([]))
|
|
197
|
+
|
|
198
|
+
try:
|
|
199
|
+
result = compare_las_dimensions(file1, file2)
|
|
200
|
+
assert result is True, "Two empty files should return True"
|
|
201
|
+
finally:
|
|
202
|
+
# Clean up
|
|
203
|
+
file1.unlink()
|
|
204
|
+
file2.unlink()
|
|
205
|
+
|
|
206
|
+
def test_single_point():
|
|
207
|
+
"""Test with single point files"""
|
|
208
|
+
points = 1
|
|
209
|
+
x = np.random.rand(points) * 1000
|
|
210
|
+
y = np.random.rand(points) * 1000
|
|
211
|
+
z = np.random.rand(points) * 100
|
|
212
|
+
dimensions = {
|
|
213
|
+
'classification': np.array([1]),
|
|
214
|
+
'intensity': np.array([100]),
|
|
215
|
+
'return_number': np.array([1])
|
|
216
|
+
}
|
|
217
|
+
file1 = create_test_las_file(x, y, z, dimensions)
|
|
218
|
+
file2 = create_test_las_file(x, y, z, dimensions)
|
|
219
|
+
|
|
220
|
+
try:
|
|
221
|
+
result = compare_las_dimensions(file1, file2)
|
|
222
|
+
assert result is True, "Single point files with same dimensions should return True"
|
|
223
|
+
finally:
|
|
224
|
+
# Clean up
|
|
225
|
+
file1.unlink()
|
|
226
|
+
file2.unlink()
|
|
227
|
+
|
|
228
|
+
def test_main_function():
|
|
229
|
+
"""Test the main function with direct sys.argv"""
|
|
230
|
+
import sys
|
|
231
|
+
from io import StringIO
|
|
232
|
+
from contextlib import redirect_stdout
|
|
233
|
+
|
|
234
|
+
# Test with identical files
|
|
235
|
+
points = 100
|
|
236
|
+
x = np.random.rand(points) * 1000
|
|
237
|
+
y = np.random.rand(points) * 1000
|
|
238
|
+
z = np.random.rand(points) * 100
|
|
239
|
+
classification = np.random.randint(0, 10, points)
|
|
240
|
+
|
|
241
|
+
file1 = create_test_las_file(x, y, z, {'classification': classification})
|
|
242
|
+
file2 = create_test_las_file(x, y, z, {'classification': classification})
|
|
243
|
+
file3 = create_test_las_file(x, y, z, {'classification': classification + 1}) # Different classification
|
|
244
|
+
|
|
245
|
+
try:
|
|
246
|
+
# Test with identical files
|
|
247
|
+
sys.argv = ['script_name', str(file1), str(file2)]
|
|
248
|
+
with redirect_stdout(StringIO()) as f:
|
|
249
|
+
result = main()
|
|
250
|
+
assert result is True
|
|
251
|
+
|
|
252
|
+
sys.argv = ['script_name', str(file1), str(file2), '--dimensions', 'classification']
|
|
253
|
+
with redirect_stdout(StringIO()) as f:
|
|
254
|
+
result = main()
|
|
255
|
+
assert result is True
|
|
256
|
+
|
|
257
|
+
sys.argv = ['script_name', str(file1), str(file2), '--dimensions', 'classification', 'intensity']
|
|
258
|
+
with redirect_stdout(StringIO()) as f:
|
|
259
|
+
result = main()
|
|
260
|
+
assert result is True
|
|
261
|
+
|
|
262
|
+
# Test with different files
|
|
263
|
+
sys.argv = ['script_name', str(file1), str(file3)]
|
|
264
|
+
with redirect_stdout(StringIO()) as f:
|
|
265
|
+
result = main()
|
|
266
|
+
assert result is False
|
|
267
|
+
|
|
268
|
+
finally:
|
|
269
|
+
# Clean up
|
|
270
|
+
for f in [file1, file2, file3]:
|
|
271
|
+
if f.exists():
|
|
272
|
+
f.unlink()
|
|
273
|
+
|
|
274
|
+
if __name__ == "__main__":
|
|
275
|
+
pytest.main()
|
|
File without changes
|
|
File without changes
|
{ign_pdal_tools-1.11.1 → ign_pdal_tools-1.12.0}/ign_pdal_tools.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|