amulet-core 1.9.19__py3-none-any.whl → 1.9.20__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.

Potentially problematic release.


This version of amulet-core might be problematic. Click here for more details.

Files changed (198) hide show
  1. amulet/__init__.py +27 -27
  2. amulet/__pyinstaller/__init__.py +2 -2
  3. amulet/__pyinstaller/hook-amulet.py +4 -4
  4. amulet/_version.py +21 -21
  5. amulet/api/__init__.py +2 -2
  6. amulet/api/abstract_base_entity.py +128 -128
  7. amulet/api/block.py +630 -630
  8. amulet/api/block_entity.py +71 -71
  9. amulet/api/cache.py +107 -107
  10. amulet/api/chunk/__init__.py +6 -6
  11. amulet/api/chunk/biomes.py +207 -207
  12. amulet/api/chunk/block_entity_dict.py +175 -175
  13. amulet/api/chunk/blocks.py +46 -46
  14. amulet/api/chunk/chunk.py +389 -389
  15. amulet/api/chunk/entity_list.py +75 -75
  16. amulet/api/chunk/status.py +167 -167
  17. amulet/api/data_types/__init__.py +4 -4
  18. amulet/api/data_types/generic_types.py +4 -4
  19. amulet/api/data_types/operation_types.py +16 -16
  20. amulet/api/data_types/world_types.py +49 -49
  21. amulet/api/data_types/wrapper_types.py +71 -71
  22. amulet/api/entity.py +74 -74
  23. amulet/api/errors.py +119 -119
  24. amulet/api/history/__init__.py +36 -36
  25. amulet/api/history/base/__init__.py +3 -3
  26. amulet/api/history/base/base_history.py +26 -26
  27. amulet/api/history/base/history_manager.py +63 -63
  28. amulet/api/history/base/revision_manager.py +73 -73
  29. amulet/api/history/changeable.py +15 -15
  30. amulet/api/history/data_types.py +7 -7
  31. amulet/api/history/history_manager/__init__.py +3 -3
  32. amulet/api/history/history_manager/container.py +102 -102
  33. amulet/api/history/history_manager/database.py +279 -279
  34. amulet/api/history/history_manager/meta.py +93 -93
  35. amulet/api/history/history_manager/object.py +116 -116
  36. amulet/api/history/revision_manager/__init__.py +2 -2
  37. amulet/api/history/revision_manager/disk.py +33 -33
  38. amulet/api/history/revision_manager/ram.py +12 -12
  39. amulet/api/item.py +75 -75
  40. amulet/api/level/__init__.py +4 -4
  41. amulet/api/level/base_level/__init__.py +1 -1
  42. amulet/api/level/base_level/base_level.py +1035 -1026
  43. amulet/api/level/base_level/chunk_manager.py +227 -227
  44. amulet/api/level/base_level/clone.py +389 -389
  45. amulet/api/level/base_level/player_manager.py +101 -101
  46. amulet/api/level/immutable_structure/__init__.py +1 -1
  47. amulet/api/level/immutable_structure/immutable_structure.py +94 -94
  48. amulet/api/level/immutable_structure/void_format_wrapper.py +117 -117
  49. amulet/api/level/structure.py +22 -22
  50. amulet/api/level/world.py +19 -19
  51. amulet/api/partial_3d_array/__init__.py +2 -2
  52. amulet/api/partial_3d_array/base_partial_3d_array.py +263 -263
  53. amulet/api/partial_3d_array/bounded_partial_3d_array.py +528 -528
  54. amulet/api/partial_3d_array/data_types.py +15 -15
  55. amulet/api/partial_3d_array/unbounded_partial_3d_array.py +229 -229
  56. amulet/api/partial_3d_array/util.py +152 -152
  57. amulet/api/player.py +65 -65
  58. amulet/api/registry/__init__.py +2 -2
  59. amulet/api/registry/base_registry.py +34 -34
  60. amulet/api/registry/biome_manager.py +153 -153
  61. amulet/api/registry/block_manager.py +156 -156
  62. amulet/api/selection/__init__.py +2 -2
  63. amulet/api/selection/abstract_selection.py +315 -315
  64. amulet/api/selection/box.py +805 -805
  65. amulet/api/selection/group.py +488 -488
  66. amulet/api/structure.py +37 -37
  67. amulet/api/wrapper/__init__.py +8 -8
  68. amulet/api/wrapper/chunk/interface.py +441 -441
  69. amulet/api/wrapper/chunk/translator.py +567 -567
  70. amulet/api/wrapper/format_wrapper.py +772 -772
  71. amulet/api/wrapper/structure_format_wrapper.py +116 -116
  72. amulet/api/wrapper/world_format_wrapper.py +63 -63
  73. amulet/level/__init__.py +1 -1
  74. amulet/level/formats/anvil_forge_world.py +40 -40
  75. amulet/level/formats/anvil_world/__init__.py +3 -3
  76. amulet/level/formats/anvil_world/_sector_manager.py +291 -384
  77. amulet/level/formats/anvil_world/data_pack/__init__.py +2 -2
  78. amulet/level/formats/anvil_world/data_pack/data_pack.py +224 -224
  79. amulet/level/formats/anvil_world/data_pack/data_pack_manager.py +77 -77
  80. amulet/level/formats/anvil_world/dimension.py +177 -177
  81. amulet/level/formats/anvil_world/format.py +769 -769
  82. amulet/level/formats/anvil_world/region.py +384 -384
  83. amulet/level/formats/construction/__init__.py +3 -3
  84. amulet/level/formats/construction/format_wrapper.py +515 -515
  85. amulet/level/formats/construction/interface.py +134 -134
  86. amulet/level/formats/construction/section.py +60 -60
  87. amulet/level/formats/construction/util.py +165 -165
  88. amulet/level/formats/leveldb_world/__init__.py +3 -3
  89. amulet/level/formats/leveldb_world/chunk.py +33 -33
  90. amulet/level/formats/leveldb_world/dimension.py +385 -419
  91. amulet/level/formats/leveldb_world/format.py +659 -641
  92. amulet/level/formats/leveldb_world/interface/chunk/__init__.py +36 -36
  93. amulet/level/formats/leveldb_world/interface/chunk/base_leveldb_interface.py +836 -836
  94. amulet/level/formats/leveldb_world/interface/chunk/generate_interface.py +31 -31
  95. amulet/level/formats/leveldb_world/interface/chunk/leveldb_0.py +30 -30
  96. amulet/level/formats/leveldb_world/interface/chunk/leveldb_1.py +12 -12
  97. amulet/level/formats/leveldb_world/interface/chunk/leveldb_10.py +12 -12
  98. amulet/level/formats/leveldb_world/interface/chunk/leveldb_11.py +12 -12
  99. amulet/level/formats/leveldb_world/interface/chunk/leveldb_12.py +12 -12
  100. amulet/level/formats/leveldb_world/interface/chunk/leveldb_13.py +12 -12
  101. amulet/level/formats/leveldb_world/interface/chunk/leveldb_14.py +12 -12
  102. amulet/level/formats/leveldb_world/interface/chunk/leveldb_15.py +12 -12
  103. amulet/level/formats/leveldb_world/interface/chunk/leveldb_16.py +12 -12
  104. amulet/level/formats/leveldb_world/interface/chunk/leveldb_17.py +12 -12
  105. amulet/level/formats/leveldb_world/interface/chunk/leveldb_18.py +12 -12
  106. amulet/level/formats/leveldb_world/interface/chunk/leveldb_19.py +12 -12
  107. amulet/level/formats/leveldb_world/interface/chunk/leveldb_2.py +12 -12
  108. amulet/level/formats/leveldb_world/interface/chunk/leveldb_20.py +12 -12
  109. amulet/level/formats/leveldb_world/interface/chunk/leveldb_21.py +12 -12
  110. amulet/level/formats/leveldb_world/interface/chunk/leveldb_22.py +12 -12
  111. amulet/level/formats/leveldb_world/interface/chunk/leveldb_23.py +10 -10
  112. amulet/level/formats/leveldb_world/interface/chunk/leveldb_24.py +10 -10
  113. amulet/level/formats/leveldb_world/interface/chunk/leveldb_25.py +24 -24
  114. amulet/level/formats/leveldb_world/interface/chunk/leveldb_26.py +10 -10
  115. amulet/level/formats/leveldb_world/interface/chunk/leveldb_27.py +10 -10
  116. amulet/level/formats/leveldb_world/interface/chunk/leveldb_28.py +10 -10
  117. amulet/level/formats/leveldb_world/interface/chunk/leveldb_29.py +33 -33
  118. amulet/level/formats/leveldb_world/interface/chunk/leveldb_3.py +57 -57
  119. amulet/level/formats/leveldb_world/interface/chunk/leveldb_30.py +10 -10
  120. amulet/level/formats/leveldb_world/interface/chunk/leveldb_31.py +10 -10
  121. amulet/level/formats/leveldb_world/interface/chunk/leveldb_32.py +10 -10
  122. amulet/level/formats/leveldb_world/interface/chunk/leveldb_33.py +10 -10
  123. amulet/level/formats/leveldb_world/interface/chunk/leveldb_34.py +10 -10
  124. amulet/level/formats/leveldb_world/interface/chunk/leveldb_35.py +10 -10
  125. amulet/level/formats/leveldb_world/interface/chunk/leveldb_36.py +10 -10
  126. amulet/level/formats/leveldb_world/interface/chunk/leveldb_37.py +10 -10
  127. amulet/level/formats/leveldb_world/interface/chunk/leveldb_38.py +10 -10
  128. amulet/level/formats/leveldb_world/interface/chunk/leveldb_39.py +12 -12
  129. amulet/level/formats/leveldb_world/interface/chunk/leveldb_4.py +12 -12
  130. amulet/level/formats/leveldb_world/interface/chunk/leveldb_40.py +16 -16
  131. amulet/level/formats/leveldb_world/interface/chunk/leveldb_5.py +12 -12
  132. amulet/level/formats/leveldb_world/interface/chunk/leveldb_6.py +12 -12
  133. amulet/level/formats/leveldb_world/interface/chunk/leveldb_7.py +12 -12
  134. amulet/level/formats/leveldb_world/interface/chunk/leveldb_8.py +180 -180
  135. amulet/level/formats/leveldb_world/interface/chunk/leveldb_9.py +18 -18
  136. amulet/level/formats/leveldb_world/interface/chunk/leveldb_chunk_versions.py +79 -79
  137. amulet/level/formats/mcstructure/__init__.py +3 -3
  138. amulet/level/formats/mcstructure/chunk.py +50 -50
  139. amulet/level/formats/mcstructure/format_wrapper.py +408 -408
  140. amulet/level/formats/mcstructure/interface.py +175 -175
  141. amulet/level/formats/schematic/__init__.py +3 -3
  142. amulet/level/formats/schematic/chunk.py +55 -55
  143. amulet/level/formats/schematic/data_types.py +4 -4
  144. amulet/level/formats/schematic/format_wrapper.py +373 -373
  145. amulet/level/formats/schematic/interface.py +142 -142
  146. amulet/level/formats/sponge_schem/__init__.py +4 -4
  147. amulet/level/formats/sponge_schem/chunk.py +62 -62
  148. amulet/level/formats/sponge_schem/format_wrapper.py +463 -463
  149. amulet/level/formats/sponge_schem/interface.py +118 -118
  150. amulet/level/formats/sponge_schem/varint/__init__.py +1 -1
  151. amulet/level/formats/sponge_schem/varint/varint.py +87 -87
  152. amulet/level/interfaces/chunk/anvil/anvil_0.py +72 -72
  153. amulet/level/interfaces/chunk/anvil/anvil_1444.py +336 -336
  154. amulet/level/interfaces/chunk/anvil/anvil_1466.py +94 -94
  155. amulet/level/interfaces/chunk/anvil/anvil_1467.py +37 -37
  156. amulet/level/interfaces/chunk/anvil/anvil_1484.py +20 -20
  157. amulet/level/interfaces/chunk/anvil/anvil_1503.py +20 -20
  158. amulet/level/interfaces/chunk/anvil/anvil_1519.py +34 -34
  159. amulet/level/interfaces/chunk/anvil/anvil_1901.py +20 -20
  160. amulet/level/interfaces/chunk/anvil/anvil_1908.py +20 -20
  161. amulet/level/interfaces/chunk/anvil/anvil_1912.py +21 -21
  162. amulet/level/interfaces/chunk/anvil/anvil_1934.py +20 -20
  163. amulet/level/interfaces/chunk/anvil/anvil_2203.py +69 -69
  164. amulet/level/interfaces/chunk/anvil/anvil_2529.py +19 -19
  165. amulet/level/interfaces/chunk/anvil/anvil_2681.py +76 -76
  166. amulet/level/interfaces/chunk/anvil/anvil_2709.py +19 -19
  167. amulet/level/interfaces/chunk/anvil/anvil_2844.py +267 -267
  168. amulet/level/interfaces/chunk/anvil/anvil_3463.py +19 -19
  169. amulet/level/interfaces/chunk/anvil/anvil_na.py +607 -607
  170. amulet/level/interfaces/chunk/anvil/base_anvil_interface.py +326 -326
  171. amulet/level/load.py +59 -59
  172. amulet/level/loader.py +95 -95
  173. amulet/level/translators/chunk/bedrock/__init__.py +267 -267
  174. amulet/level/translators/chunk/bedrock/bedrock_nbt_blockstate_translator.py +46 -46
  175. amulet/level/translators/chunk/bedrock/bedrock_numerical_translator.py +39 -39
  176. amulet/level/translators/chunk/bedrock/bedrock_psudo_numerical_translator.py +37 -37
  177. amulet/level/translators/chunk/java/java_1_18_translator.py +40 -40
  178. amulet/level/translators/chunk/java/java_blockstate_translator.py +94 -94
  179. amulet/level/translators/chunk/java/java_numerical_translator.py +62 -62
  180. amulet/libs/leveldb/__init__.py +7 -7
  181. amulet/operations/__init__.py +5 -5
  182. amulet/operations/clone.py +18 -18
  183. amulet/operations/delete_chunk.py +32 -32
  184. amulet/operations/fill.py +30 -30
  185. amulet/operations/paste.py +65 -65
  186. amulet/operations/replace.py +58 -58
  187. amulet/utils/__init__.py +14 -14
  188. amulet/utils/format_utils.py +41 -41
  189. amulet/utils/generator.py +15 -15
  190. amulet/utils/matrix.py +243 -243
  191. amulet/utils/numpy_helpers.py +46 -46
  192. amulet/utils/world_utils.py +349 -349
  193. {amulet_core-1.9.19.dist-info → amulet_core-1.9.20.dist-info}/METADATA +97 -97
  194. amulet_core-1.9.20.dist-info/RECORD +208 -0
  195. amulet_core-1.9.19.dist-info/RECORD +0 -208
  196. {amulet_core-1.9.19.dist-info → amulet_core-1.9.20.dist-info}/WHEEL +0 -0
  197. {amulet_core-1.9.19.dist-info → amulet_core-1.9.20.dist-info}/entry_points.txt +0 -0
  198. {amulet_core-1.9.19.dist-info → amulet_core-1.9.20.dist-info}/top_level.txt +0 -0
