pye57 0.3.1__tar.gz → 0.4.2__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.

Potentially problematic release.


This version of pye57 might be problematic. Click here for more details.

Files changed (85) hide show
  1. {pye57-0.3.1/src/pye57.egg-info → pye57-0.4.2}/PKG-INFO +9 -8
  2. {pye57-0.3.1 → pye57-0.4.2}/README.md +1 -1
  3. {pye57-0.3.1 → pye57-0.4.2}/setup.py +4 -3
  4. pye57-0.4.2/src/pye57/__version__.py +1 -0
  5. {pye57-0.3.1 → pye57-0.4.2}/src/pye57/e57.py +39 -10
  6. {pye57-0.3.1 → pye57-0.4.2}/src/pye57/scan_header.py +37 -1
  7. pye57-0.4.2/src/pye57/utils.py +42 -0
  8. {pye57-0.3.1 → pye57-0.4.2/src/pye57.egg-info}/PKG-INFO +9 -8
  9. {pye57-0.3.1 → pye57-0.4.2}/src/pye57.egg-info/SOURCES.txt +30 -1
  10. pye57-0.4.2/tests/test_main.py +305 -0
  11. pye57-0.3.1/src/pye57/__version__.py +0 -1
  12. pye57-0.3.1/src/pye57/utils.py +0 -21
  13. {pye57-0.3.1 → pye57-0.4.2}/LICENSE +0 -0
  14. {pye57-0.3.1 → pye57-0.4.2}/MANIFEST.in +0 -0
  15. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/LICENSE.md +0 -0
  16. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/README.md +0 -0
  17. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/extern/CRCpp/LICENSE +0 -0
  18. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/extern/CRCpp/README.md +0 -0
  19. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/extern/CRCpp/inc/CRC.h +0 -0
  20. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/include/E57Exception.h +0 -0
  21. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/include/E57Format.h +0 -0
  22. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/include/E57SimpleData.h +0 -0
  23. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/include/E57SimpleReader.h +0 -0
  24. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/include/E57SimpleWriter.h +0 -0
  25. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/BlobNodeImpl.cpp +0 -0
  26. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/BlobNodeImpl.h +0 -0
  27. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/CheckedFile.cpp +0 -0
  28. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/CheckedFile.h +0 -0
  29. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/Common.cpp +0 -0
  30. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/Common.h +0 -0
  31. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/CompressedVectorNodeImpl.cpp +0 -0
  32. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/CompressedVectorNodeImpl.h +0 -0
  33. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/CompressedVectorReaderImpl.cpp +0 -0
  34. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/CompressedVectorReaderImpl.h +0 -0
  35. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/CompressedVectorWriterImpl.cpp +0 -0
  36. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/CompressedVectorWriterImpl.h +0 -0
  37. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/DecodeChannel.cpp +0 -0
  38. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/DecodeChannel.h +0 -0
  39. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/Decoder.cpp +0 -0
  40. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/Decoder.h +0 -0
  41. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/E57Exception.cpp +0 -0
  42. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/E57Format.cpp +0 -0
  43. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/E57SimpleData.cpp +0 -0
  44. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/E57SimpleReader.cpp +0 -0
  45. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/E57SimpleWriter.cpp +0 -0
  46. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/E57Version.h +0 -0
  47. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/E57XmlParser.cpp +0 -0
  48. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/E57XmlParser.h +0 -0
  49. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/Encoder.cpp +0 -0
  50. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/Encoder.h +0 -0
  51. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/FloatNodeImpl.cpp +0 -0
  52. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/FloatNodeImpl.h +0 -0
  53. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/ImageFileImpl.cpp +0 -0
  54. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/ImageFileImpl.h +0 -0
  55. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/IntegerNodeImpl.cpp +0 -0
  56. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/IntegerNodeImpl.h +0 -0
  57. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/NodeImpl.cpp +0 -0
  58. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/NodeImpl.h +0 -0
  59. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/Packet.cpp +0 -0
  60. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/Packet.h +0 -0
  61. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/ReaderImpl.cpp +0 -0
  62. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/ReaderImpl.h +0 -0
  63. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/ScaledIntegerNodeImpl.cpp +0 -0
  64. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/ScaledIntegerNodeImpl.h +0 -0
  65. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/SectionHeaders.cpp +0 -0
  66. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/SectionHeaders.h +0 -0
  67. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/SourceDestBufferImpl.cpp +0 -0
  68. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/SourceDestBufferImpl.h +0 -0
  69. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/StringNodeImpl.cpp +0 -0
  70. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/StringNodeImpl.h +0 -0
  71. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/StructureNodeImpl.cpp +0 -0
  72. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/StructureNodeImpl.h +0 -0
  73. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/VectorNodeImpl.cpp +0 -0
  74. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/VectorNodeImpl.h +0 -0
  75. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/WriterImpl.cpp +0 -0
  76. {pye57-0.3.1 → pye57-0.4.2}/libE57Format/src/WriterImpl.h +0 -0
  77. {pye57-0.3.1 → pye57-0.4.2}/pyproject.toml +0 -0
  78. {pye57-0.3.1 → pye57-0.4.2}/setup.cfg +0 -0
  79. {pye57-0.3.1 → pye57-0.4.2}/src/pye57/__init__.py +0 -0
  80. {pye57-0.3.1 → pye57-0.4.2}/src/pye57/exception.py +0 -0
  81. {pye57-0.3.1 → pye57-0.4.2}/src/pye57/libe57_wrapper.cpp +0 -0
  82. {pye57-0.3.1 → pye57-0.4.2}/src/pye57.egg-info/dependency_links.txt +0 -0
  83. {pye57-0.3.1 → pye57-0.4.2}/src/pye57.egg-info/not-zip-safe +0 -0
  84. {pye57-0.3.1 → pye57-0.4.2}/src/pye57.egg-info/requires.txt +0 -0
  85. {pye57-0.3.1 → pye57-0.4.2}/src/pye57.egg-info/top_level.txt +0 -0
