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.
- amulet/__init__.py +27 -27
- amulet/__pyinstaller/__init__.py +2 -2
- amulet/__pyinstaller/hook-amulet.py +4 -4
- amulet/_version.py +21 -21
- amulet/api/__init__.py +2 -2
- amulet/api/abstract_base_entity.py +128 -128
- amulet/api/block.py +630 -630
- amulet/api/block_entity.py +71 -71
- amulet/api/cache.py +107 -107
- amulet/api/chunk/__init__.py +6 -6
- amulet/api/chunk/biomes.py +207 -207
- amulet/api/chunk/block_entity_dict.py +175 -175
- amulet/api/chunk/blocks.py +46 -46
- amulet/api/chunk/chunk.py +389 -389
- amulet/api/chunk/entity_list.py +75 -75
- amulet/api/chunk/status.py +167 -167
- amulet/api/data_types/__init__.py +4 -4
- amulet/api/data_types/generic_types.py +4 -4
- amulet/api/data_types/operation_types.py +16 -16
- amulet/api/data_types/world_types.py +49 -49
- amulet/api/data_types/wrapper_types.py +71 -71
- amulet/api/entity.py +74 -74
- amulet/api/errors.py +119 -119
- amulet/api/history/__init__.py +36 -36
- amulet/api/history/base/__init__.py +3 -3
- amulet/api/history/base/base_history.py +26 -26
- amulet/api/history/base/history_manager.py +63 -63
- amulet/api/history/base/revision_manager.py +73 -73
- amulet/api/history/changeable.py +15 -15
- amulet/api/history/data_types.py +7 -7
- amulet/api/history/history_manager/__init__.py +3 -3
- amulet/api/history/history_manager/container.py +102 -102
- amulet/api/history/history_manager/database.py +279 -279
- amulet/api/history/history_manager/meta.py +93 -93
- amulet/api/history/history_manager/object.py +116 -116
- amulet/api/history/revision_manager/__init__.py +2 -2
- amulet/api/history/revision_manager/disk.py +33 -33
- amulet/api/history/revision_manager/ram.py +12 -12
- amulet/api/item.py +75 -75
- amulet/api/level/__init__.py +4 -4
- amulet/api/level/base_level/__init__.py +1 -1
- amulet/api/level/base_level/base_level.py +1035 -1026
- amulet/api/level/base_level/chunk_manager.py +227 -227
- amulet/api/level/base_level/clone.py +389 -389
- amulet/api/level/base_level/player_manager.py +101 -101
- amulet/api/level/immutable_structure/__init__.py +1 -1
- amulet/api/level/immutable_structure/immutable_structure.py +94 -94
- amulet/api/level/immutable_structure/void_format_wrapper.py +117 -117
- amulet/api/level/structure.py +22 -22
- amulet/api/level/world.py +19 -19
- amulet/api/partial_3d_array/__init__.py +2 -2
- amulet/api/partial_3d_array/base_partial_3d_array.py +263 -263
- amulet/api/partial_3d_array/bounded_partial_3d_array.py +528 -528
- amulet/api/partial_3d_array/data_types.py +15 -15
- amulet/api/partial_3d_array/unbounded_partial_3d_array.py +229 -229
- amulet/api/partial_3d_array/util.py +152 -152
- amulet/api/player.py +65 -65
- amulet/api/registry/__init__.py +2 -2
- amulet/api/registry/base_registry.py +34 -34
- amulet/api/registry/biome_manager.py +153 -153
- amulet/api/registry/block_manager.py +156 -156
- amulet/api/selection/__init__.py +2 -2
- amulet/api/selection/abstract_selection.py +315 -315
- amulet/api/selection/box.py +805 -805
- amulet/api/selection/group.py +488 -488
- amulet/api/structure.py +37 -37
- amulet/api/wrapper/__init__.py +8 -8
- amulet/api/wrapper/chunk/interface.py +441 -441
- amulet/api/wrapper/chunk/translator.py +567 -567
- amulet/api/wrapper/format_wrapper.py +772 -772
- amulet/api/wrapper/structure_format_wrapper.py +116 -116
- amulet/api/wrapper/world_format_wrapper.py +63 -63
- amulet/level/__init__.py +1 -1
- amulet/level/formats/anvil_forge_world.py +40 -40
- amulet/level/formats/anvil_world/__init__.py +3 -3
- amulet/level/formats/anvil_world/_sector_manager.py +291 -384
- amulet/level/formats/anvil_world/data_pack/__init__.py +2 -2
- amulet/level/formats/anvil_world/data_pack/data_pack.py +224 -224
- amulet/level/formats/anvil_world/data_pack/data_pack_manager.py +77 -77
- amulet/level/formats/anvil_world/dimension.py +177 -177
- amulet/level/formats/anvil_world/format.py +769 -769
- amulet/level/formats/anvil_world/region.py +384 -384
- amulet/level/formats/construction/__init__.py +3 -3
- amulet/level/formats/construction/format_wrapper.py +515 -515
- amulet/level/formats/construction/interface.py +134 -134
- amulet/level/formats/construction/section.py +60 -60
- amulet/level/formats/construction/util.py +165 -165
- amulet/level/formats/leveldb_world/__init__.py +3 -3
- amulet/level/formats/leveldb_world/chunk.py +33 -33
- amulet/level/formats/leveldb_world/dimension.py +385 -419
- amulet/level/formats/leveldb_world/format.py +659 -641
- amulet/level/formats/leveldb_world/interface/chunk/__init__.py +36 -36
- amulet/level/formats/leveldb_world/interface/chunk/base_leveldb_interface.py +836 -836
- amulet/level/formats/leveldb_world/interface/chunk/generate_interface.py +31 -31
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_0.py +30 -30
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_1.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_10.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_11.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_12.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_13.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_14.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_15.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_16.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_17.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_18.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_19.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_2.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_20.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_21.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_22.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_23.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_24.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_25.py +24 -24
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_26.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_27.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_28.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_29.py +33 -33
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_3.py +57 -57
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_30.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_31.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_32.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_33.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_34.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_35.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_36.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_37.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_38.py +10 -10
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_39.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_4.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_40.py +16 -16
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_5.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_6.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_7.py +12 -12
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_8.py +180 -180
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_9.py +18 -18
- amulet/level/formats/leveldb_world/interface/chunk/leveldb_chunk_versions.py +79 -79
- amulet/level/formats/mcstructure/__init__.py +3 -3
- amulet/level/formats/mcstructure/chunk.py +50 -50
- amulet/level/formats/mcstructure/format_wrapper.py +408 -408
- amulet/level/formats/mcstructure/interface.py +175 -175
- amulet/level/formats/schematic/__init__.py +3 -3
- amulet/level/formats/schematic/chunk.py +55 -55
- amulet/level/formats/schematic/data_types.py +4 -4
- amulet/level/formats/schematic/format_wrapper.py +373 -373
- amulet/level/formats/schematic/interface.py +142 -142
- amulet/level/formats/sponge_schem/__init__.py +4 -4
- amulet/level/formats/sponge_schem/chunk.py +62 -62
- amulet/level/formats/sponge_schem/format_wrapper.py +463 -463
- amulet/level/formats/sponge_schem/interface.py +118 -118
- amulet/level/formats/sponge_schem/varint/__init__.py +1 -1
- amulet/level/formats/sponge_schem/varint/varint.py +87 -87
- amulet/level/interfaces/chunk/anvil/anvil_0.py +72 -72
- amulet/level/interfaces/chunk/anvil/anvil_1444.py +336 -336
- amulet/level/interfaces/chunk/anvil/anvil_1466.py +94 -94
- amulet/level/interfaces/chunk/anvil/anvil_1467.py +37 -37
- amulet/level/interfaces/chunk/anvil/anvil_1484.py +20 -20
- amulet/level/interfaces/chunk/anvil/anvil_1503.py +20 -20
- amulet/level/interfaces/chunk/anvil/anvil_1519.py +34 -34
- amulet/level/interfaces/chunk/anvil/anvil_1901.py +20 -20
- amulet/level/interfaces/chunk/anvil/anvil_1908.py +20 -20
- amulet/level/interfaces/chunk/anvil/anvil_1912.py +21 -21
- amulet/level/interfaces/chunk/anvil/anvil_1934.py +20 -20
- amulet/level/interfaces/chunk/anvil/anvil_2203.py +69 -69
- amulet/level/interfaces/chunk/anvil/anvil_2529.py +19 -19
- amulet/level/interfaces/chunk/anvil/anvil_2681.py +76 -76
- amulet/level/interfaces/chunk/anvil/anvil_2709.py +19 -19
- amulet/level/interfaces/chunk/anvil/anvil_2844.py +267 -267
- amulet/level/interfaces/chunk/anvil/anvil_3463.py +19 -19
- amulet/level/interfaces/chunk/anvil/anvil_na.py +607 -607
- amulet/level/interfaces/chunk/anvil/base_anvil_interface.py +326 -326
- amulet/level/load.py +59 -59
- amulet/level/loader.py +95 -95
- amulet/level/translators/chunk/bedrock/__init__.py +267 -267
- amulet/level/translators/chunk/bedrock/bedrock_nbt_blockstate_translator.py +46 -46
- amulet/level/translators/chunk/bedrock/bedrock_numerical_translator.py +39 -39
- amulet/level/translators/chunk/bedrock/bedrock_psudo_numerical_translator.py +37 -37
- amulet/level/translators/chunk/java/java_1_18_translator.py +40 -40
- amulet/level/translators/chunk/java/java_blockstate_translator.py +94 -94
- amulet/level/translators/chunk/java/java_numerical_translator.py +62 -62
- amulet/libs/leveldb/__init__.py +7 -7
- amulet/operations/__init__.py +5 -5
- amulet/operations/clone.py +18 -18
- amulet/operations/delete_chunk.py +32 -32
- amulet/operations/fill.py +30 -30
- amulet/operations/paste.py +65 -65
- amulet/operations/replace.py +58 -58
- amulet/utils/__init__.py +14 -14
- amulet/utils/format_utils.py +41 -41
- amulet/utils/generator.py +15 -15
- amulet/utils/matrix.py +243 -243
- amulet/utils/numpy_helpers.py +46 -46
- amulet/utils/world_utils.py +349 -349
- {amulet_core-1.9.19.dist-info → amulet_core-1.9.20.dist-info}/METADATA +97 -97
- amulet_core-1.9.20.dist-info/RECORD +208 -0
- amulet_core-1.9.19.dist-info/RECORD +0 -208
- {amulet_core-1.9.19.dist-info → amulet_core-1.9.20.dist-info}/WHEEL +0 -0
- {amulet_core-1.9.19.dist-info → amulet_core-1.9.20.dist-info}/entry_points.txt +0 -0
- {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
|
amulet/utils/numpy_helpers.py
CHANGED
|
@@ -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
|