Airspace

Fetch airspace data from OpenAIP, the FAA NASR database, FAA TFR feed, and FlightPlanDB oceanic-track service, and check flight lines for conflicts. OpenAIP requires a free API key — set the OPENAIP_API_KEY environment variable or pass it to OpenAIPClient.

Data model

class Airspace[source]

Bases: object

A single airspace volume with lateral boundary and vertical limits.

Variables:
  • name – Human-readable airspace name (e.g. “R-2508 Complex”).

  • airspace_class – ICAO classification or SUA type. Values include "A" through "G" for controlled airspace, plus "RESTRICTED", "PROHIBITED", "DANGER", "TMA", "CTR", "FIR", "SFRA", "TFR", etc.

  • airspace_type – Numeric type code (0=other, 1=restricted, 2=danger, 3=prohibited, 4=CTR, 31=TFR, 33=CLASS_B, 34=CLASS_C, 35=CLASS_D, 36=CLASS_E, 37=SFRA, …).

  • floor_ft – Lower altitude limit in feet MSL. 0 means surface.

  • ceiling_ft – Upper altitude limit in feet MSL.

  • geometry – Shapely polygon of the lateral boundary.

  • country – ISO 3166-1 alpha-2 country code (e.g. "US").

  • source – Data source identifier ("openaip", "faa_nasr", "faa_tfr").

  • ceiling_unlimited – True if the airspace has no defined ceiling.

  • effective_start – ISO date string for TFR start, or None.

  • effective_end – ISO date string for TFR end, or None.

  • floor_reference"MSL" or "SFC" (AGL). Use convert_agl_floors() to convert SFC to MSL.

  • schedule – Active-hours text from NASR (e.g. "0700 - 1800, MON - FRI"). Use filter_by_schedule() to filter inactive airspaces.

  • gmt_offset – Hours from UTC for the airspace location.

  • dst_code0 = no DST, 1 = uses DST.

name: str
airspace_class: str
airspace_type: int
floor_ft: float
ceiling_ft: float
geometry: Polygon | MultiPolygon
country: str = ''
source: str = 'openaip'
ceiling_unlimited: bool = False
effective_start: str | None = None
effective_end: str | None = None
floor_reference: str = 'MSL'
schedule: str | None = None
gmt_offset: float | None = None
dst_code: int | None = None
__init__(name, airspace_class, airspace_type, floor_ft, ceiling_ft, geometry, country='', source='openaip', ceiling_unlimited=False, effective_start=None, effective_end=None, floor_reference='MSL', schedule=None, gmt_offset=None, dst_code=None)
Parameters:
Return type:

None

class AirspaceConflict[source]

Bases: object

A detected conflict between a flight line and an airspace volume.

Variables:
  • airspace – The conflicting airspace.

  • flight_line_index – Index of the flight line in the input list.

  • horizontal_intersection – Shapely geometry of the lateral overlap.

  • vertical_overlap_ft(overlap_floor, overlap_ceiling) in feet MSL describing the altitude band where the flight line and airspace overlap.

  • severity"HARD", "ADVISORY", "INFO", or "NEAR_MISS" (from classify_severity() or check_airspace_proximity()).

  • entry_point(lon, lat) where the flight line enters the airspace, or None.

  • exit_point(lon, lat) where the flight line exits, or None.

  • distance_to_boundary_m – For near-miss conflicts, the closest approach distance in meters. None for actual conflicts.

airspace: Airspace
flight_line_index: int
horizontal_intersection: BaseGeometry
vertical_overlap_ft: Tuple[float, float]
severity: str = ''
entry_point: Tuple[float, float] | None = None
exit_point: Tuple[float, float] | None = None
distance_to_boundary_m: float | None = None
__init__(airspace, flight_line_index, horizontal_intersection, vertical_overlap_ft, severity='', entry_point=None, exit_point=None, distance_to_boundary_m=None)
Parameters:
Return type:

None

class OceanicTrack[source]

Bases: object

A single oceanic track (NAT or PACOT).

