Metadata-Version: 2.4
Name: gri-pos
Version: 0.2.3
Summary: Geodetic position handling with lazy coordinate conversion between XYZ and LLA
Project-URL: Homepage, https://geosolresearch.com
Project-URL: Repository, https://gitlab.com/geosol-foss/python/gri-pos
Project-URL: Issues, https://gitlab.com/geosol-foss/python/gri-pos/-/issues
Project-URL: Changelog, https://gitlab.com/geosol-foss/python/gri-pos/-/releases
Author-email: GeoSol Research Inc <contact@geosolresearch.com>
License-Expression: MIT
License-File: LICENSE
Keywords: ECEF,LLA,coordinate-conversion,geodetic,position
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Scientific/Engineering
Classifier: Topic :: Scientific/Engineering :: GIS
Requires-Python: >=3.12
Requires-Dist: gri-utils>=0.3.3
Requires-Dist: numpy>=2.3.3
Requires-Dist: scipy>=1.16.2
Description-Content-Type: text/markdown

[![GeoSol Research Logo](https://geosolresearch.com/logos/foss_logo.png "GeoSol Research")](https://geosolresearch.com)

# Pos (Position)

Geodetic position handling with lazy coordinate conversion between XYZ (ECEF) and LLA (Lat/Lon/Alt).

## Overview

gri-pos provides the `Pos` class for working with geospatial positions. Initialize with either XYZ or LLA coordinates; the other representation is computed and cached on first access. `Pos` supports distance calculations, coordinate deltas, translations, and tolerance-based equality.

`Vel` extends `Pos` with velocity and `Acc` extends `Vel` with acceleration. Both use the same lazy-loaded TriplePoint pattern for frame conversion (ECEF/ENU).

All coordinate types (`XYZ`, `LLA`, `ENU`, `NED`, `AER`) are numpy.ndarray subclasses, so they work directly in numpy and scipy operations.

Requires Python 3.12+.

## Mathematical Background

Positions use the WGS-84 reference ellipsoid. LLA coordinates are geodetic latitude (degrees), longitude (degrees), and altitude above the ellipsoid (meters). XYZ coordinates are Earth-Centered, Earth-Fixed (ECEF) in meters. Conversion between LLA and XYZ uses iterative methods accurate to sub-millimeter precision.

Equality comparison uses per-coordinate tolerances: LLA defaults to ~1 cm accuracy (1e-7 degrees for lat/lon, 0.01 m for altitude).

## Installation

```bash
pip install gri-pos
```

For development:

```bash
git clone https://gitlab.com/geosol-foss/python/gri-pos.git
cd gri-pos
uv sync
```

## Quick Start

```python
from gri_pos import Pos

# Create from LLA or XYZ
p1 = Pos.LLA(40.0, -105.0, 1600.0)
p2 = Pos.XYZ(-1270367.0, -4800297.0, 4091069.0)

# Access either representation (lazy-computed)
print(p1.xyz)  # ECEF coordinates (meters)
print(p2.lla)  # Geodetic lat, lon, alt

# Distance calculations
dist = p1.dist_m(p2)                  # 3D Euclidean (meters)
surf = p1.dist_surface_m(p2)          # Vincenty surface distance
fast_surf = p1.dist_surface_simple_m(p2)  # Fast spherical approximation

# Coordinate deltas
enu = p1.delta_enu(p2)   # East, North, Up offset
aer = p1.delta_aer(p2)   # Azimuth, Elevation, Range

# Translation (create new position from offset)
p3 = p1.translate_enu([100, 200, 0])
```

## Pos Class

### Creating Positions

```python
from gri_pos import Pos, XYZ, LLA

# Static constructors (preferred)
p = Pos.LLA(40.0, -105.0, 1600.0)
p = Pos.XYZ(-1270367.0, -4800297.0, 4091069.0)

# From existing objects
p = Pos(XYZ(-1270367.0, -4800297.0, 4091069.0))
p = Pos(LLA(40.0, -105.0, 1600.0))
p = Pos(other_pos)  # Copy
```

### Distance Methods

| Method | Algorithm | Accuracy |
|--------|-----------|----------|
| `dist_m(other)` | 3D Euclidean (XYZ) | Exact straight-line |
| `dist_surface_m(other)` | Vincenty (oblate spheroid) | ~0.5 mm |
| `dist_surface_simple_m(other)` | Spherical approximation | Good for <500 km |

### Delta and Translation

All delta/translate methods accept and return numpy-compatible types:

```python
enu = p1.delta_enu(p2)    # Returns ENU (east, north, up)
ned = p1.delta_ned(p2)    # Returns NED (north, east, down)
aer = p1.delta_aer(p2)    # Returns AER (azimuth_deg, elevation_deg, range_m)
xyz = p1.delta_xyz(p2)    # Returns XYZ delta

p3 = p1.translate_enu(enu)
p3 = p1.translate_ned(ned)
p3 = p1.translate_aer(aer)
```

### Coordinate Types

All types are numpy.ndarray subclasses with named attributes:

| Type | Attributes | Units |
|------|-----------|-------|
| `XYZ` | `x`, `y`, `z` | meters (ECEF) |
| `LLA` | `lat_deg`, `lon_deg`, `alt_m` | degrees, degrees, meters |
| `ENU` | `east`, `north`, `up` | meters |
| `NED` | `north`, `east`, `down` | meters |
| `AER` | `azim_deg`, `elev_deg`, `range_m` | degrees, degrees, meters |

## Dependencies

- **gri-utils**: Coordinate conversion and distance functions
- **numpy**: Array operations


## Other Projects

Current list of other [GRI FOSS Projects](https://gitlab.com/geosol-foss/python/gri-pos/-/blob/main/.docs_other_projects.md) we are building and maintaining.

## License

MIT License. See [LICENSE](https://gitlab.com/geosol-foss/python/gri-pos/-/blob/main/LICENSE) for details.