amulet/utils/matrix.py CHANGED
@@ -1,243 +1,243 @@
1
- from typing import Tuple
2
- import math
3
- import numpy
4
- from amulet.api.data_types import FloatTriplet, PointCoordinates
5
-
6
-
7
- def scale_matrix(sx: float, sy: float, sz: float) -> numpy.ndarray:
8
- """
9
- Create a scale matrix from the inputs specified
10
-
11
- :param sx: The scale in the x axis
12
- :param sy: The scale in the y axis
13
- :param sz: The scale in the z axis
14
- :return: The 4x4 scale matrix
15
- """
16
- return numpy.array(
17
- [[sx, 0, 0, 0], [0, sy, 0, 0], [0, 0, sz, 0], [0, 0, 0, 1]], dtype=numpy.float64
18
- )
19
-
20
-
21
- def displacement_matrix(x: float, y: float, z: float) -> numpy.ndarray:
22
- """
23
- Create a displacement matrix from the inputs specified
24
-
25
- :param x: The displacement in the x axis
26
- :param y: The displacement in the y axis
27
- :param z: The displacement in the z axis
28
- :return: The 4x4 displacement matrix
29
- """
30
- return numpy.array(
31
- [[1, 0, 0, x], [0, 1, 0, y], [0, 0, 1, z], [0, 0, 0, 1]], dtype=numpy.float64
32
- )
33
-
34
-
35
- def _rotation_matrix(*angles: float, order=None) -> numpy.ndarray:
36
- """
37
- Create a rotation matrix from the inputs specified
38
-
39
- :param angles: The angles in radians
40
- :param order: The order the angles are specified. Transforms will be applied in this order.
41
- :return: The 4x4 rotation matrix
42
- """
43
- assert isinstance(order, str) and len(order) == len(
44
- angles
45
- ), "Order must be a string of the same length as angles."
46
- mat = numpy.identity(4, dtype=numpy.float64)
47
-
48
- for angle, axis in zip(angles, order):
49
- if angle:
50
- c = math.cos(angle)
51
- s = math.sin(angle)
52
- if axis == "x":
53
- mat = numpy.matmul(
54
- numpy.array(
55
- [[1, 0, 0, 0], [0, c, -s, 0], [0, s, c, 0], [0, 0, 0, 1]],
56
- dtype=numpy.float64,
57
- ),
58
- mat,
59
- )
60
- elif axis == "y":
61
- mat = numpy.matmul(
62
- numpy.array(
63
- [[c, 0, s, 0], [0, 1, 0, 0], [-s, 0, c, 0], [0, 0, 0, 1]],
64
- dtype=numpy.float64,
65
- ),
66
- mat,
67
- )
68
- elif axis == "z":
69
- mat = numpy.matmul(
70
- numpy.array(
71
- [[c, -s, 0, 0], [s, c, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]],
72
- dtype=numpy.float64,
73
- ),
74
- mat,
75
- )
76
-
77
- return mat
78
-
79
-
80
- def rotation_matrix_x(rx: float) -> numpy.ndarray:
81
- """
82
- Create a rotation matrix in the x axis
83
-
84
- :param rx: The angle in radians
85
- :return: The 4x4 rotation matrix
86
- """
87
- return _rotation_matrix(rx, order="x")
88
-
89
-
90
- def rotation_matrix_y(ry: float) -> numpy.ndarray:
91
- """
92
- Create a rotation matrix in the x axis
93
-
94
- :param ry: The angle in radians
95
- :return: The 4x4 rotation matrix
96
- """
97
- return _rotation_matrix(ry, order="y")
98
-
99
-
100
- def rotation_matrix_z(rz: float) -> numpy.ndarray:
101
- """
102
- Create a rotation matrix in the x axis
103
-
104
- :param rz: The angle in radians
105
- :return: The 4x4 rotation matrix
106
- """
107
- return _rotation_matrix(rz, order="z")
108
-
109
-
110
- def rotation_matrix_xy(rx: float, ry: float) -> numpy.ndarray:
111
- """
112
- Create a rotation matrix from the inputs specified
113
-
114
- :param rx: The rotation in radians in the x axis
115
- :param ry: The rotation in radians in the y axis
116
- :return: The 4x4 rotation matrix
117
- """
118
- return _rotation_matrix(rx, ry, order="xy")
119
-
120
-
121
- def rotation_matrix_yx(ry: float, rx: float) -> numpy.ndarray:
122
- """
123
- Create a rotation matrix from the inputs specified
124
-
125
- :param rx: The rotation in radians in the x axis
126
- :param ry: The rotation in radians in the y axis
127
- :return: The 4x4 rotation matrix
128
- """
129
- return _rotation_matrix(ry, rx, order="yx")
130
-
131
-
132
- def rotation_matrix_xyz(x: float, y: float, z: float) -> numpy.ndarray:
133
- """
134
- Create a rotation matrix from the inputs specified
135
-
136
- :param x: The rotation in radians in the x axis
137
- :param y: The rotation in radians in the y axis
138
- :param z: The rotation in radians in the z axis
139
- :return: The 4x4 rotation matrix
140
- """
141
- return _rotation_matrix(x, y, z, order="xyz")
142
-
143
-
144
- def transform_matrix(
145
- scale: FloatTriplet,
146
- rotation: FloatTriplet,
147
- displacement: PointCoordinates,
148
- order="xyz",
149
- ):
150
- """Create a 4x4 transformation matrix from the scale, rotation and displacement specified.
151
-
152
- :param scale: The scale in the x, y and z axis
153
- :param rotation: The rotation in the x, y and z axis in radians. (axis can be changed using `order`)
154
- :param displacement: The displacement in the x, y and z axis
155
- :param order: The order to apply the rotations in.
156
- :return: The 4x4 transformation matrix of combined scale, rotation and displacement
157
- """
158
- scale_transform = scale_matrix(*scale)
159
- rotation_transform = _rotation_matrix(*rotation, order=order)
160
- displacement_transform = displacement_matrix(*displacement)
161
- return numpy.matmul(
162
- displacement_transform,
163
- numpy.matmul(rotation_transform, scale_transform),
164
- )
165
-
166
-
167
- def inverse_transform_matrix(
168
- scale: FloatTriplet,
169
- rotation: FloatTriplet,
170
- displacement: PointCoordinates,
171
- order="xyz",
172
- ):
173
- """Create the inverse of the 4x4 transformation matrix from the scale, rotation and displacement specified.
174
- This should be the inverse of transform_matrix
175
-
176
- :param scale: The scale in the x, y and z axis
177
- :param rotation: The rotation in the x, y and z axis (axis can be changed using `order`)
178
- :param displacement: The displacement in the x, y and z axis
179
- :param order: The order to apply the rotations in.
180
- :return: The 4x4 transformation matrix of combined scale, rotation and displacement
181
- """
182
- scale_transform = scale_matrix(*1 / numpy.asarray(scale))
183
- ra, rb, rc = -numpy.asarray(rotation)
184
- rotation_transform = _rotation_matrix(
185
- rc, rb, ra, order="".join(list(reversed(order)))
186
- )
187
- displacement_transform = displacement_matrix(*-numpy.asarray(displacement))
188
- return numpy.matmul(
189
- scale_transform,
190
- numpy.matmul(rotation_transform, displacement_transform),
191
- )
192
-
193
-
194
- def decompose_transformation_matrix(
195
- matrix: numpy.ndarray,
196
- ) -> Tuple[
197
- Tuple[float, float, float], Tuple[float, float, float], Tuple[float, float, float]
198
- ]:
199
- """
200
- Decompose a 4x4 transformation matrix into scale, rotation and displacement tuples.
201
-
202
- :param matrix: The matrix to decompose.
203
- :return: The scale, rotation and displacement.
204
- """
205
- assert isinstance(matrix, numpy.ndarray), "Matrix must be an ndarray"
206
- assert matrix.shape == (4, 4), "Expected a 4x4 numpy array"
207
- # https://gist.github.com/Aerilius/0cbc46271c163746717902b36bea8fd4
208
- # 0 4 8 12
209
- # 1 5 9 13
210
- # 2 6 10 14
211
- # 3 7 11 15
212
- matrix = matrix.copy() # just in case
213
- displacement = tuple(matrix[:3, 3].tolist())
214
- matrix[:3, 3] = 0
215
- scale_np = numpy.linalg.norm(matrix[:3, :3], axis=0) * matrix[3, 3]
216
- scale = tuple(scale_np.tolist())
217
- matrix[:3, :3] = matrix[:3, :3] / scale_np
218
-
219
- matrix[3, 3] = 1
220
-
221
- if (
222
- numpy.dot(
223
- numpy.cross(
224
- matrix[:3, 0],
225
- matrix[:3, 1],
226
- ),
227
- matrix[:3, 2],
228
- )
229
- < 0
230
- ):
231
- scale = (-scale[0], scale[1], scale[2])
232
- matrix[:3, 0] *= -1
233
-
234
- rotation = (
235
- math.atan2(matrix[2, 1], matrix[2, 2]),
236
- math.atan2(
237
- -matrix[2, 0],
238
- (matrix[2, 1] ** 2 + matrix[2, 2] ** 2) ** 0.5,
239
- ),
240
- math.atan2(matrix[1, 0], matrix[0, 0]),
241
- )
242
-
243
- return scale, rotation, displacement
1
+ from typing import Tuple
2
+ import math
3
+ import numpy
4
+ from amulet.api.data_types import FloatTriplet, PointCoordinates
5
+
6
+
7
+ def scale_matrix(sx: float, sy: float, sz: float) -> numpy.ndarray:
8
+ """
9
+ Create a scale matrix from the inputs specified
10
+
11
+ :param sx: The scale in the x axis
12
+ :param sy: The scale in the y axis
13
+ :param sz: The scale in the z axis
14
+ :return: The 4x4 scale matrix
15
+ """
16
+ return numpy.array(
17
+ [[sx, 0, 0, 0], [0, sy, 0, 0], [0, 0, sz, 0], [0, 0, 0, 1]], dtype=numpy.float64
18
+ )
19
+
20
+
21
+ def displacement_matrix(x: float, y: float, z: float) -> numpy.ndarray:
22
+ """
23
+ Create a displacement matrix from the inputs specified
24
+
25
+ :param x: The displacement in the x axis
26
+ :param y: The displacement in the y axis
27
+ :param z: The displacement in the z axis
28
+ :return: The 4x4 displacement matrix
29
+ """
30
+ return numpy.array(
31
+ [[1, 0, 0, x], [0, 1, 0, y], [0, 0, 1, z], [0, 0, 0, 1]], dtype=numpy.float64
32
+ )
33
+
34
+
35
+ def _rotation_matrix(*angles: float, order=None) -> numpy.ndarray:
36
+ """
37
+ Create a rotation matrix from the inputs specified
38
+
39
+ :param angles: The angles in radians
40
+ :param order: The order the angles are specified. Transforms will be applied in this order.
41
+ :return: The 4x4 rotation matrix
42
+ """
43
+ assert isinstance(order, str) and len(order) == len(
44
+ angles
45
+ ), "Order must be a string of the same length as angles."
46
+ mat = numpy.identity(4, dtype=numpy.float64)
47
+
48
+ for angle, axis in zip(angles, order):
49
+ if angle:
50
+ c = math.cos(angle)
51
+ s = math.sin(angle)
52
+ if axis == "x":
53
+ mat = numpy.matmul(
54
+ numpy.array(
55
+ [[1, 0, 0, 0], [0, c, -s, 0], [0, s, c, 0], [0, 0, 0, 1]],
56
+ dtype=numpy.float64,
57
+ ),
58
+ mat,
59
+ )
60
+ elif axis == "y":
61
+ mat = numpy.matmul(
62
+ numpy.array(
63
+ [[c, 0, s, 0], [0, 1, 0, 0], [-s, 0, c, 0], [0, 0, 0, 1]],
64
+ dtype=numpy.float64,
65
+ ),
66
+ mat,
67
+ )
68
+ elif axis == "z":
69
+ mat = numpy.matmul(
70
+ numpy.array(
71
+ [[c, -s, 0, 0], [s, c, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]],
72
+ dtype=numpy.float64,
73
+ ),
74
+ mat,
75
+ )
76
+
77
+ return mat
78
+
79
+
80
+ def rotation_matrix_x(rx: float) -> numpy.ndarray:
81
+ """
82
+ Create a rotation matrix in the x axis
83
+
84
+ :param rx: The angle in radians
85
+ :return: The 4x4 rotation matrix
86
+ """
87
+ return _rotation_matrix(rx, order="x")
88
+
89
+
90
+ def rotation_matrix_y(ry: float) -> numpy.ndarray:
91
+ """
92
+ Create a rotation matrix in the x axis
93
+
94
+ :param ry: The angle in radians
95
+ :return: The 4x4 rotation matrix
96
+ """
97
+ return _rotation_matrix(ry, order="y")
98
+
99
+
100
+ def rotation_matrix_z(rz: float) -> numpy.ndarray:
101
+ """
102
+ Create a rotation matrix in the x axis
103
+
104
+ :param rz: The angle in radians
105
+ :return: The 4x4 rotation matrix
106
+ """
107
+ return _rotation_matrix(rz, order="z")
108
+
109
+
110
+ def rotation_matrix_xy(rx: float, ry: float) -> numpy.ndarray:
111
+ """
112
+ Create a rotation matrix from the inputs specified
113
+
114
+ :param rx: The rotation in radians in the x axis
115
+ :param ry: The rotation in radians in the y axis
116
+ :return: The 4x4 rotation matrix
117
+ """
118
+ return _rotation_matrix(rx, ry, order="xy")
119
+
120
+
121
+ def rotation_matrix_yx(ry: float, rx: float) -> numpy.ndarray:
122
+ """
123
+ Create a rotation matrix from the inputs specified
124
+
125
+ :param rx: The rotation in radians in the x axis
126
+ :param ry: The rotation in radians in the y axis
127
+ :return: The 4x4 rotation matrix
128
+ """
129
+ return _rotation_matrix(ry, rx, order="yx")
130
+
131
+
132
+ def rotation_matrix_xyz(x: float, y: float, z: float) -> numpy.ndarray:
133
+ """
134
+ Create a rotation matrix from the inputs specified
135
+
136
+ :param x: The rotation in radians in the x axis
137
+ :param y: The rotation in radians in the y axis
138
+ :param z: The rotation in radians in the z axis
139
+ :return: The 4x4 rotation matrix
140
+ """
141
+ return _rotation_matrix(x, y, z, order="xyz")
142
+
143
+
144
+ def transform_matrix(
145
+ scale: FloatTriplet,
146
+ rotation: FloatTriplet,
147
+ displacement: PointCoordinates,
148
+ order="xyz",
149
+ ):
150
+ """Create a 4x4 transformation matrix from the scale, rotation and displacement specified.
151
+
152
+ :param scale: The scale in the x, y and z axis
153
+ :param rotation: The rotation in the x, y and z axis in radians. (axis can be changed using `order`)
154
+ :param displacement: The displacement in the x, y and z axis
155
+ :param order: The order to apply the rotations in.
156
+ :return: The 4x4 transformation matrix of combined scale, rotation and displacement
157
+ """
158
+ scale_transform = scale_matrix(*scale)
159
+ rotation_transform = _rotation_matrix(*rotation, order=order)
160
+ displacement_transform = displacement_matrix(*displacement)
161
+ return numpy.matmul(
162
+ displacement_transform,
163
+ numpy.matmul(rotation_transform, scale_transform),
164
+ )
165
+
166
+
167
+ def inverse_transform_matrix(
168
+ scale: FloatTriplet,
169
+ rotation: FloatTriplet,
170
+ displacement: PointCoordinates,
171
+ order="xyz",
172
+ ):
173
+ """Create the inverse of the 4x4 transformation matrix from the scale, rotation and displacement specified.
174
+ This should be the inverse of transform_matrix
175
+
176
+ :param scale: The scale in the x, y and z axis
177
+ :param rotation: The rotation in the x, y and z axis (axis can be changed using `order`)
178
+ :param displacement: The displacement in the x, y and z axis
179
+ :param order: The order to apply the rotations in.
180
+ :return: The 4x4 transformation matrix of combined scale, rotation and displacement
181
+ """
182
+ scale_transform = scale_matrix(*1 / numpy.asarray(scale))
183
+ ra, rb, rc = -numpy.asarray(rotation)
184
+ rotation_transform = _rotation_matrix(
185
+ rc, rb, ra, order="".join(list(reversed(order)))
186
+ )
187
+ displacement_transform = displacement_matrix(*-numpy.asarray(displacement))
188
+ return numpy.matmul(
189
+ scale_transform,
190
+ numpy.matmul(rotation_transform, displacement_transform),
191
+ )
192
+
193
+
194
+ def decompose_transformation_matrix(
195
+ matrix: numpy.ndarray,
196
+ ) -> Tuple[
197
+ Tuple[float, float, float], Tuple[float, float, float], Tuple[float, float, float]
198
+ ]:
199
+ """
200
+ Decompose a 4x4 transformation matrix into scale, rotation and displacement tuples.
201
+
202
+ :param matrix: The matrix to decompose.
203
+ :return: The scale, rotation and displacement.
204
+ """
205
+ assert isinstance(matrix, numpy.ndarray), "Matrix must be an ndarray"
206
+ assert matrix.shape == (4, 4), "Expected a 4x4 numpy array"
207
+ # https://gist.github.com/Aerilius/0cbc46271c163746717902b36bea8fd4
208
+ # 0 4 8 12
209
+ # 1 5 9 13
210
+ # 2 6 10 14
211
+ # 3 7 11 15
212
+ matrix = matrix.copy() # just in case
213
+ displacement = tuple(matrix[:3, 3].tolist())
214
+ matrix[:3, 3] = 0
215
+ scale_np = numpy.linalg.norm(matrix[:3, :3], axis=0) * matrix[3, 3]
216
+ scale = tuple(scale_np.tolist())
217
+ matrix[:3, :3] = matrix[:3, :3] / scale_np
218
+
219
+ matrix[3, 3] = 1
220
+
221
+ if (
222
+ numpy.dot(
223
+ numpy.cross(
224
+ matrix[:3, 0],
225
+ matrix[:3, 1],
226
+ ),
227
+ matrix[:3, 2],
228
+ )
229
+ < 0
230
+ ):
231
+ scale = (-scale[0], scale[1], scale[2])
232
+ matrix[:3, 0] *= -1
233
+
234
+ rotation = (
235
+ math.atan2(matrix[2, 1], matrix[2, 2]),
236
+ math.atan2(
237
+ -matrix[2, 0],
238
+ (matrix[2, 1] ** 2 + matrix[2, 2] ** 2) ** 0.5,
239
+ ),
240
+ math.atan2(matrix[1, 0], matrix[0, 0]),
241
+ )
242
+
243
+ return scale, rotation, displacement
@@ -1,46 +1,46 @@
1
- from typing import Tuple, Sequence
2
- import numpy
3
-
4
-
5
- def brute_sort_objects(data) -> Tuple[numpy.ndarray, numpy.ndarray]:
6
- indexes = {}
7
- unique = []
8
- inverse = []
9
- index = 0
10
- for d in data:
11
- if d not in indexes:
12
- indexes[d] = index
13
- index += 1
14
- unique.append(d)
15
- inverse.append(indexes[d])
16
-
17
- unique_ = numpy.empty(len(unique), dtype=object)
18
- for index, obj in enumerate(unique):
19
- unique_[index] = obj
20
-
21
- return unique_, numpy.array(inverse)
22
-
23
-
24
- def brute_sort_objects_no_hash(data) -> Tuple[numpy.ndarray, numpy.ndarray]:
25
- unique = []
26
- inverse = numpy.zeros(dtype=numpy.uint32, shape=len(data))
27
- for i, d in enumerate(data):
28
- try:
29
- index = unique.index(d)
30
- except ValueError:
31
- index = len(unique)
32
- unique.append(d)
33
- inverse[i] = index
34
-
35
- unique_ = numpy.empty(len(unique), dtype=object)
36
- for index, obj in enumerate(unique):
37
- unique_[index] = obj
38
-
39
- return unique_, numpy.array(inverse)
40
-
41
-
42
- def direct_object_array(array: Sequence) -> numpy.ndarray:
43
- np_array = numpy.empty(len(array), dtype=object)
44
- for index, obj in array:
45
- np_array[index] = object
46
- return np_array
1
+ from typing import Tuple, Sequence
2
+ import numpy
3
+
4
+
5
+ def brute_sort_objects(data) -> Tuple[numpy.ndarray, numpy.ndarray]:
6
+ indexes = {}
7
+ unique = []
8
+ inverse = []
9
+ index = 0
10
+ for d in data:
11
+ if d not in indexes:
12
+ indexes[d] = index
13
+ index += 1
14
+ unique.append(d)
15
+ inverse.append(indexes[d])
16
+
17
+ unique_ = numpy.empty(len(unique), dtype=object)
18
+ for index, obj in enumerate(unique):
19
+ unique_[index] = obj
20
+
21
+ return unique_, numpy.array(inverse)
22
+
23
+
24
+ def brute_sort_objects_no_hash(data) -> Tuple[numpy.ndarray, numpy.ndarray]:
25
+ unique = []
26
+ inverse = numpy.zeros(dtype=numpy.uint32, shape=len(data))
27
+ for i, d in enumerate(data):
28
+ try:
29
+ index = unique.index(d)
30
+ except ValueError:
31
+ index = len(unique)
32
+ unique.append(d)
33
+ inverse[i] = index
34
+
35
+ unique_ = numpy.empty(len(unique), dtype=object)
36
+ for index, obj in enumerate(unique):
37
+ unique_[index] = obj
38
+
39
+ return unique_, numpy.array(inverse)
40
+
41
+
42
+ def direct_object_array(array: Sequence) -> numpy.ndarray:
43
+ np_array = numpy.empty(len(array), dtype=object)
44
+ for index, obj in array:
45
+ np_array[index] = object
46
+ return np_array