---
title: "Map Projections"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Map Projections}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
```

```{r setup}
library(geographiclib)
```

This vignette covers the map projections available in geographiclib. Each
projection has different properties making it suitable for different purposes.

## Contents

- [Example Locations](#example-locations)
- [UTM/UPS - Universal Transverse Mercator](#utmups---universal-transverse-mercator)
- [Transverse Mercator (Custom)](#transverse-mercator-custom)
- [Lambert Conformal Conic (LCC)](#lambert-conformal-conic-lcc)
- [Albers Equal Area](#albers-equal-area)
- [Polar Stereographic](#polar-stereographic)
- [Azimuthal Equidistant](#azimuthal-equidistant)
- [Cassini-Soldner Projection](#cassini-soldner-projection)
- [Gnomonic Projection](#gnomonic-projection)
- [OSGB - Ordnance Survey National Grid](#osgb---ordnance-survey-national-grid)
- [Projection Comparison](#projection-comparison)
- [See Also](#see-also)

## Example Locations

We'll use a mix of Northern and Southern Hemisphere locations:

```{r locations}
# Australian cities
australia <- cbind(
  lon = c(151.21, 144.96, 153.02, 115.86, 138.60),
  lat = c(-33.87, -37.81, -27.47, -31.95, -34.93)
)
rownames(australia) <- c("Sydney", "Melbourne", "Brisbane", "Perth", "Adelaide")

# Antarctic stations
antarctic <- cbind(
  lon = c(166.67, 77.97, 39.58, -64.05, 0),
  lat = c(-77.85, -68.58, -67.60, -64.25, -90)
)
rownames(antarctic) <- c("McMurdo", "Davis", "Mawson", "Palmer", "South Pole")

# World cities
world_pts <- cbind(
  lon = c(-0.13, -74.01, 139.69, 151.21, -43.17),
  lat = c(51.51, 40.71, 35.69, -33.87, -22.91)
)
rownames(world_pts) <- c("London", "New York", "Tokyo", "Sydney", "Rio")
```

## UTM/UPS - Universal Transverse Mercator

UTM divides the Earth into 60 zones, each 6 degrees wide. For polar regions (>84N
or <80S), UPS (Universal Polar Stereographic) is used instead.

### Basic Conversion

```{r utm-basic}
# Convert Australian cities
utmups_fwd(australia)
```

### Understanding UTM Zones

```{r utm-zones}
# Points at different longitudes show different zones
lon_transect <- cbind(
  lon = seq(-180, 180, by = 30),
  lat = -45
)

result <- utmups_fwd(lon_transect)
data.frame(
  lon = result$lon,
  zone = result$zone,
  northp = result$northp,
  crs = result$crs
)
```

### Polar Regions (UPS)

When zone = 0, the projection is UPS rather than UTM:

```{r utm-polar}
# Antarctic stations
utmups_fwd(antarctic)
```

### Round-trip Conversion

```{r utm-roundtrip}
fwd <- utmups_fwd(australia)
rev <- utmups_rev(fwd$x, fwd$y, fwd$zone, fwd$northp)

# Verify accuracy
max(abs(rev$lon - australia[,1]))
max(abs(rev$lat - australia[,2]))
```

## Transverse Mercator (Custom)

For custom Transverse Mercator projections with user-defined central meridian
and scale factor (unlike UTM which auto-selects zones):

```{r tm-custom}
# Custom TM centered on Tasmania
tm_fwd(australia, lon0 = 147, k0 = 1.0)

