Skip to main content

PyPI version PyPI download month License: MIT Build Main Build Preview

spatial-transform

Lightweight libary for creating hierarchies in a 3D space, like Unity, Unreal, Blender or any other 3D application.

Properties like positions, rotations, directions and scales can be easily accessed and are calculated based on the parents space for the world space. Individual transforms can be attatched and detatched at any point and have some more comfort methods for easy modifications.

Why and intention

This libary is a side product of my master thesis, in order to extract conveniently local and world data features from a humanoid skeleton hierarchy. I could not find any libary that could do that, without bloat or the features I required for extraction or modification.

Installation

pip install spatial-transform

Notes

  • Pose is the class for all local space properties and operations. There is no awareness about other related space or hierarchy.
  • Transform extend the Pose class to add hierarchical wareness and provides additional properties and methods for the world space.
  • Euler is a class with static members only for converting euler angle into quaternions or matrices. It supports diffrent rotation orders and can be used to convert between
  • The package PyGLM is used for matrix, quaternion and vector calculations.
  • Same coordination space as openGL and GLM is used. Which is: Right-Handed, - Y+ is up, Z- is forward and positive rotations are counter clockwise.

Examples

Create and attach transforms

from SpatialTransform import Transform, Euler

# defining the transforms
hips = Transform('Hips', position=(0,2,0))
LeftLegUpper = Transform('LeftLegUpper', position=(+0.2,0,0))
LeftLegLower = Transform('LeftLegLower', position=(0,-1,0))
LeftLegFoot = Transform('LeftLegFoot', position=(0,-1,0))
RightLegUpper = Transform('RightLegUpper', position=(-0.2,0,0))
RightLegLower = Transform('RightLegLower', position=(0,-1,0))
RightLegFoot = Transform('RightLegFoot', position=(0,-1,0))

# defining the hierarchy
hips.attach(LeftLegUpper)
LeftLegUpper.attach(LeftLegLower)
LeftLegLower.attach(LeftLegFoot)

hips.attach(RightLegUpper)
RightLegUpper.attach(RightLegLower)
RightLegLower.attach(RightLegFoot)

# show the created hierarchy
hips.printTree()
print('\nWorld positions, local positions, joint directions:')
for item, index, depth in hips.layout():
    print(f'{item.PositionWorld} {item.Position} {item.ForwardWorld} {item.Name}')

# --------------------------- OUTPUT ---------------------------
# Hips
# +- LeftLegUpper
# |  +- LeftLegLower
# |     +- LeftLegFoot
# +- RightLegUpper
#    +- RightLegLower
#       +- RightLegFoot

# World positions, local positions, joint direction:
# vec3(            0,            2,            0 ) vec3(            0,            2,            0 ) Hips
# vec3(          0.2,            2,            0 ) vec3(          0.2,            0,            0 ) LeftLegUpper
# vec3(          0.2,            1,            0 ) vec3(            0,           -1,            0 ) LeftLegLower
# vec3(          0.2,            0,            0 ) vec3(            0,           -1,            0 ) LeftLegFoot
# vec3(         -0.2,            2,            0 ) vec3(         -0.2,            0,            0 ) RightLegUpper
# vec3(         -0.2,            1,            0 ) vec3(            0,           -1,            0 ) RightLegLower
# vec3(         -0.2,            0,            0 ) vec3(            0,           -1,            0 ) RightLegFoot

Interacting with transforms

from SpatialTransform import Transform

# the basic properties of the transform as position, scale and rotation can be changed by setting the value
# but the inverse-properties are read only
root = Transform()
root.PositionWorld = (1,2,3)
root.Scale = .1                     # accepts either a single value or a tuple of three
root.RotationWorld = (1, 0, 0, 0)   # rotations are in quaternions

# the rotation can be also read and changed with extra methods for simplified usage
root.setEuler((0, 90, 0))
root.getEuler(order='ZYX')
root.lookAtWorld((1, 1, 1))

# some methods do update the transform and keep childrens spatially unchanged
root.clearParent(keep=['position', 'rotation', 'scale'])
root.clearChildren(keep=['position', 'rotation', 'scale'])
root.applyPosition()
root.applyRotation(recursive=True)
root.appyScale(recursive=True)

# the transform provide two methods to convert arbitrary points and direction from and to the spaces
root.pointToWorld((5,4,3))
root.directionToLocal((2,3,4))

Fluent interface usage

from SpatialTransform import Transform

# because almost every method on the "Transform" object returns itself,
# the previous code of creating and attaching can also be written like:
hips = Transform('Hips', position=(0,2,0)).attach(
    Transform('LeftLegUpper', position=(+0.2,0,0)).attach(
        Transform('LeftLegLower', position=(0,-1,0)).attach(
            Transform('LeftLegFoot', position=(0,-1,0))
        )
    ),
    Transform('RightLegUpper', position=(-0.2,0,0)).attach(
        Transform('RightLegLower', position=(0,-1,0)).attach(
            Transform('RightLegFoot', position=(0,-1,0))
        )
    )
)

