# Requirements Document

## Introduction

This specification defines the requirements for implementing 3D Elliptic Fourier Analysis (EFA) normalization in the ktch library. Currently, the `EllipticFourierAnalysis` class supports normalization only for 2D outlines (`n_dim=2`), with `_normalize_3d` raising `NotImplementedError`. This feature extends normalization to 3D closed curves, enabling size-invariant, orientation-invariant, and starting-point-invariant shape comparison of three-dimensional outlines.

The 3D normalization follows the approach of Godefroy et al. (2012), extending the Kuhl-Giardina (1982) 2D normalization concept: the first harmonic ellipse in 3D space defines a reference plane, orientation, and scale for normalizing all higher-harmonic coefficients.

Additionally, this feature addresses a known bug in the 3D arc-length parameterization where the z-component is missing from the distance calculation.

## Requirements

### Requirement 1: 3D Coefficient Normalization

**Objective:** As a morphometrics researcher, I want to normalize 3D EFA coefficients by the first harmonic ellipse, so that I can compare shapes across specimens regardless of size, orientation, and starting point.

#### Acceptance Criteria

1. When `transform` is called with `n_dim=3` and `norm=True`, the EllipticFourierAnalysis shall compute normalized coefficients using the first harmonic ellipse as the reference frame.
2. The EllipticFourierAnalysis shall normalize 3D coefficients by performing: (a) alignment of the first harmonic ellipse plane to a canonical orientation, (b) alignment of the semi-major axis of the first harmonic ellipse within that plane, and (c) division by the semi-major axis length as the scale factor.
3. When `norm=True` for 3D data, the EllipticFourierAnalysis shall produce first-harmonic coefficients that are canonical (i.e., the normalized first harmonic has a fixed, predictable structure analogous to the 2D case).
4. The EllipticFourierAnalysis shall apply the normalization rotation and scaling consistently to all harmonics n >= 1.

### Requirement 2: Orientation and Scale Return for 3D

**Objective:** As a morphometrics researcher, I want to retrieve orientation and scale parameters from the 3D normalization, so that I can analyze size and orientation variation separately from shape.

#### Acceptance Criteria

1. When `transform` is called with `n_dim=3`, `norm=True`, and `return_orientation_scale=True`, the EllipticFourierAnalysis shall append orientation and scale values to the output coefficient array.
2. The EllipticFourierAnalysis shall return the 3D rotation parameters (defining the transformation from the original orientation to the canonical orientation) and the scale factor used for normalization.
3. The EllipticFourierAnalysis shall document the exact parameterization of the returned orientation (e.g., Euler angles or rotation matrix elements) in the docstring.

### Requirement 3: 3D Inverse Transform with Normalization

**Objective:** As a morphometrics researcher, I want to reconstruct 3D outlines from normalized coefficients, so that I can visualize mean shapes and shape variation from normalized data.

#### Acceptance Criteria

1. When `inverse_transform` is called with `n_dim=3` and `norm=True`, the EllipticFourierAnalysis shall reconstruct coordinate values from normalized coefficients with the centroid zeroed (DC components set to zero).
2. When `inverse_transform` is called with `n_dim=3` and `norm=False`, the EllipticFourierAnalysis shall reconstruct coordinate values using the raw (unnormalized) DC components.
3. The EllipticFourierAnalysis shall produce reconstructed 3D outlines that are consistent with the normalization: applying `transform(norm=True)` followed by `inverse_transform(norm=True)` shall yield a normalized shape that is translation-free, scale-normalized, and orientation-aligned.

### Requirement 4: Arc-Length Parameterization Fix for 3D

**Objective:** As a morphometrics researcher, I want the 3D arc-length parameterization to correctly account for all three spatial dimensions, so that the Fourier coefficients are computed accurately.

#### Acceptance Criteria

1. When `t=None` for 3D data, the EllipticFourierAnalysis shall compute the arc-length parameter `dt` as `sqrt(dx^2 + dy^2 + dz^2)` (Euclidean distance in 3D).
2. The EllipticFourierAnalysis shall use the corrected 3D arc-length computation in `_transform_single_3d`.

### Requirement 5: Backward Compatibility

**Objective:** As a library user, I want existing 2D EFA workflows to remain unchanged, so that upgrading does not break my analysis pipelines.

#### Acceptance Criteria

1. The EllipticFourierAnalysis shall preserve identical behavior for `n_dim=2` with `norm=True` (no change to `_normalize_2d` or `_transform_single_2d`).
2. The EllipticFourierAnalysis shall preserve identical behavior for `n_dim=3` with `norm=False` (raw coefficient computation unchanged, except for the arc-length fix in Requirement 4).
3. The EllipticFourierAnalysis shall not modify the public API signature of `transform`, `inverse_transform`, or `__init__`.

### Requirement 6: Testing and Validation

**Objective:** As a developer, I want comprehensive tests for 3D normalization, so that correctness is verified against known mathematical properties and regression is prevented.

#### Acceptance Criteria

1. The EllipticFourierAnalysis shall include unit tests verifying that 3D normalization produces invariant coefficients under translation (shifting coordinates).
2. The EllipticFourierAnalysis shall include unit tests verifying that 3D normalization produces invariant coefficients under uniform scaling (multiplying coordinates by a constant).
3. The EllipticFourierAnalysis shall include unit tests verifying that 3D normalization produces invariant coefficients under rotation (applying an arbitrary 3D rotation matrix to coordinates).
4. The EllipticFourierAnalysis shall include unit tests verifying that 3D normalization produces invariant coefficients under starting-point shift (cyclic permutation of outline points).
5. The EllipticFourierAnalysis shall include a round-trip test: `inverse_transform(transform(X, norm=True), norm=True)` produces a shape geometrically consistent with the normalized input.
6. The EllipticFourierAnalysis shall include a test verifying the corrected 3D arc-length parameterization (Requirement 4).
