agmission/Development/server/helpers/file_obstacle.js

123 lines
4.6 KiB
JavaScript

'use strict';
const fs = require('fs'),
{ Errors } = require('./constants'),
{ AppInputError, AppParamError } = require('./app_error');
function splitDMS(dms) {
if (!dms || dms.length !== 13) AppInputError.throw(Errors.INVALID_DMS);
const fields = dms.trim().split(new RegExp('\\s+')).map(it => it.trim());
return {
deg: fields[0],
min: fields[1],
sec: fields[2].slice(0, fields[2].length - 1),
hem: fields[2].slice(-1)
};
}
function trimProps(objectToTrim) {
for (const key in objectToTrim) {
if (objectToTrim[key].constructor && objectToTrim[key].constructor == Object)
trimProps(objectToTrim[key]);
else if (objectToTrim[key].trim)
objectToTrim[key] = objectToTrim[key].trim();
}
}
function readObstacles(filePath, cb) {
//# .Dat files have fixed-width columns; the data is always in the same position within a row
fs.readFile(filePath, 'utf8', function (err, data) {
// fs.truncateSync(testRes);
if (err) throw err;
let failed = false;
let lines = data.toString().split('\n');
let obs = [];
let startLat = -1, startLatDeg = -1, startLonDeg = -1, startAGL = -1, startHT = -1, startType = -1, startAct = -1; // startASML = -1;
try {
for (let i = 0; i < lines.length; i++) {
if (failed)
break;
let line = lines[i];
let latDms, lonDms, ob = {};
// Skip the first 4 rows (they include poorly formatted header information)
if (i === 1) {
startLat = line.toUpperCase().indexOf("LATITUDE");
startAGL = line.toUpperCase().indexOf("AGL");
// startASML = line.toUpperCase().indexOf("AMSL");
startAct = line.toUpperCase().indexOf("ACTION");
} else if (i === 2) {
startLatDeg = line.toUpperCase().indexOf("DEG");
startLonDeg = line.toUpperCase().indexOf("DEG", startLatDeg + 1);
startHT = line.toUpperCase().indexOf("HT");
startType = line.toUpperCase().indexOf("TYPE");
}
if (i < 4 || line.trim().length === 0) continue;
// Verify file format, then to know where to get important fields
if (!(startLat >= startLatDeg && startAGL === startHT) || (!startLat || !startLatDeg || !startLonDeg || !startAGL || !startHT || !startType || !startAct))
AppParamError.throw(Errors.INVALID_OBSTACLE_FILE_FORMAT);
ob.ors = line.slice(0, 9); // The first 9 characters of the row represent the Obstacle number
ob.v = line.slice(10, 11);
latDms = splitDMS(line.substring(startLatDeg, startLatDeg + 13));
ob.latDeg = latDms.deg;
ob.latMin = latDms.min;
ob.latSec = latDms.sec;
ob.latHem = latDms.hem;
lonDms = splitDMS(line.substring(startLonDeg, startLonDeg + 13));
ob.lonDeg = lonDms.deg;
ob.lonMin = lonDms.min;
ob.lonSec = lonDms.sec;
ob.lonHem = lonDms.hem;
ob.type = line.substring(startType, startType + 17);
ob.agl = line.substring(startAGL, startAGL + 5);
ob.amsl = line.substring(startAGL + 6, (startAGL + 6) + 5);
ob.action = line.substring(startAct, startAct + 3);
//Convert DMS to Decimal Degrees (N vs. S determines if the value is positive or negative)
if (ob.latHem == "N")
ob.latitude = (parseFloat(ob.latDeg) + (parseFloat(ob.latMin) / 60) + (parseFloat(ob.latSec) / 3600));
else
ob.latitude = -1 * (parseFloat(ob.latDeg) + (parseFloat(ob.latMin) / 60) + (parseFloat(ob.latSec) / 3600));
// Convert DMS to Decimal Degrees (E vs. W determines if the value is positive or negative)
if (ob.lonHem == "E")
ob.longitude = (parseFloat(ob.lonDeg) + (parseFloat(ob.lonMin) / 60) + (parseFloat(ob.lonSec) / 3600));
else
ob.longitude = -1 * (parseFloat(ob.lonDeg) + (parseFloat(ob.lonMin) / 60) + (parseFloat(ob.lonSec) / 3600));
trimProps(ob);
ob.latitude = ob.latitude.toFixed(7);
ob.longitude = ob.longitude.toFixed(7);
const geoObstacle = {
properties: {
name: ob.ors,
type: ob.type,
agl: parseFloat(ob.agl), // Above ground level in feet
amsl: parseFloat(ob.amsl), // Average mean sea level in feet
},
geometry: {
type: 'Point',
coordinates: [ob.longitude, ob.latitude]
}
};
obs.push(geoObstacle);
}
return cb(null, obs.slice(0));
} catch (err) {
// debug(err.message, "\n", err.stack);
failed = true;
return cb(err.message);
}
// fs.appendFileSync(testRes, JSON.stringify(obs, null, 2));
});
}
module.exports = {
readObstacles
}