py4dgeo 0.7.0__cp39-cp39-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.
- _py4dgeo.cpython-39-darwin.so +0 -0
- py4dgeo/.dylibs/libomp.dylib +0 -0
- py4dgeo/UpdateableZipFile.py +81 -0
- py4dgeo/__init__.py +32 -0
- py4dgeo/cloudcompare.py +32 -0
- py4dgeo/epoch.py +814 -0
- py4dgeo/fallback.py +159 -0
- py4dgeo/logger.py +77 -0
- py4dgeo/m3c2.py +244 -0
- py4dgeo/m3c2ep.py +855 -0
- py4dgeo/pbm3c2.py +3870 -0
- py4dgeo/py4dgeo_python.cpp +487 -0
- py4dgeo/registration.py +474 -0
- py4dgeo/segmentation.py +1280 -0
- py4dgeo/util.py +263 -0
- py4dgeo-0.7.0.dist-info/METADATA +200 -0
- py4dgeo-0.7.0.dist-info/RECORD +21 -0
- py4dgeo-0.7.0.dist-info/WHEEL +5 -0
- py4dgeo-0.7.0.dist-info/entry_points.txt +3 -0
- py4dgeo-0.7.0.dist-info/licenses/COPYING.md +17 -0
- py4dgeo-0.7.0.dist-info/licenses/LICENSE.md +5 -0
|
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 *
|
py4dgeo/cloudcompare.py
ADDED
|
@@ -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)
|