Skip to main content
Version: Next

Data

Offline First

The SDK is offline first. All tracked turbulence data is stored offline until successfully sent to the server and the fetched data from the server is stored on the disk and accessible offline according to the description below. All configurations are stored on the disk and stay across app launches until explicit change.

Data Query

At first request, the whole data according to SkyPath.dataQuery is fetched and then only the new data that appeared (delta) is fetched to save network traffic. When cached data expires or a delta can't be received, the whole fresh data will be received again.

There are thousands of turbulence reports around the globe. To reduce network traffic usage and keep only data that is currently needed the data fetch is separated into the different types controlled by the SkyPath.dataQuery object that is set initially to default values and can be updated at any time. All of the below are optional to set but recommended due to your specific flow.

After updating SkyPath.dataQuery in any way, the check, if need to fetch new data, will be made. And if the change requires a new server fetch, the server request will be made immediately. No need to call SkyPath.fetchData(refresh:).

You can update data queries at any time. When updating just one field, use one call

SkyPath.shared.dataQuery.types = [.turbulence, .turbulencePolygons]

When updating multiple fields prefer to copy a current object, modify, and set to update dataQuery in SDK in one call only. On any dataQuery object update SDK will check if need to update the data, for example because the polygon has been updated. Updating dataQuery multiple times immediately could result in a situation when you will not get fresh data immediately but in the next fetch cycle in a minute or so.

var dataQuery = SkyPath.shared.dataQuery
dataQuery.types = [.turbulence, .turbulencePolygons]
dataQuery.polygon = some_polygon
SkyPath.shared.dataQuery = dataQuery
info

Updating SkyPath.dataQuery will trigger a fetch from the server if needed automatically. Receiving server response will take some time so SkyPathDelegate callbacks will be called in a delay, not immediately after SkyPath.dataQuery update. Delegate callbacks will not be called if no new server fetch is needed or no new data will be received.

tip

Update the visible data by querying SDK after updating the SkyPath.dataQuery not waiting for the SkyPathDelegate. SDK caches data locally, so querying after the DataQuery update will return cached data if any. Then, update data again in the SkyPathDelegate callback.

Turbulence Polygons

A planet-wide aggregated turbulence area polygons as a GeoJSON string. Used to show turbulence areas worldwide without fetching too much data. DataQuery.types should have .turbulencePolygons to fetch it. Stored on disk, accessible offline.

Turbulence polygons are generated per time history separately and by default, only selected time history is fetched for polygons. To enable fetching polygons for all time histories up to selected set a corresponding flag. For example, if set to fetch 4h, then to have polygons available offline for 0.5h, 1h, 2h, and 4h you need to set this flag to true.

SkyPath.shared.dataQuery.globalTurbulencePolygonsUpToEnabled = false
warning

globalTurbulencePolygonsUpToEnabled = true consumes more network traffic

SDK periodically fetches global turbulence polygons and calls the delegate method when receiving new data.

// SkyPathDelegate
func didReceiveNewTurbulencePolygons() { }

Polygons data is generated per each history time separately, so if SkyPath.dataHistory is set to .twoHours for example, polygons for .fourHours will not be available to query, because it will not be fetched from the server. It is possible also to fetch polygons for times up to selected by setting DataQuery. globalTurbulencePolygonsUpToEnabled = true. It means that if set to .fourHours polygons will be fetched also for .halfHour, .hour, .twoHours, and .fourHours. It will allow you to change time and see polygons data when offline.

If DataQuery.globalEnabled == true turbulence polygons will be fetched worldwide, otherwise, if polygon is set - only inside the polygon. The default is true.

It is recommended to keep turbulence polygons and low-level hexagons data on separate layers. Show and hide the corresponding layer when zooming in/out of the map. Here is an approximate zoom level when switching from hexagons to global polygons:

3320 meters/point (1660 meters/pixel) or 10892 feet/point (5446 feet/pixel)

Here is an example screenshot of the iPad Pro 9.7 inch screen with a visible area when to switch.

Turbulence PolygonsTurbulence Polygons

Route Corridor (Polygon)

Route corridor polygon is a geo-fence area to fetch data inside only. It should be a valid GeoJSON Polygon RFC 7946. Use your route line coordinates to create a polygon with some width distance (50-150 NM is good).

SDK will fetch all data in the corridor at first and then only the delta since the previous fetch in this corridor. When changing the corridor to a different then all data will be fetched in the new corridor (not delta) and then will use delta again. So the route corridor should change only when the route line changes. Changing corridors frequently will result in big network traffic use. Also, choose the corridor width according to your needs because a bigger width and bigger corridor will consume more network traffic.

warning

Frequent changes and a bigger width of the corridor consume more network traffic

It is fetched separately from other data types and as fast as possible, and also stored offline. Stored on disk, accessible offline.

let polygon: [CLLocationCoordinate2D] = []
SkyPath.shared.dataQuery.polygon = polygon

Route PolygonRoute Polygon

According to GeoJSON Polygon RFC 7946 it should be a closed ring with up to 250 coordinates, otherwise SkyPath.didFailToFetchNewData will be called with an error. It is recommended to have fewer coordinates and simplify the polygon with enough tolerance.

To make a route corridor and simplification of the polygon you can use the provided [CLLocationCoordinate2D].buffer(widthNM:simplify:tolerance:) from the SDK. Usage example (a background thread is recommended to not block the main thread):

// where `polygon` is [CLLocationCoordinate2D]
dataQuery.polygon = polygon.buffer(widthNM: 100, simplify: true)
warning

