py4dgeo 0.7.0__cp313-cp313-macosx_14_0_arm64.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.
Binary file
Binary file
@@ -0,0 +1,81 @@
1
+ import operator
2
+ import zipfile
3
+
4
+
5
+ class UpdateableZipFile(zipfile.ZipFile):
6
+ """A patched version of Python's zipfile that supports removing files in 'a' mode
7
+
8
+ Python does not implement this although the issue has been
9
+ known for over a decade and a fix exists:
10
+ https://github.com/python/cpython/pull/19358
11
+
12
+ This class ports the CPython fix forward.
13
+ """
14
+
15
+ def remove(self, member):
16
+ """Remove a file from the archive. The archive must be open with mode 'a'"""
17
+
18
+ if self.mode != "a":
19
+ raise RuntimeError("remove() requires mode 'a'")
20
+ if not self.fp:
21
+ raise ValueError("Attempt to write to ZIP archive that was already closed")
22
+ if self._writing:
23
+ raise ValueError(
24
+ "Can't write to ZIP archive while an open writing handle exists."
25
+ )
26
+
27
+ # Make sure we have an info object
28
+ if isinstance(member, zipfile.ZipInfo):
29
+ # 'member' is already an info object
30
+ zinfo = member
31
+ else:
32
+ # get the info object
33
+ zinfo = self.getinfo(member)
34
+
35
+ return self._remove_member(zinfo)
36
+
37
+ def _remove_member(self, member):
38
+ # get a sorted filelist by header offset, in case the dir order
39
+ # doesn't match the actual entry order
40
+ fp = self.fp
41
+ entry_offset = 0
42
+ filelist = sorted(self.filelist, key=operator.attrgetter("header_offset"))
43
+ for i in range(len(filelist)):
44
+ info = filelist[i]
45
+ # find the target member
46
+ if info.header_offset < member.header_offset:
47
+ continue
48
+
49
+ # get the total size of the entry
50
+ entry_size = None
51
+ if i == len(filelist) - 1:
52
+ entry_size = self.start_dir - info.header_offset
53
+ else:
54
+ entry_size = filelist[i + 1].header_offset - info.header_offset
55
+
56
+ # found the member, set the entry offset
57
+ if member == info:
58
+ entry_offset = entry_size
59
+ continue
60
+
61
+ # Move entry
62
+ # read the actual entry data
63
+ fp.seek(info.header_offset)
64
+ entry_data = fp.read(entry_size)
65
+
66
+ # update the header
67
+ info.header_offset -= entry_offset
68
+
69
+ # write the entry to the new position
70
+ fp.seek(info.header_offset)
71
+ fp.write(entry_data)
72
+ fp.flush()
73
+
74
+ # update state
75
+ self.start_dir -= entry_offset
76
+ self.filelist.remove(member)
77
+ del self.NameToInfo[member.filename]
78
+ self._didModify = True
79
+
80
+ # seek to the start of the central dir
81
+ fp.seek(self.start_dir)
py4dgeo/__init__.py ADDED
@@ -0,0 +1,32 @@
1
+ from py4dgeo.logger import set_py4dgeo_logfile
2
+ from py4dgeo.cloudcompare import CloudCompareM3C2
3
+ from py4dgeo.epoch import (
4
+ Epoch,
5
+ read_from_las,
6
+ read_from_xyz,
7
+ save_epoch,
8
+ load_epoch,
9
+ )
10
+ from py4dgeo.m3c2 import M3C2, write_m3c2_results_to_las
11
+ from py4dgeo.m3c2ep import M3C2EP
12
+ from py4dgeo.registration import (
13
+ iterative_closest_point,
14
+ point_to_plane_icp,
15
+ icp_with_stable_areas,
16
+ )
17
+ from py4dgeo.segmentation import (
18
+ RegionGrowingAlgorithm,
19
+ SpatiotemporalAnalysis,
20
+ regular_corepoint_grid,
21
+ temporal_averaging,
22
+ )
23
+ from py4dgeo.util import (
24
+ __version__,
25
+ find_file,
26
+ MemoryPolicy,
27
+ set_memory_policy,
28
+ get_num_threads,
29
+ set_num_threads,
30
+ )
31
+
32
+ from py4dgeo.pbm3c2 import *
@@ -0,0 +1,32 @@
1
+ from py4dgeo.m3c2 import M3C2
2
+
3
+
4
+ _cloudcompare_param_mapping = {
5
+ "normalscale": "normal_radii",
6
+ "registrationerror": "reg_error",
7
+ "searchdepth": "max_distance",
8
+ "searchscale": "cyl_radius",
9
+ "usemedian": "robust_aggr",
10
+ }
11
+
12
+
13
+ class CloudCompareM3C2(M3C2):
14
+ def __init__(self, **params):
15
+ """An M3C2 implementation that uses parameter names from CloudCompare"""
16
+ # Remap parameters using above mapping
17
+ py4dgeo_params = {
18
+ _cloudcompare_param_mapping.get(k, k): v for k, v in params.items()
19
+ }
20
+
21
+ # Apply changes that are not a mere renaming
22
+
23
+ # Scale parameters are diameters in CloudCompare and radii in py4dgeo
24
+ if "cyl_radius" in py4dgeo_params:
25
+ py4dgeo_params["cyl_radius"] = py4dgeo_params["cyl_radius"] * 0.5
26
+ if "normal_radii" in py4dgeo_params:
27
+ py4dgeo_params["normal_radii"] = tuple(
28
+ 0.5 * r for r in py4dgeo_params["normal_radii"]
29
+ )
30
+
31
+ # Intialize base class with remapped parameters
32
+ super().__init__(**py4dgeo_params)