# GPS Toolkit for Python

[![PyPI version](https://img.shields.io/pypi/v/gps-toolkit-py.svg)](https://pypi.org/project/gps-toolkit-py/)
[![Python versions](https://img.shields.io/pypi/pyversions/gps-toolkit-py.svg)](https://pypi.org/project/gps-toolkit-py/)
[![License](https://img.shields.io/pypi/l/gps-toolkit-py.svg)](https://github.com/username/GPS-tools-python-package/blob/main/LICENSE)

A powerful, comprehensive Python library for working with GPS coordinates, with support for multiple coordinate systems, distance calculations, and coordinate transformations.

## Features

- **Multiple Coordinate Systems**
  - Decimal degrees (latitude/longitude)
  - Universal Transverse Mercator (UTM)
  - Military Grid Reference System (MGRS)

- **Distance Calculations**
  - Haversine formula (great-circle distance)
  - Vincenty's formula (ellipsoidal distance)
  - Path distances for multiple points

- **Coordinate Conversions**
  - Convert between lat/lon, UTM, and MGRS
  - Parse coordinates from various string formats
  - Unified conversion interface

- **Advanced Utilities**
  - Calculate bearings between points
  - Find destination points from a starting position
  - Calculate centroids and bounding boxes
  - Create coordinate collections with custom properties

## Installation

### Basic Installation

```bash
pip install gps-toolkit-py
```

### With Optional Features

```bash
# For visualization capabilities (matplotlib, folium)
pip install gps-toolkit-py[viz]

# For GIS integrations (shapely, geopandas)
pip install gps-toolkit-py[gis]

# For development (testing, linting, etc.)
pip install gps-toolkit-py[dev]
```

## Quick Start

### Basic Coordinate Usage

```python
from gps_toolkit_py import Coordinate

# Create a coordinate
nyc = Coordinate(40.7128, -74.0060, name="New York")
sf = Coordinate(37.7749, -122.4194, name="San Francisco")

# Access properties
print(f"NYC is at {nyc.latitude}°N, {abs(nyc.longitude)}°W")
# Output: NYC is at 40.7128°N, 74.006°W

# String representation
print(nyc)
# Output: New York: 40.7128°N, 74.0060°W
```

### Distance Calculations

```python
from gps_toolkit_py import Coordinate
from gps_toolkit_py.distance import haversine_distance, vincenty_distance

# Create coordinates
nyc = Coordinate(40.7128, -74.0060, name="New York")
la = Coordinate(34.0522, -118.2437, name="Los Angeles")

# Calculate distances
haversine_dist = haversine_distance(nyc, la)
vincenty_dist = vincenty_distance(nyc, la)

print(f"Haversine distance: {haversine_dist/1000:.2f} km")
print(f"Vincenty distance: {vincenty_dist/1000:.2f} km")
```

### Coordinate Conversions

```python
from gps_toolkit_py import Coordinate
from gps_toolkit_py.converters import latlon_to_utm, utm_to_latlon, latlon_to_mgrs

# Convert to UTM
lat, lon = 40.7128, -74.0060  # NYC
zone_number, zone_letter, easting, northing = latlon_to_utm(lat, lon)
print(f"UTM: {zone_number}{zone_letter} {easting:.1f}E {northing:.1f}N")

# Convert back to lat/lon
lat2, lon2 = utm_to_latlon(zone_number, zone_letter, easting, northing)
print(f"Back to lat/lon: {lat2:.4f}, {lon2:.4f}")

# Convert to MGRS
mgrs = latlon_to_mgrs(lat, lon)
print(f"MGRS: {mgrs}")
```

### Working with Coordinate Collections

```python
from gps_toolkit_py import Coordinate, CoordinateList
from gps_toolkit_py.calculations import calculate_path_distance, calculate_centroid

# Create a path of coordinates
path = CoordinateList([
    Coordinate(40.7128, -74.0060, name="New York"),
    Coordinate(39.9526, -75.1652, name="Philadelphia"),
    Coordinate(38.9072, -77.0369, name="Washington DC")
])

# Calculate the total path distance
total_distance = calculate_path_distance(path.coordinates)
print(f"Total path distance: {total_distance/1000:.2f} km")

# Find the centroid of the coordinates
centroid = calculate_centroid(path.coordinates)
print(f"Centroid: {centroid}")
```

## API Reference

### Core Classes

- `Coordinate` - Basic latitude/longitude coordinate representation
- `UTMCoordinate` - UTM coordinate representation
- `MGRSCoordinate` - MGRS coordinate representation
- `CoordinateList` - Collection of coordinates

### Distance Calculation Functions

- `haversine_distance` - Great-circle distance
- `vincenty_distance` - Ellipsoidal distance
- `bearing` - Calculate bearing between two points
- `destination_point` - Find destination from start point
- `path_distance` - Total distance along a path
- `midpoint` - Find midpoint between two coordinates

### Conversion Functions

- `latlon_to_utm`, `utm_to_latlon` - UTM conversions
- `decimal_to_dms`, `dms_to_decimal` - DMS format conversions
- `latlon_to_mgrs`, `mgrs_to_latlon` - MGRS conversions
- `convert_to_latlon` - Unified conversion interface

### Calculation Functions

- `calculate_distance` - High-level distance calculator
- `calculate_destination` - Calculate destination coordinate
- `calculate_path_distance` - Distance along multiple points
- `calculate_centroid` - Find centroid of multiple coordinates
- `calculate_bbox` - Calculate a bounding box

## Function Examples

### Core Coordinate Classes

```python
from gps_toolkit_py import Coordinate, UTMCoordinate, MGRSCoordinate, CoordinateList

# Basic coordinate
nyc = Coordinate(40.7128, -74.0060, name="New York", elevation=10)
print(nyc)  # New York: 40.7128°N, 74.0060°W

# UTM coordinate
utm_coord = UTMCoordinate(18, 'T', 583591.9, 4507213.2, name="NYC in UTM")
print(utm_coord)  # NYC in UTM: 18T 583591.90E 4507213.20N

# MGRS coordinate
mgrs_coord = MGRSCoordinate(18, 'T', 'WL', 83455, 7213, name="NYC in MGRS")
print(mgrs_coord)  # NYC in MGRS: 18TWL8345507213

# Coordinate collection
cities = CoordinateList([
    Coordinate(40.7128, -74.0060, name="New York"),
    Coordinate(51.5074, -0.1278, name="London"),
    Coordinate(35.6762, 139.6503, name="Tokyo")
])
print(len(cities))  # 3
print(cities.get_by_name("London"))  # London: 51.5074°N, 0.1278°W
```

### Distance Functions

```python
from gps_toolkit_py import Coordinate
from gps_toolkit_py.distance import (
    haversine_distance, vincenty_distance, bearing,
    destination_point, path_distance, midpoint
)

# Create test coordinates
nyc = Coordinate(40.7128, -74.0060, name="New York")
london = Coordinate(51.5074, -0.1278, name="London")
tokyo = Coordinate(35.6762, 139.6503, name="Tokyo")

# Calculate haversine distance
distance_km = haversine_distance(nyc, london) / 1000
print(f"NYC to London: {distance_km:.1f} km")  # ~5570 km

# Calculate vincenty distance (more accurate)
distance_km = vincenty_distance(nyc, london) / 1000
print(f"NYC to London (Vincenty): {distance_km:.1f} km")  # ~5570 km

# Calculate bearing from NYC to London
initial_bearing = bearing(nyc, london)
print(f"Initial bearing from NYC to London: {initial_bearing:.1f}°")  # ~51.4°

# Find destination 100km east of NYC
dest = destination_point(nyc, 90.0, 100000)
print(f"100km east of NYC: {dest}")  # ~40.71°N, 72.63°W

# Calculate path distance
route = [nyc, london, tokyo]
total_distance = path_distance(route)
print(f"Total route distance: {total_distance/1000:.1f} km")  # ~15200 km

# Find midpoint between NYC and London
mid = midpoint(nyc, london)
print(f"Midpoint: {mid}")  # ~48.7°N, 42.5°W
```

### Conversion Functions

```python
from gps_toolkit_py.converters import (
    latlon_to_utm, utm_to_latlon, decimal_to_dms, dms_to_decimal,
    latlon_to_mgrs, mgrs_to_latlon, mgrs_to_utm
)
from gps_toolkit_py.unified_converter import convert_to_latlon

# Convert lat/lon to UTM
zone_number, zone_letter, easting, northing = latlon_to_utm(40.7128, -74.0060)
print(f"UTM: {zone_number}{zone_letter} {easting:.1f}E {northing:.1f}N")
# Output: UTM: 18T 583591.9E 4507213.2N

# Convert UTM to lat/lon
lat, lon = utm_to_latlon(18, 'T', 583591.9, 4507213.2)
print(f"Lat/Lon: {lat:.4f}°, {lon:.4f}°")  # ~40.7128°, -74.0060°

# Convert decimal degrees to DMS
nyc_lat_dms = decimal_to_dms(40.7128, is_latitude=True)
nyc_lon_dms = decimal_to_dms(-74.0060, is_latitude=False)
print(f"NYC: {nyc_lat_dms}, {nyc_lon_dms}")  # 40°42'46.08"N, 74°0'21.6"W

# Convert DMS to decimal degrees
lat_decimal = dms_to_decimal("40°42'46.08\"N")
lon_decimal = dms_to_decimal("74°0'21.6\"W")
print(f"Decimal: {lat_decimal:.4f}°, {lon_decimal:.4f}°")  # 40.7128°, -74.0060°

# Convert lat/lon to MGRS
mgrs = latlon_to_mgrs(40.7128, -74.0060)
print(f"MGRS: {mgrs}")  # 18TWL8345507213 (approximately)

# Convert MGRS to lat/lon
lat, lon = mgrs_to_latlon("18TWL8345507213")
print(f"Lat/Lon: {lat:.4f}°, {lon:.4f}°")  # ~40.7128°, -74.0060°

# Convert MGRS to UTM
zone_number, zone_letter, easting, northing = mgrs_to_utm("18TWL8345507213")
print(f"UTM: {zone_number}{zone_letter} {easting:.1f}E {northing:.1f}N")
# Output: UTM: 18T 583455.0E 4507213.0N

# Unified converter - accepts various coordinate formats
lat, lon, elev = convert_to_latlon("18TWL8345507213")
print(f"Lat/Lon: {lat:.4f}°, {lon:.4f}°")  # ~40.7128°, -74.0060°
```

### Calculation Functions

```python
from gps_toolkit_py import Coordinate
from gps_toolkit_py.calculations import (
    calculate_distance, calculate_destination, calculate_path_distance,
    calculate_centroid, calculate_bbox, normalize_longitude
)

# Create test coordinates
nyc = Coordinate(40.7128, -74.0060, name="New York")
dc = Coordinate(38.9072, -77.0369, name="Washington DC") 
sf = Coordinate(37.7749, -122.4194, name="San Francisco")

# Calculate distance between points
distance = calculate_distance(nyc, dc)
print(f"NYC to DC: {distance/1000:.1f} km")  # ~328 km

# Calculate destination from bearing and distance
bearing = 45.0  # Northeast
distance = 100000  # 100 km
destination = calculate_destination(nyc, bearing, distance)
print(f"100km NE of NYC: {destination}")  # ~41.4°N, 72.7°W

# Calculate total path distance
cities = [nyc, dc, sf]
path_distance = calculate_path_distance(cities)
print(f"Total path distance: {path_distance/1000:.1f} km")  # ~4620 km

# Calculate centroid (geographic center)
centroid = calculate_centroid(cities)
print(f"Centroid: {centroid}")  # ~39.1°N, 91.2°W

# Calculate bounding box
sw, ne = calculate_bbox(cities)
print(f"Bounding box SW: {sw}")  # ~37.8°N, 122.4°W
print(f"Bounding box NE: {ne}")  # ~40.7°N, 74.0°W

# Normalize longitude to -180 to 180 range
normalized = normalize_longitude(185.5)
print(f"Normalized longitude: {normalized}°")  # -174.5°
```

## Requirements

- Python 3.7+
- numpy
- scipy
- pyproj

## Contributing

Contributions are welcome! Whether it's bug reports, feature requests, or pull requests, all contributions help improve the library.

1. **Fork the repository**
2. **Create your feature branch**: `git checkout -b feature/amazing-feature`
3. **Commit your changes**: `git commit -m 'Add some amazing feature'`
4. **Push to the branch**: `git push origin feature/amazing-feature`
5. **Open a Pull Request**

Before submitting:
- Make sure your code follows the project's style
- Add or update tests as necessary
- Update documentation to reflect your changes

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

## Acknowledgments

- Thanks to all contributors who have helped improve GPS Toolkit
- Inspired by various GPS and geospatial libraries

---

Made with ❤️ by the GPS Toolkit Team 