# Compare series approximation vs exact
pts <- cbind(lon = c(147, 148, 149), lat = c(-42, -43, -44))
tm_fwd(pts, lon0 = 147)       # Fast (~5nm accuracy)
tm_exact_fwd(pts, lon0 = 147) # Exact (slower)
```

## Lambert Conformal Conic (LCC)

LCC is ideal for mid-latitude regions with greater east-west extent.
It can use one standard parallel (tangent cone) or two (secant cone).

### Single Standard Parallel

```{r lcc-single}
# Project Australia using a single standard parallel at -35
lcc_fwd(australia, lon0 = 135, stdlat = -35)
```

### Two Standard Parallels

Two standard parallels give better scale distribution across the region:

```{r lcc-two}
# Project Australia using two standard parallels
result <- lcc_fwd(australia, lon0 = 135, stdlat1 = -18, stdlat2 = -36)
result
```

### LCC for Antarctica

```{r lcc-antarctic}
# Antarctic projection centered on the pole
lcc_fwd(antarctic, lon0 = 0, stdlat1 = -71, stdlat2 = -89)
```

## Albers Equal Area

Albers is an equal-area conic projection, ideal for thematic maps where
accurate area representation is important.

### Two Standard Parallels (Most Common)

```{r albers-two}
# Albers Equal Area for Australia
albers_fwd(australia, lon0 = 132, stdlat1 = -18, stdlat2 = -36)
```

### CONUS Albers (US Standard)

```{r albers-conus}
# Continental US configuration
conus <- cbind(
  lon = c(-122.42, -74.01, -87.63, -104.99, -118.24),
  lat = c(37.77, 40.71, 41.88, 39.74, 34.05)
)
rownames(conus) <- c("San Francisco", "New York", "Chicago", "Denver", "Los Angeles")

albers_fwd(conus, lon0 = -96, stdlat1 = 29.5, stdlat2 = 45.5)
```

### Antarctic Albers

```{r albers-antarctic}
# Antarctic equal-area projection
albers_fwd(antarctic, lon0 = 0, stdlat1 = -72, stdlat2 = -60)
```

### Why Equal-Area Matters

Albers preserves area, making it suitable for:
- Choropleth maps (population density, land use)
- Statistical analysis where area matters
- Environmental mapping

```{r albers-vs-lcc}
# Compare Albers (equal-area) vs LCC (conformal)
albers_result <- albers_fwd(australia, lon0 = 132, stdlat1 = -18, stdlat2 = -36)
lcc_result <- lcc_fwd(australia, lon0 = 132, stdlat1 = -18, stdlat2 = -36)

data.frame(
  city = rownames(australia),
  albers_scale = round(albers_result$scale, 4),
  lcc_scale = round(lcc_result$scale, 4)
)
```

## Polar Stereographic

Conformal projection for polar regions. The default scale factor (k0 = 0.994)
corresponds to UPS. Use k0 = 1.0 for true stereographic.

### Antarctic Stations

```{r polarstereo-antarctic}
# Antarctic stations with UPS-standard scale
polarstereo_fwd(antarctic, northp = FALSE, k0 = 0.994)
```

### Arctic Points

```{r polarstereo-arctic}
# Arctic circle of points
arctic <- cbind(lon = seq(0, 315, by = 45), lat = 85)
polarstereo_fwd(arctic, northp = TRUE)

# All points at same latitude have same distance from pole
result <- polarstereo_fwd(arctic, northp = TRUE)
sqrt(result$x^2 + result$y^2)  # All equal
```

### Pole at Origin

The pole is always at the origin:

```{r polarstereo-pole}
# South pole
polarstereo_fwd(c(0, -90), northp = FALSE)

# North pole
polarstereo_fwd(c(0, 90), northp = TRUE)
```

## Azimuthal Equidistant

This projection preserves distances from the center point. Useful for showing
distances from a specific location.

### Distances from Sydney

```{r azeq-sydney}
# Project world cities relative to Sydney
sydney <- c(151.21, -33.87)
result <- azeq_fwd(world_pts, lon0 = sydney[1], lat0 = sydney[2])
result

# Distance from Sydney (in km) = sqrt(x^2 + y^2) / 1000
distances <- sqrt(result$x^2 + result$y^2) / 1000
data.frame(
  city = rownames(world_pts),
  distance_km = round(distances)
)
```

### Distances from South Pole

```{r azeq-pole}
# Distance from South Pole to Antarctic stations
result <- azeq_fwd(antarctic, lon0 = 0, lat0 = -90)

