Metadata-Version: 2.4
Name: grood-suntay
Version: 0.1.0
Summary: Grood-Suntay knee coordinates with floating-axis-consistent translations
Author: Francesco Magnani
License: # Code License (MIT)
        
        This MIT License applies only to these software files in this repository:
        
        - `src/`
        - `tests/`
        - `calculate_grood_suntay_from_T21.m`
        - `pyproject.toml`
        - `README.md`, `CHANGELOG.md`, `CONTRIBUTING.md`, and `RELEASE.md`
        
        It does not apply to the article PDF, LaTeX manuscript, bibliography, or
        figures. Those scholarly materials are governed by `ARTICLE_STATUS.md`.
        
        ## MIT License
        
        Copyright (c) 2026 Francesco Magnani
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
        
Project-URL: Homepage, https://github.com/fmagno98-hub/grood-and-suntay-knee-coordinate-implementation
Project-URL: Repository, https://github.com/fmagno98-hub/grood-and-suntay-knee-coordinate-implementation
Project-URL: Issues, https://github.com/fmagno98-hub/grood-and-suntay-knee-coordinate-implementation/issues
Keywords: biomechanics,knee,kinematics,grood-suntay
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.24
Dynamic: license-file

# grood-suntay

[![Tests](https://github.com/fmagno98-hub/grood-and-suntay-knee-coordinate-implementation/actions/workflows/test.yml/badge.svg)](https://github.com/fmagno98-hub/grood-and-suntay-knee-coordinate-implementation/actions/workflows/test.yml)
[![PyPI](https://img.shields.io/pypi/v/grood-suntay.svg)](https://pypi.org/project/grood-suntay/)
[![Python](https://img.shields.io/pypi/pyversions/grood-suntay.svg)](https://pypi.org/project/grood-suntay/)

`grood-suntay` is a lightweight Python library for calculating six
Grood--Suntay knee joint coordinates from a femur-with-respect-to-tibia
homogeneous transform.

It reports three rotations and three translations. Crucially, AP, PD, and ML
translations are resolved using the Grood--Suntay floating-axis system; they
are **not** treated as direct Cartesian entries of the transform translation.

## Install

From a published release:

```bash
pip install grood-suntay
```

For local development:

```bash
pip install -e .
```

## Quick start

```python
import numpy as np
from grood_suntay import calculate

# T21 maps femur-frame coordinates into the tibia frame:
# r2 = R21 @ r1 + t21
T21 = np.eye(4)

result = calculate(T21)

print(result.flexion_extension_deg)
print(result.anterior_posterior)
print(result.as_array())
```

`result.as_array()` uses this column order:

```text
[flexion_extension_deg,
 ab_adduction_deg,
 internal_external_rotation_deg,
 anterior_posterior,
 proximal_distal,
 medial_lateral]
```

Angles are in degrees. Translation values preserve your input unit (usually
millimetres).

## Supplying global poses

If femur and tibia poses are both expressed in one global frame, construct the
relative transform first:

```python
from grood_suntay import calculate, relative_transform

T21 = relative_transform(T01=femur_pose, T02=tibia_pose)
result = calculate(T21)
```

This evaluates `T21 = inv(T02) @ T01`.

## Transform series

Pass a stack of transforms with shape `(N, 4, 4)` to calculate one result per
frame:

```python
results = calculate(T21_series)
print(results.flexion_extension_deg.shape)  # (N,)
print(results.as_array().shape)             # (N, 6)
```

For one `(4, 4)` transform, coordinate properties are plain floats. For a
series they are NumPy arrays.

## The floating-axis translation correction

The Grood--Suntay system uses two bone-fixed axes and a floating axis. The
translation vector `t21` in a rigid transform is the femoral-origin
displacement expressed in tibial coordinates. It is useful, but it is not yet
the final AP/PD/ML joint translation.

`calculate()` solves for the displacement in the joint-coordinate basis and
reports the corrected translations. This is the library default and core
purpose.

For validation or comparison with another pipeline, the uncorrected vector is
available as `result.raw_translation`; it should not be interpreted as final
Grood--Suntay AP/PD/ML output.

## Conventions

- Frame 1: femoral anatomical coordinate system.
- Frame 2: tibial anatomical coordinate system.
- `T21` maps frame-1 coordinates to frame-2 coordinates.
- Flexion/extension: femur `Z1` axis.
- Ab/adduction: Grood--Suntay floating axis.
- Internal/external rotation: tibia `Y2` axis.

The rotation sequence is:

```text
R21 = Ry(internal_external) @ Rx(ab_adduction) @ Rz(flexion_extension)
```

At the Grood--Suntay singularity (the relevant fixed axes are parallel), the
decomposition is not unique. The package emits a `RuntimeWarning`, marks the
frame in `result.singularity_mask`, and returns `NaN` coordinates for it.

## Validation details

By default, `calculate()` verifies that every rotation block is orthonormal
with determinant `+1`. Set `validate_rigid=False` only when you deliberately
want to process a non-rigid or approximate transform.

The result also exposes `rotation_error`, `rotation_determinant`, and
`joint_basis_translation` for inspection.

## Development

Run the test suite with:

```bash
python -m unittest discover -s tests
```

See [CONTRIBUTING.md](CONTRIBUTING.md) for development conventions and
[RELEASE.md](RELEASE.md) for the release process.

## MATLAB and mathematical note

`calculate_grood_suntay_from_T21.m` remains a self-contained MATLAB reference
implementation. The repository also contains an unpublished mathematical
preprint and LaTex source. See [ARTICLE_STATUS.md](ARTICLE_STATUS.md) for the
manuscript's copyright and reuse terms.

## Reference 

Grood ES, Suntay WJ. *A Joint Coordinate System for the Clinical Description
of Three-Dimensional Motions: Application to the Knee.* Journal of
Biomechanical Engineering. 1983;105(2):136--144. [https://doi.org/10.1115/1.3138397](https://doi.org/10.1115/1.3138397)