Variables:
  • ident – Track identifier (e.g. “A”, “Z”, 1, 2).

  • system"NAT" or "PACOT".

  • valid_from – ISO 8601 start of validity window.

  • valid_to – ISO 8601 end of validity window.

  • waypoints – List of (lon, lat, ident) tuples.

  • east_levels – Permitted eastbound flight levels, or None.

  • west_levels – Permitted westbound flight levels, or None.

  • geometry – Shapely LineString of the track.

ident: str | int
system: str
valid_from: str
valid_to: str
waypoints: List[Tuple[float, float, str]]
east_levels: List[str] | None = None
west_levels: List[str] | None = None
geometry: LineString | None = None
__init__(ident, system, valid_from, valid_to, waypoints, east_levels=None, west_levels=None, geometry=None)
Parameters:
Return type:

None

Conflict detection

check_airspace_conflicts(flight_lines, airspaces)[source]

Check flight lines for airspace conflicts.

For each flight line the function tests:

  1. Horizontal — does the line geometry intersect the airspace polygon?

  2. Vertical — does the flight altitude overlap the airspace [floor_ft, ceiling_ft] range?

A conflict is reported only when both checks are true.

Parameters:
  • flight_lines – Iterable of objects with .geometry (Shapely LineString) and .altitude_msl (pint Quantity) attributes — typically FlightLine instances.

  • airspaces (List[Airspace]) – List of Airspace objects to check against.

Return type:

List[AirspaceConflict]

Returns:

List of AirspaceConflict for every flight-line / airspace pair that conflicts.

check_airspace_proximity(flight_lines, airspaces, buffer_m=1000.0)[source]

Check for near-miss proximity to airspace without penetration.

Returns conflicts where the flight line does not intersect the airspace polygon but passes within buffer_m meters of its boundary. The distance_to_boundary_m field is populated with the closest approach distance.

Parameters:
  • flight_lines – Iterable of objects with .geometry and .altitude_msl attributes.

  • airspaces (List[Airspace]) – List of Airspace objects.

  • buffer_m (float) – Proximity threshold in meters.

Return type:

List[AirspaceConflict]

Returns:

List of AirspaceConflict with severity="NEAR_MISS" for each flight-line / airspace pair within the buffer.

fetch_and_check(flight_lines, api_key=None, buffer_m=1000.0, country=None, max_age_hours=24.0, type_filter=None, use_faa=True)[source]

Fetch nearby airspaces and check flight lines for conflicts.

This is a one-call convenience function that:

  1. Computes a bounding box from the flight lines (with buffer).

  2. Fetches airspaces (US: FAA SUA + SFRA + TFRs; international: OpenAIP).

  3. Runs check_airspace_conflicts().

For US queries (when use_faa is True and bounds fall within US territory), airspace data is sourced from the FAA ArcGIS portal and GeoServer — no API key required. For international queries, an OpenAIP API key is needed.

Parameters:
  • flight_lines – Iterable of objects with .geometry and .altitude_msl attributes.

  • api_key (Optional[str]) – OpenAIP API key (or set OPENAIP_API_KEY env var). Only used for international queries.

  • buffer_m (float) – Buffer in meters added to the bounding box.

  • country (str | list[str] | None) – Optional ISO 2-letter country code(s).

  • max_age_hours (float) – Maximum cache age before re-fetching.

  • type_filter (int | str | list[int | str] | None) – Filter to specific airspace types (see OpenAIPClient.fetch_airspaces()).

  • use_faa (bool) – If True (default), use FAA sources for US queries instead of OpenAIP.

Return type:

List[AirspaceConflict]

Returns:

List of AirspaceConflict objects.

Severity and schedule helpers

classify_severity(airspace_type)[source]

Return conflict severity for an airspace type code.

Returns "HARD", "ADVISORY", or "INFO".

Return type:

str

Parameters:

airspace_type (int)

filter_by_schedule(airspaces, at_datetime=None)[source]

Filter airspaces by their active schedule.

Parses the schedule field (e.g. "0700 - 1800, MON - FRI") and returns only those airspaces active at the given time. Airspaces without schedule data are always included (conservative).

