Import navigation data from Navigraph files
This commit is contained in:
197
app/Console/Commands/NavdataCommand.php
Normal file
197
app/Console/Commands/NavdataCommand.php
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
|
use App\Models\Navdata;
|
||||||
|
use App\Models\Enums\NavaidType;
|
||||||
|
|
||||||
|
|
||||||
|
class NavdataCommand extends Command
|
||||||
|
{
|
||||||
|
protected $signature = 'phpvms:navdata';
|
||||||
|
protected $description = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Streaming file read
|
||||||
|
* @param $filename
|
||||||
|
* @return \Generator
|
||||||
|
*/
|
||||||
|
protected function readFile($filename)
|
||||||
|
{
|
||||||
|
$fp = fopen($filename, 'rb');
|
||||||
|
|
||||||
|
while (($line = fgets($fp)) !== false) {
|
||||||
|
$line = rtrim($line, "\r\n");
|
||||||
|
if($line[0] === ';') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
yield $line;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose($fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read and parse in the navaid file
|
||||||
|
*/
|
||||||
|
public function read_wp_nav_aid()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* ....,....1....,....2....,....3....,....4....,....5....,....6..
|
||||||
|
* CORPUS CHRISTI CRP VORD 27.903764 -97.444881115.50H
|
||||||
|
* CORPUS CHRISTI ICRP ILSD 27.759597 -97.495508110.30T
|
||||||
|
* ROCKPORT RKP NDB 28.090569 -97.045544391.00N
|
||||||
|
* NNNNNNNNNNNNNNNNNNNNNNNNIIII TTTT dd.dddddd ddd.ddddddfff.ffC NNNN
|
||||||
|
* COL 1-24 Facility Name IIII
|
||||||
|
* COL 25-28 ID TTTT
|
||||||
|
* COL 30-33 Type ILS Insturment Landing System (Localizer)
|
||||||
|
* ILSD ILS/DME
|
||||||
|
* NDB Nondirectional Beacon
|
||||||
|
* NDBM NDB/Locator Middle Marker (LMM)
|
||||||
|
* NDBO NDB/Locator Outer Marker (LOM)
|
||||||
|
* MARI Unknown - seems to be same as MHW class NDB
|
||||||
|
* VOR VHF Omnidirectional Radio
|
||||||
|
* VORD VOR/DME (no separate code for VORTAC)
|
||||||
|
* dd.dddddd COL 34-43 Latitude (-Lat for South)
|
||||||
|
* ddd.dddddd COL 44-54 Longitude ( -Lon for West)
|
||||||
|
* fff.ff COL 55-60 Frequency (MHz for ILS/VOR KHz for NDB) See Note Below C
|
||||||
|
* Col 61 Class H High Altitude/Long Range
|
||||||
|
* N NDB
|
||||||
|
* T Terminal/Short RangeNote:
|
||||||
|
* If NDB frequency is above 999.99 KHz then the
|
||||||
|
* frequecy field still starts in col 55 and C is col 62,
|
||||||
|
* for example:....,....1....,....2....,....3....,....4....,....5....,....6..
|
||||||
|
* EREBUNI Y NDBM 40.104053 44.4505831180.00N
|
||||||
|
* Where the frequency above is 1180.00 KHz (1.180 MHz)
|
||||||
|
*/
|
||||||
|
|
||||||
|
$file_path = storage_path('/navdata/WPNAVAID.txt');
|
||||||
|
if (!file_exists($file_path)) {
|
||||||
|
$this->error('WPNAVAID.txt not found in storage/navdata');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->info('Importing navaids (WPNAVAID.txt) ...');
|
||||||
|
$generator = $this->readFile($file_path);
|
||||||
|
|
||||||
|
$imported = 0;
|
||||||
|
foreach($generator as $line) {
|
||||||
|
$navaid = [
|
||||||
|
'id' => trim(substr($line, 24, 4)), // ident column
|
||||||
|
'name' => trim(substr($line, 0, 24)),
|
||||||
|
'type' => trim(substr($line, 29, 4)),
|
||||||
|
'lat' => trim(substr($line, 33, 9)),
|
||||||
|
'lon' => trim(substr($line, 44, 10)),
|
||||||
|
'freq' => trim(substr($line, 54, 6)),
|
||||||
|
'class' => trim($line[60]),
|
||||||
|
];
|
||||||
|
|
||||||
|
switch($navaid['type'])
|
||||||
|
{
|
||||||
|
case 'ILS':
|
||||||
|
$navaid['type'] = NavaidType::LOC;
|
||||||
|
break;
|
||||||
|
case 'ILSDME':
|
||||||
|
$navaid['type'] = NavaidType::LOC_DME;
|
||||||
|
break;
|
||||||
|
case 'NDB':
|
||||||
|
case 'NDBM':
|
||||||
|
case 'NDBO':
|
||||||
|
case 'MARI':
|
||||||
|
$navaid['type'] = NavaidType::NDB;
|
||||||
|
break;
|
||||||
|
case 'VOR':
|
||||||
|
$navaid['type'] = NavaidType::VOR;
|
||||||
|
break;
|
||||||
|
case 'VORD':
|
||||||
|
$navaid['type'] = NavaidType::VOR_DME;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$navaid['type'] = NavaidType::UNKNOWN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Navdata::updateOrCreate(['id' => $navaid['id']], $navaid);
|
||||||
|
|
||||||
|
$imported++;
|
||||||
|
if($imported % 100 === 0) {
|
||||||
|
$this->info('Imported ' . $imported . ' entries...');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->info('Imported a total of ' . $imported . ' nav aids');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function read_wp_nav_fix()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* ....,....1....,....2....,...3....,....4....,....
|
||||||
|
* 5.8750W 8750W-87.000000 -50.000000
|
||||||
|
* GAREP GAREP 37.619689 128.073419
|
||||||
|
* CIHAD CIHAD 37.619719 -86.013228
|
||||||
|
* FOLAB FOLAB 37.619931 -87.359411
|
||||||
|
* KEKAD KEKAD 37.620000 67.518333
|
||||||
|
* NIKDE NIKDE 37.620567-122.563328
|
||||||
|
* ZUMAS ZUMAS 37.620575-113.167747
|
||||||
|
* NNNNN NNNNN dd.dddddd dd.dddddd
|
||||||
|
* Col 1-5 & 25-30 Fix Name
|
||||||
|
* dd.dddddd Col 32-40 Latitude degrees (-Lat for South, sign Col 31)
|
||||||
|
* ddd.dddddd Col 41-51 Longitude degrees (-Lon for West, decimal always Col 45)
|
||||||
|
* Note: The duplicate name fields may be the result how the FAA
|
||||||
|
* provides data, where there are many more fixes defined than provide
|
||||||
|
* in the airac data. For example, most terminal data is not included.
|
||||||
|
* This data includes airway crossing, radar service boundaries, etc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
$file_path = storage_path('/navdata/WPNAVFIX.txt');
|
||||||
|
if(!file_exists($file_path)) {
|
||||||
|
$this->error('WPNAVFIX.txt not found in storage/navdata');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->info('Importing navaids (WPNAVFIX.txt) ...');
|
||||||
|
$generator = $this->readFile($file_path);
|
||||||
|
|
||||||
|
$imported = 0;
|
||||||
|
foreach ($generator as $line) {
|
||||||
|
$navfix = [
|
||||||
|
'id' => trim(substr($line, 0, 4)), // ident column
|
||||||
|
'name' => trim(substr($line, 24, 6)),
|
||||||
|
'type' => NavaidType::FIX,
|
||||||
|
'lat' => trim(substr($line, 30, 10)),
|
||||||
|
'lon' => trim(substr($line, 40, 11)),
|
||||||
|
];
|
||||||
|
|
||||||
|
switch ($navfix['type']) {
|
||||||
|
default:
|
||||||
|
$navfix['type'] = NavaidType::UNKNOWN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Navdata::updateOrCreate(['id' => $navfix['id']], $navfix);
|
||||||
|
|
||||||
|
$imported++;
|
||||||
|
if ($imported % 100 === 0) {
|
||||||
|
$this->info('Imported ' . $imported . ' entries...');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->info('Imported a total of ' . $imported . ' nav fixes');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$this->info('Emptying the current navdata...');
|
||||||
|
Navdata::query()->truncate();
|
||||||
|
|
||||||
|
$this->info('Looking for nav files...');
|
||||||
|
$this->read_wp_nav_aid();
|
||||||
|
$this->read_wp_nav_fix();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App\Console\Commands;
|
|
||||||
|
|
||||||
use Illuminate\Console\Command;
|
|
||||||
|
|
||||||
|
|
||||||
class Test extends Command
|
|
||||||
{
|
|
||||||
protected $signature = 'phpvms:test';
|
|
||||||
protected $description = '';
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
parent::__construct();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function handle()
|
|
||||||
{
|
|
||||||
print resource_path();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -17,21 +17,16 @@ class CreateNavdataTables extends Migration
|
|||||||
* See for defs, modify/update based on this
|
* See for defs, modify/update based on this
|
||||||
* https://github.com/skiselkov/openfmc/blob/master/airac.h
|
* https://github.com/skiselkov/openfmc/blob/master/airac.h
|
||||||
*/
|
*/
|
||||||
Schema::create('navpoints', function (Blueprint $table) {
|
Schema::create('navdata', function (Blueprint $table) {
|
||||||
$table->bigIncrements('id');
|
$table->string('id', 4);
|
||||||
$table->string('name', 10);
|
$table->string('name', 24);
|
||||||
$table->string('title', 25);
|
$table->unsignedInteger('type');
|
||||||
$table->string('airway', 7)->nullable();
|
|
||||||
$table->string('airway_type', 1)->nullable();
|
|
||||||
$table->bigInteger('seq')->nullable();
|
|
||||||
$table->string('loc', 4)->nullable();
|
|
||||||
$table->float('lat', 7, 4)->default(0.0);
|
$table->float('lat', 7, 4)->default(0.0);
|
||||||
$table->float('lon', 7, 4)->default(0.0);
|
$table->float('lon', 7, 4)->default(0.0);
|
||||||
$table->string('freq', 7);
|
$table->string('freq', 7)->nullable();
|
||||||
$table->integer('type');
|
|
||||||
|
|
||||||
|
$table->index('id');
|
||||||
$table->index('name');
|
$table->index('name');
|
||||||
$table->index('airway');
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,6 +37,6 @@ class CreateNavdataTables extends Migration
|
|||||||
*/
|
*/
|
||||||
public function down()
|
public function down()
|
||||||
{
|
{
|
||||||
Schema::dropIfExists('navpoints');
|
Schema::dropIfExists('navdata');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ class Airport extends Model
|
|||||||
];
|
];
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
'id' => 'string',
|
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -5,16 +5,19 @@
|
|||||||
|
|
||||||
namespace App\Models\Enums;
|
namespace App\Models\Enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Days
|
||||||
|
* @package App\Models\Enums
|
||||||
|
*/
|
||||||
class Days extends EnumBase {
|
class Days extends EnumBase {
|
||||||
|
|
||||||
const MONDAY = 1;
|
const MONDAY = 1 << 0;
|
||||||
const TUESDAY = 2;
|
const TUESDAY = 1 << 1;
|
||||||
const WEDNESDAY = 4;
|
const WEDNESDAY = 1 << 2;
|
||||||
const THURSDAY = 8;
|
const THURSDAY = 1 << 3;
|
||||||
const FRIDAY = 16;
|
const FRIDAY = 1 << 4;
|
||||||
const SATURDAY = 32;
|
const SATURDAY = 1 << 5;
|
||||||
const SUNDAY = 64;
|
const SUNDAY = 1 << 6;
|
||||||
|
|
||||||
protected static $labels = [
|
protected static $labels = [
|
||||||
Days::MONDAY => 'system.days.mon',
|
Days::MONDAY => 'system.days.mon',
|
||||||
|
|||||||
45
app/Models/Enums/NavaidType.php
Normal file
45
app/Models/Enums/NavaidType.php
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* The types of navaids
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Models\Enums;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class NavaidType
|
||||||
|
* Types based on/compatible with OpenFMC
|
||||||
|
* https://github.com/skiselkov/openfmc/blob/master/airac.h
|
||||||
|
* @package App\Models\Enums
|
||||||
|
*/
|
||||||
|
class NavaidType extends EnumBase
|
||||||
|
{
|
||||||
|
const VOR = 1 << 0;
|
||||||
|
const VOR_DME = 1 << 1;
|
||||||
|
const LOC = 1 << 4;
|
||||||
|
const LOC_DME = 1 << 5;
|
||||||
|
const NDB = 1 << 6;
|
||||||
|
const TACAN = 1 << 7;
|
||||||
|
const UNKNOWN = 1 << 8;
|
||||||
|
const INNER_MARKER = 1 << 9;
|
||||||
|
const OUTER_MARKER = 1 << 10;
|
||||||
|
const FIX = 1 << 11;
|
||||||
|
const ANY_VOR = NavaidType::VOR | NavaidType::VOR_DME;
|
||||||
|
const ANY_LOC = NavaidType::LOC | NavaidType::LOC_DME;
|
||||||
|
const ANY = (NavaidType::UNKNOWN << 1) - 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Names and titles
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
public static $labels = [
|
||||||
|
NavaidType::VOR => 'VOR',
|
||||||
|
NavaidType::VOR_DME => 'VOR DME',
|
||||||
|
NavaidType::LOC => 'Localizer',
|
||||||
|
NavaidType::LOC_DME => 'Localizer DME',
|
||||||
|
NavaidType::NDB => 'Non-directional Beacon',
|
||||||
|
NavaidType::TACAN => 'TACAN',
|
||||||
|
NavaidType::UNKNOWN => 'Unknown',
|
||||||
|
NavaidType::ANY_VOR => 'VOR',
|
||||||
|
NavaidType::ANY_LOC => 'Localizer',
|
||||||
|
];
|
||||||
|
}
|
||||||
26
app/Models/Navdata.php
Normal file
26
app/Models/Navdata.php
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Navdata extends Model
|
||||||
|
{
|
||||||
|
public $table = 'navdata';
|
||||||
|
public $timestamps = false;
|
||||||
|
public $incrementing = false;
|
||||||
|
|
||||||
|
public $fillable = [
|
||||||
|
'id',
|
||||||
|
'name',
|
||||||
|
'type',
|
||||||
|
'lat',
|
||||||
|
'lon',
|
||||||
|
'freq',
|
||||||
|
];
|
||||||
|
|
||||||
|
public $casts = [
|
||||||
|
'id' => 'string',
|
||||||
|
'type' => 'integer',
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace App;
|
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
|
|
||||||
class Navpoint extends Model
|
|
||||||
{
|
|
||||||
public $table = 'navpoints';
|
|
||||||
}
|
|
||||||
2
storage/navdata/.gitignore
vendored
Executable file
2
storage/navdata/.gitignore
vendored
Executable file
@@ -0,0 +1,2 @@
|
|||||||
|
*
|
||||||
|
!.gitignore
|
||||||
Reference in New Issue
Block a user