# multiple actions on a transform can be performed on a single line
feets = hips.setEuler((0, 180, 0)).applyRotation().filter('Foot')

# show the created hierarchy
hips.printTree()
print('\nPositions:')
for item, index, depth in hips.layout():
    print(f'{item.PositionWorld} {item.Position} {item.Name}')

# --------------------------- OUTPUT ---------------------------
# Hips
# +- LeftLegUpper
# |  +- LeftLegLower
# |     +- LeftLegFoot
# +- RightLegUpper
#    +- RightLegLower
#       +- RightLegFoot

# Positions:
# vec3(            0,            2,            0 ) vec3(            0,            2,            0 ) Hips
# vec3(         -0.2,            2,  1.74846e-08 ) vec3(         -0.2,            0,  1.74846e-08 ) LeftLegUpper
# vec3(         -0.2,            1,  1.74846e-08 ) vec3(            0,           -1,            0 ) LeftLegLower
# vec3(         -0.2,            0,  1.74846e-08 ) vec3(            0,           -1,            0 ) LeftLegFoot
# vec3(          0.2,            2, -1.74846e-08 ) vec3(          0.2,            0, -1.74846e-08 ) RightLegUpper
# vec3(          0.2,            1, -1.74846e-08 ) vec3(            0,           -1,            0 ) RightLegLower
# vec3(          0.2,            0, -1.74846e-08 ) vec3(            0,           -1,            0 ) RightLegFoot

Euler angles conversions

# the package also provides the static class 'Euler'
# the 'Transform' does also rely on that to convert between rotation representations
from SpatialTransform import Euler

# rotations are in radians here
matrix = Euler.toMatFrom((1, 2, .5), order='YZX', extrinsic=True)
quaternion = Euler.toQuatFrom((1, 2, .5), order='YZX', extrinsic=True)

angles1 = Euler.fromMatTo(matrix, order='XYZ', extrinsic=False)
angles2 = Euler.fromQuatTo(quaternion, order='XYZ', extrinsic=False)

print(angles1 - angles2)

# --------------------------- OUTPUT ---------------------------
# vec3(            0,            0,            0 )

Metadata

Release files for spatial-transform 1.3.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for spatial-transform 1.3.3
File Size Uploaded
spatial_transform-1.3.3.tar.gz 18.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for spatial-transform 1.3.3
File Interpreter ABI Platform
spatial_transform-1.3.3-py3-none-any.whl Python 3 none any Details

Total release size: 39.0 kB

Release files / spatial_transform-1.3.3.tar.gz

Download URL spatial_transform-1.3.3.tar.gz
Size 18.3 kB
Tags Source
SHA-256 checksum
How to use checksums
4b31f9a2132166e6f5337af155b96a1576e2a4bb0935b82750f74632fc1b95d2
BLAKE2b-256 checksum
How to use checksums
938e097d2dfc585925c2e7cd0e1bc06577138212a069749be9d680c939d56499
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2025.

Transparency log

Release files / spatial_transform-1.3.3-py3-none-any.whl

Download URL spatial_transform-1.3.3-py3-none-any.whl
Size 20.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0616333ca64e3efa50ec883ca87f96ff049e4a5fdb58af97b2d6ffcdd224001c
BLAKE2b-256 checksum
How to use checksums
ba8afd9c94bd327ad8212f3cda6a8788f6c8c23fdd848fb203c23040902d9c84
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 12, 2025.

Transparency log

Release history Release notifications | RSS feed

This release

1.3.3 This release

2 release files

1.3.2

2 release files

1.3.1

2 release files

1.3.0

2 release files

1.2.15

2 release files

1.2.13

2 release files

1.2.9

2 release files

1.2.8

2 release files

1.2.7

2 release files

1.2.6

2 release files

1.2.5

2 release files

1.2.4

2 release files

1.2.3

2 release files

1.2.2

2 release files

1.2.1

2 release files

1.2.0

2 release files

1.1.12

2 release files

1.1.11

2 release files

1.1.9

2 release files

1.1.8

2 release files

1.1.7

2 release files

1.1.6

2 release files

1.1.5

2 release files

1.1.4

2 release files

1.1.3

2 release files

1.1.2

2 release files

1.1.0

2 release files

1.0.17

2 release files

1.0.16

2 release files

1.0.15

2 release files

1.0.14

2 release files

1.0.13

2 release files

1.0.12

2 release files

1.0.11

2 release files

1.0.9

2 release files

1.0.8

2 release files

1.0.7

2 release files

1.0.6

2 release files

1.0.5

2 release files

1.0.4

2 release files

1.0.3

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page