For performance and network optimization, we recommend limiting the polygon to an area no larger in size than the route corridor in 250 NM width.

Viewport

A viewport is a polygon of a visible map area in the app to fetch the right data when it's needed. Please keep in mind, that the SDK will try to fetch the data for the viewport as soon as possible after updating SkyPath.shared.dataQuery.viewport. So to save network traffic consider updating viewport when it's needed.

All data in the viewport will be fetched at first and then a delta will be fetched only. But when changing a viewport all data will be fetched again.

warning

Frequent changes and a bigger viewport consumes more network traffic

A good place could be when the pilot moved the map manually, released the finger and the map stopped moving after animation, or when the focused map area is moved by code far from the previously focused area. Stored in memory, accessible offline until app relaunch. The previous viewport data is replaced with new viewport data.

let polygon: [CLLocationCoordinate2D] = []
SkyPath.shared.dataQuery.viewport = polygon

Route PolygonRoute Polygon

The simplest viewport polygon would be a currently visible rectangle on the map like [NorthWest, NorthEast, SouthEast, SouthWest, NorthWest]. For a more complex polygon, the following rules are applied.

Should be a closed ring and have max 250 coordinates, otherwise SkyPath.didFailToFetchNewData will be called with an error. Simplify the polygon with enough tolerance.

To make a viewport and simplification of the polygon you can use the provided [CLLocationCoordinate2D].buffer(widthNM:simplify:tolerance:) from the SDK. Usage example (a background thread is recommended to not block the main thread):

// where `polygon` is [CLLocationCoordinate2D]
dataQuery.viewport = polygon.buffer(widthNM: 100, simplify: true)
// or
dataQuery.viewport = polygon.simplify()
warning

For performance and network optimization, we recommend limiting the viewport to an area no larger in size than the Continental US for example.

History Time

Set DataHistoryTime to fetch data for. It's an enum with cases: halfHour, hour, twoHours, fourHours, and sixHours. The default is twoHours. The server does some data precalculations so only the specified time frames are supported.

SkyPath.shared.dataHistoryTime = .twoHours

When started, SDK fetches initial data from time back in time and then receives only updates since the last update.

It determines the data history to be fetched from the server. So if it is set to .twoHours for example (the default one), there will be no data locally available for more than 2 hours ago. If need 4 hours of history, set SkyPath.dataHistoryTime to .fourHours.

Changing from lower time to higher will require an API request to fetch data, when changing from higher to lower time, data could be available immediately as it was already included in the higher history time fetch. Alternatively, time can be set to .sixTime once to fetch 6 hours of history data always and then just query with a different time history to show on the map. Please note, that it will increase network traffic but will allow having more data available immediately and offline during changing time history.

Update

Set DataUpdateFrequency, it's an enum with cases: none, minimal, medium, fast. The default is fast (every 1 min). It controls time intervals to fetch data for global turbulence polygons, route polygons, viewport, and other data. When the data query route polygon or the viewport is changed, they are fetched as fast as possible not waiting for the next time interval.

SkyPath.shared.dataUpdateFrequency = .fast

To save network traffic, you can set it to none to disable periodic new data fetch from the server at all or set it to minimal to update with bigger time intervals. Can be updated at any time in the project. Value is stored across app launches until changed. The default is fast.

When you change some query parameters SDK will start fetching fresh data immediately if needed. No need to force fetch manually.

At some point, if need to fetch fresh data immediately (not after a data query update) call the following:

SkyPath.shared.fetchData(refresh: true)
warning

Frequent fetchData(refresh: true) consumes more network traffic

It could be helpful to know if SkyPath data was updated a long time ago (when offline for example), so check when the last time data was successfully received from the server.

SkyPath.shared.dataUpdatedAt
info

Implement SkyPathDelegate.didFailToFetchNewData(with:) to monitor if there is any error and handle it accordingly.

Stop Fetching

The preferred way to stop data fetching is to change the update frequency SkyPath.shared.dataUpdateFrequency = .none.

Based on your implementation you can use other options:

  • Set DataQuery.types to an empty set SkyPath.shared.dataQuery.types = [].

  • Remove the polygon, and viewport in the SkyPath.dataQuery and set globalEnabled to false. It can stop fetching because no area is set to fetch data in.

SDK will continue recording and reporting data.

info

Removing a flight by SkyPath.setFlight(nil) does not stop fetching data because SDK allows fetching data without it, for example for a map visible viewport or global polygons.

Data Types

SkyPath provides different data types, see DataTypeOptions. The default is turbulence only. Set it if you need more than just turbulence data.

SkyPath.shared.dataQuery.types = [.turbulence, .turbulencePolygons]

Turbulence Severity

H3H3

Color Legend

Smooth #FFFFFF (alpha 0.6) Border #898989 (alpha 0.8)
Light #FFF04C (alpha 0.8)
Light-Moderate #FFBC09 (alpha 0.8)
Moderate #FF7100 (alpha 0.8)
Moderate-Occasionally Severe #FF0000 (alpha 0.8)

By default, all severities of turbulence will be fetched, but you can provide a list of severities to fetch.

SkyPath.shared.dataQuery.sevs = [.moderate, .moderateSevere]

.none or smooth severity means that the pilot who crossed this hexagon didn't experience any turbulence, so his report is none. Each hexagon can have multiple reports left for it because multiple flights crossed this hexagon. By default, TurbulenceQuery has aggregate = true which means you'll get one TurbulenceItem per hexagon (tile) with the most severe report for this hexagon.