distances <- sqrt(result$x^2 + result$y^2) / 1000
data.frame(
  station = rownames(antarctic),
  lat = antarctic[,2],
  distance_from_pole_km = round(distances)
)
```

## Cassini-Soldner Projection

A historical projection used for large-scale topographic mapping. It's a
transverse cylindrical projection that preserves scale along the central
meridian.

### Regional Mapping

```{r cassini-basic}
# Tasmania centered on Hobart
tasmania <- cbind(
  lon = c(147.32, 145.49, 146.82, 148.29, 147.13),
  lat = c(-42.88, -40.83, -41.44, -42.15, -43.21)
)
rownames(tasmania) <- c("Hobart", "Launceston", "Devonport", "St Helens", "Dover")

cassini_fwd(tasmania, lon0 = 147, lat0 = -42)
```

### Cassini for Antarctic Survey

```{r cassini-antarctic}
# McMurdo area survey
mcmurdo_area <- cbind(
  lon = c(166.67, 166.40, 167.00, 166.87, 168.40),
  lat = c(-77.85, -77.55, -78.15, -78.65, -77.18)
)
rownames(mcmurdo_area) <- c("McMurdo", "Marble Point", "Black Island",
                            "Minna Bluff", "Cape Adare")

cassini_fwd(mcmurdo_area, lon0 = 166.67, lat0 = -77.85)
```

## Gnomonic Projection

The gnomonic projection has a unique property: geodesics (great circles)
appear as straight lines. This makes it invaluable for route planning.

### Great Circle Routes Appear Straight

```{r gnomonic-routes}
# Project Sydney-London great circle path
sydney_london <- geodesic_path(c(151.21, -33.87), c(-0.13, 51.51), n = 10)

# Project onto gnomonic centered between them
gnomonic_fwd(cbind(sydney_london$lon, sydney_london$lat),
             lon0 = 75, lat0 = 10)
```

### Route Planning

```{r gnomonic-planning}
# Flights from Sydney - project candidate destinations
destinations <- cbind(
  lon = c(-0.13, -74.01, 139.69, 77.22, -43.17),
  lat = c(51.51, 40.71, 35.69, 28.61, -22.91)
)
rownames(destinations) <- c("London", "New York", "Tokyo", "Delhi", "Rio")

# Gnomonic from Sydney shows great circle routes as straight lines
gnomonic_fwd(destinations, lon0 = 151.21, lat0 = -33.87)
```

## OSGB - Ordnance Survey National Grid

OSGB is specific to Great Britain. Note: It uses the OSGB36 datum, not WGS84.

```{r osgb}
# British locations (using approximate OSGB36 coordinates)
britain <- cbind(
  lon = c(-0.127, -3.188, -4.251, -1.890, -2.587),
  lat = c(51.507, 55.953, 55.864, 52.486, 51.454)
)
rownames(britain) <- c("London", "Edinburgh", "Glasgow", "Birmingham", "Cardiff")

# Convert to OSGB grid
osgb_fwd(britain)
```

### Grid References

```{r osgb-gridref}
# Get alphanumeric grid references
osgb_gridref(britain, precision = 3)  # 100m precision

# Parse a grid reference
osgb_gridref_rev("TQ308080")
```

## Projection Comparison

Different projections preserve different properties:

| Projection | Preserves | Best For |
|------------|-----------|----------|
| UTM/UPS | Shape (conformal) | Global standard, topographic maps |
| Transverse Mercator | Shape (conformal) | Custom zone definitions |
| LCC | Shape (conformal) | Mid-latitude regional maps |
| Albers Equal Area | Area | Thematic/statistical maps |
| Polar Stereographic | Shape (conformal) | Polar regions |
| Azimuthal Equidistant | Distance from center | Showing distances from a point |
| Cassini-Soldner | Scale on central meridian | Large-scale surveys |
| Gnomonic | Great circles as straight lines | Route planning |
| OSGB | Shape (conformal) | British mapping |

## See Also

- `vignette("geodesics")` for distance and bearing calculations
- `vignette("grid-reference-systems")` for MGRS, Geohash, etc.
- `vignette("local-coordinates")` for Local Cartesian (ENU) and Geocentric