Parameters:
  • airspaces (List[Airspace]) – List of airspaces to filter.

  • at_datetime (Optional[datetime]) – UTC datetime to check against. Defaults to now.

Return type:

List[Airspace]

Returns:

Filtered list of airspaces that are active at the given time.

convert_agl_floors(airspaces, dem_file)[source]

Convert AGL (SFC-referenced) floors to MSL using terrain elevations.

For each airspace whose floor_reference is "SFC", computes the maximum terrain elevation within its boundary and adds the AGL floor to it. This is a conservative estimate — the worst-case MSL floor across the airspace polygon.

Parameters:
  • airspaces (List[Airspace]) – List of airspaces (modified in place and returned).

  • dem_file (str) – Path to a DEM GeoTIFF file.

Return type:

List[Airspace]

Returns:

The same list with AGL floors converted to MSL.

summarize_airspaces(airspaces, header='')[source]

Return a formatted summary table of airspaces.

Parameters:
  • airspaces (List[Airspace]) – List of Airspace objects.

  • header (str) – Optional header line (e.g. "SUA zones").

Return type:

str

Returns:

Multi-line string suitable for print().

Data sources

class OpenAIPClient[source]

Bases: object

Fetch and cache airspace data from the OpenAIP API.

Parameters:

api_key (Optional[str]) – OpenAIP API key. If None, reads from the OPENAIP_API_KEY environment variable.

Raises:

HyPlanValueError – If no API key is provided or found.

BASE_URL = 'https://api.core.openaip.net/api'
__init__(api_key=None)[source]
Parameters:

api_key (str | None)

fetch_airspaces(bounds, country=None, max_age_hours=24.0, type_filter=None)[source]

Fetch airspaces within a bounding box.

Uses a local JSON cache; stale entries are re-fetched.

Parameters:
  • bounds (Tuple[float, float, float, float]) – (min_lon, min_lat, max_lon, max_lat) bounding box.

  • country (str | list[str] | None) – Optional ISO 2-letter country code(s). A single string or a list of strings for multi-country queries.

  • max_age_hours (float) – Maximum cache age before re-fetching.

  • type_filter (int | str | list[int | str] | None) – Filter results to specific airspace types. Accepts an int type code, a type name string (e.g. "RESTRICTED"), a list of either, or None for all.

Return type:

List[Airspace]

Returns:

List of Airspace objects.

Raises:

HyPlanRuntimeError – On network or API errors.

fetch_airspaces_raw(bounds, country=None, max_age_hours=24.0)[source]

Fetch airspaces and return both parsed objects and raw JSON items.

Same as fetch_airspaces() but also returns the raw API response items, which can be persisted for later re-parsing.

Parameters:
Return type:

Tuple[List[Airspace], List[dict]]

Returns:

(airspaces, raw_items) tuple.

class FAATFRClient[source]

Bases: object

Fetch active Temporary Flight Restrictions from the FAA.

Queries the FAA GeoServer WFS endpoint for TFR polygons and the tfrapi JSON endpoint for metadata, then merges them by NOTAM ID. No API key required.

TFRs are cached locally with a short TTL (default 1 hour) since they change frequently.

Parameters:

cache_ttl_hours (float) – Cache time-to-live in hours.

TFR_WFS_URL = 'https://tfr.faa.gov/geoserver/TFR/ows'
TFR_LIST_URL = 'https://tfr.faa.gov/tfrapi/getTfrList'
__init__(cache_ttl_hours=1.0)[source]
Parameters:

cache_ttl_hours (float)

fetch_tfrs(bounds=None, effective_only=False)[source]

Fetch active TFRs, optionally filtered to a bounding box.

Parameters:
  • bounds (Optional[Tuple[float, float, float, float]]) – Optional (min_lon, min_lat, max_lon, max_lat). If provided, only TFRs whose geometry intersects the bounding box are returned.

  • effective_only (bool) – If True, filter out TFRs whose description text indicates a start date in the future. Best-effort parsing — TFRs without parseable dates are kept.

Return type:

List[Airspace]

Returns:

List of Airspace objects with source="faa_tfr".