@@ -1,31 +1,34 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pye57
3
- Version: 0.3.1
3
+ Version: 0.4.2
4
4
  Summary: Python .e57 files reader/writer
5
5
  Home-page: https://www.github.com/davidcaron/pye57
6
6
  Author: David Caron
7
7
  Author-email: dcaron05@gmail.com
8
8
  License: MIT
9
- Platform: UNKNOWN
10
9
  Classifier: License :: OSI Approved :: MIT License
11
10
  Classifier: Programming Language :: Python
12
11
  Classifier: Programming Language :: Python :: 3
13
- Classifier: Programming Language :: Python :: 3.7
14
12
  Classifier: Programming Language :: Python :: 3.8
15
13
  Classifier: Programming Language :: Python :: 3.9
16
14
  Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
17
  Classifier: Programming Language :: Python :: Implementation :: CPython
18
- Requires-Python: >=3.7
18
+ Requires-Python: >=3.8
19
19
  Description-Content-Type: text/markdown
20
- Provides-Extra: test
21
20
  License-File: LICENSE
21
+ Requires-Dist: numpy
22
+ Requires-Dist: pyquaternion
23
+ Provides-Extra: test
24
+ Requires-Dist: pytest; extra == "test"
22
25
 
23
26
 
24
27
  # pye57
25
28
 
