metar-plot
Version:
METAR parsing and ploting library
281 lines (280 loc) • 8.77 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseAltimeter = exports.parseWind = exports.parseClouds = exports.parseVisibility = exports.parseWeather = exports.parseTempNA = exports.parseTempInternation = exports.parseAuto = exports.parseCavok = exports.parseDate = exports.parseStation = exports.parseMetar = exports.METAR = void 0;
var Weather_1 = require("./parts/Weather");
var Cloud_1 = require("./parts/Cloud");
var Wind_1 = require("./parts/Wind");
//Meassage types
var TYPES = ["METAR", "SPECI"];
//Metar Object
var METAR = /** @class */ (function () {
/**
* Extracted Metar data in a human readable format.
* @param metarString raw metar string if provided station and time will be ignored and replaced with the content in the raw METAR
* @param station staion name for instance creation
* @param time time for instance creation
*/
function METAR(metarString, station, time) {
//Wind speed, direction and unit
this.wind = new Wind_1.Wind();
//List of weather conditions reported
this.weather = new Array();
//List of Cloud observations
this.clouds = new Array();
this.station = station !== null && station !== void 0 ? station : "----";
this.time = time !== null && time !== void 0 ? time : new Date();
if (metarString != null) {
parseMetar(metarString, this);
}
}
return METAR;
}());
exports.METAR = METAR;
/**
* Parses a raw metar and binds or creates a METAR object
* @param metarString Raw METAR string
* @param ref Reference to a METAR object. This objects contents will be shallow replaced with the Raw metars values.
* Meaning values will be updated or added but not removed.
* @returns
*/
function parseMetar(metarString, ref) {
var station = parseStation(metarString);
var time = parseDate(metarString);
if (ref != null) {
ref.station = station;
ref.time = time;
}
else {
ref = new METAR(undefined, station, time);
}
//Parse Auto
ref.auto = parseAuto(metarString);
//Parse Wind
ref.wind = parseWind(metarString);
//Parse CAVOK
ref.cavok = parseCavok(metarString);
//Parse Visablility
ref.visibility = parseVisibility(metarString);
//Parse Runway VIS
//TODO
//Parse Weather
ref.weather = parseWeather(metarString);
//Parse Clouds
ref.clouds = parseClouds(metarString);
//Parse Temp Point Internations
var temps_int = parseTempInternation(metarString);
if (temps_int != null) {
ref.temperature = temps_int[0];
ref.dewpoint = temps_int[1];
}
//Parse Temp North american Will overwirte international since it is more precise
var temps_ne = parseTempNA(metarString);
if (temps_ne != null) {
ref.temperature = temps_ne[0];
ref.dewpoint = temps_ne[1];
}
//Parse Altimeter
ref.altimeter = parseAltimeter(metarString);
return ref;
}
exports.parseMetar = parseMetar;
/**
* Parses the station name form the metar
* @param metar raw metar
* @returns
*/
function parseStation(metar) {
var re = /^(METAR\s)?([A-Z]{1,4})\s/g;
var matches = re.exec(metar);
if (matches != null) {
return matches[2];
}
else {
throw new Error("Station could not be found invalid metar");
}
}
exports.parseStation = parseStation;
/**
* Parse Date object from metar.
* NOTE: Raw metar data does not contain month or year data. So this function assumes this metar was created in the current month and current year
* @param metar raw metar
* @returns
*/
function parseDate(metar) {
var re = /([\d]{2})([\d]{2})([\d]{2})Z/g;
var matches = re.exec(metar);
if (matches != null) {
var d = new Date();
d.setUTCDate(parseInt(matches[1]));
d.setUTCHours(parseInt(matches[2]));
d.setUTCMinutes(parseInt(matches[3]));
d.setUTCSeconds(0);
d.setUTCMilliseconds(0);
return d;
}
else {
throw new Error("Failed to parse Date");
}
}
exports.parseDate = parseDate;
/**
* Parses for CAVOK (Ceiling and visabiliy OK)
* @param metar raw metar
* @returns
*/
function parseCavok(metar) {
var re = /\sCAVOK\s/g;
return metar.match(re) != null ? true : false;
}
exports.parseCavok = parseCavok;
/**
* Parses for Automation
* @param metar raw metar
* @returns
*/
function parseAuto(metar) {
var re = /\s(AUTO)?(AO1)?(AO2)?\s/g;
return metar.match(re) != null ? true : false;
}
exports.parseAuto = parseAuto;
/**
* Parse international temp dewp point format.
* @param metar raw metar
* @returns
*/
function parseTempInternation(metar) {
var re = /\s(M)?(\d{2})\/(M)?(\d{2})\s/g;
var matches = re.exec(metar);
if (matches != null) {
var temp = parseInt(matches[2]) * (matches[1] == null ? 1 : -1);
var dew_point = parseInt(matches[4]) * (matches[3] == null ? 1 : -1);
return [temp, dew_point];
}
}
exports.parseTempInternation = parseTempInternation;
/**
* Parse North American temp dew point format
* @param metar raw metar
* @returns
*/
function parseTempNA(metar) {
var re = /(T)(\d{1})(\d{2})(\d{1})(\d{1})(\d{2})(\d{1})/g;
var matches = re.exec(metar);
if (matches != null) {
var temp = parseFloat(matches[3] + "." + matches[4]) * (matches[2] === "0" ? 1 : -1);
var dew_point = parseFloat(matches[6] + "." + matches[7]) * (matches[5] === "0" ? 1 : -1);
return [temp, dew_point];
}
}
exports.parseTempNA = parseTempNA;
/**
* Parse Weather items
* @param metar raw metar
* @returns
*/
function parseWeather(metar) {
var obs_keys = Object.keys(Weather_1.WEATHER).join('|').replace(/\+/g, "\\+");
var re = new RegExp("\\s?(" + obs_keys + ")\\s", 'g');
var matches = metar.match(re);
if (matches != null) {
return matches.map(function (match) {
console.log(match);
var key = match.trim();
return {
abbreviation: key,
meaning: Weather_1.WEATHER[key].text
};
});
}
else {
return new Array();
}
}
exports.parseWeather = parseWeather;
/**
* Parse visability
* @param metar raw metar
* @returns
*/
function parseVisibility(metar) {
var re = /\s([0-9]{1,2})?\s?([0-9]{1}\/[0-9]{1})?(SM)\s|\s([0-9]{1,4})\s/g;
if (metar.match(re)) {
var vis_parts = re.exec(metar);
if (vis_parts != null) {
var meters = vis_parts[4];
var miles = vis_parts[1];
var frac_miles = vis_parts[2];
//Metric case ex: 1000, 9999
if (meters != null) {
return parseInt(meters);
}
//whole miles case ex: 1SM 10SM
else if (frac_miles != null) {
var total = 0.0;
if (miles != null) {
total += parseFloat(miles);
}
total += parseFloat(eval(frac_miles));
return total * 1609.34;
}
//factional miles case "1 1/2SM" "1/4SM"
else {
return parseInt(miles) * 1609.34;
}
}
}
return undefined;
}
exports.parseVisibility = parseVisibility;
/**
* Parse cloud coverages
* @param metarString raw metar
* @returns
*/
function parseClouds(metarString) {
var _a;
var re = /(NCD|SKC|CLR|NSC|FEW|SCT|BKN|OVC|VV)(\d{3})/g;
var clouds = new Array();
var matches;
while ((matches = re.exec(metarString)) != null) {
var cloud = {
abbreviation: matches[1],
meaning: (_a = Cloud_1.CLOUDS[matches[1]]) === null || _a === void 0 ? void 0 : _a.text,
altitude: parseInt(matches[2]) * 100
};
clouds.push(cloud);
}
return clouds;
}
exports.parseClouds = parseClouds;
/**
* Parse wind data
* @param metar raw metar
* @returns
*/
function parseWind(metar) {
var wind = new Wind_1.Wind();
var re = /\s(\d{3})(\d{2})(G)?(\d{2})?(KT|MPS)\s/g;
var matches = re.exec(metar);
if (matches != null) {
wind.direction = parseInt(matches[1]);
wind.speed = parseInt(matches[2]);
wind.unit = matches[5];
}
return wind;
}
exports.parseWind = parseWind;
function parseAltimeter(metar) {
var re = /(A|Q)(\d{2})(\d{2})/g;
var matches = re.exec(metar);
if (matches != null) {
if (matches[1] === "Q") {
var pressure = parseFloat(matches[2] + matches[3]);
return parseFloat((pressure * 0.029529).toFixed(2));
}
else {
return parseFloat(matches[2] + "." + matches[3]);
}
}
}
exports.parseAltimeter = parseAltimeter;