123 lines
4.6 KiB
JavaScript
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 && cb(null, obs.slice(0));
|
|
} catch (err) {
|
|
// debug(err.message, "\n", err.stack);
|
|
failed = true;
|
|
return cb && cb(err.message);
|
|
}
|
|
// fs.appendFileSync(testRes, JSON.stringify(obs, null, 2));
|
|
});
|
|
}
|
|
|
|
module.exports = {
|
|
readObstacles
|
|
} |