26
29
  [![PyPI](https://img.shields.io/pypi/v/pye57.svg)](https://pypi.org/project/pye57)
27
30
  [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/pye57.svg)](https://pypi.org/project/pye57)
28
- ![GitHub](https://img.shields.io/github/workflow/status/davidcaron/pye57/build)
31
+ ![GitHub](https://img.shields.io/github/actions/workflow/status/davidcaron/pye57/build.yml?branch=master)
29
32
 
30
33
  Python wrapper of [LibE57Format](https://github.com/asmaloney/libE57Format) to read and write .e57 point cloud files
31
34
 
@@ -137,5 +140,3 @@ Use pip again
137
140
  ```
138
141
  python -m pip uninstall pye57
139
142
  ```
140
-
141
-
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![PyPI](https://img.shields.io/pypi/v/pye57.svg)](https://pypi.org/project/pye57)
4
4
  [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/pye57.svg)](https://pypi.org/project/pye57)
5
- ![GitHub](https://img.shields.io/github/workflow/status/davidcaron/pye57/build)
5
+ ![GitHub](https://img.shields.io/github/actions/workflow/status/davidcaron/pye57/build.yml?branch=master)
6
6
 
7
7
  Python wrapper of [LibE57Format](https://github.com/asmaloney/libE57Format) to read and write .e57 point cloud files
8
8
 
@@ -107,7 +107,7 @@ setup(
107
107
  ext_modules=ext_modules,
108
108
  packages=["pye57"],
109
109
  package_dir={"": "src"},
110
- include_package_data=True,
110
+ # include_package_data=True,
111
111
  package_data={"pye57": package_data},
112
112
  extras_require={"test": "pytest"},
113
113
  license="MIT",
@@ -115,13 +115,14 @@ setup(
115
115
  "License :: OSI Approved :: MIT License",
116
116
  "Programming Language :: Python",
117
117
  "Programming Language :: Python :: 3",
118
- "Programming Language :: Python :: 3.7",
119
118
  "Programming Language :: Python :: 3.8",
120
119
  "Programming Language :: Python :: 3.9",
121
120
  "Programming Language :: Python :: 3.10",
121
+ "Programming Language :: Python :: 3.11",
122
+ "Programming Language :: Python :: 3.12",
122
123
  "Programming Language :: Python :: Implementation :: CPython",
123
124
  ],
124
125
  cmdclass={"build_ext": BuildExt},
125
126
  zip_safe=False,
126
- python_requires=">=3.7",
127
+ python_requires=">=3.8",
127
128
  )
@@ -0,0 +1 @@
1
+ __version__ = "0.4.2"
@@ -1,7 +1,7 @@
1
1
  import uuid
2
2
  import os
3
-
4
3
  from typing import Dict
4
+ from enum import Enum
5
5
 
6
6
  import numpy as np
7
7
  from pyquaternion import Quaternion
@@ -9,6 +9,7 @@ from pyquaternion import Quaternion
9
9
  from pye57.__version__ import __version__
10
10
  from pye57 import libe57
11
11
  from pye57 import ScanHeader
12
+ from pye57.utils import convert_spherical_to_cartesian
12
13
 
13
14
  try:
14
15
  from exceptions import WindowsError
@@ -16,10 +17,26 @@ except ImportError:
16
17
  class WindowsError(OSError):
17
18
  pass
18
19
 
19
- SUPPORTED_POINT_FIELDS = {
20
+
21
+ SUPPORTED_CARTESIAN_POINT_FIELDS = {
20
22
  "cartesianX": "d",
21
23
  "cartesianY": "d",
22
24
  "cartesianZ": "d",
25
+ }
26
+
27
+ SUPPORTED_SPHERICAL_POINT_FIELDS = {
28
+ "sphericalRange": "d",
29
+ "sphericalAzimuth": "d",
30
+ "sphericalElevation": "d",
31
+ }
32
+
33
+ class COORDINATE_SYSTEMS(Enum):
34
+ CARTESIAN = SUPPORTED_CARTESIAN_POINT_FIELDS
35
+ SPHERICAL = SUPPORTED_SPHERICAL_POINT_FIELDS
36
+
37
+ SUPPORTED_POINT_FIELDS = {
38
+ **SUPPORTED_CARTESIAN_POINT_FIELDS,
39
+ **SUPPORTED_SPHERICAL_POINT_FIELDS,
23
40
  "intensity": "f",
24
41
  "colorRed": "B",
25
42
  "colorGreen": "B",
@@ -27,6 +44,7 @@ SUPPORTED_POINT_FIELDS = {
27
44
  "rowIndex": "H",
28
45
  "columnIndex": "H",
29
46
  "cartesianInvalidState": "b",
47
+ "sphericalInvalidState": "b",
30
48
  }
31
49
 
32
50
 
@@ -147,7 +165,13 @@ class E57:
147
165
  header = self.get_header(index)
148
166
  n_points = header.point_count
149
167
 
150
- fields = ["cartesianX", "cartesianY", "cartesianZ"]
168
+ coordinate_system = header.get_coordinate_system(COORDINATE_SYSTEMS)
169
+ if coordinate_system is COORDINATE_SYSTEMS.CARTESIAN:
170
+ validState = "cartesianInvalidState"
171
+ fields = list(SUPPORTED_CARTESIAN_POINT_FIELDS.keys())
172
+ elif coordinate_system is COORDINATE_SYSTEMS.SPHERICAL:
173
+ validState = "sphericalInvalidState"
174
+ fields = list(SUPPORTED_SPHERICAL_POINT_FIELDS.keys())
151
175
  if intensity:
152
176
  fields.append("intensity")
153
177
  if colors:
@@ -157,7 +181,7 @@ class E57:
157
181
  if row_column:
158
182
  fields.append("rowIndex")
159
183
  fields.append("columnIndex")
160
- fields.append("cartesianInvalidState")
184
+ fields.append(validState)
161
185
 
162
186
  for field in fields[:]:
163
187
  if field not in header.point_fields:
@@ -170,22 +194,27 @@ class E57:
170
194
  data, buffers = self.make_buffers(fields, n_points)
171
195
  header.points.reader(buffers).read()
172
196
 
173
- if "cartesianInvalidState" in data.keys():
174
- valid = ~data["cartesianInvalidState"].astype("?")
197
+ if validState in data:
198
+ valid = ~data[validState].astype("?")
175
199
 
176
200
  for field in data:
177
201
  data[field] = data[field][valid]
178
202
 
179
- del data["cartesianInvalidState"]
203
+ del data[validState]
180
204
 
181
205
  if transform:
182
- xyz = np.array([data["cartesianX"], data["cartesianY"], data["cartesianZ"]]).T
206
+ if coordinate_system is COORDINATE_SYSTEMS.CARTESIAN:
207
+ xyz = np.array([data["cartesianX"], data["cartesianY"], data["cartesianZ"]]).T
208
+ elif coordinate_system is COORDINATE_SYSTEMS.SPHERICAL:
209
+ rae = np.array([data["sphericalRange"], data["sphericalAzimuth"], data["sphericalElevation"]]).T
210
+ # rae to xyz
211
+ xyz = convert_spherical_to_cartesian(rae)
212
+ # translation to global coordinates
183
213
  if header.has_pose():
184
214
  xyz = self.to_global(xyz, header.rotation, header.translation)
185
215
  data["cartesianX"] = xyz[:, 0]
186
216
  data["cartesianY"] = xyz[:, 1]
187
217
  data["cartesianZ"] = xyz[:, 2]
188
-
189
218
  return data
190
219
 
191
220
  def write_scan_raw(self, data: Dict, *, name=None, rotation=None, translation=None, scan_header=None):
@@ -194,7 +223,7 @@ class E57:
194
223
  raise ValueError("Unsupported point field: %s" % field)
195
224
 
196
225
  if rotation is None:
197
- rotation = getattr(scan_header, "rotation", np.array([0, 0, 0, 0]))
226
+ rotation = getattr(scan_header, "rotation", np.array([1, 0, 0, 0]))
198
227
 
199
228
  if translation is None:
200
229
  translation = getattr(scan_header, "translation", np.array([0, 0, 0]))
@@ -4,7 +4,6 @@ from pyquaternion import Quaternion
4
4
  from pye57 import libe57
5
5
  from pye57.utils import get_fields, get_node
6
6
 
7
-
8
7
  class ScanHeader:
9
8
  def __init__(self, scan_node):
10
9
  self.node = scan_node
@@ -53,6 +52,15 @@ class ScanHeader:
53
52
 
54
53
  def __getitem__(self, item):
55
54
  return self.node[item]
55
+
56
+ def get_coordinate_system(self, COORDINATE_SYSTEMS):
57
+ if all(x in self.point_fields for x in COORDINATE_SYSTEMS.CARTESIAN.value):
58
+ coordinate_system = COORDINATE_SYSTEMS.CARTESIAN
59
+ elif all(x in self.point_fields for x in COORDINATE_SYSTEMS.SPHERICAL.value):
60
+ coordinate_system = COORDINATE_SYSTEMS.SPHERICAL
61
+ else:
62
+ raise Exception(f"Scans coordinate system not supported, unsupported point field {self.point_fields}")
63
+ return coordinate_system
56
64
 
57
65
  @property
58
66
  def guid(self):
@@ -138,6 +146,34 @@ class ScanHeader:
138
146
  def zMaximum(self):
139
147
  return self.cartesianBounds["zMaximum"].value()
140
148
 
149
+ @property
150
+ def sphericalBounds(self):
151
+ return self["sphericalBounds"]
152
+
153
+ @property
154
+ def rangeMinimum(self):
155
+ return self.sphericalBounds["rangeMinimum"].value()
156
+
157
+ @property
158
+ def rangeMaximum(self):
159
+ return self.sphericalBounds["rangeMaximum"].value()
160
+
161
+ @property
162
+ def elevationMinimum(self):
163
+ return self.sphericalBounds["elevationMinimum"].value()
164
+
165
+ @property
166
+ def elevationMaximum(self):
167
+ return self.sphericalBounds["elevationMaximum"].value()
168
+
169
+ @property
170
+ def azimuthStart(self):
171
+ return self.sphericalBounds["azimuthStart"].value()
172
+
173
+ @property
174
+ def azimuthEnd(self):
175
+ return self.sphericalBounds["azimuthEnd"].value()
176
+
141
177
  @property
142
178
  def pose(self):
143
179
  return self["pose"]
@@ -0,0 +1,42 @@
1
+ from typing import Type
2
+
3
+ from pye57 import libe57
4
+ from pye57.libe57 import NodeType
5
+
6
+ import numpy as np
7
+
8
+ def get_fields(node):
9
+ return [node.get(id_).elementName() for id_ in range(node.childCount())]
10
+
11
+
12
+ def get_node(node, name):
13
+ cast = {
14
+ NodeType.E57_BLOB: libe57.BlobNode,
15
+ NodeType.E57_COMPRESSED_VECTOR: libe57.CompressedVectorNode,
16
+ NodeType.E57_FLOAT: libe57.FloatNode,
17
+ NodeType.E57_INTEGER: libe57.IntegerNode,
18
+ NodeType.E57_SCALED_INTEGER: libe57.ScaledIntegerNode,
19
+ NodeType.E57_STRING: libe57.StringNode,
20
+ NodeType.E57_STRUCTURE: libe57.StructureNode,
21
+ NodeType.E57_VECTOR: libe57.VectorNode
22
+ }
23
+ n = node.get(name)
24
+ return cast[n.type()](n)
25
+
26
+ def convert_spherical_to_cartesian(rae):
27
+ """
28
+ Converts spherical(rae) to cartesian(xyz), where rae = range, azimuth(theta),
29
+ elevation(phi). Where range is in meters and angles are in radians.
30
+
31
+ Reference for formula: http://www.libe57.org/bestCoordinates.html (Note: the
32
+ formula is different from the one online, so please use formula at the above reference)
33
+ """
34
+ range_ = rae[:, :1]
35
+ theta = rae[:, 1:2]
36
+ phi = rae[:, 2:3]
37
+ range_cos_phi = range_ * np.cos(phi)
38
+ return np.concatenate((
39
+ range_cos_phi * np.cos(theta),
40
+ range_cos_phi * np.sin(theta),
41
+ range_ * np.sin(phi)
42
+ ), axis=1)
@@ -1,31 +1,34 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pye57
3
- Version: 0.3.1
3
+ Version: 0.4.2
4
4
  Summary: Python .e57 files reader/writer
5
5
  Home-page: https://www.github.com/davidcaron/pye57
6
6
  Author: David Caron
7
7
  Author-email: dcaron05@gmail.com
8
8
  License: MIT
9
- Platform: UNKNOWN
10
9
  Classifier: License :: OSI Approved :: MIT License
11
10
  Classifier: Programming Language :: Python
12
11
  Classifier: Programming Language :: Python :: 3
13
- Classifier: Programming Language :: Python :: 3.7
14
12
  Classifier: Programming Language :: Python :: 3.8
15
13
  Classifier: Programming Language :: Python :: 3.9
16
14
  Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
17
  Classifier: Programming Language :: Python :: Implementation :: CPython
18
- Requires-Python: >=3.7
18
+ Requires-Python: >=3.8
19
19
  Description-Content-Type: text/markdown
20
- Provides-Extra: test
21
20
  License-File: LICENSE
21
+ Requires-Dist: numpy
22
+ Requires-Dist: pyquaternion
23
+ Provides-Extra: test
24
+ Requires-Dist: pytest; extra == "test"
22
25
 
23
26
 
24
27
  # pye57
25
28
 
26
29
  [![PyPI](https://img.shields.io/pypi/v/pye57.svg)](https://pypi.org/project/pye57)
27
30
  [![PyPI - Python Version](https://img.shields.io/pypi/pyversions/pye57.svg)](https://pypi.org/project/pye57)
28
- ![GitHub](https://img.shields.io/github/workflow/status/davidcaron/pye57/build)
31
+ ![GitHub](https://img.shields.io/github/actions/workflow/status/davidcaron/pye57/build.yml?branch=master)
29
32
 
30
33
  Python wrapper of [LibE57Format](https://github.com/asmaloney/libE57Format) to read and write .e57 point cloud files
31
34
 
@@ -137,5 +140,3 @@ Use pip again
137
140
  ```
138
141
  python -m pip uninstall pye57
139
142
  ```
140
-
141
-
@@ -3,6 +3,34 @@ MANIFEST.in
3
3
  README.md
4
4
  pyproject.toml
5
5
  setup.py
6
+ /home/runner/work/pye57/pye57/libE57Format/src/BlobNodeImpl.cpp
7
+ /home/runner/work/pye57/pye57/libE57Format/src/CheckedFile.cpp
8
+ /home/runner/work/pye57/pye57/libE57Format/src/Common.cpp
9
+ /home/runner/work/pye57/pye57/libE57Format/src/CompressedVectorNodeImpl.cpp
10
+ /home/runner/work/pye57/pye57/libE57Format/src/CompressedVectorReaderImpl.cpp
11
+ /home/runner/work/pye57/pye57/libE57Format/src/CompressedVectorWriterImpl.cpp
12
+ /home/runner/work/pye57/pye57/libE57Format/src/DecodeChannel.cpp
13
+ /home/runner/work/pye57/pye57/libE57Format/src/Decoder.cpp
14
+ /home/runner/work/pye57/pye57/libE57Format/src/E57Exception.cpp
15
+ /home/runner/work/pye57/pye57/libE57Format/src/E57Format.cpp
16
+ /home/runner/work/pye57/pye57/libE57Format/src/E57SimpleData.cpp
17
+ /home/runner/work/pye57/pye57/libE57Format/src/E57SimpleReader.cpp
18
+ /home/runner/work/pye57/pye57/libE57Format/src/E57SimpleWriter.cpp
19
+ /home/runner/work/pye57/pye57/libE57Format/src/E57XmlParser.cpp
20
+ /home/runner/work/pye57/pye57/libE57Format/src/Encoder.cpp
21
+ /home/runner/work/pye57/pye57/libE57Format/src/FloatNodeImpl.cpp
22
+ /home/runner/work/pye57/pye57/libE57Format/src/ImageFileImpl.cpp
23
+ /home/runner/work/pye57/pye57/libE57Format/src/IntegerNodeImpl.cpp
24
+ /home/runner/work/pye57/pye57/libE57Format/src/NodeImpl.cpp
25
+ /home/runner/work/pye57/pye57/libE57Format/src/Packet.cpp
26
+ /home/runner/work/pye57/pye57/libE57Format/src/ReaderImpl.cpp
27
+ /home/runner/work/pye57/pye57/libE57Format/src/ScaledIntegerNodeImpl.cpp
28
+ /home/runner/work/pye57/pye57/libE57Format/src/SectionHeaders.cpp
29
+ /home/runner/work/pye57/pye57/libE57Format/src/SourceDestBufferImpl.cpp
30
+ /home/runner/work/pye57/pye57/libE57Format/src/StringNodeImpl.cpp
31
+ /home/runner/work/pye57/pye57/libE57Format/src/StructureNodeImpl.cpp
32
+ /home/runner/work/pye57/pye57/libE57Format/src/VectorNodeImpl.cpp
33
+ /home/runner/work/pye57/pye57/libE57Format/src/WriterImpl.cpp
6
34
  libE57Format/LICENSE.md
7
35
  libE57Format/README.md
8
36
  libE57Format/extern/CRCpp/LICENSE
@@ -77,4 +105,5 @@ src/pye57.egg-info/SOURCES.txt
77
105
  src/pye57.egg-info/dependency_links.txt
78
106
  src/pye57.egg-info/not-zip-safe
79
107
  src/pye57.egg-info/requires.txt
80
- src/pye57.egg-info/top_level.txt
108
+ src/pye57.egg-info/top_level.txt
109
+ tests/test_main.py
@@ -0,0 +1,305 @@
1
+ import pytest
2
+ import os
3
+ import time
4
+
5
+ import numpy as np
6
+
7
+ import pye57
8
+ from pye57 import libe57
9
+ from pye57.utils import get_fields
10
+
11
+ try:
12
+ from exceptions import WindowsError
13
+ except ImportError:
14
+ class WindowsError(OSError):
15
+ pass
16
+
17
+
18
+ def test_hi():
19
+ assert libe57.__doc__
20
+
21
+
22
+ def test_data(*args):
23
+ here = os.path.split(__file__)[0]
24
+ return os.path.join(here, "test_data", *args)
25
+
26
+
27
+ def delete_retry(path):
28
+ try:
29
+ if os.path.exists(path):
30
+ os.remove(path)
31
+ except WindowsError:
32
+ time.sleep(0.1)
33
+ if os.path.exists(path):
34
+ os.remove(path)
35
+
36
+
37
+ @pytest.fixture
38
+ def e57_path():
39
+ return test_data("test.e57")
40
+
41
+ @pytest.fixture
42
+ def e57_spherical_path():
43
+ return test_data("testSpherical.e57")
44
+
45
+ @pytest.fixture
46
+ def temp_e57_write(request):
47
+ path = test_data("test_write.e57")
48
+ request.addfinalizer(lambda: delete_retry(path))
49
+ return path
50
+
51
+
52
+ @pytest.fixture
53
+ def image_and_points(e57_path):
54
+ f = libe57.ImageFile(e57_path, mode="r")
55
+ scan_0 = libe57.StructureNode(libe57.VectorNode(f.root().get("/data3D")).get(0))
56
+ points = libe57.CompressedVectorNode(scan_0.get("points"))
57
+ return f, points
58
+
59
+
60
+ def test_constants():
61
+ assert libe57.CHECKSUM_POLICY_NONE == 0
62
+ assert libe57.CHECKSUM_POLICY_SPARSE == 25
63
+ assert libe57.CHECKSUM_POLICY_HALF == 50
64
+ assert libe57.CHECKSUM_POLICY_ALL == 100
65
+ assert libe57.E57_INT8_MIN == -128
66
+ assert libe57.E57_INT8_MAX == 127
67
+ assert libe57.E57_INT16_MIN == -32768
68
+ assert libe57.E57_INT16_MAX == 32767
69
+ assert libe57.E57_INT32_MIN == -2147483647 - 1
70
+ assert libe57.E57_INT32_MAX == 2147483647
71
+ assert libe57.E57_INT64_MIN == -9223372036854775807 - 1
72
+ assert libe57.E57_INT64_MAX == 9223372036854775807
73
+ assert libe57.E57_UINT8_MIN == 0
74
+ assert libe57.E57_UINT8_MAX == 255
75
+ assert libe57.E57_UINT16_MIN == 0
76
+ assert libe57.E57_UINT16_MAX == 65535
77
+ assert libe57.E57_UINT32_MIN == 0
78
+ assert libe57.E57_UINT32_MAX == 4294967295
79
+ assert libe57.E57_UINT64_MIN == 0
80
+ assert libe57.E57_UINT64_MAX == 18446744073709551615
81
+
82
+
83
+ def test_open_imagefile(e57_path):
84
+ f = libe57.ImageFile(e57_path, mode="r")
85
+ assert f.isOpen()
86
+ f.close()
87
+
88
+
89
+ def test_open_imagefile_write(temp_e57_write):
90
+ f = libe57.ImageFile(temp_e57_write, mode="w")
91
+ assert f.isOpen()
92
+ f.close()
93
+
94
+
95
+ def test_e57_mode_error(temp_e57_write):
96
+ with pytest.raises(ValueError):
97
+ f = pye57.E57(temp_e57_write, mode="pasta")
98
+
99
+
100
+ def test_get_structure_names(e57_path):
101
+ f = libe57.ImageFile(e57_path, "r")
102
+ root = f.root()
103
+ names = []
104
+ for id_ in range(root.childCount()):
105
+ names.append(root.get(id_).pathName())
106
+ assert names == ['/formatName', '/guid', '/versionMajor', '/versionMinor', '/e57LibraryVersion',
107
+ '/coordinateMetadata', '/creationDateTime', '/data3D', '/images2D']
108
+
109
+
110
+ def test_get_data3d_nodes(e57_path):
111
+ f = libe57.ImageFile(e57_path, "r")
112
+ root = f.root()
113
+ node = root.get("data3D")
114
+ data3d = libe57.VectorNode(node)
115
+ scan_count = data3d.childCount()
116
+ assert scan_count == 4
117
+ for scan_id in range(scan_count):
118
+ assert isinstance(data3d.get(scan_id), libe57.Node)
119
+
120
+
121
+ def test_get_read_data3d(e57_path):
122
+ f = libe57.ImageFile(e57_path, "r")
123
+ scan_0 = libe57.StructureNode(libe57.VectorNode(f.root().get("/data3D")).get(0))
124
+ points = libe57.CompressedVectorNode(scan_0.get("points"))
125
+ assert points.childCount() == 281300
126
+
127
+
128
+ def test_source_dest_buffers(e57_path):
129
+ f = libe57.ImageFile(e57_path, "r")
130
+ capacity = 1000
131
+ types = list("bBhHlLq?fd")
132
+ sizes = [1, 1, 2, 2, 4, 4, 8, 1, 4, 8]
133
+ buffers = libe57.VectorSourceDestBuffer()
134
+ for t in types:
135
+ data = np.zeros(capacity, t)
136
+ sdb = libe57.SourceDestBuffer(f, "something", data, capacity, True, True)
137
+ buffers.append(sdb)
138
+
139
+ for t, sdb, size, in zip(types, buffers, sizes):
140
+ assert sdb.pathName() == "something"
141
+ assert sdb.capacity() == capacity
142
+ assert sdb.stride() == size
143
+ assert sdb.doScaling()
144
+ assert sdb.doConversion()
145
+
146
+
147
+ def test_unsupported_point_field(temp_e57_write):
148
+ with pye57.E57(temp_e57_write, mode="w") as f:
149
+ with pytest.raises(ValueError):
150
+ data = {"cartesianX": np.random.rand(10),
151
+ "bananas": np.random.rand(10)}
152
+ f.write_scan_raw(data)
153
+
154
+
155
+ def test_source_dest_buffers_raises(e57_path):
156
+ f = libe57.ImageFile(e57_path, "r")
157
+ capacity = 1000
158
+ data = np.zeros(capacity, "i")
159
+ with pytest.raises(ValueError):
160
+ libe57.SourceDestBuffer(f, "something", data, capacity, True, True)
161
+
162
+
163
+ def test_read_points_x(image_and_points):
164
+ imf, points = image_and_points
165
+ bufs = libe57.VectorSourceDestBuffer()
166
+ capacity = 10000
167
+ X = np.zeros(capacity, "f")
168
+ bufs.append(libe57.SourceDestBuffer(imf, "cartesianX", X, capacity, True, True))
169
+ data_reader = points.reader(bufs)
170
+ size = data_reader.read()
171
+ assert size == capacity
172
+ assert not np.all(np.zeros(capacity, "f") == X)
173
+
174
+
175
+ def test_index_out_of_range(e57_path):
176
+ f = libe57.ImageFile(e57_path, "r")
177
+ with pytest.raises(IndexError):
178
+ scan = f.root()["data3D"][-1]
179
+ with pytest.raises(IndexError):
180
+ scan = f.root()["data3D"][5]
181
+ scan_0 = f.root()["data3D"][0]
182
+ with pytest.raises(IndexError):
183
+ r = scan_0["pose"]["rotation"][-1]
184
+ with pytest.raises(IndexError):
185
+ r = scan_0["pose"]["rotation"][5]
186
+
187
+
188
+ def test_read_header(e57_path):
189
+ f = libe57.ImageFile(e57_path, "r")
190
+ data3d = f.root()["data3D"]
191
+ headers = pye57.ScanHeader.from_data3d(data3d)
192
+ fields = ['cartesianX', 'cartesianY', 'cartesianZ', 'intensity', 'rowIndex', 'columnIndex', 'cartesianInvalidState']
193
+ for header in headers:
194
+ assert fields == header.point_fields
195
+ assert headers[0].pretty_print()
196
+ scan_0_rot = [[-0.4443, 0.8958, 0.],
197
+ [-0.8958, -0.4443, 0.],
198
+ [0., 0., 1.]]
199
+ assert np.allclose(scan_0_rot, headers[0].rotation_matrix, atol=1e-3)
200
+ scan_0_tra = [301336.23199, 5042597.23676, 15.46649]
201
+ assert np.allclose(scan_0_tra, headers[0].translation)
202
+
203
+
204
+ def test_read_xyz(e57_path):
205
+ e57 = pye57.E57(e57_path)
206
+ xyz = e57.read_scan(0)
207
+ assert np.any(xyz)
208
+
209
+
210
+ def test_read_header_spherical(e57_spherical_path):
211
+ f = libe57.ImageFile(e57_spherical_path, "r")
212
+ data3d = f.root()["data3D"]
213
+ headers = pye57.ScanHeader.from_data3d(data3d)
214
+ fields = ['sphericalRange', 'sphericalAzimuth', 'sphericalElevation', 'intensity', 'colorRed', 'colorGreen', 'colorBlue', 'sphericalInvalidState']
215
+ for header in headers:
216
+ assert fields == header.point_fields
217
+ assert headers[0].pretty_print()
218
+
219
+
220
+ def test_read_xyz_spherical(e57_spherical_path):
221
+ e57 = pye57.E57(e57_spherical_path)
222
+ xyz = e57.read_scan(0)
223
+ assert np.any(xyz)
224
+
225
+
226
+ def test_read_raw(e57_path):
227
+ e57 = pye57.E57(e57_path)
228
+ header = e57.get_header(0)
229
+ fields = header.point_fields
230
+ data = e57.read_scan_raw(0)
231
+ assert sorted(fields) == sorted(data.keys())
232
+ assert np.any(data["cartesianX"])
233
+ assert len(data["cartesianX"]) == header.point_count
234
+
235
+
236
+ def test_read_write_single_scan(e57_path, temp_e57_write):
237
+ e57 = pye57.E57(e57_path)
238
+ header_source = e57.get_header(0)
239
+ with pye57.E57(temp_e57_write, mode="w") as e57_write:
240
+ raw_data_0 = e57.read_scan_raw(0)
241
+ e57_write.write_scan_raw(raw_data_0, rotation=header_source.rotation, translation=header_source.translation)
242
+ scan_0 = pye57.E57(e57_path).read_scan_raw(0)
243
+ written = pye57.E57(temp_e57_write)
244
+ header = written.get_header(0)
245
+ assert np.allclose(header.rotation, header_source.rotation)
246
+ assert np.allclose(header.translation, header_source.translation)
247
+ scan_0_written = written.read_scan_raw(0)
248
+ fields = "cartesianX cartesianY cartesianZ intensity rowIndex columnIndex cartesianInvalidState".split()
249
+ for field in fields:
250
+ assert np.allclose(scan_0[field], scan_0_written[field])
251
+
252
+ scan_0 = e57.read_scan(0)
253
+ scan_0_written = written.read_scan(0)
254
+ for field in scan_0:
255
+ assert np.allclose(scan_0[field], scan_0_written[field])
256
+
257
+
258
+ def test_copy_file(e57_path, temp_e57_write):
259
+ e57 = pye57.E57(e57_path)
260
+ with pye57.E57(temp_e57_write, mode="w") as f:
261
+ for scan_id in range(e57.scan_count):
262
+ header = e57.get_header(scan_id)
263
+ data = e57.read_scan_raw(scan_id)
264
+ f.write_scan_raw(data, scan_header=header)
265
+ header_written = f.get_header(scan_id)
266
+ assert header_written.guid
267
+ assert header_written.temperature == header_written.temperature
268
+ assert header_written.relativeHumidity == header_written.relativeHumidity
269
+ assert header_written.atmosphericPressure == header_written.atmosphericPressure
270
+ assert header_written.rowMinimum == header.rowMinimum
271
+ assert header_written.rowMaximum == header.rowMaximum
272
+ assert header_written.columnMinimum == header.columnMinimum
273
+ assert header_written.columnMaximum == header.columnMaximum
274
+ assert header_written.returnMinimum == header.returnMinimum
275
+ assert header_written.returnMaximum == header.returnMaximum
276
+ assert header_written.intensityMinimum == header.intensityMinimum
277
+ assert header_written.intensityMaximum == header.intensityMaximum
278
+ assert header_written.xMinimum == header.xMinimum
279
+ assert header_written.xMaximum == header.xMaximum
280
+ assert header_written.yMinimum == header.yMinimum
281
+ assert header_written.yMaximum == header.yMaximum
282
+ assert header_written.zMinimum == header.zMinimum
283
+ assert header_written.zMaximum == header.zMaximum
284
+ assert np.allclose(header_written.rotation, header.rotation)
285
+ assert np.allclose(header_written.translation, header.translation)
286
+ assert header_written.acquisitionStart_dateTimeValue == header.acquisitionStart_dateTimeValue
287
+ assert header_written.acquisitionStart_isAtomicClockReferenced == header.acquisitionStart_isAtomicClockReferenced
288
+ assert header_written.acquisitionEnd_dateTimeValue == header.acquisitionEnd_dateTimeValue
289
+ assert header_written.acquisitionEnd_isAtomicClockReferenced == header.acquisitionEnd_isAtomicClockReferenced
290
+ # todo: point groups
291
+ # header.pointGroupingSchemes["groupingByLine"]["idElementName"].value()
292
+ # header.pointGroupingSchemes["groupingByLine"]["groups"]
293
+
294
+ assert f.scan_count == e57.scan_count
295
+
296
+
297
+ def test_read_color_absent(e57_path):
298
+ e57 = pye57.E57(e57_path)
299
+ with pytest.raises(ValueError):
300
+ data = e57.read_scan(0, colors=True)
301
+
302
+
303
+ def test_scan_position(e57_path):
304
+ e57 = pye57.E57(e57_path)
305
+ assert np.allclose(e57.scan_position(3), np.array([[3.01323456e+05, 5.04260184e+06, 1.56040279e+01]]))
@@ -1 +0,0 @@
1
- __version__ = "0.3.1"
@@ -1,21 +0,0 @@
1
- from pye57 import libe57
2
- from pye57.libe57 import NodeType
3
-
4
-
5
- def get_fields(node):
6
- return [node.get(id_).elementName() for id_ in range(node.childCount())]
7
-
8
-
9
- def get_node(node, name):
10
- cast = {
11
- NodeType.E57_BLOB: libe57.BlobNode,
12
- NodeType.E57_COMPRESSED_VECTOR: libe57.CompressedVectorNode,
13
- NodeType.E57_FLOAT: libe57.FloatNode,
14
- NodeType.E57_INTEGER: libe57.IntegerNode,
15
- NodeType.E57_SCALED_INTEGER: libe57.ScaledIntegerNode,
16
- NodeType.E57_STRING: libe57.StringNode,
17
- NodeType.E57_STRUCTURE: libe57.StructureNode,
18
- NodeType.E57_VECTOR: libe57.VectorNode
19
- }
20
- n = node.get(name)
21
- return cast[n.type()](n)
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