Skip to content

Commit

Permalink
Refactored the vatsys client. Initial ATC sectors.
Browse files Browse the repository at this point in the history
  • Loading branch information
Kahn committed Aug 2, 2021
1 parent ff699fc commit 3024390
Show file tree
Hide file tree
Showing 8 changed files with 283 additions and 208 deletions.
21 changes: 19 additions & 2 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,33 @@
## TODO

* Show ATC polys and state from controllers API
** Add a turf function for centerOfMass to get ATC sector labels


## Future

### Features

* Theme switch light / dark
** Turn off POI labels at high zoom

* Markers clickable
* Modal or inline window
* Geocoder search for marker names

* Show ATC polys and state from controllers API

* Add airport markers and counters for arr/deps
* Add ATC markers for tower, gnd, dep
* Use AFV to get extended sectors
* Switch icons between prop and jet based on callsign or type.
Filter aircraft_type by types from https://vatstats.net/
* Use nav API for progressive taxi or draw on ground map routes

### Tech debt

* Retest the xmlToPoly client with a single Line XML file
* Fail gracefully on vatsys dataset cache expiry

### Current stats
In FIR now
Top types
Expand All @@ -36,5 +47,11 @@ Blue B0D1FC A10

## References

Flight path fill with hdg and speed? Ala FR24
https://docs.mapbox.com/mapbox-gl-js/example/animate-marker/
https://docs.mapbox.com/mapbox-gl-js/example/forward-geocode-custom-data/

Local search
https://docs.mapbox.com/mapbox-gl-js/example/forward-geocode-custom-data/

Progressive taxi? / taxi markup for pilot assist
https://docs.mapbox.com/mapbox-gl-js/example/measure/
177 changes: 0 additions & 177 deletions api.js

This file was deleted.

12 changes: 12 additions & 0 deletions atc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { getLineFeatures } from './client.js';
import { polygon, featureCollection } from '@turf/helpers';

export async function getATCSectors(){
try{
var sectors = await getLineFeatures('https://raw.githubusercontent.com/vatSys/australia-dataset/master/Maps/ALL_SECTORS.xml');
return featureCollection(sectors);
}catch(err){
console.log(err)
return false;
}
}
127 changes: 127 additions & 0 deletions client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import NodeCache from 'node-cache';
import fetch from 'node-fetch';
import { xml2js } from 'xml-js';
import dms2dec from 'dms2dec';
import { lineToPolygon, lineString } from '@turf/turf';

const cache = new NodeCache( { stdTTL: 15, checkperiod: 30 } );

/**
* @typedef {Object} LineObj
* @property {string} name
* @property {Array.<{longitude, latitude}>} line
* @property {Feature.Polygon} poly
*/

export function clearCache(){
console.log('Clearing cache')
cache.flushAll();
return true;
}

function checkHTTPStatus(res) {
if (res.ok) { // res.status >= 200 && res.status < 300
return res;
} else {
throw HTTPError(res.statusText);
}
}

export async function getVatsimData (url) {
var data = cache.get("vatsimData");
if (data == undefined) {
const res = await fetch(url)
.then(checkHTTPStatus)
.then(res => res.json())
.then( data => {
return data;
})
.catch(err => console.log(err));
data = res;
console.log(`cache:set url:${url} keys:${Object.keys(data).length}`)
cache.set("vatsimData", data, 15);
}else{
console.log(`cache:get url:${url} keys:${Object.keys(data).length}`)
}
return data;
}

/**
* Gets a vatsys dataset URL and returns turf Features
* @param {string} url
* @returns {import('@turf/turf').Feature}
*/
export async function getLineFeatures (url) {
// Extract vatSys polys into object
var data = cache.get(url);
if (data == undefined) {
try{
// Download and parse XML
const res = await fetch(url)
.then(checkHTTPStatus)
.then(res => res.text())
.then( data => {
return data;
})
.catch(err => console.log(err));
data = await xml2js(res, {compact: true, spaces: 4});
}catch(err){
throw Error(err);
}

var features = xmlToFeatures(data);
console.log(features);

console.log(`cache:set url:${url} objs:${features.length}`)
cache.set(url, features, 86400);
return features;
}else{
console.log(`cache:get url:${url} objs:${data.length}`)
return data;
}
}

function xmlToFeatures (data) {
var polys = [];
// Take vatSys lines and parse into line array
// ±DDMMSS.SSSS±DDDMMSS.SSSS
// (?<latD>[+-][0-9]{2})(?<latM>[0-9]{2})(?<latS>[0-9]{2}\.[0-9]{3})(?<lonD>[+-][0-9]{3})(?<lonM>[0-9]{2})(?<lonS>[0-9]{2}\.[0-9]{3})
const re = new RegExp(/(?<latRef>[+-])(?<latD>[0-9]{2})(?<latM>[0-9]{2})(?<latS>[0-9]{2}\.[0-9]{3})(?<lonRef>[+-])(?<lonD>[0-9]{3})(?<lonM>[0-9]{2})(?<lonS>[0-9]{2}\.[0-9]{3})/g)

data.Maps.Map.Line.forEach(function(obj){
var lineStringArr = [];
var matches = [...obj._text.matchAll(re)];
matches.forEach(function(match){
// Convert vaySys DMS into decimal degrees
// https://github.com/vatSys/xml-tools/blob/master/DotAIPtoXML/DotAIPtoXML/Coordinate.cs#L119
var pos = {
latitude: [
parseInt(match.groups.latD),
parseInt(match.groups.latM),
parseFloat(match.groups.latS)
],
latRef: (match.groups.latRef == '+') ? "N" : "S",
longitude: [
parseInt(match.groups.lonD),
parseInt(match.groups.lonM),
parseFloat(match.groups.lonS)
],
lonRef: (match.groups.lonRef == '+') ? "E" : "W"
}
var [ latitude, longitude ] = dms2dec(pos.latitude,pos.latRef,pos.longitude,pos.lonRef);
// Turf is geoJSON so we continue the stupidity here with long THEN lat.
lineStringArr.push([longitude, latitude]);
});
polys.push(lineToPolygon(lineString(lineStringArr),{mutate: true, properties: {name: obj._attributes.Name}}));
})
return polys
};

// function firLineToPoly (firs) {
// // Line arrays into turf polys
// firs.forEach(function(fir){
// var poly = turf.lineToPolygon(turf.lineString(fir.line),{mutate: true});
// fir.poly = poly;
// });
// return firs;
// }
1 change: 1 addition & 0 deletions data/test-mrm.json

Large diffs are not rendered by default.

Loading

0 comments on commit 3024390

Please sign in to comment.