class NASRAirspaceSource[source]

Bases: object

Fetch US airspace data from the FAA ArcGIS open data portal.

Uses the AIS Data Delivery Service to query Special Use Airspace (SUA) and Special Flight Rules Areas (SFRAs) as GeoJSON. No API key required.

Cached locally with a 28-day TTL matching the NASR subscription cycle.

Parameters:
  • cache_ttl_days (float) – Cache time-to-live in days.

  • base_url (Optional[str]) – Override the SUA ArcGIS Feature Server URL.

DEFAULT_BASE_URL = 'https://services6.arcgis.com/ssFJjBXIUyZDrSYZ/arcgis/rest/services/Special_Use_Airspace/FeatureServer/0/query'
SFRA_BASE_URL = 'https://services6.arcgis.com/ssFJjBXIUyZDrSYZ/arcgis/rest/services/Airspace/FeatureServer/0/query'
CLASS_AIRSPACE_URL = 'https://services6.arcgis.com/ssFJjBXIUyZDrSYZ/arcgis/rest/services/Class_Airspace/FeatureServer/0/query'
__init__(cache_ttl_days=28.0, base_url=None)[source]
Parameters:
  • cache_ttl_days (float)

  • base_url (str | None)

fetch_airspaces(bounds, sua_types=None)[source]

Fetch NASR airspace data within bounds.

Parameters:
Return type:

List[Airspace]

Returns:

List of Airspace objects with source="faa_nasr".

fetch_sfras(bounds)[source]

Fetch Special Flight Rules Areas (SFRAs) within bounds.

Queries the FAA Airspace ArcGIS layer for features with TYPE_CODE='SATA' (Special Air Traffic Rules), which includes DC SFRA, Grand Canyon, NYC Hudson River SFRA, and others.

Parameters:

bounds (Tuple[float, float, float, float]) – (min_lon, min_lat, max_lon, max_lat) bounding box.

Return type:

List[Airspace]

Returns:

List of Airspace objects with source="faa_nasr" and airspace_class="SFRA".

fetch_class_airspace(bounds, classes=None)[source]

Fetch FAA Class B/C/D/E airspace within bounds.

Parameters:
  • bounds (Tuple[float, float, float, float]) – (min_lon, min_lat, max_lon, max_lat) bounding box.

  • classes (Optional[List[str]]) – Optional filter, e.g. ["B", "C", "D"]. Defaults to ["B", "C", "D"] (E is omitted by default as it covers very large areas and is rarely restrictive).

Return type:

List[Airspace]

Returns:

List of Airspace objects with source="faa_nasr".

class FlightPlanDBClient[source]

Bases: object

Fetch NAT and PACOT oceanic tracks from FlightPlanDatabase.com.

No API key required (100 requests/day unauthenticated). An optional key raises the limit to 2,500/day.

Parameters:
  • api_key (Optional[str]) – Optional FlightPlanDB API key.

  • cache_ttl_hours (float) – Cache time-to-live in hours (default 6).

BASE_URL = 'https://api.flightplandatabase.com'
NAT_URL = 'https://api.flightplandatabase.com/nav/NATS'
PACOT_URL = 'https://api.flightplandatabase.com/nav/PACOTS'
__init__(api_key=None, cache_ttl_hours=6.0)[source]
Parameters:
  • api_key (str | None)

  • cache_ttl_hours (float)

fetch_nats()[source]

Fetch current North Atlantic Tracks.

Return type:

List[OceanicTrack]

fetch_pacots()[source]

Fetch current Pacific Organized Tracks.

Return type:

List[OceanicTrack]

Cache management

clear_airspace_cache()[source]

Remove all cached airspace data.

This forces the next OpenAIPClient.fetch_airspaces() call to re-query the API instead of using stale local data.

Return type:

None

Parsing helpers

parse_airspace_items(items)[source]

Parse a list of raw OpenAIP JSON items into Airspace objects.

Items that cannot be parsed (missing geometry, non-polygon geometry, etc.) are silently skipped.

Return type:

List[Airspace]

Parameters:

items (List[dict])