# Implementation Plan

- [ ] 1. Add normalization method parameter to the EFA constructor
- [x] 1.1 Add `norm_method` parameter with validation and default value
  - Accept a normalization method parameter in the constructor with a default value of "area"
  - Validate that the parameter is one of the supported values ("area" or "semi_major_axis"); raise an informative error for unsupported values
  - Store as an instance attribute accessible by internal normalization methods
  - Verify that sklearn's `get_params()` / `set_params()` automatically discovers the new parameter
  - Update the class-level docstring to document the new parameter and describe both normalization methods with their mathematical definitions
  - _Requirements: 2.1, 2.2, 2.4_

- [ ] 2. Implement semi-major axis scale factor in 3D normalization
- [x] 2.1 Branch the scale computation based on the normalization method
  - When the normalization method is "area", preserve the existing scale computation using the ellipse area
  - When the normalization method is "semi_major_axis", use the semi-major axis length of the first harmonic ellipse as the scale factor
  - All other normalization steps (reorientation, phase shift, direction correction) remain shared regardless of method
  - The returned scale value reflects the method used, so that `return_orientation_scale=True` returns the correct scale
  - Update the method docstring to document the conditional scale computation
  - Update the per-specimen 3D transform method docstring where it references the scale value
  - _Requirements: 1.1, 1.2, 1.3, 2.3, 3.1, 3.2_

- [ ] 3. Verify backward compatibility
- [x] 3.1 Confirm that default behavior produces identical output to the current implementation
  - Run the existing 3D normalization test suite without any parameter changes and verify all tests pass
  - Verify that constructing with no `norm_method` argument produces bit-identical results to the current code for all existing test cases
  - Verify that 2D EFA behavior is completely unaffected by the new parameter
  - _Requirements: 5.1, 5.2, 5.3_

- [ ] 4. Add tests for semi-major axis normalization
- [x] 4.1 Test parameter validation and constructor behavior
  - Verify that an invalid normalization method value raises a descriptive error
  - Verify that the default value preserves the existing area-based normalization
  - _Requirements: 2.4, 5.2, 6.6_

- [x] 4.2 (P) Test that the normalized first harmonic has semi-major axis length equal to 1
  - Construct a 3D outline, normalize with the semi-major axis method, and verify that the first harmonic ellipse semi-major axis length is 1.0 (up to numerical tolerance)
  - _Requirements: 1.3, 6.5_

- [x] 4.3 (P) Test invariance properties of semi-major axis normalization
  - Verify translation invariance: normalized coefficients match after shifting coordinates by a random 3D vector
  - Verify scale invariance: normalized coefficients match after multiplying coordinates by a random scalar
  - Verify rotation invariance: normalized coefficients match after applying a random 3D rotation
  - Verify approximate starting-point shift invariance: normalized shapes remain geometrically close after cyclic permutation of outline points
  - Parameterize with or extend existing invariance tests to cover both normalization methods
  - _Requirements: 6.1, 6.2, 6.3, 6.4_

- [x] 4.4 (P) Add regression test for area-based normalization
  - Capture a snapshot of current area-based normalization output and verify that the default method continues to produce identical results
  - This guards against accidental changes to the existing normalization during refactoring
  - _Requirements: 6.6_
