Merge branch 'master' of https://github.com/Portree-Kid/flightgear-airports
@ -125,6 +125,18 @@ let rendererConfig = {
|
||||
new HtmlWebpackPlugin({
|
||||
filename: 'index.html',
|
||||
template: path.resolve(__dirname, '../src/index.ejs'),
|
||||
templateParameters(compilation, assets, options) {
|
||||
return {
|
||||
compilation: compilation,
|
||||
webpack: compilation.getStats().toJson(),
|
||||
webpackConfig: compilation.options,
|
||||
htmlWebpackPlugin: {
|
||||
files: assets,
|
||||
options: options
|
||||
},
|
||||
process,
|
||||
};
|
||||
},
|
||||
minify: {
|
||||
collapseWhitespace: true,
|
||||
removeAttributeQuotes: true,
|
||||
|
@ -97,7 +97,18 @@ let webConfig = {
|
||||
new HtmlWebpackPlugin({
|
||||
filename: 'index.html',
|
||||
template: path.resolve(__dirname, '../src/index.ejs'),
|
||||
minify: {
|
||||
templateParameters(compilation, assets, options) {
|
||||
return {
|
||||
compilation: compilation,
|
||||
webpack: compilation.getStats().toJson(),
|
||||
webpackConfig: compilation.options,
|
||||
htmlWebpackPlugin: {
|
||||
files: assets,
|
||||
options: options
|
||||
},
|
||||
process,
|
||||
};
|
||||
}, minify: {
|
||||
collapseWhitespace: true,
|
||||
removeAttributeQuotes: true,
|
||||
removeComments: true
|
||||
|
10
.travis.yml
@ -54,13 +54,9 @@ jobs:
|
||||
- stage: Deploy
|
||||
install:
|
||||
- pwd
|
||||
- find -name *osx-binaries*
|
||||
- tar -xzf ${CASHER_DIR}/osx-binaries-fetch.tgz
|
||||
- find -name flightgear-airports*
|
||||
# - find -name windows-binaries
|
||||
# - find -name osx-binaries
|
||||
# - find -name linux-binaries
|
||||
# - ls -l | grep "^d"
|
||||
# - ls -l "C:"
|
||||
- cp ./Users/travis/build/Portree-Kid/flightgear-airports/osx-binaries/*.dmg build/
|
||||
- cp ./C:/Users/travis/build/Portree-Kid/flightgear-airports/windows-binaries/*.exe build/
|
||||
- cp ./linux-binaries/*.AppImage build/
|
||||
@ -75,12 +71,12 @@ jobs:
|
||||
skip_cleanup: true
|
||||
overwrite: true
|
||||
draft: true
|
||||
name: '0.0.20'
|
||||
name: '0.0.33'
|
||||
provider: releases
|
||||
api_key:
|
||||
secure: ECdYNrvCA7+qSnbktJPstwXrluqKZTWDD7K3X/dyoxRO4+ZL/K19r60LXF9g90troWgdZSN3tFxNktkGeIOuTo83Q3B6qjXnKtdW3JhefvztlHQadUIf2p8Ype2spicNAl2629Mwr7ksqJuV0rR0T4zYT1SIFWkuwGYhR+tmS94m6QmnocGPzjset3y23lJ/rczJiiWIkaLrOfeCj5VjWtSaVQEWWlolmuji0qGHvOT/mq1X+jfI9RIlJTpV2ZNYaa3fr+M+8tIreaHDjbKrYAuIA/JzpDxmXtWGnxkxLbDxonp6OhzcJ7z9hpdkg38HKxNTL9Bdv0LpZKCTo2C+0G6yR3kQqXhoIzbfFeTX0G6d7I8oYxL1JGCsrnmU3OyhCLMRcOWL294hhDIUMWveBRNVRGVaOzeXRphO4nnMhGNd4KxwxvRPBMNeguhL/ZBwjcw6puYL3m86UT5iwjMuYvcbEVEDXwHSyi96zjHzolkMUn8hPOIUfgmCOIsqIMMpbCXJqdyha0pu9x1qKrXbF+hQ5JXPvTN8/ZG4dLXhvsZJdD50vZu+GW33vU96c+mwIkCz0CS5t+vuHfdT/OOuBN7HV46q/9WrZMSlz5ZD+A2dY57QVL+CucjMZlVoU/iJhfRpV5XPYvLlYI+tpH0yX5JQqtcRdZJzKsYknwZNj5o=
|
||||
file_glob: true
|
||||
file: build/*
|
||||
on:
|
||||
branches: '0.0.20'
|
||||
branches: '0.0.33'
|
||||
repo: Portree-Kid/flightgear-airports
|
||||
|
8
build/installer.nsh
Normal file
@ -0,0 +1,8 @@
|
||||
!macro preInit
|
||||
SetRegView 64
|
||||
WriteRegExpandStr HKLM "${INSTALL_REGISTRY_KEY}" InstallLocation "$PROGRAMFILES64\flightgear-airports"
|
||||
WriteRegExpandStr HKCU "${INSTALL_REGISTRY_KEY}" InstallLocation "$PROGRAMFILES64\flightgear-airports"
|
||||
SetRegView 32
|
||||
WriteRegExpandStr HKLM "${INSTALL_REGISTRY_KEY}" InstallLocation "$PROGRAMFILES32\flightgear-airports"
|
||||
WriteRegExpandStr HKCU "${INSTALL_REGISTRY_KEY}" InstallLocation "$PROGRAMFILES32\flightgear-airports"
|
||||
!macroend
|
2044
package-lock.json
generated
30
package.json
@ -1,15 +1,14 @@
|
||||
{
|
||||
"name": "flightgear-airports",
|
||||
"version": "0.0.20",
|
||||
"version": "0.0.34",
|
||||
"author": "portree_kid <keith.paterson@gmx.de>",
|
||||
"description": "An software to design Flightgear groundnets",
|
||||
"license": "GPL v3",
|
||||
"license": "GPL-3.0",
|
||||
"main": "./dist/electron/main.js",
|
||||
"scripts": {
|
||||
"build": "node .electron-vue/build.js && electron-builder",
|
||||
"build:dir": "node .electron-vue/build.js && electron-builder --dir",
|
||||
"build:clean": "cross-env BUILD_TARGET=clean node .electron-vue/build.js",
|
||||
"build:web": "cross-env BUILD_TARGET=web node .electron-vue/build.js",
|
||||
"dev": "SET NODE_ENV=development&& node .electron-vue/dev-runner.js",
|
||||
"e2e": "npm run pack && mocha test/e2e",
|
||||
"lint": "eslint --ext .js,.vue -f ./node_modules/eslint-friendly-formatter src test",
|
||||
@ -18,6 +17,7 @@
|
||||
"pack:main": "cross-env NODE_ENV=production webpack --progress --colors --config .electron-vue/webpack.main.config.js",
|
||||
"pack:renderer": "cross-env NODE_ENV=production webpack --progress --colors --config .electron-vue/webpack.renderer.config.js",
|
||||
"test": "npm run unit && npm run e2e",
|
||||
"mocha": "SET NODE_ENV=mocha&& mocha test/mocha/**/*.js",
|
||||
"unit": "karma start test/unit/karma.conf.js",
|
||||
"postinstall": ""
|
||||
},
|
||||
@ -70,30 +70,35 @@
|
||||
]
|
||||
},
|
||||
"mac": {
|
||||
"icon": "build/icons/icon.icns"
|
||||
"icon": "build/icons/icon.icns",
|
||||
"publish": []
|
||||
},
|
||||
"win": {
|
||||
"icon": "build/icons/icon.ico"
|
||||
"icon": "build/icons/icon.ico",
|
||||
"publish": []
|
||||
},
|
||||
"nsis": {
|
||||
"oneClick": false,
|
||||
"perMachine": true,
|
||||
"allowToChangeInstallationDirectory": true
|
||||
},
|
||||
"linux": {
|
||||
"icon": "build/icons",
|
||||
"target": "AppImage"
|
||||
"target": "AppImage",
|
||||
"publish": []
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@turf/intersect": "^6.1.3",
|
||||
"@turf/turf": "^5.1.6",
|
||||
"axios": "^0.18.1",
|
||||
"axios": "^0.21.1",
|
||||
"coordinate-parser": "^1.0.3",
|
||||
"dijkstrajs": "^1.0.1",
|
||||
"electron-debug": "^3.0.1",
|
||||
"element-ui": "^2.13.2",
|
||||
"element-ui": "^2.15.1",
|
||||
"file-url": "^3.0.0",
|
||||
"fs": "0.0.1-security",
|
||||
"fs-extra": "^9.0.1",
|
||||
"geo-coordinates-parser": "^1.2.4",
|
||||
"geodesy": "^2.2.0",
|
||||
"idb": "^4.0.5",
|
||||
@ -101,11 +106,14 @@
|
||||
"leaflet": "^1.5.1",
|
||||
"leaflet-editable": "^1.2.0",
|
||||
"leaflet-polylinedecorator": "^1.6.0",
|
||||
"leaflet-search": "^2.9.9",
|
||||
"leaflet-sidebar-v2": "^3.2.1",
|
||||
"leaflet-textpath": "^1.2.0",
|
||||
"leaflet.pattern": "^0.1.0",
|
||||
"lokijs": "^1.5.8",
|
||||
"mathjs": "^6.2.5",
|
||||
"path": "^0.12.7",
|
||||
"tiny-worker": "^2.3.0",
|
||||
"vue": "^2.5.16",
|
||||
"vue-electron": "^1.0.6",
|
||||
"vue-idb": "^0.2.0",
|
||||
@ -134,7 +142,7 @@
|
||||
"babel-register": "^6.26.0",
|
||||
"babili-webpack-plugin": "^0.1.2",
|
||||
"cfonts": "^2.1.2",
|
||||
"chai": "^4.1.2",
|
||||
"chai": "^4.2.0",
|
||||
"chalk": "^2.4.1",
|
||||
"copy-webpack-plugin": "^4.5.1",
|
||||
"cross-env": "^5.1.6",
|
||||
@ -142,7 +150,7 @@
|
||||
"del": "^3.0.0",
|
||||
"devtron": "^1.4.0",
|
||||
"electron": "^7.2.4",
|
||||
"electron-builder": "^21.2.0",
|
||||
"electron-builder": "^22.10.4",
|
||||
"electron-devtools-installer": "^2.2.4",
|
||||
"eslint": "^4.19.1",
|
||||
"eslint-config-standard": "^11.0.0",
|
||||
@ -168,7 +176,7 @@
|
||||
"mocha": "^5.2.0",
|
||||
"multispinner": "^0.2.1",
|
||||
"node-loader": "^0.6.0",
|
||||
"node-sass": "^4.9.2",
|
||||
"node-sass": "^4.14.1",
|
||||
"require-dir": "^1.0.0",
|
||||
"sass-loader": "^7.0.3",
|
||||
"spectron": "^3.8.0",
|
||||
|
@ -6,7 +6,7 @@
|
||||
<% if (htmlWebpackPlugin.options.nodeModules) { %>
|
||||
<!-- Add `node_modules/` to global paths so `require` works properly in development -->
|
||||
<script>
|
||||
require('module').globalPaths.push('<%= htmlWebpackPlugin.options.nodeModules.replace(/\\/g, '\\\\') %>')
|
||||
require('module').globalPaths.push('<%= htmlWebpackPlugin.options.nodeModules.replace(/\\/g, "\\\\") %>')
|
||||
</script>
|
||||
<% } %>
|
||||
</head>
|
||||
|
@ -1,6 +1,6 @@
|
||||
'use strict'
|
||||
|
||||
import { app, BrowserWindow } from 'electron'
|
||||
import { app, BrowserWindow, Menu } from 'electron'
|
||||
|
||||
const { ipcMain } = require('electron')
|
||||
ipcMain.on('OpenDebugger', (event, arg) => {
|
||||
@ -20,6 +20,7 @@ const winURL = process.env.NODE_ENV === 'development'
|
||||
: `file://${__dirname}/index.html`
|
||||
|
||||
function createWindow () {
|
||||
Menu.setApplicationMenu(null)
|
||||
/**
|
||||
* Initial window options
|
||||
*/
|
||||
@ -30,6 +31,7 @@ function createWindow () {
|
||||
nodeIntegration: true,
|
||||
nodeIntegrationInWorker: true
|
||||
},
|
||||
closable: true,
|
||||
width: 1000
|
||||
})
|
||||
mainWindow.loadURL(winURL)
|
||||
|
67
src/renderer/check/mapper.js
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
Copyright 2020 Keith Paterson
|
||||
|
||||
This file is part of FG Airports.
|
||||
|
||||
FG Airports is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
FG Airports is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with FG Airports. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
/* eslint-disable */
|
||||
var L = require('leaflet');
|
||||
|
||||
export function checkMapper(o) {
|
||||
if (o instanceof L.ParkingSpot) {
|
||||
/*
|
||||
if( o.box === undefined ) {
|
||||
debugger;
|
||||
} */
|
||||
return {
|
||||
'index': Number(o['id']),
|
||||
'_leaflet_id': o._leaflet_id,
|
||||
'type': 'parking',
|
||||
'parkingType': o.options.attributes.type,
|
||||
'name': o.options.attributes.name,
|
||||
'radius': String(o.options.attributes.radius),
|
||||
'lat': o._latlng.lat,
|
||||
'lng': o._latlng.lng,
|
||||
'box': o.box !== undefined ? o.box.getLatLngs() : null
|
||||
};
|
||||
} else if (o instanceof L.RunwayNode) {
|
||||
console.log(o)
|
||||
return { 'index': Number(o['glueindex']), '_leaflet_id': o._leaflet_id, 'lat': o._latlng.lat, 'lng': o._latlng.lng, 'type': 'runway' };
|
||||
} else if (o instanceof L.HoldNode) {
|
||||
console.log(o)
|
||||
return { 'index': Number(o['glueindex']), '_leaflet_id': o._leaflet_id, 'type': o.holdPointType };
|
||||
} else if (o instanceof L.RunwayPolygon) {
|
||||
return {
|
||||
'type': 'runway_poly',
|
||||
'pavement': o.getLatLngs()
|
||||
}
|
||||
} else if (o instanceof L.TakeoffPolygon) {
|
||||
return {
|
||||
'type': 'takeoffpad_poly',
|
||||
'pavement': o.getLatLngs()
|
||||
}
|
||||
} else if (o instanceof L.Polyline) {
|
||||
console.log(o)
|
||||
var latLngs = o.getLatLngs().map(l => ({ lat: l.lat, lng: l.lng, index: l.glueindex }));
|
||||
if (o.options.attributes===undefined) {
|
||||
return null;
|
||||
}
|
||||
return { 'start': Number(o['begin']), 'end': Number(o['end']), '_leaflet_id': o._leaflet_id, 'type': 'poly', 'direction': o.options.attributes.direction, 'isPushBackRoute': o.options.attributes.isPushBackRoute, latLngs: latLngs };
|
||||
}
|
||||
else {
|
||||
console.log('Unknown Type ')
|
||||
console.log(typeof o)
|
||||
}
|
||||
}
|
||||
|
||||
export function groMapper(o) {
|
||||
if (o instanceof L.Polygon) {
|
||||
|
||||
}
|
||||
}
|
@ -10,7 +10,9 @@
|
||||
props: [],
|
||||
mounted () {
|
||||
this.aiLayer = aiLayer({url: this.$store.state.Settings.settings.phi_url})
|
||||
if(this.aiLayer) {
|
||||
this.aiLayer.addTo(this.$parent.mapObject)
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
|
100
src/renderer/components/AirlineItem.vue
Normal file
@ -0,0 +1,100 @@
|
||||
<!--
|
||||
Copyright 2021 Keith Paterson
|
||||
|
||||
This file is part of FG Airports.
|
||||
|
||||
FG Airports is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
FG Airports is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with FG Airports. If not, see http://www.gnu.org/licenses/.
|
||||
-->
|
||||
<template>
|
||||
<div :key="airline.label + '-div'">
|
||||
<div v-for="item in traffic" v-bind:key="airline.label + '-' + item.id + '-innerdiv'">
|
||||
<div :key="item.id + '-dep'" v-if="direction == 0">{{ item.departure.time }} {{ item.callsign }} {{ item.departure.port }} --> {{ item.arrival.port }} {{ item['required-aircraft'] }} {{ item.flighttype }}</div>
|
||||
<div :key="item.id + '-arr'" v-if="direction == 1">{{ item.arrival.time }} {{ item.callsign }} {{ item.departure.port }} --> {{ item.arrival.port }} {{ item['required-aircraft'] }} {{ item.flighttype }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="js">
|
||||
import {readTrafficXML} from '../loaders/traffic_loader'
|
||||
import ParkingItem from './ParkingItem'
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
export default {
|
||||
name: 'airline-traffic',
|
||||
components: {ParkingItem},
|
||||
props: {airline: Object},
|
||||
data () {
|
||||
return {}
|
||||
},
|
||||
methods: {
|
||||
traverseDir (dir, airline) {
|
||||
var result = []
|
||||
if (!fs.existsSync(dir)) {
|
||||
return result
|
||||
}
|
||||
var iaco = airline.label
|
||||
fs.readdirSync(dir).forEach(file => {
|
||||
let fullPath = path.join(dir, file)
|
||||
if (fs.lstatSync(fullPath).isDirectory()) {
|
||||
var children = this.traverseDir(fullPath, airline)
|
||||
result = result.concat(children)
|
||||
} else {
|
||||
if (file.match(new RegExp(`${iaco}.xml`, 'i'))) {
|
||||
result.push(fullPath)
|
||||
}
|
||||
}
|
||||
})
|
||||
return result
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
direction: function () {
|
||||
return this.$parent.$parent.$parent.$data.direction
|
||||
},
|
||||
filename: function () {
|
||||
var ret = this.traverseDir(this.$store.state.Settings.settings.flightgearDirectory_traffic, this.airline)
|
||||
if (ret.length > 0) {
|
||||
return ret[0]
|
||||
}
|
||||
},
|
||||
trafficFile: function () {
|
||||
return readTrafficXML(this.filename)
|
||||
},
|
||||
traffic: function () {
|
||||
if (this.filename) {
|
||||
var aircraftLookup = this.trafficFile.filter(a => a['required-aircraft'])
|
||||
.reduce((req, acc) => {
|
||||
req[acc['required-aircraft']] = acc
|
||||
return req
|
||||
}, {})
|
||||
var ret = this.trafficFile.filter(f => f.callsign).filter(f =>
|
||||
(f.departure.port === this.$store.state.Airports.currentAirport.icao && this.direction === 0) ||
|
||||
(f.arrival.port === this.$store.state.Airports.currentAirport.icao && this.direction === 1))
|
||||
.map(obj => ({ ...obj, flighttype: aircraftLookup[obj['required-aircraft']].flighttype }))
|
||||
.filter((v, i, a) => a.findIndex(t => (t.id === v.id)) === i)
|
||||
return ret
|
||||
}
|
||||
},
|
||||
aircraft: function () {
|
||||
if (this.filename) {
|
||||
return this.trafficFile.filter(f => f.registration)
|
||||
}
|
||||
console.debug(this.filename)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
div.row.div {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
@ -58,9 +58,12 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
const $ = require('jquery');
|
||||
import 'element-ui/lib/theme-chalk/index.css'
|
||||
import {removeWip} from '../loaders/groundnet_functions'
|
||||
import Vue from 'vue'
|
||||
import { EventBus } from './event-bus.js';
|
||||
|
||||
export default {
|
||||
name: 'airport',
|
||||
components: { },
|
||||
props: {airport: Object, editing: Boolean},
|
||||
mounted () {
|
||||
this.$forceUpdate();
|
||||
@ -83,7 +86,14 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
this.$store.dispatch('removeWip', this.airport.icao);
|
||||
},
|
||||
upload() {
|
||||
|
||||
let airports = this.$store.state.Airports.airports
|
||||
.filter(a => a.properties.icao.match(this.airport.icao))
|
||||
if (airports.length > 0) {
|
||||
this.$store.commit('CENTER', [airports[0].geometry.coordinates[1], airports[0].geometry.coordinates[0]])
|
||||
}
|
||||
Vue.set(this.$parent.$parent.$parent, 'uploadVisible', true)
|
||||
this.$parent.$parent.$parent.$refs.upload.status()
|
||||
this.$parent.$parent.$parent.$refs.upload.check()
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
@ -1,95 +1,231 @@
|
||||
<!--
|
||||
Copyright 2020 Keith Paterson
|
||||
|
||||
This file is part of FG Airports.
|
||||
|
||||
FG Airports is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
FG Airports is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with FG Airports. If not, see http://www.gnu.org/licenses/.
|
||||
-->
|
||||
<template>
|
||||
<div v-if="airport">
|
||||
<Upload :visible.sync="uploadVisible" ref="upload"></Upload>
|
||||
<el-dialog
|
||||
title="Add Airline"
|
||||
:visible.sync="dialogVisible"
|
||||
width="20%"
|
||||
:before-close="handleClose">
|
||||
width="40%"
|
||||
:before-close="handleClose"
|
||||
>
|
||||
<span>Add an selectable airline to {{ icao }} {{ name }}</span>
|
||||
<el-input
|
||||
placeholder="Please input airline"
|
||||
placeholder="Please input airline(s)"
|
||||
v-model="airlineCode"
|
||||
maxlength="3"
|
||||
></el-input>
|
||||
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="dialogVisible = false">Cancel</el-button>
|
||||
<el-button type="primary" @click="addAirline">Confirm</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
<el-dialog
|
||||
title="Import File"
|
||||
:visible.sync="showImportFile"
|
||||
width="20%"
|
||||
:before-close="handleClose"
|
||||
>
|
||||
<span>Beware wip will be overwritten</span>
|
||||
<el-row>
|
||||
<el-col :span="20">
|
||||
<el-input placeholder="Please input file" v-model="fileImportName">
|
||||
</el-input>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<file-select @input="fileImportFileName"></file-select>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="showImportFile = false">Cancel</el-button>
|
||||
<el-button type="primary" @click="importFile">Confirm</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
<h1 class="leaflet-sidebar-header">{{ icao }} {{ name }}</h1>
|
||||
<div width="100%" >
|
||||
<div width="100%">
|
||||
<el-row>
|
||||
<el-popover
|
||||
placement="top-start"
|
||||
title="Description"
|
||||
width="50"
|
||||
trigger="hover"
|
||||
content="Edit"
|
||||
>
|
||||
<el-button @click="edit" v-if="!editing" slot="reference"
|
||||
><i class="fas fa-edit"></i
|
||||
></el-button>
|
||||
</el-popover>
|
||||
<el-popover
|
||||
placement="top-start"
|
||||
title="Description"
|
||||
width="200"
|
||||
trigger="hover"
|
||||
content="Import groundnet"
|
||||
>
|
||||
<el-button
|
||||
@click="showImportFile = true"
|
||||
v-if="!editing"
|
||||
slot="reference"
|
||||
><i class="fas fa-file-import"></i
|
||||
></el-button>
|
||||
</el-popover>
|
||||
<el-popover
|
||||
placement="top-start"
|
||||
title="Description"
|
||||
width="220"
|
||||
trigger="hover"
|
||||
content="Export groundnet to export directory"
|
||||
>
|
||||
<el-button @click="test" v-if="!editing" slot="reference"
|
||||
><i class="fas fa-file-export"></i
|
||||
></el-button>
|
||||
</el-popover>
|
||||
<el-popover
|
||||
placement="top-start"
|
||||
title="Description"
|
||||
width="200"
|
||||
trigger="hover"
|
||||
content="Upload Airport"
|
||||
>
|
||||
<el-button @click="upload" v-if="!editing" slot="reference"
|
||||
><i class="fas fa-upload"></i
|
||||
></el-button>
|
||||
</el-popover>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="7"><span class="label"> Airlines :</span></el-col>
|
||||
<el-col :span="15">
|
||||
<el-tag v-for="item in airlines" :key="item.value">{{item.value}}</el-tag>
|
||||
<el-tag v-for="item in airlines" :key="item.value">{{
|
||||
item.value
|
||||
}}</el-tag>
|
||||
</el-col>
|
||||
<el-col :span="2">
|
||||
<el-button @click="dialogVisible = true" v-if="editing"
|
||||
><i class="fas fa-plus"></i
|
||||
></el-button>
|
||||
</el-col>
|
||||
<el-col :span="2"><el-button @click="dialogVisible = true" v-if="editing" ><i class="fas fa-plus"></i></el-button></el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<el-tabs v-model="activeTab" >
|
||||
<el-tabs v-model="activeTab">
|
||||
<el-tab-pane label="Frequencies" name="first">
|
||||
<div>
|
||||
<el-row v-for="f in frequencyList" :key="f.index">
|
||||
<Frequency :frequency="f"></Frequency>
|
||||
</el-row>
|
||||
<el-button @click="addFrequency" v-if="editing" >Add</el-button>
|
||||
<el-button @click="addFrequency" v-if="editing">Add</el-button>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="Parkings" name="second">
|
||||
<ParkingList></ParkingList>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="Statistics" name="third">
|
||||
<el-row><el-col :span="8"><span class="label">Traffic :</span></el-col></el-row>
|
||||
<el-row
|
||||
><el-col :span="8"
|
||||
><span class="label">Traffic :</span></el-col
|
||||
></el-row
|
||||
>
|
||||
<el-row>
|
||||
<el-col :span="8">Flights :</el-col>
|
||||
<el-col :span="4">{{ flights }}</el-col>
|
||||
<el-col :span="8"></el-col>
|
||||
<el-col :span="4"></el-col>
|
||||
</el-row>
|
||||
<el-row><el-col :span="16"><span class="label">GIT/Terrasync :</span></el-col></el-row>
|
||||
<el-row
|
||||
><el-col :span="16"
|
||||
><span class="label">GIT/Terrasync :</span></el-col
|
||||
></el-row
|
||||
>
|
||||
<el-row>
|
||||
<el-col :span="8">Parking Positions :</el-col>
|
||||
<el-col :span="4">{{ parking }}</el-col>
|
||||
<el-col :span="8">Groundnet Nodes :</el-col>
|
||||
<el-col :span="4">{{groundnet}}</el-col>
|
||||
<el-col :span="4">{{ groundnet }}</el-col>
|
||||
</el-row>
|
||||
<el-row><el-col :span="8"><span class="label">Work :</span></el-col></el-row>
|
||||
<el-row
|
||||
><el-col :span="8"><span class="label">Work :</span></el-col></el-row
|
||||
>
|
||||
<el-row v-if="wip">
|
||||
<el-col :span="8">Work Parking Positions :</el-col>
|
||||
<el-col :span="4">{{ wipparking }}</el-col>
|
||||
<el-col :span="8">Work Groundnet Nodes :</el-col>
|
||||
<el-col :span="4">{{wipgroundnet}}</el-col>
|
||||
<el-col :span="4">{{ wipgroundnet }}</el-col>
|
||||
</el-row>
|
||||
<el-row v-if="wip">
|
||||
<el-col :span="4">Saved :</el-col>
|
||||
<el-col :span="8" class="text">{{date}}</el-col>
|
||||
<el-col :span="8" class="text">{{ date }}</el-col>
|
||||
<el-col :span="4">Uploaded :</el-col>
|
||||
<el-col :span="8" class="text">{{upload_date}}</el-col>
|
||||
<el-col :span="8" class="text">{{ upload_date }}</el-col>
|
||||
</el-row>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="Traffic" name="fourth">
|
||||
<TrafficList></TrafficList>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="js">
|
||||
import EditButton from './EditButton'
|
||||
import FileSelect from './FileSelect'
|
||||
import Frequency from './Frequency'
|
||||
import ParkingList from './ParkingList'
|
||||
import TrafficList from './TrafficList'
|
||||
import Upload from './Upload'
|
||||
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {activeTab: 'first', editing: false, dialogVisible: false, airlineCode: ''}
|
||||
return {showImportFile: false, activeTab: 'first', editing: false, uploadVisible: false, dialogVisible: false, airlineCode: '', fileImport: null}
|
||||
},
|
||||
components: {
|
||||
Frequency, ParkingList
|
||||
EditButton, FileSelect, Frequency, ParkingList, TrafficList, Upload
|
||||
},
|
||||
methods: {
|
||||
fileImportFileName (f) {
|
||||
this.fileImport = f
|
||||
},
|
||||
edit () {
|
||||
this.isEditing = true
|
||||
this.$emit('edit', true)
|
||||
},
|
||||
upload () {
|
||||
this.uploadVisible = true
|
||||
this.$refs.upload.status()
|
||||
this.$refs.upload.check()
|
||||
},
|
||||
test () {
|
||||
this.$parent.$parent.$parent.$refs.editLayer.test()
|
||||
},
|
||||
importFile () {
|
||||
this.showImportFile = false
|
||||
var fDir = this.$store.state.Settings.settings.airportsDirectory
|
||||
var fNew = path.join(fDir, this.icao[0], this.icao[1], this.icao[2], this.icao + '.groundnet.new.xml')
|
||||
|
||||
var editLayer = this.$parent.$parent.$parent.$refs.editLayer
|
||||
fs.copyFile(this.fileImport.path, fNew, () => {
|
||||
editLayer.reload(false)
|
||||
})
|
||||
},
|
||||
setEditing (editing) {
|
||||
this.editing = editing
|
||||
},
|
||||
addAirline () {
|
||||
this.dialogVisible = false
|
||||
this.$store.dispatch('addAirline', this.airlineCode)
|
||||
this.airlineCode.split(/[ ,]/).forEach(element => {
|
||||
if (element.length === 3) {
|
||||
this.$store.dispatch('addAirline', element)
|
||||
}
|
||||
})
|
||||
},
|
||||
addFrequency () {
|
||||
this.$store.dispatch('addFrequency', {type: 'AWOS', value: 0})
|
||||
@ -108,6 +244,13 @@ export default {
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
fileImportName: function () {
|
||||
if (this.fileImport !== null) {
|
||||
console.log(this.fileImport)
|
||||
return this.fileImport.path
|
||||
}
|
||||
return 'Please select'
|
||||
},
|
||||
icao: function () {
|
||||
return this.$store.state.Airports.currentAirport.icao
|
||||
},
|
||||
@ -177,10 +320,10 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.el-row {
|
||||
.el-row {
|
||||
padding: 0em;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
}
|
||||
.label {
|
||||
display: flex;
|
||||
justify-content: left;
|
||||
|
106
src/renderer/components/ArcEditMulti.vue
Normal file
@ -0,0 +1,106 @@
|
||||
<!--
|
||||
Copyright 2020 Keith Paterson
|
||||
|
||||
This file is part of FG Airports.
|
||||
|
||||
FG Airports is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
FG Airports is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with FG Airports. If not, see http://www.gnu.org/licenses/.
|
||||
-->
|
||||
<template>
|
||||
<div width="100%" v-if="multiarc">
|
||||
<!--
|
||||
airlineCodes: 0
|
||||
heading: 341.34
|
||||
index: 13
|
||||
lat: "N59 52.610885"
|
||||
lon: "W1 17.855144"
|
||||
name: "Western_Apron_Hanger"
|
||||
pushBackRoute: 27
|
||||
radius: 18
|
||||
type: "gate"
|
||||
-->
|
||||
<el-row>
|
||||
<el-col :span="7">
|
||||
<span class="demo-input-label">Name :</span>
|
||||
</el-col>
|
||||
<el-col :span="15">
|
||||
<el-input placeholder="Please input" v-model="name"></el-input>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="7">
|
||||
<span class="demo-input-label">Pushback :</span>
|
||||
</el-col>
|
||||
<el-col :span="15">
|
||||
<el-switch v-model="isPushback"></el-switch>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="7">
|
||||
<span class="demo-input-label">Direction :</span>
|
||||
</el-col>
|
||||
<el-col :span="15">
|
||||
<el-select v-model="direction" placeholder="Select">
|
||||
<el-option
|
||||
v-for="type in options"
|
||||
:key="type.value"
|
||||
:label="type.label"
|
||||
:value="type.value"
|
||||
></el-option>
|
||||
</el-select>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="js">
|
||||
export default {
|
||||
computed: {
|
||||
multiarc: function () {
|
||||
return this.$store.state.Editable.type === 'multiarc'
|
||||
},
|
||||
// ga (general aviation), cargo (cargo), gate (commercial passenger traffic),
|
||||
// mil-fighter (military fighter), mil-cargo (military transport)
|
||||
options: function () {
|
||||
return [{value: 'bi-directional', label: 'bi-directional'},
|
||||
{value: 'forward', label: 'forward'},
|
||||
{value: 'backward', label: 'backward'}
|
||||
]
|
||||
},
|
||||
name: {
|
||||
// getter
|
||||
get: function () {
|
||||
return this.$store.state.Editable.data.multiarc.name
|
||||
},
|
||||
// setter
|
||||
set: function (newValue) {
|
||||
this.$store.commit('SET_EDIT_ARC_NAME', newValue)
|
||||
}
|
||||
},
|
||||
isPushback: {
|
||||
// getter
|
||||
get: function () {
|
||||
return this.$store.state.Editable.data.multiarc.isPushBackRoute === '1' ||
|
||||
Number(this.$store.state.Editable.data.multiarc.isPushBackRoute) === Number(1)
|
||||
},
|
||||
// setter
|
||||
set: function (newValue) {
|
||||
this.$store.commit('SET_EDIT_PUSHBACK', newValue ? '1' : '0')
|
||||
}
|
||||
},
|
||||
direction: {
|
||||
// getter
|
||||
get: function () {
|
||||
return this.$store.state.Editable.data.multiarc.direction
|
||||
},
|
||||
// setter
|
||||
set: function (newValue) {
|
||||
this.$store.commit('SET_EDIT_DIRECTION', newValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -7,10 +7,23 @@
|
||||
</div>
|
||||
</h1>
|
||||
<div id="panel" width="100%">
|
||||
<el-row v-if="!results || results.length === 0 "><h3>Check not run</h3></el-row>
|
||||
<el-row v-for="(result,idx) in results" :key="idx">
|
||||
<el-col :span="2" v-if="result.id<0"><span class="label"><i class="far fa-check-circle"></i></span></el-col>
|
||||
<el-col :span="2" v-if="result.id==-1"><span class="label"><i class="far fa-check-circle"></i></span></el-col>
|
||||
<el-col :span="2" v-if="result.id>=0"><span class="label"><i class="fas fa-exclamation-triangle"></i></span></el-col>
|
||||
<el-col :span="15"><span class="label">{{ result.message }}</span></el-col>
|
||||
<el-col :span="2" v-if="result.id==-2"><span class="label"><i class="fas fa-exclamation-triangle"></i></span></el-col>
|
||||
<el-col :span="15">
|
||||
<el-popover
|
||||
placement="top-start"
|
||||
title="Description"
|
||||
width="200"
|
||||
trigger="hover"
|
||||
v-if="result.message"
|
||||
:content=result.message[1]
|
||||
>
|
||||
<span class="label" slot="reference">{{ result.message[0] }}</span>
|
||||
</el-popover>
|
||||
</el-col>
|
||||
<el-col :span="4" v-if="result.id>=0"><el-button v-on:click="show(result.id)" class="button"><i class="fas fa-bullseye"></i></el-button></el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
@ -53,6 +66,9 @@
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
h3 {
|
||||
text-align: center;
|
||||
}
|
||||
.label {
|
||||
display: flex;
|
||||
justify-content: left;
|
||||
|
@ -3,7 +3,7 @@
|
||||
<div class="select-button">
|
||||
...
|
||||
</div>
|
||||
<input type="file" @change="handleFileChange" webkitdirectory directory/>
|
||||
<input name="hiddenDir" type="file" v-on:change="handleFileChange($event)" webkitdirectory directory tabindex="-1"/>
|
||||
</label>
|
||||
</template>
|
||||
|
||||
@ -20,10 +20,16 @@
|
||||
|
||||
methods: {
|
||||
handleFileChange (e) {
|
||||
try {
|
||||
if (e.target.files && e.target.files.length>0) {
|
||||
var first = e.target.files[0].webkitRelativePath.split("/")[0];
|
||||
var webkitdirectoryPath = e.target.files[0].path.split(first)[0] + first;
|
||||
this.$emit('input', webkitdirectoryPath)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -39,6 +45,8 @@
|
||||
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
.directory-select > input[type="file"] {
|
||||
|
@ -11,34 +11,84 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
-->
|
||||
<template>
|
||||
<div id="EditBar">
|
||||
<Upload :visible.sync="uploadVisible" ref="upload"></Upload>
|
||||
<ZoomButton icon="fas fa-th" v-on:click="zoomin" :show="true" tooltip="Zoomin"></ZoomButton>
|
||||
<ZoomButton icon="fas fa-th-large" v-on:click="zoomout" :show="!editing" tooltip="Zoomout"></ZoomButton>
|
||||
<!--<ZoomButton icon="far fa-eye-slash" v-on:click="hideAPT" :show='true' tooltip="Hide APT"></ZoomButton>-->
|
||||
|
||||
<EditButton icon="fas fa-upload" v-on:click="upload" :show="!editing" tooltip="Upload"></EditButton>
|
||||
<EditButton icon="fas fa-plane" v-on:click="test" :show="!editing" tooltip="Export"></EditButton>
|
||||
<EditButton icon="fas fa-edit" v-on:click="edit" :show="!editing" tooltip="Edit"></EditButton>
|
||||
<EditButton
|
||||
icon="fas fa-undo"
|
||||
v-on:click="centerDialogVisible = true"
|
||||
:show="editing"
|
||||
tooltip="Undo"
|
||||
></EditButton>
|
||||
<el-dialog title="Reload" :visible.sync="centerDialogVisible" width="30%" center>
|
||||
<span style="center">Reload from last save? You will lose the current edits.</span>
|
||||
<el-dialog
|
||||
title="Checking"
|
||||
width="30%"
|
||||
center
|
||||
:visible.sync="checkDialogVisible"
|
||||
>
|
||||
<el-container direction="vertical">
|
||||
<el-progress
|
||||
:percentage="Number(((progress / max) * 100).toPrecision(3))"
|
||||
v-if="max > 0"
|
||||
></el-progress>
|
||||
</el-container>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
title="Revert"
|
||||
:visible.sync="centerDialogVisible"
|
||||
width="550px"
|
||||
center
|
||||
>
|
||||
<span>
|
||||
Please select the Version to revert to.
|
||||
<el-row v-for="item in saves" :key="item.file">
|
||||
<el-button @click="revert(item.file)">{{item.mtime}}</el-button>
|
||||
</el-row>
|
||||
</span>
|
||||
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="undoFirst">Base version (GIT)</el-button>
|
||||
<el-button type="primary" @click="undoLast">Last save</el-button>
|
||||
<el-button type="primary" @click="cancel">Cancel</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
<el-dialog title="Saving" :visible.sync="saveDialogVisible" width="30%" center>
|
||||
<el-dialog
|
||||
title="Saving"
|
||||
:visible.sync="saveDialogVisible"
|
||||
width="30%"
|
||||
center
|
||||
>
|
||||
<span style="center">Saving..</span>
|
||||
</el-dialog>
|
||||
|
||||
<EditButton icon="fas fa-save" v-on:click="save" :show="editing" tooltip="Save"></EditButton>
|
||||
<EditButton icon="far fa-check-square" v-on:click="showCheck" :show="editing" tooltip="Check"></EditButton>
|
||||
<ZoomButton
|
||||
icon="fas fa-th"
|
||||
v-on:click="zoomin"
|
||||
:show="true"
|
||||
tooltip="Zoomin"
|
||||
></ZoomButton>
|
||||
<ZoomButton
|
||||
icon="fas fa-th-large"
|
||||
v-on:click="zoomout"
|
||||
:show="!editing"
|
||||
tooltip="Zoomout"
|
||||
></ZoomButton>
|
||||
|
||||
<EditButton
|
||||
icon="fa fa-window-close"
|
||||
v-on:click="close"
|
||||
:show="editing"
|
||||
tooltip="Close/Save Editing"
|
||||
></EditButton>
|
||||
<EditButton
|
||||
icon="fas fa-undo"
|
||||
v-on:click="openReload"
|
||||
:show="editing"
|
||||
tooltip="Revert to Savepoint"
|
||||
></EditButton>
|
||||
<EditButton
|
||||
icon="fas fa-save"
|
||||
v-on:click="save"
|
||||
:show="editing"
|
||||
tooltip="Save"
|
||||
></EditButton>
|
||||
<EditButton
|
||||
icon="far fa-check-square"
|
||||
v-on:click="showCheck"
|
||||
:show="editing"
|
||||
tooltip="Check"
|
||||
></EditButton>
|
||||
<EditButton
|
||||
icon="fas fa-draw-polygon"
|
||||
v-on:click="drawPolyline"
|
||||
@ -63,38 +113,39 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
:show="editing"
|
||||
tooltip="Draw Parking"
|
||||
></EditButton>
|
||||
<EditButton icon="fas fa-trash-alt" v-on:click="deleteFeature" :show="editing" tooltip="Remove"></EditButton>
|
||||
<el-dialog title="Checking" width="30%" center :visible.sync="checkDialogVisible">
|
||||
<el-container direction="vertical">
|
||||
<el-progress :percentage="Number(((progress / max)*100).toPrecision(3))" v-if="max>0"></el-progress>
|
||||
</el-container>
|
||||
</el-dialog>
|
||||
<EditButton
|
||||
icon="fas fa-trash-alt"
|
||||
v-on:click="deleteFeature"
|
||||
:show="editing"
|
||||
tooltip="Remove"
|
||||
></EditButton>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="js">
|
||||
/* eslint-disable */
|
||||
const path = require('path')
|
||||
const fs = require('fs');
|
||||
const mapper = require('../check/mapper');
|
||||
|
||||
import {listSaves} from '../loaders/groundnet_loader'
|
||||
|
||||
import EditButton from './EditButton'
|
||||
import ZoomButton from './ZoomButton';
|
||||
import Upload from './Upload'
|
||||
import Vue from 'vue'
|
||||
|
||||
import fileUrl from 'file-url'
|
||||
const path = require('path')
|
||||
const fs = require('fs');
|
||||
|
||||
export default {
|
||||
components: { EditButton, Upload, ZoomButton },
|
||||
components: { EditButton, ZoomButton },
|
||||
data () {
|
||||
return {isEditing: false, uploadVisible: false, centerDialogVisible: false, saveDialogVisible: false, checkDialogVisible: false, checking: false, progress: 0, max: 0, pavementLayerVisible: true}
|
||||
return {isEditing: false, uploadVisible: false, centerDialogVisible: false, saveDialogVisible: false, checkDialogVisible: false, checking: false, progress: 0, max: 0, pavementLayerVisible: true, saves: [] }
|
||||
},
|
||||
created () {
|
||||
},
|
||||
methods: {
|
||||
upload() {
|
||||
this.uploadVisible = true
|
||||
this.$refs.upload.status()
|
||||
this.$refs.upload.check()
|
||||
cancel () {
|
||||
this.centerDialogVisible = false
|
||||
},
|
||||
zoomout() {
|
||||
this.$parent.$parent.$refs.editLayer.stopDrawing()
|
||||
@ -110,42 +161,57 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
},
|
||||
edit () {
|
||||
this.isEditing = true
|
||||
this.$emit('edit')
|
||||
this.$emit('edit', true)
|
||||
},
|
||||
undoFirst () {
|
||||
setEditing (editing) {
|
||||
this.isEditing = editing
|
||||
},
|
||||
revert (file) {
|
||||
this.isEditing = false
|
||||
this.$emit('edit')
|
||||
this.$emit('edit', false)
|
||||
this.centerDialogVisible = false
|
||||
this.$parent.$parent.$refs.map.mapObject.options.minZoom = 1;
|
||||
this.$parent.$parent.$refs.editLayer.disableEdit()
|
||||
this.$parent.$parent.$refs.editLayer.reload(true)
|
||||
this.$parent.$parent.$refs.towerLayer.disableEdit()
|
||||
this.$parent.$parent.$refs.thresholdLayer.disableEdit()
|
||||
this.$parent.$parent.$refs.editLayer.reload(file)
|
||||
},
|
||||
undoLast () {
|
||||
this.isEditing = false
|
||||
this.$emit('edit')
|
||||
this.centerDialogVisible = false
|
||||
this.$parent.$parent.$refs.map.mapObject.options.minZoom = 1;
|
||||
this.$parent.$parent.$refs.editLayer.disableEdit()
|
||||
this.$parent.$parent.$refs.editLayer.reload(false)
|
||||
},
|
||||
save () {
|
||||
close () {
|
||||
this.$parent.$parent.$refs.editLayer.stopDrawing()
|
||||
this.isEditing = false
|
||||
this.$emit('edit')
|
||||
this.$emit('edit', false)
|
||||
this.$parent.$parent.$refs.map.mapObject.options.minZoom = 1;
|
||||
Vue.set(this, 'saveDialogVisible', true)
|
||||
this.$emit('edit')
|
||||
this.$emit('edit', false)
|
||||
Vue.nextTick( function () {
|
||||
setTimeout( this.closeDefered.bind(this), 100);
|
||||
}, this)
|
||||
},
|
||||
closeDefered () {
|
||||
this.$parent.$parent.$refs.editLayer.save()
|
||||
this.$parent.$parent.$refs.towerLayer.save()
|
||||
this.$parent.$parent.$refs.thresholdLayer.save()
|
||||
this.$parent.$parent.$refs.editLayer.disableEdit()
|
||||
this.$parent.$parent.$refs.towerLayer.disableEdit()
|
||||
this.$parent.$parent.$refs.thresholdLayer.disableEdit()
|
||||
this.rescanCurrentGroundnet()
|
||||
Vue.set(this, 'saveDialogVisible', false)
|
||||
},
|
||||
save () {
|
||||
Vue.set(this, 'saveDialogVisible', true)
|
||||
this.$parent.$parent.$refs.editLayer.stopDrawing()
|
||||
Vue.nextTick( function () {
|
||||
setTimeout( this.saveDefered.bind(this), 100);
|
||||
}, this)
|
||||
},
|
||||
saveDefered () {
|
||||
this.$parent.$parent.$refs.editLayer.save()
|
||||
this.$parent.$parent.$refs.editLayer.disableEdit()
|
||||
this.scanGroundnets()
|
||||
this.$parent.$parent.$refs.towerLayer.save()
|
||||
this.$parent.$parent.$refs.thresholdLayer.save()
|
||||
this.rescanCurrentGroundnet()
|
||||
Vue.set(this, 'saveDialogVisible', false)
|
||||
},
|
||||
scanGroundnets () {
|
||||
rescanCurrentGroundnet () {
|
||||
try {
|
||||
const winURL = process.env.NODE_ENV === 'development'
|
||||
? `http://localhost:9080/src/renderer/utils/worker.js`
|
||||
@ -188,10 +254,7 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
view.scanning = Boolean(workery.checking)
|
||||
workery.view = view
|
||||
}
|
||||
}, 1000)
|
||||
},
|
||||
test() {
|
||||
this.$parent.$parent.$refs.editLayer.test()
|
||||
}, 500)
|
||||
},
|
||||
check () {
|
||||
try {
|
||||
@ -200,8 +263,25 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
? `http://localhost:9080/src/renderer/utils/check.js`
|
||||
: `file://${process.resourcesPath}/workers/check.js`
|
||||
console.log('make a check worker: ', path.resolve(__dirname, 'check.js'))
|
||||
if(!this.$parent.$parent.$refs.pavementLayer.pavement) {
|
||||
this.max = 0
|
||||
this.checkDialogVisible = false
|
||||
this.$message({
|
||||
type: 'Error',
|
||||
showClose: true,
|
||||
message: `Check can't run without pavementlayer since runways aren't known. Is the APT file set correctly?`
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
const worker = new Worker(winURL)
|
||||
worker.onerror = function(e) {
|
||||
worker.terminate()
|
||||
worker.view.max = 0
|
||||
worker.view.checkDialogVisible = false
|
||||
e.preventDefault(); // <-- "Hey browser, I handled it!"
|
||||
}
|
||||
|
||||
console.log(fileUrl('src/renderer/utils/check.js'))
|
||||
|
||||
worker.checking = this.checking
|
||||
@ -211,15 +291,27 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
worker.progress = 0
|
||||
// var worker = new Worker(fileUrl('src/renderer/utils/worker.js'))
|
||||
this.worker = worker
|
||||
var xml = []
|
||||
var groundnet = []
|
||||
this.$parent.$parent.$refs.editLayer.groundnetLayerGroup.eachLayer(l => {
|
||||
console.log(l)
|
||||
xml.push(l)
|
||||
groundnet.push(l)
|
||||
})
|
||||
var features = groundnet.map(mapper.checkMapper).filter(n => n)
|
||||
var pavement = []
|
||||
this.$parent.$parent.$refs.pavementLayer.pavement.eachLayer(l => {
|
||||
console.log(l)
|
||||
pavement.push(l)
|
||||
})
|
||||
var thresholds = []
|
||||
this.$parent.$parent.$refs.thresholdLayer.getLayer().eachLayer(l => {
|
||||
console.log(l)
|
||||
thresholds.push(l)
|
||||
})
|
||||
var pavementFeatures = pavement.map(mapper.checkMapper).filter(n => n)
|
||||
//TODO
|
||||
var thresholdFeatures = thresholds.map(mapper.checkMapper).filter(n => n)
|
||||
|
||||
var features = xml.map(this.featuresMapper).filter(n => n)
|
||||
|
||||
worker.postMessage(['check', features ] )
|
||||
worker.postMessage(['check', features.concat(pavementFeatures).concat(thresholdFeatures) ] )
|
||||
this.pollData()
|
||||
// the reply
|
||||
var store = this.$store
|
||||
@ -274,36 +366,11 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
Vue.set(this, 'checkDialogVisible', true)
|
||||
this.check()
|
||||
},
|
||||
featuresMapper(o) {
|
||||
if (o instanceof L.ParkingSpot) {
|
||||
/*
|
||||
if( o.box === undefined ) {
|
||||
debugger;
|
||||
} */
|
||||
return { 'index': Number(o['id']),
|
||||
'_leaflet_id': o._leaflet_id,
|
||||
'type': 'parking',
|
||||
'parkingType': o.options.attributes.type,
|
||||
'name': o.options.attributes.name,
|
||||
'radius': String(o.options.attributes.radius),
|
||||
'lat': o._latlng.lat,
|
||||
'lng': o._latlng.lng,
|
||||
'box': o.box!==undefined?o.box.getLatLngs():null
|
||||
};
|
||||
} else if (o instanceof L.RunwayNode) {
|
||||
console.log(o)
|
||||
return { 'index': Number(o['glueindex']), '_leaflet_id': o._leaflet_id, 'type': 'runway' };
|
||||
} else if (o instanceof L.HoldNode) {
|
||||
console.log(o)
|
||||
return { 'index': Number(o['glueindex']), '_leaflet_id': o._leaflet_id, 'type': o.holdPointType };
|
||||
} else if (o instanceof L.Polyline) {
|
||||
console.log(o)
|
||||
//_latlngs[""0""].__vertex.glueindex
|
||||
var latLngs = o.getLatLngs().map(l => ({lat: l.lat, lng: l.lng, index: l.glueindex}));
|
||||
return { 'start': Number(o['begin']), 'end': Number(o['end']), '_leaflet_id': o._leaflet_id, 'type': 'poly', 'isPushBackRoute': o.options.attributes.isPushBackRoute, latLngs: latLngs };
|
||||
} else {
|
||||
console.log('Unknown Type ')
|
||||
console.log(typeof o)
|
||||
openReload: function() {
|
||||
this.centerDialogVisible = true
|
||||
var icao = this.$parent.$parent.$refs.editLayer.icao
|
||||
if (icao !== undefined && icao !== '') {
|
||||
this.saves = listSaves(this.$store.state.Settings.settings.airportsDirectory, icao).sort((a, b) => a.mtimeMs - b.mtimeMs)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -22,6 +22,7 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
import L2 from 'leaflet-textpath'
|
||||
import Vue from 'vue'
|
||||
import { MessageBox } from 'element-ui';
|
||||
|
||||
const turf = require('@turf/turf')
|
||||
|
||||
|
||||
@ -38,18 +39,17 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
components: {},
|
||||
props: [],
|
||||
created () {
|
||||
|
||||
console.log(LMap)
|
||||
console.log(LMarker)
|
||||
console.log(L)
|
||||
console.log(LEdit)
|
||||
console.log(L2)
|
||||
console.log('Created Editlayer')
|
||||
[LMap, LMarker, L, LEdit, L2]
|
||||
console.debug('Created Editlayer')
|
||||
// console.log(LSymbol)
|
||||
},
|
||||
mounted () {
|
||||
this.selectionLayerGroup = L.layerGroup();
|
||||
this.selectionLayerGroup.addTo(this.$parent.mapObject)
|
||||
this.$parent.mapObject.createPane('pushback-pane')
|
||||
this.$parent.mapObject.getPane('pushback-pane').style.zIndex = 512
|
||||
|
||||
this.$parent.mapObject.createPane('route-pane')
|
||||
this.$parent.mapObject.getPane('route-pane').style.zIndex = 511
|
||||
|
||||
this.$store.watch(
|
||||
function (state) {
|
||||
return state.Editable.data.node;
|
||||
@ -70,6 +70,16 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
deep: true //add this if u need to watch object properties change etc.
|
||||
}
|
||||
);
|
||||
this.$store.watch(
|
||||
function (state) {
|
||||
return state.Editable.data.multiarc;
|
||||
},
|
||||
() => { this.editedMultiArc() }
|
||||
,
|
||||
{
|
||||
deep: true //add this if u need to watch object properties change etc.
|
||||
}
|
||||
);
|
||||
this.$store.watch(
|
||||
function (state) {
|
||||
return state.Editable.data.parking;
|
||||
@ -96,10 +106,16 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
maxId: 1, icao: String, checking: false, editing: false
|
||||
maxId: 1, icao: '', checking: false, editing: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getLayer () {
|
||||
return this.groundnetLayerGroup;
|
||||
},
|
||||
getIdLayerGroup() {
|
||||
return this.idLayerGroup;
|
||||
},
|
||||
getParkings(ring) {
|
||||
var poly = turf.polygon(ring);
|
||||
var parkings = []
|
||||
@ -115,37 +131,46 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
this.selection = parkings;
|
||||
return parkings;
|
||||
},
|
||||
load (icao, force) {
|
||||
load (icao, filename) {
|
||||
if (this.groundnetLayerGroup !== undefined) {
|
||||
this.groundnetLayerGroup.removeFrom(this.$parent.mapObject)
|
||||
}
|
||||
this.$parent.$parent.setIcao(icao)
|
||||
this.icao = icao
|
||||
this.groundnetLayerGroup = readGroundnetXML(this.$store.state.Settings.settings.airportsDirectory, icao, force)
|
||||
var f = '';
|
||||
if (!filename) {
|
||||
var f = path.join(this.$store.state.Settings.settings.airportsDirectory, icao[0], icao[1], icao[2], icao + '.groundnet.new.xml')
|
||||
if (!fs.existsSync(f)) {
|
||||
f = path.join(this.$store.state.Settings.settings.airportsDirectory, icao[0], icao[1], icao[2], icao + '.groundnet.xml')
|
||||
}
|
||||
} else {
|
||||
f = path.join(this.$store.state.Settings.settings.airportsDirectory, icao[0], icao[1], icao[2], filename)
|
||||
}
|
||||
|
||||
console.info(`Reload from : ${f}`)
|
||||
|
||||
this.groundnetLayerGroup = readGroundnetXML(this.$store.state.Settings.settings.airportsDirectory, icao, f)
|
||||
if (this.groundnetLayerGroup === undefined) {
|
||||
console.error('ICAO not loaded ' + icao)
|
||||
console.warn('Groundnet for ICAO not loaded ' + icao)
|
||||
return
|
||||
}
|
||||
if (this.groundnetLayerGroup.getLayers().length === 0) {
|
||||
console.warn('Groundnet for ICAO not loaded ' + icao)
|
||||
}
|
||||
this.groundnetLayerGroup.eachLayer(l => {
|
||||
if (l instanceof L.TaxiwaySegment) {
|
||||
l.addListeners()
|
||||
}
|
||||
})
|
||||
/*
|
||||
this.groundnetLayerGroup.eachLayer(l => {
|
||||
if (l instanceof L.TaxiwaySegment) {
|
||||
var decorator = L.polylineDecorator(l, {
|
||||
pattern: [
|
||||
// defines a pattern of 10px-wide dashes, repeated every 20px on the line
|
||||
{offset: 5, repeat: 50, symbol: L.Symbol.arrowHead({pixelSize: 15, pathOptions: {fillOpacity: 1, weight: 0}})}
|
||||
]
|
||||
})
|
||||
decorator.addTo(this.$parent.mapObject)
|
||||
if (l.updateArrows !== undefined) {
|
||||
l.updateArrows(this.$store.state.Settings.zoom)
|
||||
}
|
||||
if (typeof l.setInteractive === 'function') {
|
||||
l.setInteractive(false)
|
||||
}
|
||||
})
|
||||
*/
|
||||
|
||||
console.log(this.groundnetLayerGroup.maxId)
|
||||
})
|
||||
console.debug(`MaxId : ${this.groundnetLayerGroup.maxId}`)
|
||||
this.buildLookup()
|
||||
|
||||
this.groundnetLayerGroup.addTo(this.$parent.mapObject)
|
||||
this.icao = icao
|
||||
@ -191,6 +216,11 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
element.updateRadius(event.wingspan/2)
|
||||
});
|
||||
break;
|
||||
case 'parking-group-type':
|
||||
this.selection.forEach(element => {
|
||||
element.updateType(event.parking_type)
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -202,9 +232,11 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
this.$store.commit('SET_EDIT', true)
|
||||
|
||||
this.featureLookup = [];
|
||||
if(!this.groundnetLayerGroup) {
|
||||
return;
|
||||
}
|
||||
this.groundnetLayerGroup.eachLayer(l => {
|
||||
l.enableEdit()
|
||||
|
||||
l.featureLookup = this.featureLookup;
|
||||
if (typeof l.extensions === 'function') {
|
||||
l.extensions(this)
|
||||
@ -212,13 +244,65 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
if (typeof l.bringToFront === 'function') {
|
||||
l.bringToFront()
|
||||
}
|
||||
if (typeof l.updateStyle === 'function') {
|
||||
l.updateStyle()
|
||||
}
|
||||
if (typeof l.setInteractive === 'function') {
|
||||
l.setInteractive(true)
|
||||
}
|
||||
})
|
||||
this.$store.dispatch('addWip', {icao: this.icao}); },
|
||||
this.$store.dispatch('addWip', {icao: this.icao});
|
||||
},
|
||||
showTooltips() {
|
||||
this.groundnetLayerGroup.eachLayer(l => {
|
||||
if (l instanceof L.Polyline) {
|
||||
l.getLatLngs().forEach(l => {
|
||||
if (this.$parent.mapObject.getBounds().contains(l)) {
|
||||
if (l.__vertex && !l.__vertex.getTooltip()) {
|
||||
l.__vertex.bindTooltip(l.glueindex, {permanent: true});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if (l instanceof L.ParkingSpot) {
|
||||
if (this.$parent.mapObject.getBounds().contains(l.getLatLng())) {
|
||||
var parkingHub = l.glueindex + " " + l.options.attributes.name + " " + l.options.attributes.number;
|
||||
if(l.box) {
|
||||
l.box.bindTooltip(parkingHub, {permanent: true, direction: 'right'});
|
||||
} else {
|
||||
l.bindTooltip(parkingHub, {permanent: true, direction: 'right'});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
setTimeout(this.closeTooltips.bind(this), 2000);
|
||||
},
|
||||
closeTooltips() {
|
||||
this.groundnetLayerGroup.eachLayer(l => {
|
||||
if (l instanceof L.Polyline) {
|
||||
l.getLatLngs().forEach(l => {
|
||||
if (l.__vertex && l.__vertex.getTooltip()) {
|
||||
l.__vertex.unbindTooltip();
|
||||
}
|
||||
});
|
||||
}
|
||||
if (l instanceof L.ParkingSpot) {
|
||||
if(l.box) {
|
||||
l.box.unbindTooltip();
|
||||
} else {
|
||||
l.unbindTooltip();
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
disableEdit () {
|
||||
this.editable = false
|
||||
this.editing = false
|
||||
this.$store.commit('SET_EDIT', false)
|
||||
this.groundnetLayerGroup.eachLayer(l => {
|
||||
if (typeof l.setInteractive === 'function') {
|
||||
l.setInteractive(false)
|
||||
}
|
||||
l.disableEdit()
|
||||
})
|
||||
},
|
||||
@ -240,6 +324,9 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
console.log('Remove : ' + this.$store.state.Editable.type)
|
||||
}
|
||||
},
|
||||
isOnRunway(latlng) {
|
||||
return this.$parent.$parent.$refs.pavementLayer.isOnRunway(latlng)
|
||||
},
|
||||
findRouteToPushback (index) {
|
||||
if (this.featureLookup===undefined || this.featureLookup[index]===undefined) {
|
||||
return
|
||||
@ -271,7 +358,7 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
});
|
||||
},
|
||||
removeArc (arc) {
|
||||
console.log(arc);
|
||||
console.debug('Remove Arc : ' + arc);
|
||||
var arcLayer = this.groundnetLayerGroup.getLayer(this.$store.state.Editable.index);
|
||||
arcLayer.removeFrom(this.groundnetLayerGroup);
|
||||
},
|
||||
@ -290,9 +377,24 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
if(Number.isNaN(index)) {
|
||||
return;
|
||||
}
|
||||
if(this.featureLookup===undefined || this.featureLookup[index]===undefined) {
|
||||
if (this.featureLookup===undefined || this.featureLookup[index]===undefined) {
|
||||
var found = false;
|
||||
this.groundnetLayerGroup.eachLayer((layer) => {
|
||||
if (layer instanceof L.Polyline && layer._leaflet_id == index) {
|
||||
layer.select();
|
||||
this.$store.dispatch('setCenter', layer.getCenter());
|
||||
found = true;
|
||||
} else {
|
||||
layer.deselect();
|
||||
}
|
||||
});
|
||||
if (found) {
|
||||
return;
|
||||
} else {
|
||||
console.error("Lookup " + index + " failed ");
|
||||
this.buildLookup()
|
||||
this.buildLookup();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (Number(this.$store.state.Editable.index) >= 0 &&
|
||||
this.featureLookup[this.$store.state.Editable.index]!==undefined) {
|
||||
@ -304,8 +406,7 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
this.featureLookup[index].forEach((element, i) => {
|
||||
if (element instanceof L.Polyline) {
|
||||
element._latlngs.forEach((e1, index1) => {
|
||||
console.log(e1);
|
||||
if (e1.attributes.index===index) {
|
||||
if (e1.attributes.index===Number(index)) {
|
||||
var latlng = {};
|
||||
latlng.lat = e1.lat;
|
||||
latlng.lng = e1.lng;
|
||||
@ -453,17 +554,6 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
}
|
||||
});
|
||||
},
|
||||
/*
|
||||
getParkings (){
|
||||
var parkings = []
|
||||
this.groundnetLayerGroup.eachLayer(l => {
|
||||
if (l instanceof L.ParkingSpot) {
|
||||
parkings.push(l)
|
||||
}
|
||||
})
|
||||
return parkings
|
||||
},
|
||||
*/
|
||||
refreshLookup(index) {
|
||||
//element.__vertex
|
||||
this.featureLookup[index] = this.featureLookup[index].filter(item => {
|
||||
@ -485,9 +575,10 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
try {
|
||||
this.featureLookup[index].forEach((element, i) => {
|
||||
if (element instanceof L.Polyline) {
|
||||
console.log('Poly : ' + i + ' ' + element.attributes);
|
||||
console.debug('Poly : ' + i + ' ' + element.attributes);
|
||||
// Complete poly with be removed
|
||||
if ( element._latlngs.length <= 3 ) {
|
||||
console.debug('Remove short ' + element);
|
||||
if(Number(element.begin) !== index) {
|
||||
this.featureLookup[Number(element.begin)] = this.featureLookup[Number(element.begin)].filter(item => item !== element);
|
||||
this.refreshLookup(Number(element.begin))
|
||||
@ -497,10 +588,11 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
this.refreshLookup(Number(element.end))
|
||||
}
|
||||
element.removeFrom(this.groundnetLayerGroup);
|
||||
element.removeFrom(this.$parent.mapObject);
|
||||
}
|
||||
else {
|
||||
element.getLatLngs().forEach((e1, index1) => {
|
||||
console.log(index1 + ' ' + e1);
|
||||
console.debug('Remove Long' + index1 + ' ' + e1);
|
||||
if (e1.attributes.index===index) {
|
||||
var splitOffNodes = element.getLatLngs().splice(index1);
|
||||
element.editor.refresh();
|
||||
@ -574,7 +666,7 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
polyLine.addListeners()
|
||||
|
||||
polyLine.on('editable:drawing:end', event => {
|
||||
console.log(event)
|
||||
console.debug(event)
|
||||
event.target.addTo(this.groundnetLayerGroup)
|
||||
})
|
||||
},
|
||||
@ -592,10 +684,10 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
polyLine.addListeners()
|
||||
|
||||
polyLine.on('editable:drawing:end', event => {
|
||||
console.log(event)
|
||||
console.debug(event)
|
||||
event.target.addTo(this.groundnetLayerGroup)
|
||||
var pt = event.sourceTarget._latlngs[event.sourceTarget._latlngs.length-1];
|
||||
pt.attributes.holdPointType = 'PushBack'
|
||||
pt.attributes['holdPointType'] = 'PushBack'
|
||||
var nIndex = pt.attributes.index
|
||||
var fa_icon = "<div style='background-color:#4838cc;' class='marker-pin'></div><i class='fas fa-arrows-alt-h'></i>";
|
||||
const icon = new L.DivIcon({
|
||||
@ -608,6 +700,7 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
node.glueindex = nIndex;
|
||||
node.addTo(this.groundnetLayerGroup);
|
||||
node.featureLookup = this.featureLookup;
|
||||
node['holdPointType'] = 'PushBack'
|
||||
this.featureLookup[nIndex].push(node);
|
||||
node.addListeners();
|
||||
node.extensions();
|
||||
@ -619,7 +712,7 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
this.featureLookup===undefined) {
|
||||
return
|
||||
}
|
||||
console.log('Edited Parking : ' + this.$store.state.Editable.data.parking)
|
||||
console.debug('Edited Parking : ' + this.$store.state.Editable.data.parking)
|
||||
//Notify list
|
||||
if (this.featureLookup[this.$store.state.Editable.index]===undefined) {
|
||||
return
|
||||
@ -638,18 +731,18 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
},
|
||||
editedParkings() {
|
||||
if (this.featureLookup===undefined) {
|
||||
console.warn("Lookup undefinded");
|
||||
console.warn("Lookup undefined");
|
||||
this.buildLookup()
|
||||
}
|
||||
if (this.featureLookup===undefined) {
|
||||
return
|
||||
}
|
||||
console.log('Edited Parkings : ' + this.$store.state.Parkings.items)
|
||||
console.debug('Edited Parkings : ' + this.$store.state.Parkings.items)
|
||||
this.$store.state.Parkings.items.forEach( newElement => {
|
||||
console.debug(newElement);
|
||||
if(this.featureLookup[newElement.index]) {
|
||||
this.featureLookup[newElement.index].forEach((element,index) => {
|
||||
if (element instanceof L.ParkingSpot) {
|
||||
console.debug(element);
|
||||
element.options.attributes.name = newElement.name
|
||||
element.options.attributes.number = newElement.number
|
||||
element.options.attributes.type = newElement.type
|
||||
@ -677,6 +770,7 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
!this.editing) {
|
||||
return;
|
||||
}
|
||||
console.debug("Edit Type : " + this.$store.state.type);
|
||||
var arc = this.groundnetLayerGroup.getLayer(this.$store.state.Editable.index);
|
||||
if (arc && arc instanceof L.Polyline) {
|
||||
console.log('Edited Arc : ' + this.$store.state.Editable.index);
|
||||
@ -684,6 +778,27 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
arc.updateStyle();
|
||||
}
|
||||
},
|
||||
editedMultiArc() {
|
||||
if (!this.groundnetLayerGroup ||
|
||||
this.$store.state.Editable.data.multiarc === undefined ||
|
||||
this.$store.state.Editable.data.multiarc.ids === undefined ||
|
||||
this.featureLookup===undefined ||
|
||||
!this.editing) {
|
||||
return;
|
||||
}
|
||||
console.debug("Edit Type : " + this.$store.state.Editable.data.multiarc.ids + ' ' + String(this.$store.state.Editable.data.multiarc.direction));
|
||||
this.$store.state.Editable.data.multiarc.ids.forEach(id => {
|
||||
console.debug(id);
|
||||
var arc = this.groundnetLayerGroup.getLayer(id);
|
||||
if (arc && arc instanceof L.Polyline) {
|
||||
console.log('Edited Arc : ' + this.$store.state.Editable.index);
|
||||
arc.options.attributes.direction = String(this.$store.state.Editable.data.multiarc.direction)
|
||||
arc.options.attributes.name = String(this.$store.state.Editable.data.multiarc.name)
|
||||
arc.options.attributes.isPushBackRoute = Number(this.$store.state.Editable.data.multiarc.isPushBackRoute)
|
||||
arc.updateStyle();
|
||||
}
|
||||
});
|
||||
},
|
||||
//Update Node
|
||||
editedNode() {
|
||||
if (this.$store.state.Editable.index === undefined ||
|
||||
@ -757,20 +872,7 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
|
||||
})
|
||||
if (!hasRunwayNode && isOnRunway && latlng !== undefined) {
|
||||
this.$store.state.Editable.data.node.holdPointType
|
||||
const icon = new L.DivIcon({
|
||||
className: 'custom-div-icon',
|
||||
html: "<div style='background-color:#4838cc;' class='marker-pin'></div><i class='fas fa-plane-departure'></i>",
|
||||
iconSize: [30, 42],
|
||||
iconAnchor: [15, 42]
|
||||
});
|
||||
const node = new L.RunwayNode(latlng, { icon: icon });
|
||||
node.glueindex = nIndex;
|
||||
node.addTo(this.groundnetLayerGroup);
|
||||
this.featureLookup[nIndex].push(node);
|
||||
node.featureLookup = this.featureLookup;
|
||||
node.addListeners();
|
||||
node.extensions();
|
||||
this.addRunwayNode(latlng, nIndex)
|
||||
}
|
||||
if (!hasHoldPointNode && isHoldPoint) {
|
||||
var fa_icon = null;
|
||||
@ -795,6 +897,21 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
node.extensions();
|
||||
}
|
||||
},
|
||||
addRunwayNode (latlng, nIndex) {
|
||||
const icon = new L.DivIcon({
|
||||
className: 'custom-div-icon',
|
||||
html: "<div style='background-color:#4838cc;' class='marker-pin'></div><i class='fas fa-plane-departure'></i>",
|
||||
iconSize: [30, 42],
|
||||
iconAnchor: [15, 42]
|
||||
});
|
||||
const node = new L.RunwayNode(latlng, { icon: icon });
|
||||
node.glueindex = nIndex;
|
||||
node.addTo(this.groundnetLayerGroup);
|
||||
this.featureLookup[nIndex].push(node);
|
||||
node.featureLookup = this.featureLookup;
|
||||
node.addListeners();
|
||||
node.extensions();
|
||||
},
|
||||
// Finde nearest node
|
||||
closestLayerSnap (eventLatlng, snap) {
|
||||
var layers = []
|
||||
@ -807,9 +924,11 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
console.warn('No glueindex : ' + latlng.__vertex);
|
||||
}
|
||||
let distance = latlng.distanceTo(eventLatlng)
|
||||
if (distance > 0 && distance < snap) {
|
||||
if (distance >= 0 && distance < snap && latlng.glueindex >=0) {
|
||||
layers.push({d: distance, l: layer, latlng: latlng.__vertex.latlng, glueindex: latlng.glueindex})
|
||||
}
|
||||
} else {
|
||||
console.log(latlng);
|
||||
}
|
||||
})
|
||||
} else if (layer instanceof L.RunwayNode) {
|
||||
@ -841,11 +960,11 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
this.$parent.mapObject.on('click', this.addParking)
|
||||
},
|
||||
removeLayerClick (event) {
|
||||
console.log(event)
|
||||
console.debug(event)
|
||||
this.groundnetLayerGroup.removeLayer(event.target)
|
||||
},
|
||||
addParking (event) {
|
||||
console.log(event.latlng)
|
||||
console.debug(event.latlng)
|
||||
if (event.latlng === undefined) {
|
||||
return
|
||||
}
|
||||
@ -855,9 +974,12 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
circle.glueindex = circle.id
|
||||
circle.addTo(this.groundnetLayerGroup)
|
||||
circle.featureLookup = this.featureLookup
|
||||
circle.addListeners()
|
||||
circle.enableEdit()
|
||||
circle.extensions()
|
||||
circle.addListeners()
|
||||
circle.updateVertexFromDirection();
|
||||
circle.updateWheelPos();
|
||||
circle.updateBox();
|
||||
if (Number(this.$store.state.Editable.index) >= 0 &&
|
||||
this.featureLookup[this.$store.state.Editable.index]!==undefined) {
|
||||
this.featureLookup[this.$store.state.Editable.index].forEach(element => {
|
||||
@ -874,8 +996,8 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
this.$parent.mapObject.off('click', this.addParking)
|
||||
this.$parent.mapObject._container.style.cursor = ''
|
||||
},
|
||||
reload (force) {
|
||||
this.load(this.icao, force)
|
||||
reload (filename) {
|
||||
this.load(this.icao, filename)
|
||||
},
|
||||
link (index) {
|
||||
var layers = []
|
||||
@ -913,9 +1035,11 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
console.warn('No glueindex : ' + latlng.__vertex);
|
||||
}
|
||||
let distance = latlng.distanceTo(centerLatLng)
|
||||
if (latlng.glueindex !== newIndex && distance < 10) {
|
||||
if (Number(latlng.glueindex) !== Number(newIndex) && distance < 10) {
|
||||
nearest.push({d: distance, l: layer, latlng: latlng.__vertex.latlng, glueindex: latlng.glueindex })
|
||||
}
|
||||
} else {
|
||||
console.error("No __Vertex", latlng);
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -964,11 +1088,10 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
save () {
|
||||
var xml = []
|
||||
this.groundnetLayerGroup.eachLayer(l => {
|
||||
console.log(l)
|
||||
//console.debug(l)
|
||||
xml.push(l)
|
||||
})
|
||||
writeGroundnetXML(this.$store.state.Settings.settings.airportsDirectory, this.icao, xml)
|
||||
this.load(this.icao, false)
|
||||
},
|
||||
//Copy to test directory
|
||||
test() {
|
||||
@ -979,11 +1102,18 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
try { fs.mkdirSync(path.join(this.$store.state.Settings.settings.testDirectory, 'Airports', this.icao[0], this.icao[1]), { recursive: true })} catch (err) { }
|
||||
try { fs.mkdirSync(path.join(this.$store.state.Settings.settings.testDirectory, 'Airports', this.icao[0], this.icao[1], this.icao[2]), { recursive: true })} catch (err) { }
|
||||
|
||||
try {
|
||||
fs.copyFileSync(f, fNew)
|
||||
this.$message({
|
||||
type: 'info',
|
||||
message: `Copied to ${fNew}`
|
||||
});
|
||||
} catch (error) {
|
||||
this.$message({
|
||||
type: 'error',
|
||||
message: `Copy error : ${error}`
|
||||
});
|
||||
}
|
||||
},
|
||||
setVisible(visible) {
|
||||
if (this.layerGroup) {
|
||||
|
@ -1,13 +1,11 @@
|
||||
<template>
|
||||
<label class="file-select">
|
||||
<div class="select-button">
|
||||
<span v-if="value">Selected File: {{value.name}}</span>
|
||||
<span v-else>Select File</span>
|
||||
...
|
||||
</div>
|
||||
<input type="file" @change="handleFileChange"/>
|
||||
</label>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
|
@ -28,10 +28,8 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
</l-control>
|
||||
-->
|
||||
<!--<l-marker :lat-lng="marker"></l-marker>-->
|
||||
<LeafletSidebar ref="sidebar" @edit="onEditSidebar"></LeafletSidebar>
|
||||
<LeafletSidebar ref="sidebar" @editParking="onEditSidebar" @edit="onEdit($event)"></LeafletSidebar>
|
||||
<AiLayer ref="aiLayer"></AiLayer>
|
||||
<PavementLayer ref="pavementLayer"></PavementLayer>
|
||||
<ThresholdLayer ref="thresholdLayer"></ThresholdLayer>
|
||||
<l-layer-group layerType="overlay" name="airports" ref="airportLayer">
|
||||
<l-circle
|
||||
v-for="(item, index) in this.$store.state.Airports.airports"
|
||||
@ -44,31 +42,36 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
></l-circle>
|
||||
</l-layer-group>
|
||||
<EditLayer ref="editLayer"></EditLayer>
|
||||
<PavementLayer ref="pavementLayer"></PavementLayer>
|
||||
<ThresholdLayer ref="thresholdLayer"></ThresholdLayer>
|
||||
<TowerLayer ref="towerLayer"></TowerLayer>
|
||||
<ToolLayer ref="toolLayer" @select-poly="onSelectedPolygon"></ToolLayer>
|
||||
<EditBar ref="editBar" @edit="onEdit"></EditBar>
|
||||
<EditBar ref="editBar" @edit="onEdit($event)"></EditBar>
|
||||
<ToolBar ref="toolBar"></ToolBar>
|
||||
</l-map>
|
||||
</template>
|
||||
|
||||
<script lang="js">
|
||||
import 'leaflet/dist/leaflet.css'
|
||||
import 'leaflet-search/dist/leaflet-search.src.css'
|
||||
import '@/assets/button.css'
|
||||
import { LMap, LTileLayer, LMarker, LCircle, LLayerGroup, LControl } from 'vue2-leaflet'
|
||||
import { LMap, LTileLayer, LMarker, LCircle, LLayerGroup, LControl, LTooltip } from 'vue2-leaflet'
|
||||
import LeafletSidebar from './LeafletSidebar'
|
||||
import AiLayer from './AiLayer'
|
||||
import EditBar from './EditBar'
|
||||
import ToolBar from './ToolBar'
|
||||
import EditLayer from './EditLayer'
|
||||
import ToolLayer from './ToolLayer'
|
||||
import TowerLayer from './TowerLayer'
|
||||
import PavementLayer from './PavementLayer'
|
||||
import ThresholdLayer from './ThresholdLayer'
|
||||
|
||||
import { Loading } from 'element-ui'
|
||||
import L from 'leaflet'
|
||||
import { LeafletSearch } from 'leaflet-search'
|
||||
|
||||
// https://github.com/KoRiGaN/Vue2Leaflet/issues/103
|
||||
delete L.Icon.Default.prototype._getIconUrl
|
||||
|
||||
L.Icon.Default.mergeOptions({
|
||||
iconRetinaUrl: require('leaflet/dist/images/marker-icon-2x.png'),
|
||||
iconUrl: require('leaflet/dist/images/marker-icon.png'),
|
||||
@ -76,8 +79,76 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
})
|
||||
export default {
|
||||
name: 'flightgear-map',
|
||||
components: { LMap, LTileLayer, LMarker, LCircle, LeafletSidebar, AiLayer, EditBar, ToolBar, EditLayer, PavementLayer, LLayerGroup, LControl, ThresholdLayer, ToolLayer },
|
||||
components: { LMap, LTileLayer, LMarker, LCircle, LTooltip, LeafletSidebar, AiLayer, EditBar, ToolBar, EditLayer, TowerLayer, PavementLayer, LLayerGroup, LControl, ThresholdLayer, ToolLayer, LeafletSearch },
|
||||
props: [],
|
||||
created () {
|
||||
this.loadingInstance = null
|
||||
this.$store.watch(
|
||||
function (state) {
|
||||
return state.Loading.icao
|
||||
},
|
||||
(newValue, oldValue) => {
|
||||
// debugger
|
||||
console.log('setIcaoLoading ' + oldValue + ' => ' + newValue + ' groundnetLoaded ' + this.groundnetLoaded + ' pavementLoaded ' + this.pavementLoaded + ' ' + this.loadingInstance)
|
||||
if (newValue !== oldValue && newValue !== '') {
|
||||
this.groundnetLoaded = newValue
|
||||
if ((this.loadingInstance === null || this.loadingInstance === undefined)) {
|
||||
this.loadingInstance = Loading.service({ fullscreen: false })
|
||||
}
|
||||
}
|
||||
}
|
||||
,
|
||||
{
|
||||
deep: false,
|
||||
immediate: true
|
||||
}
|
||||
)
|
||||
this.$store.watch(
|
||||
function (state) {
|
||||
return state.Loading.groundnetLoaded
|
||||
},
|
||||
(newValue, oldValue) => {
|
||||
// debugger
|
||||
console.log('groundnetLoaded ' + oldValue + ' => ' + newValue + ' groundnetLoaded ' + this.groundnetLoaded + ' pavementLoaded ' + this.pavementLoaded + ' ' + this.loadingInstance)
|
||||
if (newValue !== oldValue) {
|
||||
this.groundnetLoaded = newValue
|
||||
if (this.groundnetLoaded &&
|
||||
this.pavementLoaded &&
|
||||
this.loadingInstance !== null) {
|
||||
this.loadingInstance.close()
|
||||
this.loadingInstance = null
|
||||
}
|
||||
}
|
||||
}
|
||||
,
|
||||
{
|
||||
deep: false,
|
||||
immediate: true
|
||||
}
|
||||
)
|
||||
this.$store.watch(
|
||||
function (state) {
|
||||
return state.Loading.pavementLoaded
|
||||
},
|
||||
(newValue, oldValue) => {
|
||||
console.log('pavementLoaded ' + oldValue + ' => ' + newValue + ' ' + this.groundnetLoaded + ' ' + this.pavementLoaded + ' ' + this.loadingInstance)
|
||||
if (newValue !== oldValue) {
|
||||
this.pavementLoaded = newValue
|
||||
if (this.groundnetLoaded &&
|
||||
this.pavementLoaded &&
|
||||
this.loadingInstance !== null) {
|
||||
this.loadingInstance.close()
|
||||
this.loadingInstance = null
|
||||
}
|
||||
}
|
||||
}
|
||||
,
|
||||
{
|
||||
deep: false,
|
||||
immediate: true
|
||||
}
|
||||
)
|
||||
},
|
||||
mounted () {
|
||||
this.$store.dispatch('getAirports')
|
||||
this.$store.subscribe((mutation, state) => {
|
||||
@ -88,13 +159,14 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
.filter(feature => this.visible(feature))
|
||||
.map(feature => feature.properties.icao)
|
||||
if (airportsToLoad.length > 0 && airportsToLoad[0] !== this.editingAirport && this.zoom > 12) {
|
||||
let loadingInstance = Loading.service({ fullscreen: true })
|
||||
|
||||
this.$store.dispatch('setIcaoLoading', airportsToLoad[0])
|
||||
this.$nextTick(() => { // Loading should be closed asynchronously
|
||||
this.$refs.pavementLayer.load(airportsToLoad[0])
|
||||
this.$refs.editLayer.load(airportsToLoad[0])
|
||||
this.$refs.thresholdLayer.load(airportsToLoad[0])
|
||||
loadingInstance.close()
|
||||
if (this.$refs.towerLayer) {
|
||||
this.$refs.towerLayer.load(airportsToLoad[0])
|
||||
}
|
||||
this.editingAirport = airportsToLoad[0]
|
||||
})
|
||||
}
|
||||
@ -104,13 +176,15 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
if (this.$refs.airportLayer) {
|
||||
this.$refs.airportLayer.setVisible(this.zoom < 12)
|
||||
}
|
||||
|
||||
// console.log(this.groundnet)
|
||||
}
|
||||
})
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
loadingInstance: Object,
|
||||
groundnetLoaded: false,
|
||||
pavementLoaded: false,
|
||||
url: 'https://a.tile.openstreetmap.de/{z}/{x}/{y}.png',
|
||||
attribution: '<A href="https://github.com/Portree-Kid/flightgear-airports" target="_blank">Flightgear Airports ' + require('electron').remote.app.getVersion() +
|
||||
'</A> <A href="https://www.electronjs.org/" target="_blank">Electron</A> ' +
|
||||
@ -124,7 +198,6 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
},
|
||||
methods: {
|
||||
ready (e) {
|
||||
console.log(e)
|
||||
e.on('layeradd', this.onLayerAdd)
|
||||
},
|
||||
onLayerAdd (e) {
|
||||
@ -140,15 +213,45 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
if (this.$refs.pavementLayer.getLayer() === e.layer) {
|
||||
// debugger
|
||||
var l = this.layersControl._layers.filter(l => l.name === 'APT Layer')
|
||||
if (l.length > 0 && l[0].layer !== this.$refs.pavementLayer.getLayer()) {
|
||||
this.layersControl.removeLayer(l[0].layer)
|
||||
this.layersControl.addOverlay(this.$refs.pavementLayer.getLayer(), 'APT Layer')
|
||||
}
|
||||
if (l.length === 0) {
|
||||
this.layersControl.addOverlay(this.$refs.pavementLayer.getLayer(), 'APT Layer')
|
||||
}
|
||||
}
|
||||
if (this.$refs.thresholdLayer.getLayer() === e.layer) {
|
||||
if (this.$refs.thresholdLayer !== undefined && this.$refs.thresholdLayer.getLayer() === e.layer) {
|
||||
l = this.layersControl._layers.filter(l => l.name === 'Threshold Layer')
|
||||
if (l.length > 0 && l[0].layer !== this.$refs.thresholdLayer.getLayer()) {
|
||||
this.layersControl.removeLayer(l[0].layer)
|
||||
this.layersControl.addOverlay(this.$refs.thresholdLayer.getLayer(), 'Threshold Layer')
|
||||
}
|
||||
if (l.length === 0) {
|
||||
this.layersControl.addOverlay(this.$refs.thresholdLayer.getLayer(), 'Threshold Layer')
|
||||
}
|
||||
this.$refs.thresholdLayer.zoomUpdated()
|
||||
}
|
||||
if (this.$refs.towerLayer !== undefined && this.$refs.towerLayer.getLayer() === e.layer) {
|
||||
l = this.layersControl._layers.filter(l => l.name === 'Tower Layer')
|
||||
if (l.length > 0 && l[0].layer !== this.$refs.towerLayer.getLayer()) {
|
||||
this.layersControl.removeLayer(l[0].layer)
|
||||
this.layersControl.addOverlay(this.$refs.towerLayer.getLayer(), 'Tower Layer')
|
||||
}
|
||||
if (l.length === 0) {
|
||||
this.layersControl.addOverlay(this.$refs.towerLayer.getLayer(), 'Tower Layer')
|
||||
}
|
||||
this.$refs.towerLayer.zoomUpdated()
|
||||
}
|
||||
if (this.$refs.editLayer !== undefined && this.searchControl === undefined && this.$refs.editLayer.getLayer() === e.layer) {
|
||||
this.searchControl = new L.Control.Search({
|
||||
layer: this.$refs.editLayer.getLayer(),
|
||||
position: 'topleft',
|
||||
propertyName: 'searchTerm',
|
||||
marker: {animate: false},
|
||||
initial: false
|
||||
})
|
||||
this.searchControl.addTo(this.$refs.map.mapObject)
|
||||
}
|
||||
},
|
||||
onSelectedPolygon (ring) {
|
||||
@ -160,10 +263,17 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
this.$refs.sidebar.setData(parkings)
|
||||
},
|
||||
onEdit (event) {
|
||||
if (event) {
|
||||
this.$refs.map.mapObject.options.minZoom = 13
|
||||
} else {
|
||||
this.$refs.map.mapObject.options.minZoom = 1
|
||||
}
|
||||
this.$refs.editLayer.enableEdit()
|
||||
this.$refs.toolBar.setEdit(this.$refs.editBar.isEditing)
|
||||
this.$refs.sidebar.setEditing(this.$refs.editBar.isEditing)
|
||||
this.$refs.towerLayer.enableEdit()
|
||||
this.$refs.thresholdLayer.enableEdit()
|
||||
this.$refs.editBar.setEditing(event)
|
||||
this.$refs.toolBar.setEditing(event)
|
||||
this.$refs.sidebar.setEditing(event)
|
||||
},
|
||||
onEditSidebar (event) {
|
||||
this.$refs.editLayer.onEdit(event)
|
||||
@ -226,6 +336,7 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
event.target.airport = item
|
||||
// console.log(event, item)
|
||||
this.normalStyle(event.target)
|
||||
event.target.bindTooltip(event.target.airport.properties.icao + ' ' + event.target.airport.properties.name)
|
||||
},
|
||||
onClick (event, item) {
|
||||
console.log(item)
|
||||
@ -244,13 +355,38 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
if (zoom !== this.$store.state.Settings.zoom) {
|
||||
this.$store.dispatch('setZoom', zoom)
|
||||
this.$refs.airportLayer.setVisible(zoom < 12)
|
||||
if (this.$refs.towerLayer) {
|
||||
this.$refs.towerLayer.setVisible(this.zoom >= 12)
|
||||
}
|
||||
if (this.$refs.thresholdLayer) {
|
||||
this.$refs.thresholdLayer.setVisible(this.zoom >= 12)
|
||||
}
|
||||
this.$refs.pavementLayer.setVisible(zoom >= 12)
|
||||
}
|
||||
if (this.$refs.editLayer.groundnetLayerGroup) {
|
||||
this.$refs.editLayer.groundnetLayerGroup.eachLayer(function (layer) {
|
||||
if (layer.updateArrows !== undefined) {
|
||||
layer.updateArrows(zoom)
|
||||
}
|
||||
})
|
||||
}
|
||||
if (this.$refs.thresholdLayer) {
|
||||
this.$refs.thresholdLayer.zoomUpdated()
|
||||
}
|
||||
if (this.$refs.towerLayer) {
|
||||
this.$refs.towerLayer.zoomUpdated()
|
||||
}
|
||||
},
|
||||
async centerUpdated (center) {
|
||||
if (center !== this.$store.state.Settings.center) {
|
||||
this.$store.dispatch('setCenter', center)
|
||||
this.$store.dispatch('setCenter', {lat: Number(center.lat), lng: Number(center.lng)})
|
||||
this.$refs.airportLayer.setVisible(this.zoom < 12)
|
||||
if (this.$refs.thresholdLayer) {
|
||||
this.$refs.thresholdLayer.setVisible(this.zoom >= 12)
|
||||
}
|
||||
if (this.$refs.towerLayer) {
|
||||
this.$refs.towerLayer.setVisible(this.zoom >= 12)
|
||||
}
|
||||
this.$refs.pavementLayer.setVisible(this.zoom >= 12)
|
||||
}
|
||||
},
|
||||
|
@ -1,7 +1,18 @@
|
||||
<!--
|
||||
Copyright 2020 Keith Paterson
|
||||
|
||||
This file is part of FG Airports.
|
||||
|
||||
FG Airports is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
FG Airports is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with FG Airports. If not, see http://www.gnu.org/licenses/.
|
||||
-->
|
||||
<template>
|
||||
<div class="leaflet-sidebar-pane" id="home">
|
||||
<h1 class="leaflet-sidebar-header">
|
||||
Help
|
||||
{{version}}
|
||||
<div class="leaflet-sidebar-close"><i class="fa fa-caret-left"></i></div>
|
||||
</h1>
|
||||
<h2>Setup</h2>
|
||||
@ -15,22 +26,20 @@
|
||||
<h2>World view</h2>
|
||||
<p>
|
||||
When zoomed out you will see circles. Their size corresponds with the number of flights.
|
||||
Blue means Ok. Yellow to little parking. Red no groundnet.
|
||||
Blue means Ok. Yellow to little parking in comparison to the number of flights. Red no groundnet.
|
||||
</p>
|
||||
<h2>Edit view</h2>
|
||||
<p>
|
||||
</p>
|
||||
<ul>
|
||||
<li>Button with ICAO code opens the Airport data in the edit tab.</li>
|
||||
<li>The top 4 buttons in the button bar are for zooming. </li>
|
||||
<li>Upload sends the current airport to groundweb.</li>
|
||||
<li>Edit switches into edit mode</li>
|
||||
<li>Undo undos all changes or all changes during session</li>
|
||||
<li>Save, saves the groundnet</li>
|
||||
<li>Draw taxiline</li>
|
||||
<li>Check triggers the groundnet check.</li>
|
||||
<li>Draw bi directional taxiline</li>
|
||||
<li>Draw uni directional taxiline</li>
|
||||
<li>Draw pushback.</li>
|
||||
<li>Add parking</li>
|
||||
<li>Remove element, removes the currently selected element</li>
|
||||
<li>Check triggers the groundnet check.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
@ -51,7 +60,9 @@
|
||||
|
||||
},
|
||||
computed: {
|
||||
|
||||
version: function () {
|
||||
return ' Flightgear Airports ' + require('electron').remote.app.getVersion()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -11,6 +11,7 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
-->
|
||||
<template>
|
||||
<div id="sidebar" class="leaflet-sidebar collapsed">
|
||||
<Upload :visible.sync="uploadVisible" ref="upload"></Upload>
|
||||
<!-- Nav tabs -->
|
||||
<div class="leaflet-sidebar-tabs">
|
||||
<ul role="tablist"> <!-- top aligned tabs -->
|
||||
@ -37,10 +38,13 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
<div class="leaflet-sidebar-close"><i class="fa fa-caret-left"></i></div>
|
||||
</h1>
|
||||
<ParkingEdit></ParkingEdit>
|
||||
<ArcEditMulti></ArcEditMulti>
|
||||
<ArcEdit></ArcEdit>
|
||||
<ThresholdEdit></ThresholdEdit>
|
||||
<TowerEdit></TowerEdit>
|
||||
<NodeEdit></NodeEdit>
|
||||
<ParkingGroupEdit ref="parkingGroupEdit" @edit="(msg) => $emit('edit', msg)"></ParkingGroupEdit>
|
||||
<AirportEdit ref="airportEdit"></AirportEdit>
|
||||
<ParkingGroupEdit ref="parkingGroupEdit" @editParking="(msg) => $emit('editParking', msg)"></ParkingGroupEdit>
|
||||
<AirportEdit ref="airportEdit" @edit="$emit('edit', $event)"></AirportEdit>
|
||||
</div>
|
||||
<!--
|
||||
<div class="leaflet-sidebar-pane" id="parking">
|
||||
@ -73,22 +77,32 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
import L from 'leaflet'
|
||||
import AirportEdit from './AirportEdit'
|
||||
import ArcEdit from './ArcEdit'
|
||||
import TowerEdit from './TowerEdit'
|
||||
import ArcEditMulti from './ArcEditMulti'
|
||||
import CheckPanel from './CheckPanel'
|
||||
import FileSelect from './FileSelect'
|
||||
import Help from './Help'
|
||||
import NodeEdit from './NodeEdit'
|
||||
import ThresholdEdit from './ThresholdEdit'
|
||||
import ParkingEdit from './ParkingEdit'
|
||||
import ParkingGroupEdit from './ParkingGroupEdit'
|
||||
// import ParkingList from './ParkingList'
|
||||
import RunScan from './RunScan'
|
||||
import SettingsPanel from './SettingsPanel'
|
||||
import Search from './Search'
|
||||
import Upload from './Upload'
|
||||
import WorkInProgress from './WorkInProgress'
|
||||
|
||||
export default {
|
||||
name: 'leaflet-sidebar',
|
||||
components: { Help, AirportEdit, ArcEdit, CheckPanel, NodeEdit, ParkingEdit, ParkingGroupEdit, RunScan, FileSelect, SettingsPanel, Search, WorkInProgress },
|
||||
components: { Help, AirportEdit, ArcEdit, ArcEditMulti, CheckPanel, NodeEdit, ParkingEdit, ParkingGroupEdit, RunScan, TowerEdit, ThresholdEdit, FileSelect, SettingsPanel, Search, Upload, WorkInProgress },
|
||||
props: [],
|
||||
created () {
|
||||
window.addEventListener('keydown', this.doCommand)
|
||||
},
|
||||
destroyed () {
|
||||
window.removeEventListener('keydown', this.doCommand)
|
||||
},
|
||||
mounted () {
|
||||
this.add()
|
||||
},
|
||||
@ -96,10 +110,17 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
this.remove()
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
return { uploadVisible: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
doCommand (e) {
|
||||
let cmd = String.fromCharCode(e.keyCode).toLowerCase()
|
||||
if (e.keyCode === 46 /** DEL */ && e.target.type !== 'text') {
|
||||
this.$parent.$parent.$refs.editLayer.deleteFeature()
|
||||
}
|
||||
console.log(cmd)
|
||||
},
|
||||
deferredMountedTo (parent) {
|
||||
this.sidebar = L.control.sidebar({
|
||||
autopan: false, // whether to maintain the centered map point when opening the sidebar
|
||||
|
@ -36,7 +36,17 @@
|
||||
</el-select>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row><el-button @click="link"><i class="fas fa-link"></i></el-button></el-row>
|
||||
<el-row>
|
||||
<el-popover
|
||||
placement="top-start"
|
||||
title="Goto"
|
||||
width="200"
|
||||
trigger="hover"
|
||||
content="Weld/Link nodes"
|
||||
>
|
||||
<el-button @click="link" slot="reference"><i class="fas fa-link"></i></el-button>
|
||||
</el-popover>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -16,13 +16,21 @@
|
||||
<span class="label">Name :</span>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-input placeholder="Name" v-model="name" :disabled="!editing"></el-input>
|
||||
<el-input
|
||||
placeholder="Name"
|
||||
v-model="name"
|
||||
:disabled="!editing"
|
||||
></el-input>
|
||||
</el-col>
|
||||
<el-col :span="5">
|
||||
<span class="label">Number :</span>
|
||||
</el-col>
|
||||
<el-col :span="7">
|
||||
<el-input placeholder="Number" v-model="number" :disabled="!editing"></el-input>
|
||||
<el-input
|
||||
placeholder="Number"
|
||||
v-model="number"
|
||||
:disabled="!editing"
|
||||
></el-input>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
@ -40,7 +48,11 @@
|
||||
-->
|
||||
|
||||
<el-radio-group v-model="wingspan" :disabled="!editing">
|
||||
<el-tooltip content="PIPER PA-31/CESSNA 404 Titan" placement="top" effect="light">
|
||||
<el-tooltip
|
||||
content="PIPER PA-31/CESSNA 404 Titan"
|
||||
placement="top"
|
||||
effect="light"
|
||||
>
|
||||
<el-radio :label="15">A (7.5)</el-radio>
|
||||
</el-tooltip>
|
||||
<el-tooltip
|
||||
@ -64,13 +76,25 @@
|
||||
>
|
||||
<el-radio :label="36">C (18)</el-radio>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="B767 Series/AIRBUS A-310" placement="top" effect="light">
|
||||
<el-radio :label="52">D (27)</el-radio>
|
||||
<el-tooltip
|
||||
content="B767 Series/AIRBUS A-310"
|
||||
placement="top"
|
||||
effect="light"
|
||||
>
|
||||
<el-radio :label="52">D (26)</el-radio>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="B777 Series/B787 Series/A330 Family" placement="top" effect="light">
|
||||
<el-tooltip
|
||||
content="B777 Series/B787 Series/A330 Family"
|
||||
placement="top"
|
||||
effect="light"
|
||||
>
|
||||
<el-radio :label="66">E (33)</el-radio>
|
||||
</el-tooltip>
|
||||
<el-tooltip content="BOEING 747-8/AIRBUS A-380-800" placement="top" effect="light">
|
||||
<el-tooltip
|
||||
content="BOEING 747-8/AIRBUS A-380-800"
|
||||
placement="top"
|
||||
effect="light"
|
||||
>
|
||||
<el-radio :label="80">F (40)</el-radio>
|
||||
</el-tooltip>
|
||||
</el-radio-group>
|
||||
@ -80,7 +104,18 @@
|
||||
<el-col :span="7">
|
||||
<span class="label">Aircraft :</span>
|
||||
</el-col>
|
||||
<el-col :span="17">{{type}}</el-col>
|
||||
<el-col :span="17">{{ type }}</el-col>
|
||||
</el-row>
|
||||
<el-row v-if="editing">
|
||||
<el-col :span="7">
|
||||
<span class="label">Calculate :</span>
|
||||
</el-col>
|
||||
<el-col :span="17">
|
||||
<el-radio-group v-model="calculate" size="small">
|
||||
<el-radio-button label="Nose Wheel"></el-radio-button>
|
||||
<el-radio-button label="Center"></el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="7">
|
||||
@ -88,17 +123,24 @@
|
||||
</el-col>
|
||||
<el-col :span="17">
|
||||
<el-popover
|
||||
placement="top-start"
|
||||
placement="bottom-start"
|
||||
title="E-Mail"
|
||||
width="200"
|
||||
trigger="hover"
|
||||
content="D.DDD, DMS, DM supported"
|
||||
:disabled="!editing || calculate === 'Center'"
|
||||
>
|
||||
<el-input placeholder="Please input" v-model="coordinates" slot="reference" :disabled="!editing"></el-input>
|
||||
<el-input
|
||||
placeholder="Please input"
|
||||
v-model="coordinates"
|
||||
slot="reference"
|
||||
:disabled="!editing || calculate === 'Center'"
|
||||
@focus="coordFocussed = true"
|
||||
@blur="coordFocussed = false"
|
||||
></el-input>
|
||||
</el-popover>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<!--
|
||||
<el-row>
|
||||
<el-col :span="7">
|
||||
<span class="label">Nosewheel Coordinates :</span>
|
||||
@ -110,33 +152,50 @@
|
||||
width="200"
|
||||
trigger="hover"
|
||||
content="D.DDD, DMS, DM supported"
|
||||
:disabled="!editing || calculate === 'Nose Wheel'"
|
||||
>
|
||||
<el-input placeholder="Please input" v-model="coordinates" slot="reference" :disabled="!editing"></el-input>
|
||||
<el-input
|
||||
placeholder="Please input"
|
||||
v-model="noseCoordinates"
|
||||
slot="reference"
|
||||
:disabled="!editing || calculate === 'Nose Wheel'"
|
||||
@focus="noseCoordFocussed = true"
|
||||
@blur="noseCoordFocussed = false"
|
||||
></el-input>
|
||||
</el-popover>
|
||||
</el-col>
|
||||
</el-row>
|
||||
-->
|
||||
<el-row>
|
||||
<el-col :span="7">
|
||||
<span class="label">Heading :</span>
|
||||
</el-col>
|
||||
<el-col :span="17">
|
||||
<el-col :span="13">
|
||||
<el-input-number
|
||||
v-model="heading"
|
||||
:min="-361"
|
||||
:max="720"
|
||||
:step="0.1"
|
||||
:precision="1"
|
||||
:disabled="!editing"
|
||||
:disabled="!editing || calculate === 'Heading'"
|
||||
@change="headingChange"
|
||||
></el-input-number>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-button @click="rotate" class="button">
|
||||
<i class="fas fa-ruler-combined"></i>
|
||||
</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="7">
|
||||
<span class="label">Parking Type :</span>
|
||||
</el-col>
|
||||
<el-col :span="17">
|
||||
<el-select v-model="parking_type" placeholder="Select" :disabled="!editing">
|
||||
<el-select
|
||||
v-model="parking_type"
|
||||
placeholder="Select"
|
||||
:disabled="!editing"
|
||||
>
|
||||
<el-option
|
||||
v-for="type in options"
|
||||
:key="type.value"
|
||||
@ -152,7 +211,12 @@
|
||||
<span class="label">Airline :</span>
|
||||
</el-col>
|
||||
<el-col :span="17">
|
||||
<el-select v-model="airlineCodes" multiple placeholder="Select" :disabled="!editing">
|
||||
<el-select
|
||||
v-model="airlineCodes"
|
||||
multiple
|
||||
placeholder="Select"
|
||||
:disabled="!editing"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in airlines"
|
||||
:key="item.value"
|
||||
@ -166,7 +230,7 @@
|
||||
<el-col :span="7">
|
||||
<span class="label">Pushback Route End :</span>
|
||||
</el-col>
|
||||
<el-col :span="17">{{pushbackEnd}}</el-col>
|
||||
<el-col :span="17">{{ pushbackEnd }}</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
@ -174,14 +238,114 @@
|
||||
<script lang="js">
|
||||
/* eslint-disable */
|
||||
const convert = require('geo-coordinates-parser');
|
||||
const Coordinates = require('coordinate-parser');
|
||||
|
||||
const turf = require('@turf/turf');
|
||||
|
||||
const turfOptions = { units: 'kilometers' };
|
||||
|
||||
export default {
|
||||
mounted() {
|
||||
this.$store.watch(
|
||||
function (state) {
|
||||
return state.Editable.data.parking;
|
||||
},
|
||||
() => { this.editedParking() }
|
||||
,
|
||||
{
|
||||
deep: true //add this if u need to watch object properties change etc.
|
||||
}
|
||||
);
|
||||
},
|
||||
methods: {
|
||||
show (idx) {
|
||||
this.$parent.$parent.$parent.$refs.editLayer.show(idx)
|
||||
editedParking() {
|
||||
this.externalChange = true
|
||||
this.heading = Number(this.$store.state.Editable.data.parking.heading);
|
||||
this.externalChange = false
|
||||
},
|
||||
rotate() {
|
||||
var heading = this.$store.state.Editable.data.parking.heading + 90;
|
||||
while (heading>=360) {
|
||||
heading -= 360
|
||||
}
|
||||
while (heading<0) {
|
||||
heading += 360
|
||||
}
|
||||
this.headingChange(heading);
|
||||
},
|
||||
headingChange( newValue ) {
|
||||
while (newValue>=360) {
|
||||
newValue -= 360
|
||||
}
|
||||
while (newValue<0) {
|
||||
newValue += 360
|
||||
}
|
||||
if ( ( Math.abs( this.$store.state.Editable.data.parking.heading - newValue ) >= 0 && Math.abs( this.$store.state.Editable.data.parking.heading - newValue ) <= 0.1 )
|
||||
|| !this.externalChange) {
|
||||
if (Number(this.$store.state.Editable.data.parking.heading) !== newValue) {
|
||||
this.$store.commit('SET_EDIT_PARKING_HEADING', newValue)
|
||||
}
|
||||
if(this.calculate === 'Center') {
|
||||
// we change center
|
||||
const noseWheelLatLng = convert(this.$store.state.Editable.data.parking.nosecoords);
|
||||
const parkingSize = this.validRadii.indexOf(this.$store.state.Editable.data.parking.radius);
|
||||
if (parkingSize>=0) {
|
||||
var reverseHeading = this.normalizeAngle(this.$store.state.Editable.data.parking.heading+180);
|
||||
var newCenter = turf.destination(this.latToTurf(noseWheelLatLng), this.validN2M[parkingSize]/1000, reverseHeading, turfOptions);
|
||||
this.$store.commit('SET_EDIT_PARKING_COORDS', this.turfToLatLng(newCenter));
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
show (idx) {
|
||||
this.$parent.$parent.$parent.$refs.editLayer.show(idx)
|
||||
},
|
||||
normalizeAngle( angle ) {
|
||||
if(angle >= 180) {
|
||||
return angle - 360;
|
||||
}
|
||||
if(angle <= -180) {
|
||||
return angle + 360;
|
||||
}
|
||||
return angle;
|
||||
},
|
||||
latToTurf (turfPoint) {
|
||||
return [turfPoint.decimalLongitude, turfPoint.decimalLatitude];
|
||||
},
|
||||
turfToLatLng (turfPoint) {
|
||||
return '' + turfPoint.geometry.coordinates[1].toFixed(6) + ',' + turfPoint.geometry.coordinates[0].toFixed(6);
|
||||
},
|
||||
beautify (coordString) {
|
||||
var a = coordString.split(' ');
|
||||
if (a.length === 2) {
|
||||
return '' + Number(a[0]).toFixed(6) + ' ' + Number(a[1]).toFixed(6);
|
||||
} else {
|
||||
return coordString;
|
||||
}
|
||||
},
|
||||
calcWheel () {
|
||||
if(this.calculate === 'Nose Wheel') {
|
||||
// we change nosewheel
|
||||
const centerLatLng = convert(this.beautify(this.$store.state.Editable.data.parking.coords));
|
||||
const parkingSize = this.validRadii.indexOf(this.$store.state.Editable.data.parking.radius);
|
||||
if (parkingSize>=0) {
|
||||
var newNoseWheel = turf.destination(this.latToTurf(centerLatLng), this.validN2M[parkingSize]/1000, this.$store.state.Editable.data.parking.heading, turfOptions);
|
||||
this.$store.commit('SET_EDIT_PARKING_NOSE_COORDS', this.turfToLatLng(newNoseWheel));
|
||||
}
|
||||
}
|
||||
},
|
||||
calcCenter () {
|
||||
if (this.calculate === 'Center') {
|
||||
// we change center
|
||||
const noseWheelLatLng = convert(this.beautify(this.$store.state.Editable.data.parking.nosecoords));
|
||||
const parkingSize = this.validRadii.indexOf(this.$store.state.Editable.data.parking.radius);
|
||||
if (parkingSize>=0) {
|
||||
var newCenter = turf.destination(this.latToTurf(noseWheelLatLng), this.validN2M[parkingSize]/1000, this.$store.state.Editable.data.parking.heading - 180, turfOptions);
|
||||
this.$store.commit('SET_EDIT_PARKING_COORDS', this.turfToLatLng(newCenter));
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
data () { return {rotateFocussed: false, externalChange: false, coordFocussed: false, noseCoordFocussed: false, calculateState: 'Nose Wheel', noseWheel: '', validRadii: [7.5, 10, 14, 18, 26, 33, 40], validN2M: [5, 5, 6, 10, 15, 24, 24], heading: 0 }},
|
||||
computed: {
|
||||
editing: {
|
||||
get: function () {
|
||||
@ -211,7 +375,7 @@
|
||||
var codes = this.$store.state.Editable.data.parking.airlineCodes
|
||||
if (Array.isArray(codes)) {
|
||||
return codes
|
||||
} else if (codes !== undefined) {
|
||||
} else if (codes !== undefined && typeof codes === 'string') {
|
||||
return codes.split(',')
|
||||
} else {
|
||||
return []
|
||||
@ -243,6 +407,19 @@
|
||||
this.$store.commit('SET_EDIT_PARKING_NUMBER', newValue)
|
||||
}
|
||||
},
|
||||
calculate: {
|
||||
get: function () {
|
||||
return this.calculateState;
|
||||
},
|
||||
set: function (newValue) {
|
||||
this.calculateState = newValue;
|
||||
if (newValue==='Center') {
|
||||
this.calcCenter();
|
||||
} else {
|
||||
this.calcWheel();
|
||||
}
|
||||
}
|
||||
},
|
||||
coordinates: {
|
||||
// getter
|
||||
get: function () {
|
||||
@ -258,25 +435,34 @@
|
||||
if( newValue.match(/,/g) !== null && newValue.match(/,/g).length === 3) {
|
||||
newValue = newValue.replace(', ', ' ').replace(/,/g, '.').replace(' ', ', ');
|
||||
}
|
||||
if (this.coordFocussed) {
|
||||
this.$store.commit('SET_EDIT_PARKING_COORDS', newValue)
|
||||
}
|
||||
this.calcWheel();
|
||||
}
|
||||
},
|
||||
heading: {
|
||||
noseCoordinates: {
|
||||
// getter
|
||||
get: function () {
|
||||
return Number(this.$store.state.Editable.data.parking.heading)
|
||||
if(this.$store.state.Editable.index!==undefined) {
|
||||
if(!this.$store.state.Editable.data.parking.nosecoords && this.calculate === 'Nose Wheel') {
|
||||
this.calcWheel();
|
||||
}
|
||||
return this.$store.state.Editable.data.parking.nosecoords;
|
||||
}
|
||||
},
|
||||
// setter
|
||||
set: function (newValue) {
|
||||
while (newValue>=360) {
|
||||
newValue -= 360
|
||||
if (newValue==='unknown') {
|
||||
|
||||
}
|
||||
while (newValue<0) {
|
||||
newValue += 360
|
||||
if( newValue.match(/,/g) !== null && newValue.match(/,/g).length === 3) {
|
||||
newValue = newValue.replace(', ', ' ').replace(/,/g, '.').replace(' ', ', ');
|
||||
}
|
||||
if (Number(this.$store.state.Editable.data.parking.heading) !== newValue) {
|
||||
this.$store.commit('SET_EDIT_PARKING_HEADING', newValue)
|
||||
if (this.noseCoordFocussed) {
|
||||
this.$store.commit('SET_EDIT_PARKING_NOSE_COORDS', newValue);
|
||||
}
|
||||
this.calcCenter();
|
||||
}
|
||||
},
|
||||
wingspan: {
|
||||
|
@ -74,7 +74,7 @@
|
||||
<el-col :span="7">
|
||||
<span class="label">Heading :</span>
|
||||
</el-col>
|
||||
<el-col :span="17">
|
||||
<el-col :span="13">
|
||||
<el-input-number
|
||||
v-model="avgHeading" @change="headingChange"
|
||||
:min="-361"
|
||||
@ -84,14 +84,18 @@
|
||||
:disabled="!editing"
|
||||
></el-input-number>
|
||||
</el-col>
|
||||
<el-col :span="4">
|
||||
<el-button @click="rotate" class="button">
|
||||
<i class="fas fa-ruler-combined"></i>
|
||||
</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<!--
|
||||
<el-row>
|
||||
<el-col :span="7">
|
||||
<span class="label">Parking Type :</span>
|
||||
</el-col>
|
||||
<el-col :span="17">
|
||||
<el-select v-model="parking_type" placeholder="Select" :disabled="!editing">
|
||||
<el-select v-model="parking_type" @change="typeChange" placeholder="Select" :disabled="!editing">
|
||||
<el-option
|
||||
v-for="type in options"
|
||||
:key="type.value"
|
||||
@ -102,6 +106,7 @@
|
||||
</el-select>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<!--
|
||||
<el-row>
|
||||
<el-col :span="7">
|
||||
<span class="label">Airline :</span>
|
||||
@ -131,17 +136,28 @@ const convert = require('geo-coordinates-parser');
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
data: Object, avgHeading: 5, editing: Boolean, wingspan: 0
|
||||
data: Object, avgHeading: 5, editing: Boolean, wingspan: 0, parking_type: ''
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
rotate() {
|
||||
this.avgHeading = this.avgHeading + 90;
|
||||
while (this.avgHeading>=360) {
|
||||
this.avgHeading -= 360
|
||||
}
|
||||
while (this.avgHeading<0) {
|
||||
this.avgHeading += 360
|
||||
}
|
||||
this.headingChange(this.avgHeading);
|
||||
},
|
||||
show (idx) {
|
||||
this.$parent.$parent.$parent.$refs.editLayer.show(idx)
|
||||
},
|
||||
setData (data) {
|
||||
this.data = data;
|
||||
this.setAvgHeading();
|
||||
this.setAvgType();
|
||||
},
|
||||
setEditing(editing) {
|
||||
this.editing = editing
|
||||
@ -156,9 +172,20 @@ const convert = require('geo-coordinates-parser');
|
||||
return r;
|
||||
}, { sum: 0, count: 0, avg: 0 }).avg);
|
||||
},
|
||||
setAvgType() {
|
||||
if( this.data === null || this.data === undefined) {
|
||||
return 0
|
||||
}
|
||||
var types = this.data.map(parking => parking.options.attributes.type).filter((v, i, a) => a.indexOf(v) === i);
|
||||
if (types.length == 1) {
|
||||
this.parking_type = types[0];
|
||||
} else {
|
||||
this.parking_type = '';
|
||||
}
|
||||
},
|
||||
wingspanChange( newValue ) {
|
||||
if ( newValue ) {
|
||||
this.$emit('edit', {type: 'parking-group-wingspan', wingspan: newValue} )
|
||||
this.$emit('editParking', {type: 'parking-group-wingspan', wingspan: newValue} )
|
||||
}
|
||||
},
|
||||
headingChange( newValue ) {
|
||||
@ -169,7 +196,12 @@ const convert = require('geo-coordinates-parser');
|
||||
newValue += 360
|
||||
}
|
||||
if ( newValue ) {
|
||||
this.$emit('edit', {type: 'parking-group-angle', angle: newValue} )
|
||||
this.$emit('editParking', {type: 'parking-group-angle', angle: newValue} )
|
||||
}
|
||||
},
|
||||
typeChange( newValue ) {
|
||||
if ( newValue ) {
|
||||
this.$emit('editParking', {type: 'parking-group-type', parking_type: newValue} )
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -256,19 +288,6 @@ const convert = require('geo-coordinates-parser');
|
||||
{value: 'mil-fighter', label: 'military fighter'},
|
||||
{value: 'mil-cargo', label: 'military cargo'}
|
||||
]
|
||||
},
|
||||
parking_type: {
|
||||
// getter
|
||||
get: function () {
|
||||
if (this.$store.state.Editable.data.parking.type === undefined) {
|
||||
return 'none'
|
||||
}
|
||||
return this.$store.state.Editable.data.parking.type
|
||||
},
|
||||
// setter
|
||||
set: function (newValue) {
|
||||
this.$store.commit('SET_EDIT_PARKING_TYPE', newValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,17 @@
|
||||
<!--
|
||||
Copyright 2021 Keith Paterson
|
||||
|
||||
This file is part of FG Airports.
|
||||
|
||||
FG Airports is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
FG Airports is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with FG Airports. If not, see http://www.gnu.org/licenses/.
|
||||
-->
|
||||
<template>
|
||||
<div>
|
||||
<el-link v-if="!editing" type="primary" @click="show(parking.index)">{{parking.name}} {{number}} {{parking.type}}</el-link>
|
||||
<el-link v-if="!editing" type="primary" @click="show(parking.index)">{{parking.name}} {{number}} {{parking.type}} {{type}}</el-link>
|
||||
<el-input @focus="show(parking.index)" v-if="editing" placeholder="Name" v-model="name" class="wide"></el-input>
|
||||
<el-input @focus="show(parking.index)" v-if="editing" placeholder="Number" v-model="number" class="narrow"></el-input>
|
||||
<el-select @focus="show(parking.index)" v-if="editing" v-model="parking_type" placeholder="Select">
|
||||
@ -30,15 +41,19 @@
|
||||
if (this.editLayer === null) {
|
||||
this.initLayer()
|
||||
}
|
||||
if (this.editLayer) {
|
||||
return this.editLayer.show(idx)
|
||||
}
|
||||
},
|
||||
initLayer () {
|
||||
var parent = this.$parent
|
||||
while (parent.$refs.editLayer === undefined) {
|
||||
while (parent && !parent.$refs.editLayer) {
|
||||
parent = parent.$parent
|
||||
}
|
||||
if (parent) {
|
||||
this.editLayer = parent.$refs.editLayer
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
options: function () {
|
||||
@ -69,7 +84,11 @@
|
||||
number: {
|
||||
// getter
|
||||
get: function () {
|
||||
if (this.parking.number && this.parking.number !== 'undefined') {
|
||||
return this.parking.number
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
},
|
||||
// setter
|
||||
set: function (newValue) {
|
||||
@ -88,8 +107,36 @@
|
||||
set: function (newValue) {
|
||||
this.$store.commit('SET_EDIT_PARKING_ITEM_TYPE', [this.parking.index, newValue])
|
||||
}
|
||||
}
|
||||
},
|
||||
type: function () {
|
||||
/**
|
||||
* Cat Models FG Radii N2M Radii
|
||||
* B Small Regionals ERJ CRJ ATR 14 6
|
||||
* C A319 A320 A321 B737 18 10
|
||||
* D B757, B767 26 15
|
||||
* E B777 B787 A330 A340 A360 33 24
|
||||
* F A380 40 24
|
||||
*/
|
||||
|
||||
switch (this.parking.radius * 2) {
|
||||
case 15:
|
||||
return 'Piper J-3 Cub/Cessna 172'
|
||||
case 20:
|
||||
return 'Beech 200/Cessna 425'
|
||||
case 28:
|
||||
return 'BOMBARDIER Regional Jet CRJ-200/DE HAVILLAND CANADA DHC-6'
|
||||
case 36:
|
||||
return 'BOEING 737-700/AIRBUS A-320/EMBRAER ERJ 190-100'
|
||||
case 52:
|
||||
return 'B767 Series/AIRBUS A-310'
|
||||
case 66:
|
||||
return 'B777 Series/B787 Series/A330 Family'
|
||||
case 80:
|
||||
return 'BOEING 747-8/AIRBUS A-380-800'
|
||||
default:
|
||||
return 'Unknown radius : ' + this.parking.radius
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
@ -5,6 +5,7 @@
|
||||
import L from 'leaflet'
|
||||
import LEdit from 'leaflet-editable/src/Leaflet.Editable.js'
|
||||
import {readPavement} from '../loaders/pavement_loader'
|
||||
import * as turf from '@turf/turf'
|
||||
|
||||
export default {
|
||||
name: 'edit-layer',
|
||||
@ -31,12 +32,19 @@
|
||||
// Callback for add
|
||||
readPavement(this.$store.state.Settings.settings.flightgearDirectory_apt, icao, this.read)
|
||||
},
|
||||
// Callback called when pavement read
|
||||
read (layer) {
|
||||
this.pavement = layer
|
||||
if (this.pavement) {
|
||||
this.pavement.on('add', this.onAdd)
|
||||
this.pavement.addTo(this.$parent.mapObject)
|
||||
this.visible = true
|
||||
} else {
|
||||
this.$message({
|
||||
type: 'Error',
|
||||
showClose: true,
|
||||
message: `Couldn't load pavement from ${this.$store.state.Settings.settings.flightgearDirectory_apt}`
|
||||
})
|
||||
}
|
||||
},
|
||||
onAdd () {
|
||||
@ -68,6 +76,21 @@
|
||||
this.deferredMountedTo(this.$parent.mapObject)
|
||||
}
|
||||
},
|
||||
isOnRunway (latlng) {
|
||||
var ret = false
|
||||
this.pavement.eachLayer(l => {
|
||||
if (l instanceof L.RunwayPolygon) {
|
||||
console.debug(l)
|
||||
if (turf.booleanContains(l.turfyRunway, this.latToTurf(latlng))) {
|
||||
ret = true
|
||||
}
|
||||
}
|
||||
})
|
||||
return ret
|
||||
},
|
||||
latToTurf (turfPoint) {
|
||||
return turf.point([turfPoint.lng, turfPoint.lat])
|
||||
},
|
||||
setVisible (visible) {
|
||||
if (this.pavement !== undefined) {
|
||||
if (visible !== this.visible) {
|
||||
|
@ -74,6 +74,16 @@
|
||||
|
||||
const worker = new Worker(winURL)
|
||||
console.log(fileUrl('src/renderer/utils/worker.js'))
|
||||
worker.onerror = function (e) {
|
||||
console.error(e)
|
||||
worker.terminate()
|
||||
worker.scanning = false
|
||||
worker.view.progress = 0
|
||||
worker.view.max = 0
|
||||
worker.view.worker = null
|
||||
clearInterval(this.polling)
|
||||
e.preventDefault()
|
||||
}
|
||||
|
||||
worker.scanning = this.scanning
|
||||
worker.max = this.max
|
||||
@ -121,6 +131,16 @@
|
||||
|
||||
const worker = new Worker(winURL)
|
||||
console.log(fileUrl('src/renderer/utils/worker.js'))
|
||||
worker.onerror = function (e) {
|
||||
console.error(e)
|
||||
worker.terminate()
|
||||
worker.scanning = false
|
||||
worker.view.progress = 0
|
||||
worker.view.max = 0
|
||||
worker.view.worker = null
|
||||
clearInterval(this.polling)
|
||||
e.preventDefault()
|
||||
}
|
||||
|
||||
worker.scanning = this.scanning
|
||||
worker.max = this.max
|
||||
@ -169,6 +189,16 @@
|
||||
|
||||
const worker = new Worker(winURL)
|
||||
console.log(fileUrl('src/renderer/utils/worker.js'))
|
||||
worker.onerror = function (e) {
|
||||
console.error(e)
|
||||
worker.terminate()
|
||||
worker.scanning = false
|
||||
worker.view.progress = 0
|
||||
worker.view.max = 0
|
||||
worker.view.worker = null
|
||||
clearInterval(this.polling)
|
||||
e.preventDefault()
|
||||
}
|
||||
this.scanning = true
|
||||
worker.scanning = this.scanning
|
||||
worker.max = this.max
|
||||
|
@ -16,11 +16,8 @@
|
||||
|
||||
<script lang="js">
|
||||
// import scanner from '../utils/scan'
|
||||
import fileUrl from 'file-url'
|
||||
import {Table, TableColumn} from 'element-ui'
|
||||
|
||||
const path = require('path')
|
||||
|
||||
export default {
|
||||
name: 'search',
|
||||
components: { [Table.name]: Table,
|
||||
@ -36,7 +33,7 @@
|
||||
},
|
||||
methods: {
|
||||
goto (icao) {
|
||||
console.log(icao)
|
||||
console.debug('Goto : ' + icao)
|
||||
let airports = this.$store.state.Airports.airports
|
||||
.filter(a => a.properties.icao.match(icao))
|
||||
if (airports.length > 0) {
|
||||
@ -46,87 +43,11 @@
|
||||
formatter (row, column) {
|
||||
console.log('Row ' + row)
|
||||
return row
|
||||
},
|
||||
scanAPT () {
|
||||
try {
|
||||
const winURL = process.env.NODE_ENV === 'development'
|
||||
? `http://localhost:9080/src/renderer/utils/worker.js`
|
||||
: `file://${__dirname}/worker.js`
|
||||
console.log('make a worker: ', path.resolve(__dirname, 'worker.js'))
|
||||
|
||||
const worker = new Worker(winURL)
|
||||
console.log(fileUrl('src/renderer/utils/worker.js'))
|
||||
|
||||
// var worker = new Worker(fileUrl('src/renderer/utils/worker.js'))
|
||||
worker.postMessage(['scanapt'])
|
||||
// the reply
|
||||
var store = this.$store
|
||||
worker.onmessage = function (e) {
|
||||
if (e.data === 'DONE') {
|
||||
console.log('DONE')
|
||||
store.dispatch('getAirports')
|
||||
worker.terminate()
|
||||
}
|
||||
console.log(e.data)
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
},
|
||||
scanGroundnets () {
|
||||
try {
|
||||
const winURL = process.env.NODE_ENV === 'development'
|
||||
? `http://localhost:9080/src/renderer/utils/worker.js`
|
||||
: `file://${__dirname}/worker.js`
|
||||
console.log('make a worker: ', path.resolve(__dirname, 'worker.js'))
|
||||
|
||||
const worker = new Worker(winURL)
|
||||
console.log(fileUrl('src/renderer/utils/worker.js'))
|
||||
|
||||
worker.postMessage(['scan', this.$store.state.Settings.settings.airportsDirectory])
|
||||
// the reply
|
||||
var store = this.$store
|
||||
worker.onmessage = function (e) {
|
||||
if (e.data === 'DONE') {
|
||||
console.log('DONE')
|
||||
store.dispatch('getAirports')
|
||||
worker.terminate()
|
||||
}
|
||||
console.log(e.data)
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
},
|
||||
scanTraffic () {
|
||||
// let flightgearDirectory = this.$store.state.settings.flightgearDirectory
|
||||
try {
|
||||
const winURL = process.env.NODE_ENV === 'development'
|
||||
? `http://localhost:9080/src/renderer/utils/worker.js`
|
||||
: `file://${__dirname}/worker.js`
|
||||
console.log('make a worker: ', path.resolve(__dirname, 'worker.js'))
|
||||
|
||||
const worker = new Worker(winURL)
|
||||
console.log(fileUrl('src/renderer/utils/worker.js'))
|
||||
worker.postMessage(['scanai', this.$store.state.Settings.settings.flightgearDirectory])
|
||||
// the reply
|
||||
var store = this.$store
|
||||
worker.onmessage = function (e) {
|
||||
if (e.data === 'DONE') {
|
||||
console.log('DONE')
|
||||
store.dispatch('getAirports')
|
||||
worker.terminate()
|
||||
}
|
||||
console.log(e.data)
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
searched: function () {
|
||||
console.log(this.searchterm)
|
||||
console.debug('Search : ' + this.searchterm)
|
||||
if (this.searchterm !== this.lastSearchTerm) {
|
||||
let searchRegex = new RegExp(this.searchterm, 'i')
|
||||
let result = this.$store.state.Airports.airports
|
||||
@ -136,10 +57,14 @@
|
||||
.filter(a => searchRegex.test(a.properties.icao) || searchRegex.test(a.properties.name))
|
||||
// .map(a => console.log(a.properties))
|
||||
.map(a => ({ icao: a.properties.icao, name: a.properties.name }))
|
||||
.filter((v, i, a) => a.findIndex(t => (t.icao === v.icao)) === i)
|
||||
let icaoResult = result.filter(a => a.icao === this.searchterm).filter((v, i, a) => a.findIndex(t => (t.icao === v.icao)) === i)
|
||||
if (result !== undefined &&
|
||||
result.length === 0 &&
|
||||
icaoResult.length === 0 &&
|
||||
this.searchterm !== undefined &&
|
||||
this.searchterm.length >= 3) {
|
||||
this.searchterm.length >= 3 &&
|
||||
this.searchterm.length <= 4) {
|
||||
// Not found so it might have been excluded due to no traffic
|
||||
this.$store.dispatch('getAirport', this.searchterm)
|
||||
}
|
||||
this.lastResult = result
|
||||
|
@ -6,54 +6,122 @@
|
||||
<i class="fa fa-caret-left"></i>
|
||||
</div>
|
||||
</h1>
|
||||
<div id="panel" width="100%">
|
||||
<el-collapse v-model="activeName" accordion>
|
||||
<el-collapse-item title="General" name="1">
|
||||
<el-row>
|
||||
<el-col :span="12" class="label">Number of saves : </el-col>
|
||||
<el-col :span="12">
|
||||
<el-popover
|
||||
placement="top-start"
|
||||
title="Saves"
|
||||
width="200"
|
||||
trigger="hover"
|
||||
content="How many previous versions should be kept."
|
||||
>
|
||||
<el-input
|
||||
placeholder="Number of versions"
|
||||
slot="reference"
|
||||
v-model="numberOfSaves"
|
||||
></el-input>
|
||||
</el-popover>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-collapse-item>
|
||||
<el-collapse-item title="Directories" name="2">
|
||||
<el-row>
|
||||
<el-col :span="22" class="label">Airports Directory</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="20" class="file-label">{{ airports_directory }}</el-col>
|
||||
<el-col :span="4">
|
||||
<directory-select @input="airportsDirectorySelect"></directory-select>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="22" class="label">Flightgear Directory</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="20" class="file-label">{{ flightgear_directory }}</el-col>
|
||||
<el-col :span="4">
|
||||
<directory-select @input="flightgearDirectorySelect"></directory-select>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="7" class="label">Traffic Directory</el-col>
|
||||
<el-col :span="15" class="file-label">{{ Traffic_directory }}</el-col>
|
||||
<el-col
|
||||
:span="22"
|
||||
v-bind:class="{
|
||||
invalid: !airports_directory_ok,
|
||||
file_label: airports_directory_ok,
|
||||
}"
|
||||
>{{ airports_directory }}</el-col
|
||||
>
|
||||
<el-col :span="2">
|
||||
<el-popover
|
||||
placement="top-start"
|
||||
title="E-Mail"
|
||||
width="200"
|
||||
trigger="hover"
|
||||
content="The work directory. Best is a copy from groundweb"
|
||||
>
|
||||
<directory-select
|
||||
@input="airportsDirectorySelect"
|
||||
slot="reference"
|
||||
></directory-select>
|
||||
</el-popover>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="7" class="label">APT File</el-col>
|
||||
<el-col :span="15" class="file-label">{{ apt_file }}</el-col>
|
||||
<el-col :span="22" class="label">Flightgear Data Directory</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col
|
||||
:span="22"
|
||||
v-bind:class="{
|
||||
invalid: !flightgear_directory_ok,
|
||||
file_label: flightgear_directory_ok,
|
||||
}"
|
||||
>{{ flightgear_directory }}</el-col
|
||||
>
|
||||
<el-col :span="2">
|
||||
<el-popover
|
||||
placement="top-start"
|
||||
title="E-Mail"
|
||||
width="200"
|
||||
trigger="hover"
|
||||
content="The FGDATA directory."
|
||||
>
|
||||
<directory-select
|
||||
@input="flightgearDirectorySelect"
|
||||
slot="reference"
|
||||
></directory-select>
|
||||
</el-popover>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="7" class="label">Export Directory</el-col>
|
||||
<el-col :span="15" class="file-label">{{ test_directory }}</el-col>
|
||||
<el-col :span="22" class="label">Traffic Directory</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col
|
||||
:span="22"
|
||||
v-bind:class="{
|
||||
invalid: !Traffic_directory_ok,
|
||||
file_label: Traffic_directory_ok,
|
||||
}"
|
||||
>{{ Traffic_directory }}</el-col
|
||||
>
|
||||
<el-col :span="2"> </el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="22" class="label">APT File</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="22" v-bind:class="{ invalid: !apt_file_ok }">{{
|
||||
apt_file
|
||||
}}</el-col>
|
||||
<el-col :span="2"> </el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="7" class="label">Export Directory : </el-col>
|
||||
<el-col
|
||||
:span="15"
|
||||
v-bind:class="{
|
||||
invalid: !test_directory_ok,
|
||||
file_label: test_directory_ok,
|
||||
}"
|
||||
>{{ test_directory }}</el-col
|
||||
>
|
||||
<el-col :span="2">
|
||||
<directory-select @input="testDirectorySelect"></directory-select>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-collapse-item>
|
||||
<el-collapse-item title="User" name="3">
|
||||
<el-row>
|
||||
<el-col :span="22" class="label">Phi Host Url</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="24" class="label">
|
||||
<el-input placeholder="Please input a valid Phi URL" v-model="phi_url"></el-input>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
|
||||
<el-col :span="7" class="label">Author E-Mail : </el-col>
|
||||
<el-col :span="17">
|
||||
<el-popover
|
||||
@ -63,12 +131,15 @@
|
||||
trigger="hover"
|
||||
content="Only used as a committer/author for Github. This e-mail is only visible via GIT."
|
||||
>
|
||||
<el-input placeholder="Please input your email" slot="reference" v-model="email"></el-input>
|
||||
<el-input
|
||||
placeholder="Please input your email"
|
||||
slot="reference"
|
||||
v-model="email"
|
||||
></el-input>
|
||||
</el-popover>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
|
||||
<el-col :span="7" class="label">Author Name : </el-col>
|
||||
<el-col :span="17">
|
||||
<el-popover
|
||||
@ -78,10 +149,16 @@
|
||||
trigger="hover"
|
||||
content="This is saved to the file and is therefore distributed via Terrasync."
|
||||
>
|
||||
<el-input placeholder="Please input your Name" slot="reference" v-model="name"></el-input>
|
||||
<el-input
|
||||
placeholder="Please input your Name"
|
||||
slot="reference"
|
||||
v-model="name"
|
||||
></el-input>
|
||||
</el-popover>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-collapse-item>
|
||||
<el-collapse-item title="Troubleshooting" name="4">
|
||||
<el-row>
|
||||
<el-col :span="7">
|
||||
<span class="label">Scan logging :</span>
|
||||
@ -108,13 +185,27 @@
|
||||
trigger="hover"
|
||||
content="Opens the JavaScript Debugger for troubleshooting"
|
||||
>
|
||||
<el-button @click="debug" class="button" slot="reference" >
|
||||
<el-button @click="debug" class="button" slot="reference">
|
||||
<i class="fas fa-bug"></i> Debugger
|
||||
</el-button>
|
||||
</el-popover>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</el-collapse-item>
|
||||
<el-collapse-item title="Flightgear" name="5">
|
||||
<el-row>
|
||||
<el-col :span="22" class="label">Phi Host Url</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="24" class="label">
|
||||
<el-input
|
||||
placeholder="Please input a valid Phi URL"
|
||||
v-model="phi_url"
|
||||
></el-input>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -123,19 +214,30 @@
|
||||
import DirectorySelect from './DirectorySelect'
|
||||
|
||||
const { ipcRenderer } = require('electron')
|
||||
|
||||
const fs = require('fs')
|
||||
export default {
|
||||
name: 'settings-panel',
|
||||
components: { DirectorySelect, FileSelect },
|
||||
props: [],
|
||||
mounted () {
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
return { ok: true, activeName: '0', scanStoreLogging: false }
|
||||
},
|
||||
mounted () {
|
||||
this.$store.watch(
|
||||
function (state) {
|
||||
return state.Settings.settings
|
||||
},
|
||||
() => { this.loggingChanged() }
|
||||
,
|
||||
{
|
||||
deep: true // add this if u need to watch object properties change etc.
|
||||
}
|
||||
)
|
||||
},
|
||||
methods: {
|
||||
loggingChanged () {
|
||||
this.scanStoreLogging = this.$store.state.Settings.settings.scanLogging === 1
|
||||
},
|
||||
flightgearDirectorySelect: function (flightgearDirectory) {
|
||||
console.log(flightgearDirectory)
|
||||
this.$store.commit('FLIGHTGEAR_DIRECTORY', flightgearDirectory)
|
||||
@ -153,6 +255,16 @@
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
numberOfSaves: {
|
||||
// getter
|
||||
get: function () {
|
||||
return this.$store.state.Settings.settings.numberOfSaves
|
||||
},
|
||||
// setter
|
||||
set: function (newValue) {
|
||||
this.$store.commit('SET_NUMBER_OF_SAVES', newValue)
|
||||
}
|
||||
},
|
||||
email: {
|
||||
// getter
|
||||
get: function () {
|
||||
@ -186,25 +298,65 @@
|
||||
flightgear_directory: function () {
|
||||
return this.$store.state.Settings.settings.flightgearDirectory
|
||||
},
|
||||
flightgear_directory_ok: function () {
|
||||
try {
|
||||
fs.accessSync(this.$store.state.Settings.settings.flightgearDirectory)
|
||||
return true
|
||||
} catch (error) {
|
||||
return false
|
||||
}
|
||||
},
|
||||
AI_directory: function () {
|
||||
return this.$store.state.Settings.settings.flightgearDirectory_ai
|
||||
},
|
||||
Traffic_directory: function () {
|
||||
return this.$store.state.Settings.settings.flightgearDirectory_traffic
|
||||
},
|
||||
Traffic_directory_ok: function () {
|
||||
try {
|
||||
fs.accessSync(this.$store.state.Settings.settings.flightgearDirectory_traffic)
|
||||
return true
|
||||
} catch (error) {
|
||||
return false
|
||||
}
|
||||
},
|
||||
apt_file: function () {
|
||||
return this.$store.state.Settings.settings.flightgearDirectory_apt
|
||||
},
|
||||
apt_file_ok: function () {
|
||||
try {
|
||||
fs.accessSync(this.$store.state.Settings.settings.flightgearDirectory_apt)
|
||||
return true
|
||||
} catch (error) {
|
||||
return false
|
||||
}
|
||||
},
|
||||
airports_directory: function () {
|
||||
return this.$store.state.Settings.settings.airportsDirectory
|
||||
},
|
||||
airports_directory_ok: function () {
|
||||
try {
|
||||
fs.accessSync(this.$store.state.Settings.settings.airportsDirectory)
|
||||
return true
|
||||
} catch (error) {
|
||||
return false
|
||||
}
|
||||
},
|
||||
test_directory: function () {
|
||||
return this.$store.state.Settings.settings.testDirectory
|
||||
},
|
||||
test_directory_ok: function () {
|
||||
try {
|
||||
fs.accessSync(this.$store.state.Settings.settings.testDirectory)
|
||||
return true
|
||||
} catch (error) {
|
||||
return false
|
||||
}
|
||||
},
|
||||
scanLogging: {
|
||||
// getter
|
||||
get: function () {
|
||||
return this.$store.state.Settings.settings.scanLogging === 1
|
||||
return this.scanStoreLogging
|
||||
},
|
||||
// setter
|
||||
set: function (newValue) {
|
||||
@ -223,10 +375,14 @@
|
||||
border-radius: 4px;
|
||||
}
|
||||
.label {
|
||||
padding: 10px;
|
||||
padding: 5px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.file-label {
|
||||
padding: 10px;
|
||||
.file_label {
|
||||
padding: 5px;
|
||||
}
|
||||
.invalid {
|
||||
padding: 5px;
|
||||
background-color: red;
|
||||
}
|
||||
</style>
|
||||
|
95
src/renderer/components/ThresholdEdit.vue
Normal file
@ -0,0 +1,95 @@
|
||||
<!--
|
||||
Copyright 2020 Keith Paterson
|
||||
|
||||
This file is part of FG Airports.
|
||||
|
||||
FG Airports is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
FG Airports is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with FG Airports. If not, see http://www.gnu.org/licenses/.
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div width="100%" v-if="threshold">
|
||||
<div>
|
||||
<el-row>
|
||||
<el-col :span="7">
|
||||
<span class="label">Runway :</span>
|
||||
</el-col>
|
||||
<el-col :span="17">
|
||||
<el-input
|
||||
placeholder="Please input"
|
||||
v-model="runway"
|
||||
:disabled="true"
|
||||
></el-input>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="7">
|
||||
<span class="label">Displacement :</span>
|
||||
</el-col>
|
||||
<el-col :span="17">
|
||||
<el-input-number
|
||||
v-model="displacement"
|
||||
:disabled="!editing"
|
||||
></el-input-number>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script lang="js">
|
||||
/* eslint-disable */
|
||||
const Coordinates = require('coordinate-parser');
|
||||
import {writeTowerXML} from '../loaders/tower_writer'
|
||||
|
||||
|
||||
export default {
|
||||
/*
|
||||
methods: {
|
||||
updateIsOnRunway (value) {
|
||||
this.$store.commit('SET_EDIT_ISONRUNWAY', value)
|
||||
}
|
||||
},
|
||||
*/
|
||||
data () {
|
||||
return {
|
||||
coordFocussed: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
save () {
|
||||
var o = {latitude: this.latitude, longitude: this.longitude, height: this.height};
|
||||
writeTowerXML(this.$store.state.Settings.settings.airportsDirectory, this.$parent.$parent.$parent.icao, o)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
editing: {
|
||||
get: function () {
|
||||
return this.$parent.$parent.$parent.$refs.editLayer.editing
|
||||
}
|
||||
},
|
||||
threshold: function () {
|
||||
return this.$store.state.Editable.type === 'threshold'
|
||||
},
|
||||
//<rwy>07L</rwy>
|
||||
//<hdg-deg>68.77</hdg-deg>
|
||||
//<displ-m>0.0</displ-m>
|
||||
//<stopw-m>160.0</stopw-m>
|
||||
runway: function () {
|
||||
return this.$store.state.Editable.data.threshold.runway;
|
||||
},
|
||||
displacement: {
|
||||
set: function (newValue) {
|
||||
this.$store.dispatch('setDisplacement', newValue);
|
||||
},
|
||||
get: function () {
|
||||
return this.$store.state.Editable.data.threshold.displacement;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -3,8 +3,10 @@
|
||||
<script lang="js">
|
||||
import { LMap, LMarker } from 'vue2-leaflet'
|
||||
import L from 'leaflet'
|
||||
import leafletPattern from 'leaflet.pattern'
|
||||
import LEdit from 'leaflet-editable/src/Leaflet.Editable.js'
|
||||
import {readThresholdXML} from '../loaders/threshold_loader'
|
||||
import {writeThresholdXML} from '../loaders/threshold_writer'
|
||||
|
||||
export default {
|
||||
name: 'edit-layer',
|
||||
@ -12,10 +14,19 @@
|
||||
created () {
|
||||
},
|
||||
mounted () {
|
||||
console.log(LMap)
|
||||
console.log(LMarker)
|
||||
console.log(L)
|
||||
console.log(LEdit)
|
||||
console.debug(LMap, LMarker, L, LEdit, leafletPattern)
|
||||
this.$store.watch(
|
||||
function (state) {
|
||||
return state.Editable.data.threshold
|
||||
},
|
||||
() => { this.editedThreshold() }
|
||||
,
|
||||
{
|
||||
deep: true
|
||||
}
|
||||
)
|
||||
var stripes = new L.StripePattern({color: 'yellow'})
|
||||
stripes.addTo(this.$parent.mapObject)
|
||||
},
|
||||
beforeDestroy () {
|
||||
this.remove()
|
||||
@ -25,12 +36,37 @@
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
editedThreshold () {
|
||||
if (this.$store.state.Editable.data.threshold) {
|
||||
var rwy = this.$store.state.Editable.data.threshold.runway
|
||||
var displacement = this.$store.state.Editable.data.threshold.displacement
|
||||
this.layerGroup.eachLayer(l => {
|
||||
if (l instanceof L.Threshold) {
|
||||
if (l.rwy === rwy) {
|
||||
l.setDisplacement(displacement)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
getLayer () {
|
||||
return this.layerGroup
|
||||
},
|
||||
load (icao) {
|
||||
this.$parent.mapObject.createPane('threshold-pane')
|
||||
this.$parent.mapObject.getPane('threshold-pane').style.zIndex = 550
|
||||
if (this.layerGroup) {
|
||||
this.layerGroup.removeFrom(this.$parent.mapObject)
|
||||
}
|
||||
var stripes = new L.StripePattern({color: 'yellow'})
|
||||
stripes.addTo(this.$parent.mapObject)
|
||||
|
||||
// Callback for add
|
||||
this.layerGroup = readThresholdXML(this.$store.state.Settings.settings.airportsDirectory, icao, this.read)
|
||||
this.layerGroup = readThresholdXML(this.$store.state.Settings.settings.airportsDirectory, icao, this.read, stripes)
|
||||
if (!this.layerGroup) {
|
||||
console.warn('Threshold for ICAO not loaded ' + icao)
|
||||
return
|
||||
}
|
||||
this.layerGroup.addTo(this.$parent.mapObject)
|
||||
this.visible = true
|
||||
this.icao = icao
|
||||
@ -47,6 +83,24 @@
|
||||
this.deferredMountedTo(this.$parent.mapObject)
|
||||
}
|
||||
},
|
||||
enableEdit () {
|
||||
if (this.layerGroup) {
|
||||
this.layerGroup.eachLayer(l => {
|
||||
if (l instanceof L.Threshold) {
|
||||
l.setInteractive(true)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
disableEdit () {
|
||||
if (this.layerGroup) {
|
||||
this.layerGroup.eachLayer(l => {
|
||||
if (l instanceof L.Threshold) {
|
||||
l.setInteractive(false)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
setVisible (visible) {
|
||||
if (this.layerGroup !== undefined) {
|
||||
if (visible !== this.visible) {
|
||||
@ -58,13 +112,42 @@
|
||||
this.visible = visible
|
||||
}
|
||||
}
|
||||
},
|
||||
save () {
|
||||
if (this.layerGroup) {
|
||||
var list = {}
|
||||
|
||||
this.layerGroup.eachLayer(l => {
|
||||
if (l instanceof L.Threshold) {
|
||||
var latitude = l.originLatLng[0].toFixed(6)
|
||||
var longitude = l.originLatLng[1].toFixed(6)
|
||||
|
||||
if (list[l.index] === undefined) {
|
||||
list[l.index] = []
|
||||
}
|
||||
var o = {latitude: latitude, longitude: longitude, index: l.index, rwy: l.rwy, heading: l.heading, displacement: l.displacement, stopw_m: l.stopw_m}
|
||||
list[l.index].push(o)
|
||||
}
|
||||
})
|
||||
writeThresholdXML(this.$store.state.Settings.settings.airportsDirectory, this.icao, list)
|
||||
}
|
||||
},
|
||||
zoomUpdated () {
|
||||
if (this.layerGroup) {
|
||||
this.layerGroup.eachLayer(l => {
|
||||
if (l instanceof L.Threshold) {
|
||||
l.updateIcon(this.$parent.mapObject)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
computed: {
|
||||
edit: function () {
|
||||
console.log('Zoom : ' + this.$store.state.Settings.zoom)
|
||||
if (this.$store.state.Settings.zoom > 12) {
|
||||
console.log()
|
||||
console.log('Zoom above 12')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,12 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
-->
|
||||
<template>
|
||||
<div id="ToolBar">
|
||||
<ToolButton
|
||||
icon="far fa-eye"
|
||||
v-on:click="showTooltips"
|
||||
:show="editing"
|
||||
tooltip="Show Tooltips"
|
||||
></ToolButton>
|
||||
<ToolButton
|
||||
icon="fas fa-draw-polygon"
|
||||
v-on:click="drawPolyline"
|
||||
@ -42,7 +48,10 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
this.$parent.$parent.$refs.toolLayer.stopDrawing()
|
||||
this.$parent.$parent.$refs.toolLayer.drawPolyline()
|
||||
},
|
||||
setEdit (edit) {
|
||||
showTooltips () {
|
||||
this.$parent.$parent.$refs.editLayer.showTooltips()
|
||||
},
|
||||
setEditing (edit) {
|
||||
this.isEditing = edit;
|
||||
if(!this.isEditing) {
|
||||
this.$parent.$parent.$refs.toolLayer.stopDrawing()
|
||||
|
@ -6,6 +6,7 @@
|
||||
import ToolControl from '../leaflet/ToolControl.js'
|
||||
export default {
|
||||
name: 'edit-bar',
|
||||
components: { ToolControl, L },
|
||||
props: {
|
||||
icon: String,
|
||||
show: Boolean,
|
||||
@ -22,8 +23,6 @@
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
console.debug(L)
|
||||
console.debug(ToolControl)
|
||||
this.add()
|
||||
},
|
||||
beforeDestroy () {
|
||||
|
@ -56,8 +56,38 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
},
|
||||
drawPolyline () {
|
||||
var polyLine = this.$parent.mapObject.editTools.startPolygon(undefined, {color: 'green'})
|
||||
var layerGroup = this.toolLayerGroup;
|
||||
polyLine.addTo(this.toolLayerGroup)
|
||||
polyLine.on('click', event => {
|
||||
polyLine.removeFrom(layerGroup);
|
||||
});
|
||||
polyLine.on('editable:drawing:end', event => {
|
||||
console.debug('editable:drawing:end', event)
|
||||
var latLngs = event.target.getLatLngs()[0].map( latLng => ([latLng.lat, latLng.lng]));
|
||||
|
||||
|
||||
// turf rings must start/end with the same point
|
||||
latLngs.push(latLngs[0]);
|
||||
var longest = 0;
|
||||
var angleLongest = 0;
|
||||
latLngs.forEach((item, index, arr) => {
|
||||
if (index > 0) {
|
||||
var angle = turf.bearing(turf.point([arr[index-1][1], arr[index-1][0]]), turf.point([arr[index][1], arr[index][0]])) + 180;
|
||||
|
||||
var dist = turf.distance( turf.point(arr[index-1]), turf.point(arr[index]));
|
||||
if (dist>longest) {
|
||||
longest = dist;
|
||||
angleLongest = angle;
|
||||
}
|
||||
}
|
||||
});
|
||||
event.target.bindTooltip(angleLongest.toFixed(2) + '°', {permanent: true})
|
||||
|
||||
var ring = [latLngs];
|
||||
|
||||
this.$emit('select-poly', ring);
|
||||
})
|
||||
polyLine.on('editable:vertex:dragend', event => {
|
||||
console.debug(event)
|
||||
var latLngs = event.target.getLatLngs()[0].map( latLng => ([latLng.lat, latLng.lng]));
|
||||
|
||||
@ -77,14 +107,7 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
}
|
||||
}
|
||||
});
|
||||
var point1 = turf.point([-75.343, 39.984]);
|
||||
var point2 = turf.point([-75.534, 39.123]);
|
||||
|
||||
var bearing = turf.bearing(point1, point2);
|
||||
console.log(bearing);
|
||||
|
||||
|
||||
event.target.bindTooltip(angleLongest.toFixed(2) + '°', {permanent: true})
|
||||
event.target.setTooltipContent(angleLongest.toFixed(2) + '°')
|
||||
|
||||
var ring = [latLngs];
|
||||
|
||||
|
93
src/renderer/components/TowerEdit.vue
Normal file
@ -0,0 +1,93 @@
|
||||
<template>
|
||||
<div width="100%" v-if="tower">
|
||||
<div>
|
||||
<el-row>
|
||||
<el-col :span="7">
|
||||
<span class="label">Latitude :</span>
|
||||
</el-col>
|
||||
<el-col :span="17">
|
||||
<el-input placeholder="Please input" v-model="latitude" :disabled="true"
|
||||
@focus="coordFocussed = true"
|
||||
@blur="coordFocussed = false"></el-input>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="7">
|
||||
<span class="label">Longitude :</span>
|
||||
</el-col>
|
||||
<el-col :span="17">
|
||||
<el-input placeholder="Please input" v-model="longitude" :disabled="true"
|
||||
@focus="coordFocussed = true"
|
||||
@blur="coordFocussed = false"></el-input>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<el-col :span="7">
|
||||
<span class="label">Height :</span>
|
||||
</el-col>
|
||||
<el-col :span="17">
|
||||
<el-input-number placeholder="Please input" @change="handleChange" v-model="height" :disabled="!editing" :step="0.01"
|
||||
@focus="coordFocussed = true"
|
||||
@blur="coordFocussed = false"></el-input-number>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script lang="js">
|
||||
/* eslint-disable */
|
||||
const Coordinates = require('coordinate-parser');
|
||||
import {writeTowerXML} from '../loaders/tower_writer'
|
||||
|
||||
|
||||
export default {
|
||||
/*
|
||||
methods: {
|
||||
updateIsOnRunway (value) {
|
||||
this.$store.commit('SET_EDIT_ISONRUNWAY', value)
|
||||
}
|
||||
},
|
||||
*/
|
||||
data () {
|
||||
return {
|
||||
coordFocussed: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
save () {
|
||||
var o = {latitude: this.latitude, longitude: this.longitude, height: this.height};
|
||||
writeTowerXML(this.$store.state.Settings.settings.airportsDirectory, this.$parent.$parent.$parent.icao, o)
|
||||
},
|
||||
handleChange (newValue) {
|
||||
this.$store.dispatch('setTowerHeight', newValue);
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
editing: {
|
||||
get: function () {
|
||||
return this.$parent.$parent.$parent.$refs.editLayer.editing
|
||||
}
|
||||
},
|
||||
tower: function () {
|
||||
return this.$store.state.Editable.type === 'tower'
|
||||
},
|
||||
// {index: 39, lat: "N58 27.343", lon: "W03 5.153", isOnRunway: 0, holdPointType: "none"}
|
||||
latitude: function () {
|
||||
return this.$store.state.Editable.data.tower.coords.latitude;
|
||||
},
|
||||
longitude: function () {
|
||||
return this.$store.state.Editable.data.tower.coords.longitude;
|
||||
},
|
||||
height: {
|
||||
get: function () {
|
||||
return this.$store.state.Editable.data.tower.height;
|
||||
},
|
||||
set: function (newValue) {
|
||||
this.$store.dispatch('setTowerHeight', newValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
154
src/renderer/components/TowerLayer.vue
Normal file
@ -0,0 +1,154 @@
|
||||
<!--
|
||||
Copyright 2020 Keith Paterson
|
||||
|
||||
This file is part of FG Airports.
|
||||
|
||||
FG Airports is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
FG Airports is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with FG Airports. If not, see http://www.gnu.org/licenses/.
|
||||
-->
|
||||
<template></template>
|
||||
|
||||
<script lang="js">
|
||||
import { LMap, LMarker } from 'vue2-leaflet'
|
||||
import L from 'leaflet'
|
||||
import LEdit from 'leaflet-editable/src/Leaflet.Editable.js'
|
||||
import {readTowerXML} from '../loaders/tower_loader'
|
||||
import {writeTowerXML} from '../loaders/tower_writer'
|
||||
|
||||
export default {
|
||||
name: 'tower-layer',
|
||||
props: [],
|
||||
created () {
|
||||
console.debug([LMap, LMarker, L, LEdit])
|
||||
},
|
||||
mounted () {
|
||||
this.$store.watch(
|
||||
function (state) {
|
||||
return state.Editable.data.tower
|
||||
},
|
||||
() => { this.editedTower() }
|
||||
,
|
||||
{
|
||||
deep: true
|
||||
}
|
||||
)
|
||||
},
|
||||
beforeDestroy () {
|
||||
this.remove()
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
editedTower () {
|
||||
if (this.$store.state.Editable.data.tower) {
|
||||
this.layerGroup.eachLayer(l => {
|
||||
if (l instanceof L.TowerMarker) {
|
||||
l.setTowerHeight(this.$store.state.Editable.data.tower.height)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
getLayer () {
|
||||
return this.layerGroup
|
||||
},
|
||||
load (icao) {
|
||||
this.$parent.mapObject.createPane('tower-pane')
|
||||
this.$parent.mapObject.getPane('tower-pane').style.zIndex = 550
|
||||
if (this.layerGroup !== undefined) {
|
||||
this.layerGroup.removeFrom(this.$parent.mapObject)
|
||||
}
|
||||
|
||||
// Callback for add
|
||||
this.layerGroup = readTowerXML(this.$store.state.Settings.settings.airportsDirectory, icao, this.read)
|
||||
if (!this.layerGroup) {
|
||||
console.warn('Tower for ICAO not loaded ' + icao)
|
||||
return
|
||||
}
|
||||
this.layerGroup.addTo(this.$parent.mapObject)
|
||||
this.visible = true
|
||||
this.icao = icao
|
||||
},
|
||||
deferredMountedTo (parent) {
|
||||
},
|
||||
remove () {
|
||||
if (this.layerGroup) {
|
||||
this.$parent.removeLayer(this.layerGroup)
|
||||
}
|
||||
},
|
||||
add () {
|
||||
if (this.$parent._isMounted) {
|
||||
this.deferredMountedTo(this.$parent.mapObject)
|
||||
}
|
||||
},
|
||||
enableEdit () {
|
||||
if (this.layerGroup) {
|
||||
this.layerGroup.eachLayer(l => {
|
||||
if (l instanceof L.TowerMarker) {
|
||||
l.setInteractive(true)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
disableEdit () {
|
||||
if (this.layerGroup) {
|
||||
this.layerGroup.eachLayer(l => {
|
||||
if (l instanceof L.TowerMarker) {
|
||||
l.setInteractive(false)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
save () {
|
||||
if (this.layerGroup) {
|
||||
this.layerGroup.eachLayer(l => {
|
||||
if (l instanceof L.TowerMarker) {
|
||||
var latitude = l.getLatLng().lat.toFixed(6)
|
||||
var longitude = l.getLatLng().lng.toFixed(6)
|
||||
var height = l.elev_m
|
||||
|
||||
var o = {latitude: latitude, longitude: longitude, height: height}
|
||||
writeTowerXML(this.$store.state.Settings.settings.airportsDirectory, l.icao, o)
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
setVisible (visible) {
|
||||
if (this.layerGroup !== undefined) {
|
||||
if (visible !== this.visible) {
|
||||
if (visible) {
|
||||
this.layerGroup.addTo(this.$parent.mapObject)
|
||||
} else {
|
||||
this.layerGroup.removeFrom(this.$parent.mapObject)
|
||||
}
|
||||
this.visible = visible
|
||||
}
|
||||
}
|
||||
},
|
||||
zoomUpdated () {
|
||||
if (this.layerGroup) {
|
||||
this.layerGroup.eachLayer(l => {
|
||||
if (l instanceof L.TowerMarker) {
|
||||
l.updateIcon(this.$parent.mapObject)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
edit: function () {
|
||||
console.log('Zoom : ' + this.$store.state.Settings.zoom)
|
||||
if (this.$store.state.Settings.zoom > 12) {
|
||||
console.log()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
</style>
|
97
src/renderer/components/TrafficList.vue
Normal file
@ -0,0 +1,97 @@
|
||||
<!--
|
||||
Copyright 2021 Keith Paterson
|
||||
|
||||
This file is part of FG Airports.
|
||||
|
||||
FG Airports is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
FG Airports is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with FG Airports. If not, see http://www.gnu.org/licenses/.
|
||||
-->
|
||||
<template>
|
||||
<div>
|
||||
<el-radio-group v-model="direction">
|
||||
<el-radio :label="departure"
|
||||
><i class="fas fa-plane-departure"></i
|
||||
></el-radio>
|
||||
<el-radio :label="arrival"><i class="fas fa-plane-arrival"></i></el-radio>
|
||||
</el-radio-group>
|
||||
<el-collapse v-model="activeName" accordion ref="collapse">
|
||||
<el-collapse-item
|
||||
v-for="a in airlines"
|
||||
v-bind:key="a.index"
|
||||
class="row"
|
||||
:title="a.label"
|
||||
:name="a.label"
|
||||
>
|
||||
<AirlineItem :airline="a" ref="airline"></AirlineItem>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
<el-popover
|
||||
placement="top-start"
|
||||
title="Add Test Traffic"
|
||||
width="200"
|
||||
trigger="hover"
|
||||
content="Generate Testtraffic"
|
||||
>
|
||||
<el-button @click="generate" class="button" slot="reference">
|
||||
<i class="fas fa-notes-medical"></i>
|
||||
</el-button>
|
||||
</el-popover>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="js">
|
||||
import AirlineItem from './AirlineItem'
|
||||
import {writeTrafficXML} from '../loaders/traffic_writer'
|
||||
|
||||
export default {
|
||||
name: 'traffic-list',
|
||||
components: {AirlineItem},
|
||||
props: [],
|
||||
data () {
|
||||
return {
|
||||
activeName: '',
|
||||
departure: 0,
|
||||
arrival: 1,
|
||||
direction: 0,
|
||||
activeIndex: '1',
|
||||
activeIndex2: '1'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
generate () {
|
||||
// .filter((f) => f.$children[0])
|
||||
var aircraft = this.$refs.airline.flatMap((f) => {
|
||||
console.debug(f.aircraft)
|
||||
return f.aircraft
|
||||
}
|
||||
).filter(f => f)
|
||||
|
||||
writeTrafficXML(this.$store.state.Settings.settings.flightgearDirectory_traffic, this.$store.state.Parkings.items, aircraft)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
airlines: function () {
|
||||
var airlineCodes = []
|
||||
if (this.$store.state.Airports.currentAirport !== undefined && this.$store.state.Airports.currentAirport.airlines) {
|
||||
var storedairlineCodes = this.$store.state.Airports.currentAirport.airlines
|
||||
storedairlineCodes.forEach(element => {
|
||||
airlineCodes.push({value: element, label: element})
|
||||
})
|
||||
}
|
||||
return airlineCodes.filter((v, i, a) => a.indexOf(v) === i)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
div.row.div {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
@ -1,15 +1,31 @@
|
||||
<!--
|
||||
Copyright 2020 Keith Paterson
|
||||
|
||||
This file is part of FG Airports.
|
||||
|
||||
FG Airports is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
FG Airports is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with FG Airports. If not, see http://www.gnu.org/licenses/.
|
||||
-->
|
||||
|
||||
<template>
|
||||
<el-dialog :title="title" :visible.sync="visible" width="30%" center>
|
||||
<el-dialog :title.sync="title" :visible.sync="visible" width="30%" center>
|
||||
<span v-if="max>0">
|
||||
<el-progress :percentage="Number(((progress / max)*100).toPrecision(3))" v-if="max>0"></el-progress>
|
||||
</span>
|
||||
<span v-if="results.length>0" style="color: red">{{results.length}} Errors please correct first</span><br/>
|
||||
<span style="center">E-Mail : {{this.$store.state.Settings.settings.email}}</span><br/>
|
||||
<span style="center"><el-checkbox v-model="gplv2">I agree to release the groundnet under GPL v2</el-checkbox></span><br/>
|
||||
<span style="center" v-if="message">{{message}}</span><br/>
|
||||
<span style="error" v-if="error">{{message}}</span><br/>
|
||||
<span class="center">E-Mail : {{this.$store.state.Settings.settings.email}}</span><br/>
|
||||
<span class="center"><el-checkbox v-model="gplv2" class="center">I agree to release the groundnet under GPL v2</el-checkbox></span><br/>
|
||||
<span :class="textClass" v-if="message">{{message}}</span><br/>
|
||||
|
||||
<el-button @click="handleOkClicked('twr')" :disabled="!tower_comittable" >Upload Tower</el-button>
|
||||
<el-button @click="handleOkClicked('groundnet')" :disabled="!groundnet_comittable" >Upload Groundnet</el-button>
|
||||
<el-button @click="handleOkClicked('threshold')" :disabled="!threshold_comittable" >Upload Threshold</el-button>
|
||||
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="upload" :disabled="!comittable">Ok</el-button>
|
||||
<el-button @click="closeClicked">{{buttonText}}</el-button>
|
||||
</span>
|
||||
</el-dialog>
|
||||
</template>
|
||||
@ -21,40 +37,91 @@
|
||||
import axios from 'axios'
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const mapper = require('../check/mapper');
|
||||
|
||||
export default {
|
||||
name: 'upload',
|
||||
props: [],
|
||||
mounted () {
|
||||
this.$store.watch(
|
||||
function (state) {
|
||||
return state.Loading.groundnetLoaded;
|
||||
},
|
||||
() => { if(this.$store.state.Loading.groundnetLoaded &&
|
||||
this.$store.state.Loading.pavementLoaded &&
|
||||
this.visible) this.check() }
|
||||
,
|
||||
{
|
||||
deep: false
|
||||
}
|
||||
);
|
||||
this.$store.watch(
|
||||
function (state) {
|
||||
return state.Loading.pavementLoaded;
|
||||
},
|
||||
() => { if(this.$store.state.Loading.groundnetLoaded &&
|
||||
this.$store.state.Loading.pavementLoaded &&
|
||||
this.visible) this.check() }
|
||||
,
|
||||
{
|
||||
deep: false
|
||||
}
|
||||
);
|
||||
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
gplv2: false, message: null, error: false, progress: 0, max: 0, azure: false
|
||||
gplv2: false, message: null, error: false, progress: 0, max: 0, azure: false, success: false, uploading: false, buttonText: 'Ok'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
reqListener(e) {
|
||||
try {
|
||||
if(JSON.parse(e.srcElement.response).status==='OK') {
|
||||
this.message = null;
|
||||
this.azure = true;
|
||||
this.error = false;
|
||||
} else {
|
||||
this.message = 'Azure down';
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
},
|
||||
status () {
|
||||
this.azure = false;
|
||||
var xhr = new XMLHttpRequest();
|
||||
var parent = this.$parent;
|
||||
|
||||
this.message = 'Checking for Groundweb health'
|
||||
xhr.open('GET', 'http://groundweb.azurewebsites.net/groundnets/status', true);
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.status !== 200){
|
||||
parent.$refs.upload.message = 'Azure down';
|
||||
parent.$refs.upload.error = true;
|
||||
console.error(xhr);
|
||||
}
|
||||
}
|
||||
xhr.addEventListener("load", this.reqListener);
|
||||
try {
|
||||
xhr.send();
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
this.error = true;
|
||||
}
|
||||
},
|
||||
upload () {
|
||||
closeClicked () {
|
||||
Vue.set(this.$parent, 'uploadVisible', false)
|
||||
return;
|
||||
},
|
||||
handleOkClicked (type) {
|
||||
this.uploading = true;
|
||||
var f = path.join(this.$store.state.Settings.settings.airportsDirectory,
|
||||
this.icao[0],
|
||||
this.icao[1],
|
||||
this.icao[2],
|
||||
this.icao + '.groundnet.new.xml');
|
||||
this.icao + `.${type}.new.xml`);
|
||||
|
||||
if (f == null || !fs.existsSync(f)) {
|
||||
this.message = 'File doesn\'t exist';
|
||||
@ -72,25 +139,35 @@
|
||||
var formData = new FormData();
|
||||
formData.append("gpl", this.gplv2 )
|
||||
formData.append("user_email", this.$store.state.Settings.settings.email)
|
||||
formData.append('groundnet', blob, this.icao + '.groundnet.xml');
|
||||
formData.append('groundnet', blob, this.icao + `.${type}.xml`);
|
||||
|
||||
var parent = this.$parent;
|
||||
var messageField = this.message;
|
||||
// action after uploading happens
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.status !== 200){
|
||||
parent.$refs.upload.message = 'Upload Error'
|
||||
parent.$refs.upload.error = true;
|
||||
console.error(xhr);
|
||||
}
|
||||
}
|
||||
xhr.onload = function(e) {
|
||||
console.log("File uploading completed! ");
|
||||
console.log(e);
|
||||
parent.$refs.upload.uploading = false
|
||||
if (e.srcElement.status===500) {
|
||||
parent.$refs.upload.message == e.srcElement.statusText
|
||||
} else if(JSON.parse(e.srcElement.response).message.match('[A-Z0-9]* Imported Successfully')) {
|
||||
Vue.set(parent, 'uploadVisible', false)
|
||||
parent.$refs.upload.success = true
|
||||
parent.$refs.upload.message = `${type} Uploaded Successfully`
|
||||
parent.$store.commit('UPLOAD_WIP', parent.$store.state.Airports.currentAirport.icao)
|
||||
|
||||
} else if(JSON.parse(e.srcElement.response).message === 'XML Errors') {
|
||||
var response = JSON.parse(e.srcElement.response);
|
||||
if (response.validationErrors) {
|
||||
parent.$refs.upload.message = 'XML Errors : \n';
|
||||
response.validationErrors.forEach(element => {
|
||||
parent.$refs.upload.message += element.message + '\r\n';
|
||||
parent.$refs.upload.message += element.message + '\n';
|
||||
});
|
||||
}
|
||||
} else if(JSON.parse(e.srcElement.response) !== undefined) {
|
||||
@ -116,45 +193,22 @@
|
||||
view.scanning = Boolean(workery.checking)
|
||||
workery.view = view
|
||||
}
|
||||
}, 1000)
|
||||
},
|
||||
featuresMapper(o) {
|
||||
if (o instanceof L.ParkingSpot) {
|
||||
return { 'index': Number(o['id']),
|
||||
'_leaflet_id': o._leaflet_id,
|
||||
'type': 'parking',
|
||||
'parkingType': o.options.attributes.type,
|
||||
'name': o.options.attributes.name,
|
||||
'radius': String(o.options.attributes.radius),
|
||||
'lat': o._latlng.lat,
|
||||
'lng': o._latlng.lng,
|
||||
'box': o.box!==undefined?o.box.getLatLngs():null
|
||||
};
|
||||
} else if (o instanceof L.RunwayNode) {
|
||||
console.log(o)
|
||||
return { 'index': Number(o['glueindex']), '_leaflet_id': o._leaflet_id, 'type': 'runway' };
|
||||
} else if (o instanceof L.HoldNode) {
|
||||
console.log(o)
|
||||
return { 'index': Number(o['glueindex']), '_leaflet_id': o._leaflet_id, 'type': o.holdPointType };
|
||||
} else if (o instanceof L.Polyline) {
|
||||
console.log(o)
|
||||
var latLngs = o.getLatLngs().map(l => ({lat: l.lat, lng: l.lng, index: l.attributes.index}));
|
||||
return { 'start': Number(o['begin']), 'end': Number(o['end']), '_leaflet_id': o._leaflet_id, 'type': 'poly', 'isPushBackRoute': o.options.attributes.isPushBackRoute, latLngs: latLngs };
|
||||
} else {
|
||||
console.log('Unknown Type ')
|
||||
console.log(typeof o)
|
||||
}
|
||||
}, 500)
|
||||
},
|
||||
check () {
|
||||
try {
|
||||
if(!(this.$store.state.Loading.groundnetLoaded &&
|
||||
this.$store.state.Loading.pavementLoaded)) {
|
||||
return
|
||||
}
|
||||
this.scanning = true
|
||||
const winURL = process.env.NODE_ENV === 'development'
|
||||
? `http://localhost:9080/src/renderer/utils/check.js`
|
||||
: `file://${process.resourcesPath}/workers/check.js`
|
||||
console.log('make a check worker: ', path.resolve(__dirname, 'check.js'))
|
||||
console.debug('make a check worker: ', path.resolve(__dirname, 'check.js'))
|
||||
|
||||
const worker = new Worker(winURL)
|
||||
console.log(fileUrl('src/renderer/utils/check.js'))
|
||||
console.debug(fileUrl('src/renderer/utils/check.js'))
|
||||
|
||||
worker.checking = this.checking
|
||||
worker.max = this.max
|
||||
@ -163,15 +217,32 @@
|
||||
worker.progress = 0
|
||||
// var worker = new Worker(fileUrl('src/renderer/utils/worker.js'))
|
||||
this.worker = worker
|
||||
var xml = []
|
||||
this.$parent.$parent.$parent.$refs.editLayer.groundnetLayerGroup.eachLayer(l => {
|
||||
var groundnet = []
|
||||
|
||||
if (!this.editLayer().groundnetLayerGroup) {
|
||||
this.message = 'Groundnet not visible'
|
||||
}
|
||||
if (!this.pavementLayer().pavement) {
|
||||
this.message = 'Pavement not visible'
|
||||
}
|
||||
this.editLayer().groundnetLayerGroup.eachLayer(l => {
|
||||
console.log(l)
|
||||
xml.push(l)
|
||||
if (l instanceof L.Polyline) {
|
||||
l._latlngs[0].glueindex = this.begin;
|
||||
l._latlngs.slice(-1)[0].glueindex = this.end;
|
||||
l.extensions(this)
|
||||
}
|
||||
groundnet.push(l)
|
||||
})
|
||||
var features = groundnet.map(mapper.checkMapper).filter(n => n)
|
||||
var pavement = []
|
||||
this.pavementLayer().pavement.eachLayer(l => {
|
||||
console.log(l)
|
||||
pavement.push(l)
|
||||
})
|
||||
var features2 = pavement.map(mapper.checkMapper).filter(n => n)
|
||||
|
||||
var features = xml.map(this.featuresMapper).filter(n => n)
|
||||
|
||||
worker.postMessage(['check', features ] )
|
||||
worker.postMessage(['check', features.concat(features2) ] )
|
||||
this.pollData()
|
||||
// the reply
|
||||
var store = this.$store
|
||||
@ -181,7 +252,6 @@
|
||||
this.max = 4
|
||||
} else if (e.data[0] === 'DONE') {
|
||||
console.log('DONE')
|
||||
store.dispatch('setResults', e.data[1])
|
||||
worker.terminate()
|
||||
worker.view.max = 0
|
||||
worker.view.checkDialogVisible = false
|
||||
@ -200,6 +270,24 @@
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
},
|
||||
editLayer () {
|
||||
var parent = this.$parent;
|
||||
while (!parent.icao||parent.$refs.editLayer==undefined) {
|
||||
parent = parent.$parent;
|
||||
if (parent.icao&&parent.$refs.editLayer!==undefined) {
|
||||
return parent.$refs.editLayer;
|
||||
}
|
||||
}
|
||||
},
|
||||
pavementLayer () {
|
||||
var parent = this.$parent;
|
||||
while (!parent.icao||parent.$refs.pavementLayer==undefined) {
|
||||
parent = parent.$parent;
|
||||
if (parent.icao&&parent.$refs.pavementLayer!==undefined) {
|
||||
return parent.$refs.pavementLayer;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -213,28 +301,65 @@
|
||||
Vue.set(this.$parent, 'uploadVisible', newValue)
|
||||
}
|
||||
},
|
||||
textClass: function () {
|
||||
return !this.error?'centermessage':'error'
|
||||
},
|
||||
title: function () {
|
||||
return `Upload ${this.$parent.$parent.$parent.icao} to groundweb.`
|
||||
return `Upload ${this.icao} to groundweb.`
|
||||
},
|
||||
icao: {
|
||||
get: function () {
|
||||
return this.$parent.$parent.$parent.icao
|
||||
var parent = this.$parent;
|
||||
while (!parent.icao) {
|
||||
parent = parent.$parent;
|
||||
if (parent.icao) {
|
||||
return parent.icao;
|
||||
}
|
||||
}
|
||||
return this.$store.state.Airports.currentAirport.icao
|
||||
},
|
||||
set: function (newValue) {
|
||||
console.error('ICAO being set ' + newValue);
|
||||
}
|
||||
},
|
||||
tower_comittable: function () {
|
||||
var f = path.join(this.$store.state.Settings.settings.airportsDirectory,
|
||||
this.icao[0],
|
||||
this.icao[1],
|
||||
this.icao[2],
|
||||
this.icao + '.twr.new.xml');
|
||||
return fs.existsSync(f) && this.gplv2 && this.max === 0 && this.azure && !this.uploading;
|
||||
},
|
||||
groundnet_comittable: function () {
|
||||
var f = path.join(this.$store.state.Settings.settings.airportsDirectory,
|
||||
this.icao[0],
|
||||
this.icao[1],
|
||||
this.icao[2],
|
||||
this.icao + '.groundnet.new.xml');
|
||||
return fs.existsSync(f) && this.$store.state.Check.results.filter(a => a.id>=0).length === 0 && this.gplv2 && this.max === 0 && this.azure && !this.uploading
|
||||
},
|
||||
threshold_comittable: function () {
|
||||
var f = path.join(this.$store.state.Settings.settings.airportsDirectory,
|
||||
this.icao[0],
|
||||
this.icao[1],
|
||||
this.icao[2],
|
||||
this.icao + '.threshold.new.xml');
|
||||
return fs.existsSync(f) && this.gplv2 && this.max === 0 && this.azure && !this.uploading
|
||||
},
|
||||
comittable: function () {
|
||||
return this.$store.state.Check.results.filter(a => a.id>=0).length === 0 && this.gplv2 && this.max === 0 && this.azure
|
||||
return this.$store.state.Check.results.filter(a => a.id>=0).length === 0 && this.gplv2 && this.max === 0 && this.azure && !this.uploading
|
||||
},
|
||||
results: function () {
|
||||
return this.$store.state.Check.results.filter(a => a.id>=0)
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.center { text-align: center; vertical-align: middle;}
|
||||
.error { text-align: center; background-color: red;}
|
||||
.el-dialog__body {padding: 10px;}
|
||||
.center { text-align: center; vertical-align: middle; padding: 5px; font-size: 12pt; font-weight: normal}
|
||||
.centermessage { text-align: left; vertical-align: middle; padding: 5px; font-size: 12pt; font-weight: normal; white-space: pre-line;}
|
||||
.error { text-align: center; color: red; padding: 5px; font-size: 12pt; font-weight: normal;}
|
||||
.el-dialog--center .el-dialog__body { padding: 5px;}
|
||||
</style>
|
||||
|
14
src/renderer/components/event-bus.js
Normal file
@ -0,0 +1,14 @@
|
||||
/*
|
||||
Copyright 2020 Keith Paterson
|
||||
|
||||
This file is part of FG Airports.
|
||||
|
||||
FG Airports is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
FG Airports is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with FG Airports. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
import Vue from 'vue'
|
||||
export const EventBus = new Vue()
|
41
src/renderer/leaflet/Runway.js
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
Copyright 2020 Keith Paterson
|
||||
|
||||
This file is part of FG Airports.
|
||||
|
||||
FG Airports is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
FG Airports is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with FG Airports. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
/* eslint-disable */
|
||||
|
||||
const turf = require('@turf/turf')
|
||||
|
||||
L.RunwayPolygon = L.Polygon.extend({
|
||||
turfyRunway: [],
|
||||
|
||||
setTurfy: function (runwayPoints) {
|
||||
var latLngs = runwayPoints.map(this.turfToLatLng);
|
||||
latLngs.push(latLngs[0]);
|
||||
this.turfyRunway = turf.polygon([latLngs]);
|
||||
},
|
||||
|
||||
turfToLatLng: function (turfPoint) {
|
||||
return [turfPoint.lng, turfPoint.lat];
|
||||
}
|
||||
});
|
||||
|
||||
var runwayPoly = function (runwayPoints) {
|
||||
var runwayPoly = new L.RunwayPolygon(runwayPoints);
|
||||
runwayPoly.setStyle({ color: 'grey', fillColor: 'grey', opacity: 0.5, fillOpacity: 0.5, interactive: false });
|
||||
runwayPoly.setTurfy(runwayPoints);
|
||||
console.debug(runwayPoints);
|
||||
return runwayPoly;
|
||||
}
|
||||
|
||||
|
||||
|
||||
module.exports = runwayPoly;
|
41
src/renderer/leaflet/TakeoffPad.js
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
Copyright 2021 Keith Paterson
|
||||
|
||||
This file is part of FG Airports.
|
||||
|
||||
FG Airports is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
FG Airports is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with FG Airports. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
/* eslint-disable */
|
||||
|
||||
const turf = require('@turf/turf')
|
||||
|
||||
L.TakeoffPolygon = L.Polygon.extend({
|
||||
turfyRunway: [],
|
||||
|
||||
setTurfy: function (padPoints) {
|
||||
var latLngs = padPoints.map(this.turfToLatLng);
|
||||
latLngs.push(latLngs[0]);
|
||||
this.turfyRunway = turf.polygon([latLngs]);
|
||||
},
|
||||
|
||||
turfToLatLng: function (turfPoint) {
|
||||
return [turfPoint.lng, turfPoint.lat];
|
||||
}
|
||||
});
|
||||
|
||||
var takeoffPadPoly = function (padPoints) {
|
||||
var takeoffPadPoly = new L.TakeoffPolygon(padPoints);
|
||||
takeoffPadPoly.setStyle({ color: 'black', fillColor: '', opacity: 1.0, fillOpacity: 0.0, interactive: false });
|
||||
takeoffPadPoly.setTurfy(padPoints);
|
||||
console.debug(padPoints);
|
||||
return takeoffPadPoly;
|
||||
}
|
||||
|
||||
|
||||
|
||||
module.exports = takeoffPadPoly;
|
25
src/renderer/leaflet/Taxiway.js
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
Copyright 2020 Keith Paterson
|
||||
|
||||
This file is part of FG Airports.
|
||||
|
||||
FG Airports is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
FG Airports is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with FG Airports. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
/* eslint-disable */
|
||||
|
||||
L.TaxiwayPolygon = L.Polygon.extend({
|
||||
});
|
||||
|
||||
var taxiwayPoly = function (runwayPoints) {
|
||||
var taxiwayPoly = new L.TaxiwayPolygon(runwayPoints);
|
||||
taxiwayPoly.setStyle({ color: 'grey', fillColor: 'grey', opacity: 0.3, fillOpacity: 0.3, interactive: false });
|
||||
|
||||
return taxiwayPoly;
|
||||
}
|
||||
|
||||
module.exports = taxiwayPoly;
|
@ -95,6 +95,7 @@ var holdNode = function (n, layerGroup) {
|
||||
});
|
||||
const node = new L.HoldNode([latlon.decimalLatitude, latlon.decimalLongitude], { icon: icon });
|
||||
node.glueindex = n.attr('index');
|
||||
node.feature = { properties: { searchTerm: n.attr('index')}};
|
||||
node.holdPointType = n.attr('holdPointType');
|
||||
node.addTo(layerGroup);
|
||||
node.addListeners();
|
||||
|
@ -96,6 +96,10 @@ L.ParkingSpot = L.Circle.extend({
|
||||
this.updateWheelPos();
|
||||
this.updateBox();
|
||||
},
|
||||
updateType(type) {
|
||||
this.options.attributes.type = type;
|
||||
this.deselect();
|
||||
},
|
||||
// Update the direction vertex from the direction
|
||||
updateVertexFromDirection() {
|
||||
if (this.editEnabled()) {
|
||||
@ -137,6 +141,7 @@ L.ParkingSpot = L.Circle.extend({
|
||||
|
||||
if(this.frontWheel!==undefined) {
|
||||
this.frontWheel.setLatLng(this.turfToLatLng(frontWheelEnd));
|
||||
return this.turfToLatLng(frontWheelEnd);
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -190,10 +195,13 @@ L.ParkingSpot = L.Circle.extend({
|
||||
}
|
||||
event.target._parkingSpot.select();
|
||||
});
|
||||
|
||||
if(this.editor && this.editor.editLayer) {
|
||||
this.box.addTo(this.editor.editLayer);
|
||||
}
|
||||
}
|
||||
if(this.box!==undefined) {
|
||||
var latlngs = [leftBack, rightBack, rightMiddle, rightIntermediate, rightFront, leftFront, leftIntermediate, leftMiddle].map(l => this.turfToLatLng(l));
|
||||
console.debug(latlngs);
|
||||
this.box.setLatLngs(latlngs);
|
||||
}
|
||||
}
|
||||
@ -216,26 +224,59 @@ L.ParkingSpot = L.Circle.extend({
|
||||
if(this.direction) {
|
||||
this.direction.setStyle(style);
|
||||
this.frontWheel.setStyle(style);
|
||||
}
|
||||
var wheelPos = this.updateWheelPos();
|
||||
if(wheelPos) {
|
||||
store.default.dispatch('setParkingNoseCoords', wheelPos.lat.toFixed(6) + ' ' + wheelPos.lng.toFixed(6));
|
||||
}
|
||||
|
||||
this.updateBox();
|
||||
if(this.box) {
|
||||
this.box.setStyle(style);
|
||||
}
|
||||
}
|
||||
this.updateWheelPos();
|
||||
this.updateBox();
|
||||
},
|
||||
deselect() {
|
||||
var style = {};
|
||||
if(this.options.attributes.type == 'ga') {
|
||||
style['color'] = 'green';
|
||||
} else if(this.options.attributes.type == 'cargo') {
|
||||
style['color'] = 'yellow';
|
||||
} else if(this.options.attributes.type == 'gate') {
|
||||
style['color'] = '#3388ff';
|
||||
} else if(this.options.attributes.type == 'mil-fighter') {
|
||||
style['color'] = 'red';
|
||||
} else if(this.options.attributes.type == 'mil-cargo') {
|
||||
style['color'] = 'DarkRed';
|
||||
} else {
|
||||
style['color'] = '#3388ff';
|
||||
}
|
||||
this.setStyle(style);
|
||||
if(this.direction) {
|
||||
this.direction.setStyle(style);
|
||||
this.frontWheel.setStyle(style);
|
||||
if(this.box) {
|
||||
this.box.setStyle(style);
|
||||
}
|
||||
}
|
||||
this.updateWheelPos();
|
||||
this.updateBox();
|
||||
if(this.box) {
|
||||
this.box.setStyle(style);
|
||||
}
|
||||
},
|
||||
setInteractive(interactive) {
|
||||
if (interactive) {
|
||||
if(this.direction&&this.direction._path) {
|
||||
L.DomUtil.addClass(this.direction._path, 'leaflet-interactive');
|
||||
}
|
||||
if(this.box&&this.box._path) {
|
||||
L.DomUtil.addClass(this.box._path, 'leaflet-interactive');
|
||||
}
|
||||
} else {
|
||||
if(this.direction&&this.direction._path) {
|
||||
L.DomUtil.removeClass(this.direction._path, 'leaflet-interactive');
|
||||
}
|
||||
if(this.box&&this.box._path) {
|
||||
L.DomUtil.removeClass(this.box._path, 'leaflet-interactive');
|
||||
}
|
||||
}
|
||||
},
|
||||
addListeners: function () {
|
||||
this.on('editable:drawing:move', function (event) {
|
||||
@ -257,14 +298,15 @@ L.ParkingSpot = L.Circle.extend({
|
||||
}
|
||||
});
|
||||
this.on('add', function (event) {
|
||||
console.log(event);
|
||||
console.debug(event);
|
||||
event.target.updateBox();
|
||||
if(event.target.box !== undefined) {
|
||||
event.target.box.addTo(event.target._map);
|
||||
}
|
||||
event.target.setInteractive(false);
|
||||
});
|
||||
this.on('remove', function (event) {
|
||||
console.log(event);
|
||||
console.debug(event);
|
||||
if(event.target.box !== undefined) {
|
||||
event.target.box.removeFrom(event.target._map);
|
||||
}
|
||||
@ -276,7 +318,8 @@ L.ParkingSpot = L.Circle.extend({
|
||||
console.debug("DragEnd Parking : ", event);
|
||||
store.default.dispatch('setParking', event.target.options.attributes);
|
||||
store.default.dispatch('setParkingCoords', event.target.getLatLng().lat.toFixed(6) + ' ' + event.target.getLatLng().lng.toFixed(6));
|
||||
event.target.updateWheelPos();
|
||||
var wheelPos = event.target.updateWheelPos();
|
||||
store.default.dispatch('setParkingNoseCoords', wheelPos.lat.toFixed(6) + ' ' + wheelPos.lng.toFixed(6));
|
||||
event.target.updateBox();
|
||||
/*
|
||||
store.default.dispatch('setParkingHeading', this.options.attributes.heading)
|
||||
@ -330,10 +373,6 @@ L.ParkingSpot = L.Circle.extend({
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
store.default.dispatch('setParking', this.options.attributes);
|
||||
store.default.dispatch('setParkingCoords', this.getLatLng().lat.toFixed(6) + ' ' + this.getLatLng().lng.toFixed(6));
|
||||
|
||||
this.select();
|
||||
},
|
||||
turfToLatLng: function (turfPoint) {
|
||||
@ -413,12 +452,14 @@ var parkingSpot = function (n, layerGroup) {
|
||||
var latlon = convert(n.attr('lat') + " " + n.attr('lon'));
|
||||
//console.log(latlon.decimalLatitude);
|
||||
//console.log(convert(n.attr('lat') + " " + n.attr('lon')).decimalLongitude);
|
||||
const circle = new L.ParkingSpot([latlon.decimalLatitude, latlon.decimalLongitude], { radius: n.attr('radius'), attributes: {} });
|
||||
circle.on('editable:enable', function (event) {
|
||||
const parking = new L.ParkingSpot([latlon.decimalLatitude, latlon.decimalLongitude], { radius: n.attr('radius'), attributes: {} });
|
||||
parking.on('editable:enable', function (event) {
|
||||
// event.target.createDirection();
|
||||
});
|
||||
circle.id = n.attr('index');
|
||||
circle.glueindex = n.attr('index');
|
||||
parking.id = n.attr('index');
|
||||
parking.glueindex = n.attr('index');
|
||||
parking.feature = { properties: { searchTerm: n.attr('index') + ' ' + n.attr('name')}};
|
||||
|
||||
/*
|
||||
<Parking index="2"
|
||||
type="gate"
|
||||
@ -434,17 +475,18 @@ airlineCodes="VIR,KAL,DAL,KLM" />
|
||||
//circle.attributes = { type: n.attr('type'), name: n.attr('name'), radius: Number(n.attr('radius')), airlineCodes: n.attr('airlineCodes'), heading: Number(n.attr('heading')) };
|
||||
|
||||
$.each( n.attrs, function( key, value ) {
|
||||
console.debug( '$', circle.id, key , value);
|
||||
console.debug( '$', parking.id, key , value);
|
||||
|
||||
if(isNaN(value))
|
||||
circle.options.attributes[ key ] = value;
|
||||
parking.options.attributes[ key ] = value;
|
||||
else
|
||||
circle.options.attributes[ key ] = Number( value);
|
||||
parking.options.attributes[ key ] = Number( value);
|
||||
});
|
||||
circle.addListeners();
|
||||
parking.addListeners();
|
||||
|
||||
circle.addTo(layerGroup);
|
||||
return circle;
|
||||
parking.addTo(layerGroup);
|
||||
parking.deselect();
|
||||
return parking;
|
||||
}
|
||||
|
||||
module.exports = parkingSpot;
|
@ -26,6 +26,20 @@ L.RunwayNode = L.Marker.extend({
|
||||
store.default.dispatch('setRunway', event.target.options.attributes);
|
||||
}
|
||||
});
|
||||
this.on('add', function (event) {
|
||||
event.target.setInteractive(false);
|
||||
});
|
||||
},
|
||||
setInteractive(interactive) {
|
||||
if (interactive) {
|
||||
if(this._icon) {
|
||||
L.DomUtil.addClass(this._icon, 'leaflet-interactive');
|
||||
}
|
||||
} else {
|
||||
if(this._icon) {
|
||||
L.DomUtil.removeClass(this._icon, 'leaflet-interactive');
|
||||
}
|
||||
}
|
||||
},
|
||||
select() {
|
||||
try {
|
||||
@ -106,6 +120,8 @@ var runwayNode = function (n, layerGroup) {
|
||||
});
|
||||
var node = new L.RunwayNode([latlon.decimalLatitude, latlon.decimalLongitude], { icon: icon, attributes: {} });
|
||||
node.glueindex = n.attr('index');
|
||||
node.feature = n.attr('index');
|
||||
|
||||
$.each( n.attrs, function( key, value ) {
|
||||
if(isNaN(value))
|
||||
node.options.attributes[ key ] = value;
|
||||
|
@ -3,19 +3,25 @@ const Vue = require('vue');
|
||||
|
||||
var L = require('leaflet');
|
||||
const store = require('../store');
|
||||
const util = require('util');
|
||||
const assign = require('core-js/fn/object/assign');
|
||||
|
||||
exports.extendTaxiSegment = function (taxiwaySegment) {
|
||||
const extendTaxiSegment = function (taxiwaySegment) {
|
||||
taxiwaySegment.__proto__.begin;
|
||||
taxiwaySegment.__proto__.end;
|
||||
taxiwaySegment.__proto__.bidirectional;
|
||||
|
||||
taxiwaySegment.__proto__.updateBeginVertex = function (latlng) {
|
||||
if (this._latlngs[0].__vertex) {
|
||||
this._latlngs[0].__vertex.setLatLng(latlng);
|
||||
this.selectVertex(Number(this._latlngs[0].glueindex));
|
||||
}
|
||||
|
||||
};
|
||||
taxiwaySegment.__proto__.updateEndVertex = function (latlng) {
|
||||
if (this._latlngs[1].__vertex) {
|
||||
this._latlngs[1].__vertex.setLatLng(latlng);
|
||||
this.selectVertex(Number(this._latlngs[1].glueindex));
|
||||
}
|
||||
};
|
||||
|
||||
@ -33,6 +39,7 @@ exports.extendTaxiSegment = function (taxiwaySegment) {
|
||||
this.editLayer = editLayer;
|
||||
this._latlngs[0].glueindex = this.begin;
|
||||
this._latlngs.slice(-1)[0].glueindex = this.end;
|
||||
if (this.featureLookup) {
|
||||
if (typeof this.featureLookup[this.begin] === 'undefined') {
|
||||
this.featureLookup[this.begin] = new Array();
|
||||
}
|
||||
@ -42,19 +49,20 @@ exports.extendTaxiSegment = function (taxiwaySegment) {
|
||||
this.featureLookup[this.begin].push(this);
|
||||
this.featureLookup[this.end].push(this);
|
||||
this.bidirectional = true;
|
||||
}
|
||||
};
|
||||
taxiwaySegment.__proto__.select = function () {
|
||||
this.options.attributes.selected = true;
|
||||
this.updateStyle();
|
||||
};
|
||||
taxiwaySegment.__proto__.selectVertex = function () {
|
||||
this.getLatLngs().forEach( element => {
|
||||
if (Number(element.glueindex) === store.default.state.Editable.index) {
|
||||
if (element.__vertex._icon != null) {
|
||||
taxiwaySegment.__proto__.selectVertex = function (index) {
|
||||
this.getLatLngs().forEach(element => {
|
||||
if (Number(element.glueindex) === index) {
|
||||
if (element.__vertex !== undefined && element.__vertex._icon != null) {
|
||||
element.__vertex.__proto__.deselect = function () {
|
||||
if (this._icon != null) {
|
||||
this._icon.style.setProperty('background-color','white');
|
||||
this._icon.style.setProperty('color','white');
|
||||
this._icon.style.setProperty('background-color', 'white');
|
||||
this._icon.style.setProperty('color', 'white');
|
||||
} else if (this.icon != null) {
|
||||
if (this.icon.style != null) {
|
||||
this.icon.style['background-color'] = 'white';
|
||||
@ -69,8 +77,8 @@ exports.extendTaxiSegment = function (taxiwaySegment) {
|
||||
}
|
||||
}
|
||||
}
|
||||
element.__vertex._icon.style.setProperty('background-color','red');
|
||||
element.__vertex._icon.style.setProperty('color','red');
|
||||
element.__vertex._icon.style.setProperty('background-color', 'red');
|
||||
element.__vertex._icon.style.setProperty('color', 'red');
|
||||
} else if (element.__vertex !== undefined && element.__vertex.icon != null) {
|
||||
if (element.__vertex.icon.style != null) {
|
||||
element.__vertex.icon.style['background-color'] = 'red';
|
||||
@ -90,8 +98,8 @@ exports.extendTaxiSegment = function (taxiwaySegment) {
|
||||
taxiwaySegment.__proto__.deselect = function () {
|
||||
this.options.attributes.selected = false;
|
||||
this.updateStyle();
|
||||
this.getLatLngs().forEach( element => {
|
||||
if (element.__vertex!==undefined) {
|
||||
this.getLatLngs().forEach(element => {
|
||||
if (element.__vertex !== undefined) {
|
||||
if (element.__vertex._icon != null) {
|
||||
element.__vertex._icon.style['background-color'] = 'white';
|
||||
} else if (element.__vertex.icon != null) {
|
||||
@ -119,7 +127,8 @@ exports.extendTaxiSegment = function (taxiwaySegment) {
|
||||
});
|
||||
}
|
||||
event.target.select();
|
||||
console.log("Click : " + event.target);
|
||||
console.debug("Click : " + util.inspect(event.originalEvent));
|
||||
if (!event.originalEvent.ctrlKey) {
|
||||
if (store.default.state.Editable.data.arc === undefined ||
|
||||
store.default.state.Editable.data.arc !== event.target.options.attributes) {
|
||||
if (event.target.options.attributes === undefined) {
|
||||
@ -132,29 +141,138 @@ exports.extendTaxiSegment = function (taxiwaySegment) {
|
||||
event.target.options.attributes.selected = true;
|
||||
store.default.dispatch('setArc', event.target.options.attributes);
|
||||
}
|
||||
} else {
|
||||
var arcs = event.target.expandArc(event.target.options.attributes);
|
||||
var multiarc = { name: '', index: 900719925474099, ids: [], isPushBackRoute: null, direction: null };
|
||||
if (store.default.state.Editable.data.multiarc === undefined ||
|
||||
store.default.state.Editable.data.multiarc !== event.target.options.attributes) {
|
||||
if (event.target.options.attributes === undefined) {
|
||||
event.target.options.attributes = {};
|
||||
}
|
||||
event.target.options.attributes.index = event.target._leaflet_id;
|
||||
|
||||
this.editLayer.featureLookup[event.target._leaflet_id] = [];
|
||||
this.featureLookup[event.target._leaflet_id].push(this);
|
||||
event.target.options.attributes.selected = true;
|
||||
|
||||
//multiarc.name = JSON.parse(JSON.stringify(event.target.options.attributes.name));
|
||||
//multiarc.isPushBackRoute = JSON.parse(JSON.stringify(event.target.options.attributes.isPushBackRoute));
|
||||
//multiarc.direction = JSON.parse(JSON.stringify(event.target.options.attributes.direction));
|
||||
if (event.target.options.attributes.name !== undefined) {
|
||||
multiarc.name = assign(event.target.options.attributes.name);
|
||||
}
|
||||
if (event.target.options.attributes.isPushBackRoute) {
|
||||
multiarc.isPushBackRoute = assign(event.target.options.attributes.isPushBackRoute);
|
||||
} else {
|
||||
multiarc.isPushBackRoute = false;
|
||||
}
|
||||
multiarc.direction = assign(event.target.options.attributes.direction);
|
||||
|
||||
this.editLayer.featureLookup[900719925474099] = [];
|
||||
|
||||
multiarc.ids = [];
|
||||
|
||||
//TODO
|
||||
store.default.dispatch('setMultiArc', multiarc);
|
||||
}
|
||||
var editLayer = this.editLayer;
|
||||
arcs.forEach(id => {
|
||||
console.debug(id);
|
||||
var arc = editLayer.groundnetLayerGroup.getLayer(id);
|
||||
if (arc && arc instanceof L.Polyline) {
|
||||
editLayer.featureLookup[900719925474099].push(arc);
|
||||
arc.select();
|
||||
}
|
||||
});
|
||||
store.default.dispatch('setMultiArcIds', arcs);
|
||||
}
|
||||
});
|
||||
this.on('editable:drawing:move', function (event) {
|
||||
if (dragIndex >= 0) {
|
||||
console.log('GlueDrag : '+ dragIndex + '\t' + event.target.dragIndex);
|
||||
this.selectVertex(dragIndex);
|
||||
console.log('GlueDrag : ' + dragIndex + '\t' + event.target.dragIndex);
|
||||
this.follow(dragIndex, event);
|
||||
}
|
||||
});
|
||||
this.on('editable:middlemarker:mousedown', event => {
|
||||
console.debug('editable:middlemarker:mousedown');
|
||||
});
|
||||
this.on('editable:vertex:new', event => {
|
||||
console.log(event)
|
||||
console.debug('editable:vertex:new ' + event.vertex.getIndex() + '\t' + event.vertex.getLastIndex() + '\t');
|
||||
// Find nearest node
|
||||
let isOnRunway = this.editLayer.isOnRunway(event.latlng)
|
||||
let closest = this.editLayer.closestLayerSnap(event.latlng, 5)
|
||||
let taxiwaySegment = event.latlng.__vertex.editor.feature;
|
||||
let taxiwaySegment = event.vertex.editor.feature;
|
||||
if (taxiwaySegment.options.attributes === undefined) {
|
||||
taxiwaySegment.options.attributes = { direction: 'bi-directional' };
|
||||
}
|
||||
var isOnRunwayNum = 0;
|
||||
if (isOnRunway) {
|
||||
isOnRunwayNum = 1;
|
||||
}
|
||||
taxiwaySegment.updateStyle();
|
||||
if (event.vertex.getIndex() !== 0 && event.vertex.getIndex() !== event.vertex.getLastIndex()) {
|
||||
var x = taxiwaySegment.getLatLngs().filter(l => l === event.vertex.latlng);
|
||||
// Somehow the latlng is not in our Segment!?
|
||||
if (taxiwaySegment.getLatLngs().length < 3 && x.length === 0) {
|
||||
var fixed = taxiwaySegment.getLatLngs();
|
||||
fixed.splice(1, 0, event.vertex.latlng);
|
||||
taxiwaySegment.setLatLngs(fixed);
|
||||
}
|
||||
var nextIndex = ++taxiwaySegment.editLayer.groundnetLayerGroup.maxId;
|
||||
var splitOffNodes = taxiwaySegment.getLatLngs().splice(-1);
|
||||
var remainingNodes = taxiwaySegment.getLatLngs();
|
||||
if (remainingNodes.length <= 1 || !remainingNodes[1]) {
|
||||
console.error('Not enough remaining nodes', remainingNodes);
|
||||
}
|
||||
splitOffNodes.unshift(L.latLng(remainingNodes[1].lat, remainingNodes[1].lng, remainingNodes[1].alt));
|
||||
remainingNodes[1]['glueindex'] = nextIndex;
|
||||
remainingNodes[1].attributes = { index: nextIndex, isOnRunway: isOnRunwayNum };
|
||||
taxiwaySegment.options.attributes.end = nextIndex;
|
||||
splitOffNodes[0]['glueindex'] = nextIndex;
|
||||
splitOffNodes[0].attributes = { index: nextIndex, isOnRunway: isOnRunwayNum };
|
||||
taxiwaySegment.setLatLngs(remainingNodes);
|
||||
//taxiwaySegment.editor.refresh();
|
||||
//taxiwaySegment.editor.reset();
|
||||
if (splitOffNodes.length > 1) {
|
||||
var polyline = new L.Polyline(splitOffNodes, { attributes: {} });
|
||||
polyline.addTo(taxiwaySegment.editLayer.$parent.$parent.$refs.map.mapObject);
|
||||
polyline.addTo(taxiwaySegment.editLayer.groundnetLayerGroup);
|
||||
extendTaxiSegment(polyline);
|
||||
polyline.addListeners();
|
||||
polyline.setEditlayer(taxiwaySegment.editLayer);
|
||||
polyline.enableEdit(taxiwaySegment.editLayer.$parent.$parent.$refs.map.mapObject);
|
||||
polyline.editor.refresh();
|
||||
//polyline.editor.reset();
|
||||
polyline.featureLookup = this.featureLookup;
|
||||
polyline.feature = { properties: {searchTerm: 'Arc ' + nextIndex + '-' + taxiwaySegment.end}};
|
||||
|
||||
polyline.options.attributes.name = taxiwaySegment.options.attributes.name;
|
||||
polyline.options.attributes.direction = taxiwaySegment.options.attributes.direction;
|
||||
polyline.options.attributes.isPushBackRoute = taxiwaySegment.options.attributes.isPushBackRoute;
|
||||
polyline.options.attributes.begin = nextIndex;
|
||||
polyline.options.attributes.end = taxiwaySegment.end;
|
||||
polyline.updateStyle();
|
||||
polyline.begin = nextIndex;
|
||||
polyline.end = taxiwaySegment.end;
|
||||
taxiwaySegment.end = nextIndex;
|
||||
this.editLayer.featureLookup[nextIndex] = [];
|
||||
this.featureLookup[nextIndex].push(taxiwaySegment);
|
||||
this.featureLookup[nextIndex].push(polyline);
|
||||
} else {
|
||||
console.error('SplitoffNodes Short ', splitOffNodes);
|
||||
}
|
||||
} else {
|
||||
// Glue to another node
|
||||
if (closest) {
|
||||
event.latlng['glueindex'] = Number(closest.glueindex);
|
||||
event.latlng.__vertex.setLatLng(closest.latlng);
|
||||
event.latlng.attributes = { index: event.latlng.glueindex, isOnRunway: 0 };
|
||||
event.latlng.attributes = { index: event.latlng.glueindex, isOnRunway: isOnRunwayNum };
|
||||
// Push Vertex to lookup
|
||||
this.editLayer.featureLookup[event.latlng.glueindex].push(event.latlng.__vertex);
|
||||
if (isOnRunwayNum == 1) {
|
||||
this.editLayer.addRunwayNode(event.latlng, event.latlng['glueindex'])
|
||||
}
|
||||
if (taxiwaySegment.options.attributes.begin === undefined) {
|
||||
taxiwaySegment.options.attributes.begin = event.latlng['glueindex']
|
||||
} else {
|
||||
@ -164,13 +282,16 @@ exports.extendTaxiSegment = function (taxiwaySegment) {
|
||||
taxiwaySegment.begin = closest.glueindex;
|
||||
}
|
||||
taxiwaySegment.end = closest.glueindex;
|
||||
console.log(`Closest : ${closest}`)
|
||||
console.debug(`Closest : ${closest}`)
|
||||
} else {
|
||||
event.vertex.latlng['glueindex'] = ++this.editLayer.groundnetLayerGroup.maxId;
|
||||
event.vertex.latlng.attributes = { index: event.vertex.latlng.glueindex, isOnRunway: 0 };
|
||||
event.vertex.latlng.attributes = { index: event.vertex.latlng.glueindex, isOnRunway: isOnRunwayNum };
|
||||
this.editLayer.featureLookup[event.vertex.latlng.glueindex] = [];
|
||||
this.editLayer.featureLookup[event.vertex.latlng.glueindex].push(event.vertex);
|
||||
this.editLayer.featureLookup[event.vertex.latlng.glueindex].push(taxiwaySegment);
|
||||
if (isOnRunwayNum == 1) {
|
||||
this.editLayer.addRunwayNode(event.latlng, event.vertex.latlng['glueindex'])
|
||||
}
|
||||
// taxiwaySegment.editor.refresh();
|
||||
//taxiwaySegment.editor.reset();
|
||||
if (taxiwaySegment.options.attributes.begin === undefined) {
|
||||
@ -183,19 +304,28 @@ exports.extendTaxiSegment = function (taxiwaySegment) {
|
||||
taxiwaySegment.end = Number(event.vertex.latlng.glueindex);
|
||||
}
|
||||
}
|
||||
}
|
||||
//this.splitShape(taxiwaySegment.getLatLngs(), )
|
||||
});
|
||||
this.on('editable:vertex:deleted', event => {
|
||||
console.log('editable:vertex:deleted' + event)
|
||||
console.debug('editable:vertex:deleted')
|
||||
});
|
||||
this.on('editable:vertex:mousedown', event => {
|
||||
console.debug('editable:vertex:mousedown')
|
||||
event.layer.editor.map.fire('mousedown', event);
|
||||
});
|
||||
this.on('editable:vertex:click', event => {
|
||||
console.debug('editable:vertex:click')
|
||||
});
|
||||
this.on('editable:vertex:rawclick', event => {
|
||||
console.debug('editable:vertex:rawclick')
|
||||
event.cancel()
|
||||
console.log(event)
|
||||
});
|
||||
this.on('editable:vertex:clicked', function (event) {
|
||||
if (Number(store.default.state.Editable.index) >= 0 &&
|
||||
this.featureLookup[store.default.state.Editable.index] !== undefined) {
|
||||
this.featureLookup[store.default.state.Editable.index].forEach(element => {
|
||||
if(element.deselect !== undefined) {
|
||||
if (element.deselect !== undefined) {
|
||||
element.deselect();
|
||||
}
|
||||
});
|
||||
@ -211,7 +341,7 @@ exports.extendTaxiSegment = function (taxiwaySegment) {
|
||||
} else {
|
||||
this.editLayer.featureLookup[event.vertex.latlng.glueindex].forEach
|
||||
store.default.dispatch('setNode', event.vertex.latlng)
|
||||
this.selectVertex()
|
||||
this.selectVertex(store.default.state.Editable.index)
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -223,9 +353,30 @@ exports.extendTaxiSegment = function (taxiwaySegment) {
|
||||
return;
|
||||
console.log("Drag Start : ", event.vertex.latlng.glueindex);
|
||||
dragIndex = event.vertex.latlng.glueindex;
|
||||
if (Number(store.default.state.Editable.index) >= 0 &&
|
||||
this.featureLookup[store.default.state.Editable.index] !== undefined) {
|
||||
this.featureLookup[store.default.state.Editable.index].forEach(element => {
|
||||
if (element.deselect !== undefined) {
|
||||
element.deselect();
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!this.editor.map.editTools.drawing()) {
|
||||
var hold = this.featureLookup[event.vertex.latlng.glueindex].filter(n => n instanceof L.HoldNode);
|
||||
if (hold.length > 0) {
|
||||
hold[0].select();
|
||||
}
|
||||
var parking = this.featureLookup[event.vertex.latlng.glueindex].filter(n => n instanceof L.ParkingSpot);
|
||||
if (parking.length > 0) {
|
||||
parking[0].selectParking();
|
||||
} else {
|
||||
this.selectVertex(Number(dragIndex))
|
||||
}
|
||||
}
|
||||
});
|
||||
this.on('editable:vertex:dragend', function (event) {
|
||||
console.log("Dragend : ", event.vertex);
|
||||
try {
|
||||
if (dragIndex > 0) {
|
||||
event.target.featureLookup[dragIndex].forEach(element => {
|
||||
if (element instanceof L.ParkingSpot) {
|
||||
@ -235,15 +386,18 @@ exports.extendTaxiSegment = function (taxiwaySegment) {
|
||||
});
|
||||
}
|
||||
dragIndex = -1;
|
||||
if (!event.vertex.latlng.glueindex) {
|
||||
console.error('GlueIndex not found : ', event.vertex);
|
||||
}
|
||||
var parking = this.featureLookup[event.vertex.latlng.glueindex].filter(n => n instanceof L.ParkingSpot);
|
||||
if (parking.length > 0) {
|
||||
parking[0].selectParking();
|
||||
} else {
|
||||
if( Number(event.vertex.latlng.glueindex) !== store.default.state.Editable.index) {
|
||||
if (Number(event.vertex.latlng.glueindex) !== store.default.state.Editable.index) {
|
||||
if (Number(store.default.state.Editable.index) >= 0 &&
|
||||
this.featureLookup[store.default.state.Editable.index] !== undefined) {
|
||||
this.featureLookup[store.default.state.Editable.index].forEach(element => {
|
||||
if(element.deselect !== undefined) {
|
||||
if (element.deselect !== undefined) {
|
||||
element.deselect();
|
||||
}
|
||||
});
|
||||
@ -252,14 +406,67 @@ exports.extendTaxiSegment = function (taxiwaySegment) {
|
||||
}
|
||||
var lines = this.featureLookup[event.vertex.latlng.glueindex].filter(n => n instanceof L.Polyline);
|
||||
Vue.default.nextTick(function () {
|
||||
lines.forEach( line => {
|
||||
line.selectVertex()
|
||||
lines.forEach(line => {
|
||||
line.selectVertex(store.default.state.Editable.index)
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
console.error(event.vertex.latlng.glueindex);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
taxiwaySegment.__proto__.expandArc = function (attributes) {
|
||||
var isPushBackRoute = attributes.isPushBackRoute;
|
||||
var ids = [];
|
||||
var walkedNodes = [];
|
||||
var segmentIds = [];
|
||||
console.debug('start Walk');
|
||||
ids = ids.concat(this.walkPushbackRoute(attributes.begin, walkedNodes, isPushBackRoute));
|
||||
ids = ids.concat(this.walkPushbackRoute(attributes.end, walkedNodes, isPushBackRoute));
|
||||
return ids;
|
||||
}
|
||||
|
||||
taxiwaySegment.__proto__.walkPushbackRoute = function (index, walkedNodes, isPushBackRoute) {
|
||||
console.debug('Walk Level');
|
||||
walkedNodes.push(index)
|
||||
var segmentIds = [];
|
||||
var polyLines = this.featureLookup[index].filter(n => n instanceof L.Polyline);
|
||||
if (polyLines === undefined || polyLines.length > 2) {
|
||||
console.debug('Walk ' + index + '\t' + polyLines.length);
|
||||
return;
|
||||
}
|
||||
|
||||
polyLines.forEach(l => {
|
||||
segmentIds.push(l._leaflet_id);
|
||||
console.debug('Walk Next ' + index + '\t' +
|
||||
(walkedNodes.indexOf(index) < 0) + '\t' +
|
||||
l.begin + '\t' +
|
||||
(walkedNodes.indexOf(Number(l.begin)) < 0) + '\t' +
|
||||
l.end + '\t' +
|
||||
(walkedNodes.indexOf(Number(l.end)) < 0) + '\t' +
|
||||
l.options.attributes.direction + '\t' +
|
||||
l.options.attributes.begin + '\t' +
|
||||
l.options.attributes.end);
|
||||
console.debug('Walk isPushBackRoute ' + l.options.attributes.isPushBackRoute + '\t' + isPushBackRoute + '\t' + (l.options.attributes.isPushBackRoute === isPushBackRoute));
|
||||
if (l.options.attributes.isPushBackRoute === isPushBackRoute) {
|
||||
console.debug(Number(l.begin) === index && walkedNodes.indexOf(Number(l.end)) < 0);
|
||||
if (Number(l.begin) === index && walkedNodes.indexOf(Number(l.end)) < 0) {
|
||||
console.debug('Walk forward ' + l.options.attributes.direction);
|
||||
segmentIds = segmentIds.concat(this.walkPushbackRoute(Number(l.end), walkedNodes, isPushBackRoute))
|
||||
}
|
||||
console.debug(Number(l.end) === index && walkedNodes.indexOf(Number(l.begin)) < 0);
|
||||
if (Number(l.end) === index && walkedNodes.indexOf(Number(l.begin)) < 0) {
|
||||
console.debug('Walk backward ' + l.options.attributes.direction);
|
||||
segmentIds = segmentIds.concat(this.walkPushbackRoute(Number(l.begin), walkedNodes, isPushBackRoute))
|
||||
}
|
||||
}
|
||||
});
|
||||
return segmentIds;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@ -313,8 +520,58 @@ exports.extendTaxiSegment = function (taxiwaySegment) {
|
||||
})
|
||||
};
|
||||
|
||||
taxiwaySegment.__proto__.updateArrows = function (zoom) {
|
||||
if (this._map === null) {
|
||||
return;
|
||||
}
|
||||
if (this.options.attributes.direction === 'forward') {
|
||||
this.setText(null);
|
||||
if (zoom <= 16) {
|
||||
this.setText(' >', { repeat: true, offset: 6, attributes: { fill: 'red', style: 'vertical-align: bottom; vertical-align: bottom; font-weight: bold; font: bold 15px serif;' } })
|
||||
} else if (zoom <= 19) {
|
||||
this.setText(' > ', { repeat: true, offset: 7, attributes: { fill: 'red', style: 'vertical-align: bottom; vertical-align: bottom; font-weight: bold; font: bold 20px serif;' } })
|
||||
} else {
|
||||
this.setText(' > ', { repeat: true, offset: 10, attributes: { fill: 'red', style: 'vertical-align: bottom; vertical-align: bottom; font-weight: bold; font: bold 30px serif;' } })
|
||||
}
|
||||
} else if (this.options.attributes.direction === 'backward') {
|
||||
this.setText(null);
|
||||
if (zoom <= 16) {
|
||||
this.setText(' <', { repeat: true, offset: 6, attributes: { fill: 'red', style: 'vertical-align: bottom; vertical-align: bottom; font-weight: bold; font: bold 15px serif;' } })
|
||||
} else if (zoom <= 19) {
|
||||
this.setText(' < ', { repeat: true, offset: 7, attributes: { fill: 'red', style: 'vertical-align: bottom; vertical-align: bottom; font-weight: bold; font: bold 20px serif;' } })
|
||||
} else {
|
||||
this.setText(' < ', { repeat: true, offset: 10, attributes: { fill: 'red', style: 'vertical-align: bottom; vertical-align: bottom; font-weight: bold; font: bold 30px serif;' } })
|
||||
}
|
||||
} else {
|
||||
this.setText(null);
|
||||
}
|
||||
}
|
||||
|
||||
taxiwaySegment.__proto__.setInteractive = function (interactive) {
|
||||
if (this.getLayers) {
|
||||
this.getLayers().forEach(layer => {
|
||||
layer.setInteractive(interactive);
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!this._path) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.options.interactive = interactive;
|
||||
|
||||
if (interactive) {
|
||||
L.DomUtil.addClass(this._path, 'leaflet-interactive');
|
||||
} else {
|
||||
L.DomUtil.removeClass(this._path, 'leaflet-interactive');
|
||||
}
|
||||
};
|
||||
|
||||
taxiwaySegment.__proto__.updateStyle = function () {
|
||||
var style = {};
|
||||
if (!this.options.attributes) {
|
||||
return;
|
||||
}
|
||||
if (this.options.attributes.selected) {
|
||||
style.color = 'red';
|
||||
} else if (this.options.attributes.isPushBackRoute) {
|
||||
@ -323,14 +580,19 @@ exports.extendTaxiSegment = function (taxiwaySegment) {
|
||||
else {
|
||||
style.color = '#3388ff';
|
||||
}
|
||||
if (this.editEnabled()) {
|
||||
style.interactive = true;
|
||||
} else {
|
||||
style.interactive = false;
|
||||
}
|
||||
this.setStyle(style);
|
||||
if(this._map !== null) {
|
||||
if (this._map !== null) {
|
||||
if (this.options.attributes.direction === 'forward') {
|
||||
this.setText(null);
|
||||
this.setText(' > ', { repeat: true, offset: 10, attributes: { fill: 'red', style: 'vertical-align: bottom; vertical-align: bottom; font-weight: bold; font: bold 30px serif;' } })
|
||||
} else if (this.options.attributes.direction === 'backward') {
|
||||
this.setText(null);
|
||||
this.setText(' < ', { repeat: true, offset: 10, attributes: { fill: 'red', style: 'vertical-align: bottom; font-weight: bold; font: bold 30px serif;' } })
|
||||
this.setText(' < ', { repeat: true, offset: 10, attributes: { fill: 'red', style: 'vertical-align: bottom; vertical-align: bottom; font-weight: bold; font: bold 30px serif;' } })
|
||||
} else {
|
||||
this.setText(null);
|
||||
}
|
||||
@ -338,3 +600,5 @@ exports.extendTaxiSegment = function (taxiwaySegment) {
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
exports.extendTaxiSegment = extendTaxiSegment;
|
@ -1,141 +1,164 @@
|
||||
/*
|
||||
Copyright 2020 Keith Paterson
|
||||
|
||||
This file is part of FG Airports.
|
||||
|
||||
FG Airports is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
FG Airports is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with FG Airports. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
/* eslint-disable */
|
||||
|
||||
const convert = require('geo-coordinates-parser');
|
||||
const leaflet = require('leaflet');
|
||||
const turf = require('@turf/turf');
|
||||
const util = require('util');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const store = require('../store');
|
||||
const turf = require('@turf/turf');
|
||||
|
||||
var $ = require('jquery');
|
||||
L.Threshold = L.Circle.extend({
|
||||
select() {
|
||||
var style = {};
|
||||
style['color'] = 'red';
|
||||
this.setStyle(style);
|
||||
|
||||
/**http://wiki.openstreetmap.org/wiki/Zoom_levels*/
|
||||
|
||||
|
||||
L.Threshold = L.Marker.extend({
|
||||
heading: 0,
|
||||
displacement: 0,
|
||||
stopw_m: 0,
|
||||
originLatLng: null,
|
||||
rwy: '',
|
||||
interactive: false,
|
||||
stripSVG: function(fName) {
|
||||
var rx = /<\s*svg[^>]*>([\s\S]*)<\s*\/svg[^>]*>/gm;
|
||||
var svg = fs.readFileSync(path.join(__static, '/', fName), 'utf8');
|
||||
var svg2 = rx.exec(svg);
|
||||
return svg2[0];
|
||||
},
|
||||
addListeners: function () {
|
||||
this.on('editable:drawing:move', function (event) {
|
||||
console.log("Move : ", event);
|
||||
console.log("Move : ", event.latlng);
|
||||
// Is it the edit vertex (Middle) moving?
|
||||
if(event.target.editor._resizeLatLng.__vertex._icon !== event.sourceTarget._element){
|
||||
event.target.setLatLng(event.latlng);
|
||||
event.target.updateVertexFromDirection();
|
||||
this.follow(event.target.id, event);
|
||||
updateIcon : function(map) {
|
||||
console.debug(`Lat Lng Threshold ${this.getLatLng()}`);
|
||||
if(map !== null) {
|
||||
var metersPP = this.metersPerPixel(map.getCenter().lat, map.getZoom());
|
||||
console.debug('Old Meters per pixel ' + this._metersPP);
|
||||
console.debug('New Meters per pixel ' + metersPP);
|
||||
if(this._metersPP != metersPP) {
|
||||
var pixelSize = (this.iconSize/2) / metersPP;
|
||||
var scale = pixelSize/this.iconSize;
|
||||
var offset = 0;//-(this.iconSize/2);
|
||||
this.setIcon(L.divIcon({
|
||||
iconSize: 64,
|
||||
className: 'threshold-marker-icon',
|
||||
html: `<div style=\'transform: translateX(${offset}px) translateY(${offset}px) scale(${scale}) rotate(${this.heading}deg); border: 1px red\'>${this.svg}</div>`,
|
||||
}));
|
||||
this.setInteractive(this.interactive);
|
||||
|
||||
this.update(this.getLatLng());
|
||||
this.setLatLng(this.getLatLng());
|
||||
this._metersPP = metersPP;
|
||||
}
|
||||
else if(event.target.editor._resizeLatLng.__vertex._icon === event.sourceTarget._element) {
|
||||
event.target.updateDirectionFromVertex();
|
||||
event.target.updateVertexFromDirection();
|
||||
}
|
||||
});
|
||||
/*
|
||||
this.on('editable:vertex:drag', function (event) {
|
||||
console.log("Drag : ", event);
|
||||
});
|
||||
*/
|
||||
this.on('click', function (event) {
|
||||
console.log("Click : " + event.target);
|
||||
store.default.dispatch('setParking', event.target.options.attributes);
|
||||
this.select();
|
||||
this.unwatch = store.default.watch(
|
||||
function (state) {
|
||||
return state.Editable.data.parking;
|
||||
},
|
||||
() => {
|
||||
if (event.target instanceof L.Threshold) {
|
||||
event.target.setStyle({color : '#3388ff'});
|
||||
this.unwatch();
|
||||
setInteractive(interactive) {
|
||||
if (interactive) {
|
||||
if(this._icon) {
|
||||
L.DomUtil.addClass(this._icon, 'leaflet-interactive');
|
||||
}
|
||||
} else {
|
||||
if(this._icon) {
|
||||
L.DomUtil.removeClass(this._icon, 'leaflet-interactive');
|
||||
}
|
||||
}
|
||||
,
|
||||
{
|
||||
deep: true //add this if u need to watch object properties change etc.
|
||||
}
|
||||
);
|
||||
});
|
||||
this.on('editable:vertex:clicked', function (event) {
|
||||
console.log(this.featureLookup[event.vertex.glueindex]);
|
||||
if(event.target.editor._resizeLatLng.__vertex._icon !== event.sourceTarget._element){
|
||||
event.vertex._icon.style['background-color'] = 'red';
|
||||
store.default.dispatch('setParking', event.target.options.attributes);
|
||||
this.unwatch = store.default.watch(
|
||||
function (state) {
|
||||
return state.Editable.data.parking;
|
||||
this.interactive = interactive;
|
||||
},
|
||||
() => {
|
||||
event.target.setStyle({color : '#3388ff'});
|
||||
this.unwatch();
|
||||
}
|
||||
,
|
||||
{
|
||||
deep: true //add this if u need to watch object properties change etc.
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
this.on('editable:disable', function (event) {
|
||||
event.target.removeDirection();
|
||||
});
|
||||
metersPerPixel: function (latitude, zoomLevel) {
|
||||
var earthCircumference = 40075017;
|
||||
var latitudeRadians = latitude * (Math.PI / 180);
|
||||
return earthCircumference * Math.cos(latitudeRadians) / Math.pow(2, zoomLevel + 8);
|
||||
},
|
||||
updateStyle: function () {
|
||||
|
||||
pixelValue: function (latitude, meters, zoomLevel) {
|
||||
return meters / metersPerPixel(latitude, zoomLevel);
|
||||
},
|
||||
setOrigin (originLatLng) {
|
||||
this.originLatLng = originLatLng;
|
||||
},
|
||||
setHeading (heading) {
|
||||
this.heading = Number(heading);
|
||||
},
|
||||
setRunway (rwy) {
|
||||
this.rwy = Number(rwy);
|
||||
},
|
||||
setStopW (stopw_m) {
|
||||
this.stopw_m = stopw_m;
|
||||
},
|
||||
setDisplacement(displacement) {
|
||||
const turfOptions = { units: 'kilometers' };
|
||||
this.displacement = Number(displacement);
|
||||
|
||||
var newPos = turf.destination([this.originLatLng[1], this.originLatLng[0]], displacement/1000, this.normalizeAngle(this.heading), turfOptions);
|
||||
var newValue = {lat: newPos.geometry.coordinates[1].toFixed(6),
|
||||
lng: newPos.geometry.coordinates[0].toFixed(6) };
|
||||
console.debug(`Threshold Old : ${this.originLatLng} -> ${this.turfToLatLng(newPos)}`);
|
||||
this.setLatLng(newValue);
|
||||
},
|
||||
normalizeAngle( angle ) {
|
||||
if(angle >= 180) {
|
||||
return angle - 360;
|
||||
}
|
||||
if(angle <= -180) {
|
||||
return angle + 360;
|
||||
}
|
||||
return angle;
|
||||
},
|
||||
latToTurf (turfPoint) {
|
||||
return [turfPoint.lng, turfPoint.lat];
|
||||
},
|
||||
latLngToTurf (turfPoint) {
|
||||
return [turfPoint.decimalLongitude, turfPoint.decimalLatitude];
|
||||
},
|
||||
turfToLatLng: function (turfPoint) {
|
||||
return {lat: turfPoint.geometry.coordinates[1], lng: turfPoint.geometry.coordinates[0]};
|
||||
},
|
||||
extensions: function (editLayer) {
|
||||
this.createDirection();
|
||||
if (typeof this.featureLookup[this.id] === 'undefined') {
|
||||
this.featureLookup[this.id] = [];
|
||||
return '' + turfPoint.geometry.coordinates[1].toFixed(6) + ',' + turfPoint.geometry.coordinates[0].toFixed(6);
|
||||
}
|
||||
this.featureLookup[this.id].push(this);
|
||||
},
|
||||
|
||||
_getLatRadius: function () {
|
||||
return this._mRadius;
|
||||
},
|
||||
|
||||
_getLngRadius: function () {
|
||||
return this._mRadius;
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
var threshold = function (n, layerGroup) {
|
||||
//console.log(n.attr('lat') + " " + n.attr('lon'));
|
||||
var latlon = convert(n.find('lat/text()').text() + " " + n.find('lon/text()').text());
|
||||
//console.log(latlon.decimalLatitude);
|
||||
//console.log(convert(n.attr('lat') + " " + n.attr('lon')).decimalLongitude);
|
||||
const circle = new L.Threshold([latlon.decimalLatitude, latlon.decimalLongitude], { radius: 10, attributes: {} });
|
||||
circle.on('editable:enable', function (event) {
|
||||
// event.target.createDirection();
|
||||
L.Threshold.addInitHook(function(){
|
||||
this.svg = this.stripSVG('FGA_THR.svg');
|
||||
this.iconSize = 500;
|
||||
|
||||
this.on('click', function (event) {
|
||||
console.debug("Click Threshold : ", event);
|
||||
store.default.dispatch('setThreshold', {rwy: event.target.rwy, displacement: event.target.displacement});
|
||||
});
|
||||
/*
|
||||
<Parking index="2"
|
||||
type="gate"
|
||||
name="A6"
|
||||
number=""
|
||||
lat="N44 52.799"
|
||||
lon="W93 11.947"
|
||||
heading="-147.51"
|
||||
radius="18"
|
||||
pushBackRoute="541"
|
||||
airlineCodes="VIR,KAL,DAL,KLM" />
|
||||
this.on('add', function (event) {
|
||||
event.target.setInteractive(false);
|
||||
});
|
||||
});
|
||||
|
||||
//Builds a marker for a threshold
|
||||
/*
|
||||
<threshold>
|
||||
<lon>13.517142</lon>
|
||||
<lat>52.380125</lat>
|
||||
<rwy>07L</rwy>
|
||||
<hdg-deg>68.77</hdg-deg>
|
||||
<displ-m>0.0</displ-m>
|
||||
<stopw-m>160.0</stopw-m>
|
||||
</threshold>
|
||||
*/
|
||||
//circle.attributes = { type: n.attr('type'), name: n.attr('name'), radius: Number(n.attr('radius')), airlineCodes: n.attr('airlineCodes'), heading: Number(n.attr('heading')) };
|
||||
var threshold = function (n, options) {
|
||||
var latlon = convert(n.find('lat/text()').text() + " " + n.find('lon/text()').text());
|
||||
var rwy = n.find('rwy/text()').text();
|
||||
var heading = n.find('hdg-deg/text()').text();
|
||||
var displ_m = n.find('displ-m/text()').text();
|
||||
var stopw_m = n.find('stopw-m/text()').text();
|
||||
|
||||
$.each( n.attrs, function( key, value ) {
|
||||
console.log( '$', circle.id, key , value);
|
||||
|
||||
if(isNaN(value))
|
||||
circle.options.attributes[ key ] = value;
|
||||
else
|
||||
circle.options.attributes[ key ] = Number( value);
|
||||
});
|
||||
circle.addTo(layerGroup);
|
||||
return circle;
|
||||
var marker = new L.Threshold([latlon.decimalLatitude, latlon.decimalLongitude],
|
||||
{pane: 'threshold-pane'});
|
||||
marker.setOrigin([latlon.decimalLatitude, latlon.decimalLongitude]);
|
||||
marker.setHeading(heading);
|
||||
marker.setDisplacement(displ_m);
|
||||
marker.setRunway(rwy);
|
||||
marker.setStopW(stopw_m);
|
||||
return marker;
|
||||
}
|
||||
|
||||
module.exports = threshold;
|
116
src/renderer/loaders/Tower.js
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
Copyright 2020 Keith Paterson
|
||||
|
||||
This file is part of FG Airports.
|
||||
|
||||
FG Airports is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
FG Airports is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with FG Airports. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
/* eslint-disable */
|
||||
|
||||
const convert = require('geo-coordinates-parser');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const store = require('../store');
|
||||
|
||||
/**http://wiki.openstreetmap.org/wiki/Zoom_levels*/
|
||||
|
||||
|
||||
L.TowerMarker = L.Marker.extend({
|
||||
options: {
|
||||
zIndexOffset: 10000, draggable: 'true'
|
||||
},
|
||||
stripSVG: function(fName) {
|
||||
var rx = /<\s*svg[^>]*>([\s\S]*)<\s*\/svg[^>]*>/gm;
|
||||
var svg = fs.readFileSync(path.join(__static, '/', fName), 'utf8');
|
||||
var svg2 = rx.exec(svg);
|
||||
return svg2[0];
|
||||
},
|
||||
updateIcon : function(map) {
|
||||
console.debug(`Lat Lng Tower ${this.getLatLng()}`);
|
||||
if(map !== null) {
|
||||
var metersPP = this.metersPerPixel(map.getCenter().lat, map.getZoom());
|
||||
console.debug('Old Meters per pixel ' + this._metersPP);
|
||||
console.debug('New Meters per pixel ' + metersPP);
|
||||
if(this._metersPP != metersPP) {
|
||||
var pixelSize = this.iconSize / metersPP;
|
||||
var scale = pixelSize/this.iconSize;
|
||||
var offset = 0;//-(this.iconSize/2);
|
||||
this.setIcon(L.divIcon({
|
||||
iconSize: 32,
|
||||
className: 'threshold-marker-icon',
|
||||
html: `<div style=\'transform: translateX(${offset}px) translateY(${offset}px) scale(${scale}); border: 1px red\'>${this.svg}</div>`,
|
||||
}));
|
||||
this.setInteractive(this.interactive);
|
||||
|
||||
this.update(this.getLatLng());
|
||||
console.debug();
|
||||
this.setLatLng(this.getLatLng());
|
||||
this._metersPP = metersPP;
|
||||
}
|
||||
}
|
||||
},
|
||||
setInteractive(interactive) {
|
||||
if (interactive) {
|
||||
if(this._icon) {
|
||||
L.DomUtil.addClass(this._icon, 'leaflet-interactive');
|
||||
}
|
||||
} else {
|
||||
if(this._icon) {
|
||||
L.DomUtil.removeClass(this._icon, 'leaflet-interactive');
|
||||
}
|
||||
}
|
||||
this.interactive = interactive;
|
||||
},
|
||||
metersPerPixel: function (latitude, zoomLevel) {
|
||||
var earthCircumference = 40075017;
|
||||
var latitudeRadians = latitude * (Math.PI / 180);
|
||||
return earthCircumference * Math.cos(latitudeRadians) / Math.pow(2, zoomLevel + 8);
|
||||
},
|
||||
|
||||
pixelValue: function (latitude, meters, zoomLevel) {
|
||||
return meters / metersPerPixel(latitude, zoomLevel);
|
||||
},
|
||||
setTowerHeight: function (height) {
|
||||
this.elev_m = height;
|
||||
}
|
||||
});
|
||||
|
||||
L.TowerMarker.addInitHook(function(){
|
||||
this.svg = this.stripSVG('tower.svg');
|
||||
this.iconSize = 32;
|
||||
this.on('click', function (event) {
|
||||
store.default.dispatch('setTowerCoords',
|
||||
event.target.getLatLng().lat.toFixed(6) + ' ' +
|
||||
event.target.getLatLng().lng.toFixed(6) + ' ' +
|
||||
event.target.elev_m);
|
||||
store.default.dispatch('setTowerHeight', event.target.elev_m );
|
||||
});
|
||||
this.on('dragstart', function (event) {
|
||||
console.debug("Drag Tower : ", event);
|
||||
});
|
||||
this.on('dragend', function (event) {
|
||||
console.debug("DragEnd Tower : ", event);
|
||||
store.default.dispatch('setTowerCoords',
|
||||
event.target.getLatLng().lat.toFixed(6) + ' ' +
|
||||
event.target.getLatLng().lng.toFixed(6) + ' ' +
|
||||
event.target.elev_m);
|
||||
store.default.dispatch('setTowerHeight', event.target.elev_m );
|
||||
});
|
||||
this.on('add', function (event) {
|
||||
event.target.setInteractive(false);
|
||||
});
|
||||
});
|
||||
|
||||
//Builds a marker for a ai or multiplayer aircraft
|
||||
var tower = function (n, options) {
|
||||
var latlon = convert(n.find('lat/text()').text() + " " + n.find('lon/text()').text());
|
||||
var marker = new L.TowerMarker([latlon.decimalLatitude, latlon.decimalLongitude], {pane: 'tower-pane'});
|
||||
marker.elev_m = n.find('elev-m/text()').text();
|
||||
return marker;
|
||||
}
|
||||
|
||||
module.exports = tower;
|
@ -29,21 +29,38 @@ function addFrequencies (type, value) {
|
||||
}
|
||||
|
||||
exports.addFeature = function (feature) {
|
||||
featureLookup[feature.id] = new Array();
|
||||
featureLookup[feature.id] = [];
|
||||
}
|
||||
|
||||
exports.readGroundnetXML = function (fDir, icao, force) {
|
||||
exports.listSaves = function (fDir, icao) {
|
||||
var directory = path.join(fDir, icao[0], icao[1], icao[2]);
|
||||
var files = fs.readdirSync(directory);
|
||||
var ret = files
|
||||
.filter(f => f.includes(icao) )
|
||||
.filter(f => f.includes('groundnet') )
|
||||
.map(f => {
|
||||
try {
|
||||
var layerGroup = L.layerGroup();
|
||||
layerGroup.maxId = 0;
|
||||
var f = path.join(fDir, icao[0], icao[1], icao[2], icao + '.groundnet.xml');
|
||||
var fNew = path.join(fDir, icao[0], icao[1], icao[2], icao + '.groundnet.new.xml');
|
||||
|
||||
if (f == null || (!fs.existsSync(f) && force)|| (!fs.existsSync(f) && !fs.existsSync(fNew) ))
|
||||
return layerGroup;
|
||||
if (fNew != null && fs.existsSync(fNew) && !force) {
|
||||
f = fNew;
|
||||
var fileDate = fs.lstatSync(path.join(directory, f));
|
||||
return {file: f, mtime: `${fileDate.mtime}`, mtimeMs: `${fileDate.mtimeMs}`};
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
});
|
||||
ret.forEach( f => {
|
||||
console.debug(f);
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
|
||||
exports.readGroundnetXML = function (fDir, icao, f) {
|
||||
try {
|
||||
store.default.dispatch('setGroundnetLoaded', false);
|
||||
var layerGroup = L.layerGroup();
|
||||
layerGroup.minId = 9999999999;
|
||||
layerGroup.maxId = 0;
|
||||
|
||||
if (f == null || (!fs.existsSync(f) ))
|
||||
return layerGroup;
|
||||
|
||||
var features = new Array();
|
||||
|
||||
@ -84,7 +101,7 @@ exports.readGroundnetXML = function (fDir, icao, force) {
|
||||
store.default.dispatch('setFrequencies', frequencies);
|
||||
|
||||
var parkingNodes = xml.find('groundnet/parkingList/Parking');
|
||||
console.log("Parking Nodes" + parkingNodes.length);
|
||||
console.debug("Parking Nodes length" + parkingNodes.length);
|
||||
|
||||
var merged = new Array();
|
||||
|
||||
@ -97,15 +114,16 @@ exports.readGroundnetXML = function (fDir, icao, force) {
|
||||
nodesLookup[n.attr('index')] = n;
|
||||
featureLookup[n.attr('index')] = new Array();
|
||||
featureLookup[n.attr('index')].push(circle);
|
||||
layerGroup.minId = Math.min(layerGroup.minId, Number(n.attr('index')))
|
||||
layerGroup.maxId = Math.max(layerGroup.maxId, Number(n.attr('index')))
|
||||
features.push(circle);
|
||||
}).sort();
|
||||
|
||||
store.default.dispatch('setParkings', parkingNodes.map(
|
||||
p => ({index: Number(p.attrs.index), name: String(p.attrs.name), number: String(p.attrs.number), type: String(p.attrs.type)}
|
||||
p => ({index: Number(p.attrs.index), radius: Number(p.attrs.radius), name: String(p.attrs.name), number: String(p.attrs.number), type: String(p.attrs.type)}
|
||||
)).sort((p1, p2) => {
|
||||
if (p1.name === p2.name) {
|
||||
return p1.number - p2.number
|
||||
return p1.number?p1.number.localeCompare(p2.number):-1;
|
||||
} else {
|
||||
return p1.name.localeCompare(p2.name)
|
||||
}}));
|
||||
@ -123,7 +141,9 @@ exports.readGroundnetXML = function (fDir, icao, force) {
|
||||
}
|
||||
//console.log(latlon.decimalLatitude);
|
||||
|
||||
layerGroup.minId = Math.min(layerGroup.minId, Number(n.attr('index')))
|
||||
layerGroup.maxId = Math.max(layerGroup.maxId, Number(n.attr('index')))
|
||||
console.debug(`Min Id : ${layerGroup.minId} Max Id : ${layerGroup.maxId} `);
|
||||
|
||||
nodesLookup[n.attr('index')] = n;
|
||||
if (n.attr('isOnRunway') === '1') {
|
||||
@ -174,7 +194,13 @@ exports.readGroundnetXML = function (fDir, icao, force) {
|
||||
if (!bidirectional) {
|
||||
var beginlatlon = convert(beginNode.attr('lat') + " " + beginNode.attr('lon'));
|
||||
var endlatlon = convert(endNode.attr('lat') + " " + endNode.attr('lon'));
|
||||
var polyline = new L.Polyline([[beginlatlon.decimalLatitude, beginlatlon.decimalLongitude], [endlatlon.decimalLatitude, endlatlon.decimalLongitude]], { attributes: {} }).addTo(layerGroup);
|
||||
|
||||
var pane = 'route-pane';
|
||||
if(n.attr('isPushBackRoute') === '1') {
|
||||
pane = 'pushback-pane';
|
||||
}
|
||||
|
||||
var polyline = new L.Polyline([[beginlatlon.decimalLatitude, beginlatlon.decimalLongitude], [endlatlon.decimalLatitude, endlatlon.decimalLongitude]], { pane: pane, attributes: {} }).addTo(layerGroup);
|
||||
extendTaxiSegment(polyline);
|
||||
polyline.addListeners();
|
||||
polyline._latlngs[0].attributes = {};
|
||||
@ -208,6 +234,8 @@ exports.readGroundnetXML = function (fDir, icao, force) {
|
||||
|
||||
polyline.begin = beginNode.attr('index');
|
||||
polyline.end = endNode.attr('index');
|
||||
polyline.feature = { properties: { searchTerm: 'Arc ' + beginNode.attr('index') + '-' + endNode.attr('index')}};
|
||||
|
||||
// polyline.enableEdit();
|
||||
|
||||
// polyline.on('dblclick', function (event) { L.DomEvent.stop; polyline.toggleEdit; });
|
||||
@ -224,7 +252,7 @@ exports.readGroundnetXML = function (fDir, icao, force) {
|
||||
}
|
||||
}
|
||||
}).sort();
|
||||
|
||||
store.default.dispatch('setGroundnetLoaded', true);
|
||||
|
||||
return layerGroup;
|
||||
});
|
||||
|
@ -18,6 +18,11 @@ var featureLookup = [];
|
||||
var parkings = [];
|
||||
var pushBackNodeLookup = [];
|
||||
|
||||
/**
|
||||
* Walk nodes until the pushback node is found.
|
||||
* @param {*} index
|
||||
*/
|
||||
|
||||
function findRouteToPushback (index) {
|
||||
if (featureLookup===undefined) {
|
||||
return
|
||||
@ -25,6 +30,7 @@ function findRouteToPushback (index) {
|
||||
var walkedNodes = [index]
|
||||
var pushBackNodes = []
|
||||
walkPushbackRoute(index, walkedNodes, pushBackNodes)
|
||||
|
||||
return pushBackNodes
|
||||
}
|
||||
|
||||
@ -51,23 +57,48 @@ function walkPushbackRoute (index, walkedNodes, pushBackNodes) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {*} fDir The directory
|
||||
* @param {*} icao
|
||||
* @param {*} featureList
|
||||
*/
|
||||
|
||||
exports.writeGroundnetXML = function (fDir, icao, featureList) {
|
||||
try {
|
||||
try { fs.mkdirSync(path.join(fDir), { recursive: true })} catch (err) { }
|
||||
try { fs.mkdirSync(path.join(fDir, icao[0]),{ recursive: true })} catch (err) { }
|
||||
try { fs.mkdirSync(path.join(fDir, icao[0], icao[1]), { recursive: true })} catch (err) { }
|
||||
try { fs.mkdirSync(path.join(fDir, icao[0], icao[1], icao[2]), { recursive: true })} catch (err) { }
|
||||
|
||||
var fileNames = [];
|
||||
for (let index = 1; index <= store.default.state.Settings.settings.numberOfSaves; index++) {
|
||||
fileNames.push(path.join(fDir, icao[0], icao[1], icao[2], icao + `.groundnet.bak.${index}.xml`));
|
||||
}
|
||||
var f = path.join(fDir, icao[0], icao[1], icao[2], icao + '.groundnet.new.xml');
|
||||
var fBak = path.join(fDir, icao[0], icao[1], icao[2], icao + '.groundnet.bak.xml');
|
||||
|
||||
if( fs.existsSync(f) ) {
|
||||
fs.copyFileSync(f, fBak);
|
||||
var previous = '';
|
||||
fileNames.reverse().forEach(fBak => {
|
||||
if (fs.existsSync(fBak) && previous !== '') {
|
||||
console.debug( `Copy ${fBak} to ${previous}`);
|
||||
fs.copyFileSync(fBak, previous);
|
||||
}
|
||||
previous = fBak;
|
||||
});
|
||||
fs.copyFileSync(f, previous);
|
||||
}
|
||||
if (f == null)
|
||||
return;
|
||||
pushBackNodeLookup = [];
|
||||
|
||||
console.debug(featureList);
|
||||
|
||||
var parkings = featureList.map(mapParkings).filter(n => n);
|
||||
var runwayNodes = featureList.map(mapRunwayNodes).filter(n => n);
|
||||
var holdNodes = featureList.map(mapHoldPoint).filter(n => n);
|
||||
|
||||
|
||||
holdNodes.forEach(n => {
|
||||
pushBackNodeLookup[n['@index']] = n;
|
||||
});
|
||||
@ -76,17 +107,19 @@ exports.writeGroundnetXML = function (fDir, icao, featureList) {
|
||||
var arcList = [];
|
||||
var frequencies = [];
|
||||
|
||||
var version = new Date().toUTCString() + ' by FlightgearAirports';
|
||||
var version = new Date().toUTCString() + ' by FlightgearAirports ' + require('electron').remote.app.getVersion();
|
||||
var name = store.default.state.Settings.settings.name;
|
||||
|
||||
|
||||
|
||||
featureLookup = [];
|
||||
// Loaded segments
|
||||
featureList.filter(o => o instanceof L.TaxiwaySegment).filter(n => n).forEach(element => {
|
||||
var begin = mapBeginNode(element);
|
||||
if(begin['@index']==="")
|
||||
console.warn("Begin missing");
|
||||
nodes[begin['@index']] = begin;
|
||||
var end = mapEndNode(element);
|
||||
if(end['@index']==="")
|
||||
console.warn("End missing");
|
||||
nodes[end['@index']] = end;
|
||||
});
|
||||
// New segments
|
||||
@ -117,8 +150,13 @@ exports.writeGroundnetXML = function (fDir, icao, featureList) {
|
||||
arcList.push(arc);
|
||||
featureLookup[latlng.glueindex][startIndex] = arc;
|
||||
}
|
||||
if (currentArc.direction === '' || !currentArc.direction) {
|
||||
console.error( "Arc without direction " + util.inspect(currentArc) );
|
||||
}
|
||||
}
|
||||
startIndex = latlng.glueindex;
|
||||
} else {
|
||||
console.error( "LatLng without glueindex " + util.inspect(latlng) );
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -129,7 +167,7 @@ exports.writeGroundnetXML = function (fDir, icao, featureList) {
|
||||
});
|
||||
|
||||
|
||||
// delete the parkings
|
||||
// Find the index of the pushback node
|
||||
parkings.forEach(n => {
|
||||
nodes[n['@index']] = null;
|
||||
var pushBackNode = findRouteToPushback(Number(n['@index']))[0];
|
||||
@ -142,6 +180,7 @@ exports.writeGroundnetXML = function (fDir, icao, featureList) {
|
||||
arcList = arcList.filter(a => a['@begin'] !== a['@end']);
|
||||
|
||||
nodes.sort((p, p2) => { return p['@index'] - p2['@index'] });
|
||||
//console.debug(util.inspect(nodes));
|
||||
var uniqueNodes = nodes.filter((v, i, a) => a.indexOf(v) === i);
|
||||
|
||||
var approachList = store.default.state.Frequencies.items.filter(f => f.type === 'APPROACH').map(mapFrequency);
|
||||
@ -158,7 +197,54 @@ exports.writeGroundnetXML = function (fDir, icao, featureList) {
|
||||
|
||||
var unicomList = store.default.state.Frequencies.items.filter(f => f.type === 'UNICOM').map(mapFrequency);
|
||||
|
||||
var xmlObj = { groundnet: { version: version, name: name,
|
||||
|
||||
var gapStart = -1;
|
||||
var gapEnd = -1;
|
||||
|
||||
do {
|
||||
gapStart = -1;
|
||||
gapEnd = -1;
|
||||
var allIds = parkings.map(n => Number(n['@index']))
|
||||
.concat(uniqueNodes.map(n => Number(n['@index'])))
|
||||
.sort((a, b) => a - b);
|
||||
|
||||
allIds.forEach((element, index, array) => {
|
||||
if (index > 0 && array[index-1] + 1 != element && gapStart == -1 ) {
|
||||
gapStart = array[index-1];
|
||||
gapEnd = element;
|
||||
}
|
||||
});
|
||||
var gap = gapEnd - gapStart -1;
|
||||
if ( gap >= 0 ) {
|
||||
parkings = parkings.map(n => {
|
||||
if (n['@index']>gapStart) {
|
||||
n['@index'] = String(n['@index'] - gap);
|
||||
}
|
||||
if (n['@pushbackRoute']>gapStart) {
|
||||
n['@pushbackRoute'] = String(n['@pushbackRoute'] - gap);
|
||||
}
|
||||
return n;
|
||||
});
|
||||
uniqueNodes = uniqueNodes.map(n => {
|
||||
if (n['@index']>gapStart) {
|
||||
n['@index'] = String(n['@index'] - gap);
|
||||
}
|
||||
return n;
|
||||
});
|
||||
arcList = arcList.map(n => {
|
||||
if (n['@begin']>gapStart) {
|
||||
n['@begin'] = String(n['@begin'] - gap);
|
||||
}
|
||||
if (n['@end']>gapStart) {
|
||||
n['@end'] = String(n['@end'] - gap);
|
||||
}
|
||||
return n;
|
||||
});
|
||||
}
|
||||
|
||||
} while( gapStart > 0 && gapEnd > 0);
|
||||
|
||||
var xmlObj = { groundnet: { version: 1, fgaversion: version, name: name,
|
||||
'frequencies': { APPROACH: approachList, DEPARTURE: departureList, AWOS: awosList, CLEARANCE: clearanceList, GROUND: groundList, TOWER: towerList, UNICOM: unicomList },
|
||||
parkingList: { Parking: parkings }, TaxiNodes: { node: uniqueNodes }, TaxiWaySegments: { arc: arcList } } };
|
||||
|
||||
@ -181,12 +267,20 @@ var mapParkings = function (o) {
|
||||
var lat = convertLat(o.getLatLng());
|
||||
var lon = convertLon(o.getLatLng());
|
||||
// <Parking index="0" type="gate" name="GA_Parking" lat="S9 25.739923" lon="E160 2.927602" heading="67" radius="44" airlineCodes="" />
|
||||
var parking = { '@index': String(o['id']), '@type': o.options.attributes.type, '@name': o.options.attributes.name, '@lat': lat, '@lon': lon, '@heading': Number(o.options.attributes.heading%360).toFixed(1), '@radius': String(o.options.attributes.radius) };
|
||||
var parking = { '@index': String(o['id']), '@type': o.options.attributes.type, '@lat': lat, '@lon': lon, '@heading': Number(o.options.attributes.heading%360).toFixed(1), '@radius': String(o.options.attributes.radius) };
|
||||
if (o.options.attributes.name !== '' && o.options.attributes.name !== 'undefined' && o.options.attributes.name !== undefined) {
|
||||
parking['@name'] = o.options.attributes.name;
|
||||
}
|
||||
if( o.options.attributes.airlineCodes) {
|
||||
console.debug(o.options.attributes.airlineCodes);
|
||||
parking['@airlineCodes'] = o.options.attributes.airlineCodes;
|
||||
}
|
||||
if(o.options.attributes.number) {
|
||||
if(o.options.attributes.number !== undefined &&
|
||||
typeof o.options.attributes.number === 'number' || (
|
||||
typeof o.options.attributes.number === 'string' &&
|
||||
o.options.attributes.number.trim() !== ''
|
||||
)
|
||||
) {
|
||||
console.debug(o.options.attributes.number);
|
||||
parking['@number'] = o.options.attributes.number;
|
||||
}
|
||||
@ -212,13 +306,17 @@ var mapRunwayNodes = function (o) {
|
||||
|
||||
var mapHoldPoint = function (o) {
|
||||
if (o instanceof L.HoldNode) {
|
||||
if( o['holdPointType'] === undefined )
|
||||
{
|
||||
console.error('Oh dear ' + o);
|
||||
}
|
||||
return { '@index': String(o['glueindex']), '@holdPointType': o['holdPointType'] };
|
||||
}
|
||||
}
|
||||
|
||||
var mapBeginNode = function (o) {
|
||||
if (o instanceof L.TaxiwaySegment) {
|
||||
console.debug(o);
|
||||
console.debug('Map Begin : ', o['begin']);
|
||||
// <Parking index="0" type="gate" name="GA_Parking" lat="S9 25.739923" lon="E160 2.927602" heading="67" radius="44" airlineCodes="" />
|
||||
return { '@index': String(o['begin']), '@lat': convertLat(o._latlngs[0]), '@lon': convertLon(o._latlngs[0]), '@isOnRunway': '0', '@type': 'begin' };
|
||||
}
|
||||
@ -226,7 +324,7 @@ var mapBeginNode = function (o) {
|
||||
|
||||
var mapEndNode = function (o) {
|
||||
if (o instanceof L.TaxiwaySegment) {
|
||||
console.debug(o);
|
||||
console.debug('Map End : ', o['end']);
|
||||
// <Parking index="0" type="gate" name="GA_Parking" lat="S9 25.739923" lon="E160 2.927602" heading="67" radius="44" airlineCodes="" />
|
||||
return { '@index': String(o['end']), '@lat': convertLat(o._latlngs[1]), '@lon': convertLon(o._latlngs[1]), '@isOnRunway': '0', '@type': 'end' };
|
||||
}
|
||||
@ -241,31 +339,33 @@ var mapVertexNode = function (l) {
|
||||
}
|
||||
|
||||
var convertLat = function (latlng) {
|
||||
console.debug(latlng.lat);
|
||||
//console.debug(latlng.lat);
|
||||
var NS = latlng.lat > 0 ? 'N' : 'S';
|
||||
var deg = mathjs.floor(mathjs.abs(latlng.lat));
|
||||
var min = (mathjs.abs(latlng.lat) - deg) * 60;
|
||||
// console.debug(NS + deg + " " + min);
|
||||
return NS + String(deg).padStart(2, '0') + " " + mathjs.round(min, 3);
|
||||
return NS + String(deg).padStart(2, '0') + " " + mathjs.round(min, 6);
|
||||
}
|
||||
|
||||
var convertLon = function (latlng) {
|
||||
console.debug(latlng.lng);
|
||||
//console.debug(latlng.lng);
|
||||
var NS = latlng.lng > 0 ? 'E' : 'W';
|
||||
var deg = mathjs.floor(mathjs.abs(latlng.lng));
|
||||
var min = (mathjs.abs(latlng.lng) - deg) * 60;
|
||||
// console.debug(NS + deg + " " + min);
|
||||
return NS + String(deg).padStart(2, '0') + " " + mathjs.round(min, 3);
|
||||
return NS + String(deg).padStart(2, '0') + " " + mathjs.round(min, 6);
|
||||
}
|
||||
|
||||
var styleArc = function (attributes, arc) {
|
||||
console.debug(attributes);
|
||||
//console.debug(attributes);
|
||||
if(attributes !== undefined){
|
||||
if (attributes.isPushBackRoute !== undefined && Number(attributes.isPushBackRoute) === 1 ) {
|
||||
arc['@isPushBackRoute'] = "1";
|
||||
} else {
|
||||
arc['@isPushBackRoute'] = "0";
|
||||
}
|
||||
if ( attributes.name !== '' && attributes.name !== 'undefined') {
|
||||
arc['@name'] = attributes.name;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,10 +1,25 @@
|
||||
/*
|
||||
Copyright 2020 Keith Paterson
|
||||
|
||||
This file is part of FG Airports.
|
||||
|
||||
FG Airports is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
FG Airports is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with FG Airports. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
/* eslint-disable */
|
||||
const lineReader = require('readline');
|
||||
const zlib = require('zlib');
|
||||
// const geodesy = require('geodesy');
|
||||
const LatLonEllipsoidal = require('geodesy/latlon-ellipsoidal-vincenty.js').default;
|
||||
const fs = require('fs');
|
||||
|
||||
const store = require('../store');
|
||||
|
||||
const buildRunwayPoly = require('../leaflet/Runway.js');
|
||||
const buildTaxiwayPoly = require('../leaflet/Taxiway.js');
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {*} line
|
||||
@ -25,12 +40,12 @@ function bezier(line, icao, layerGroup, currentFeature) {
|
||||
var startPoint = [Number(previous[0]), Number(previous[1])];
|
||||
var endPoint = [Number(line[1]), Number(line[2])];
|
||||
|
||||
if(module.exports.debug) {
|
||||
if (module.exports.debug) {
|
||||
L.polyline([startPoint, endPoint], { color: 'fuchsia' }).addTo(layerGroup);
|
||||
var marker = new L.marker(endPoint, { title: 'endpoint', color: 'fuchsia' });
|
||||
marker.bindTooltip(String(currentFeature.slice(-1)[0].length + ' ' + line), { className: "my-label", offset: [0, 0] });
|
||||
marker.addTo(layerGroup);
|
||||
}
|
||||
}
|
||||
|
||||
var control = [Number(line[3]), Number(line[4])];
|
||||
if (!isNaN(control[0]) && control[0] !== undefined && !isNaN(control[1]) && control[1] !== undefined) {
|
||||
@ -55,7 +70,7 @@ function bezier(line, icao, layerGroup, currentFeature) {
|
||||
L.polyline([startPoint, controlReflected, endPoint], { color: 'purple' }).addTo(layerGroup);
|
||||
|
||||
var marker = new L.marker(controlReflected, { title: 'control First' });
|
||||
marker.bindTooltip(String(currentFeature.slice(-1)[0].length + ' ' + line), {className: "my-label", offset: [0, 0] });
|
||||
marker.bindTooltip(String(currentFeature.slice(-1)[0].length + ' ' + line), { className: "my-label", offset: [0, 0] });
|
||||
marker.addTo(layerGroup);
|
||||
}
|
||||
points = deCasteljau([
|
||||
@ -66,11 +81,11 @@ function bezier(line, icao, layerGroup, currentFeature) {
|
||||
if (module.exports.debug) {
|
||||
L.polyline([startPoint, exports.bezierPoint, controlReflected, endPoint], { color: 'purple' }).addTo(layerGroup);
|
||||
var marker = new L.marker(exports.bezierPoint, { title: 'exports.bezierPoint' }).addTo(layerGroup);
|
||||
marker.bindTooltip(String(currentFeature.slice(-1)[0].length + ' ' + line), {className: "my-label", offset: [0, 10] });
|
||||
marker.bindTooltip(String(currentFeature.slice(-1)[0].length + ' ' + line), { className: "my-label", offset: [0, 10] });
|
||||
marker.addTo(layerGroup);
|
||||
|
||||
var marker1 = new L.marker(controlReflected, { title: 'controlReflected' }).addTo(layerGroup);
|
||||
marker1.bindTooltip(String(currentFeature.slice(-1)[0].length + ' ' + line), {className: "my-label", offset: [0, -10] });
|
||||
marker1.bindTooltip(String(currentFeature.slice(-1)[0].length + ' ' + line), { className: "my-label", offset: [0, -10] });
|
||||
marker1.addTo(layerGroup);
|
||||
|
||||
}
|
||||
@ -253,14 +268,24 @@ function createLineString(currentFeature, layerGroup) {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.readPavement = function (f, icao, cb) {
|
||||
module.exports.readPavement = function (f, icao, callback) {
|
||||
console.log(f);
|
||||
var pavementLayerGroup = L.layerGroup();
|
||||
var currentFeature;
|
||||
|
||||
store.default.dispatch('setPavementLoaded', false);
|
||||
|
||||
if (!fs.existsSync(f)) {
|
||||
store.default.dispatch('setPavementLoaded', true);
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
fs.accessSync(f, fs.constants.R_OK);
|
||||
lineReader.createInterface({
|
||||
input: fs.createReadStream(f).pipe(zlib.createGunzip())
|
||||
}).on('line', function (line) {
|
||||
try {
|
||||
var fields = line.split(/[ ]+/);
|
||||
// var fields = line.match('([0-9]+)');
|
||||
if (fields == null)
|
||||
@ -275,13 +300,25 @@ module.exports.readPavement = function (f, icao, cb) {
|
||||
}
|
||||
// console.log('Ignored:', line);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error reading : ' + line + error);
|
||||
}
|
||||
}).on('error', function (err) {
|
||||
store.default.dispatch('setPavementLoaded', true);
|
||||
console.error(err);
|
||||
lr.close();
|
||||
callback();
|
||||
}).on('close', function () {
|
||||
store.default.dispatch('setPavementLoaded', true);
|
||||
console.log("End");
|
||||
cb(pavementLayerGroup);
|
||||
callback(pavementLayerGroup);
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('no access!');
|
||||
store.default.dispatch('setPavementLoaded', true);
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.debug = false;
|
||||
@ -304,31 +341,22 @@ var scanMethods = {
|
||||
// APTDAT 715 Segment
|
||||
10: (line, icao, layerGroup) => {
|
||||
if (module.exports.isScanning) {
|
||||
//var marker = new L.marker([line[1], line[2]], { title: '10 Point', color: 'fuchsia' });
|
||||
//marker.bindTooltip(String(line), { className: "my-label", offset: [0, 0] });
|
||||
//marker.addTo(layerGroup);
|
||||
var pointMiddle = new LatLonEllipsoidal(Number(line[1]), Number(line[2]));
|
||||
var point1 = pointMiddle.destinationPoint(line[5]/6.562, line[4]);
|
||||
var point2 = pointMiddle.destinationPoint(line[5]/6.562, line[4]-180);
|
||||
var point1 = pointMiddle.destinationPoint(line[5] / 6.562, line[4]);
|
||||
var point2 = pointMiddle.destinationPoint(line[5] / 6.562, line[4] - 180);
|
||||
|
||||
//var runwayPoly2 = new L.Polygon([point1, point2]);
|
||||
//var marker2 = new L.marker(point2, { title: '10 Point 2', color: 'fuchsia' });
|
||||
//marker2.bindTooltip(String(line), { className: "my-label", offset: [0, 0] });
|
||||
//marker2.addTo(layerGroup);
|
||||
//runwayPoly2.setStyle({ color: 'red', interactive: false });
|
||||
//runwayPoly2.addTo(layerGroup);
|
||||
var runwayPoints = [];
|
||||
|
||||
var bearing = point1.initialBearingTo(point2);
|
||||
var runwayWidth = Number(line[8])/3.281;
|
||||
// Width in ft
|
||||
var runwayWidth = Number(line[8]) / 3.281;
|
||||
|
||||
runwayPoints.push(point1.destinationPoint(runwayWidth / 2, (bearing + 90)));
|
||||
runwayPoints.push(point2.destinationPoint(runwayWidth / 2, (bearing + 90)));
|
||||
runwayPoints.push(point2.destinationPoint(runwayWidth / 2, (bearing - 90)));
|
||||
runwayPoints.push(point1.destinationPoint(runwayWidth / 2, (bearing - 90)));
|
||||
|
||||
var runwayPoly = new L.Polygon(runwayPoints);
|
||||
runwayPoly.setStyle({ color: 'grey', fillColor: 'grey', opacity: 0.5, fillOpacity: 0.5, interactive: false });
|
||||
var runwayPoly = buildTaxiwayPoly(runwayPoints);
|
||||
runwayPoly.addTo(layerGroup);
|
||||
}
|
||||
},
|
||||
@ -350,15 +378,14 @@ var scanMethods = {
|
||||
runwayPoints.push(point2.destinationPoint(runwayWidth / 2, (bearing - 90)));
|
||||
runwayPoints.push(point1.destinationPoint(runwayWidth / 2, (bearing - 90)));
|
||||
|
||||
var runwayPoly = new L.Polygon(runwayPoints);
|
||||
runwayPoly.setStyle({ color: 'grey', interactive: false });
|
||||
var runwayPoly = buildRunwayPoly(runwayPoints);
|
||||
runwayPoly.addTo(layerGroup);
|
||||
|
||||
var displacedEnd1 = point1.destinationPoint(Number(line[20]), bearing)
|
||||
var displacedEnd2 = point2.destinationPoint(Number(line[20]), bearing-180)
|
||||
var displacedEnd2 = point2.destinationPoint(Number(line[20]), bearing - 180)
|
||||
|
||||
var runwayLine = new L.Polyline([displacedEnd1, displacedEnd2]);
|
||||
runwayLine.setStyle({ color: 'yellow', stroke: true, dashArray: [50,50] });
|
||||
runwayLine.setStyle({ color: 'yellow', stroke: true, dashArray: [50, 50] });
|
||||
runwayLine.addTo(layerGroup);
|
||||
|
||||
var t1 = new L.Polyline([displacedEnd1.destinationPoint(runwayWidth / 2, (bearing - 90)),
|
||||
|
@ -1,19 +1,22 @@
|
||||
/* eslint-disable */
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
var xamel = require('xamel');
|
||||
const xamel = require('xamel');
|
||||
const convert = require('geo-coordinates-parser');
|
||||
const LatLonEllipsoidal = require('geodesy/latlon-ellipsoidal-vincenty.js').default;
|
||||
|
||||
const store = require('../store');
|
||||
|
||||
const util = require('util');
|
||||
|
||||
const takeoffPadPoly = require('../leaflet/TakeoffPad.js');
|
||||
|
||||
const threshold = require('./Threshold.js');
|
||||
|
||||
|
||||
var $ = require('jquery');
|
||||
|
||||
exports.readThresholdXML = function (fDir, icao, force) {
|
||||
exports.readThresholdXML = function (fDir, icao, force, stripes) {
|
||||
try {
|
||||
var layerGroup = L.layerGroup();
|
||||
layerGroup.maxId = 0;
|
||||
@ -40,18 +43,39 @@ exports.readThresholdXML = function (fDir, icao, force) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
var thresholdNodes = xml.find('PropertyList/runway/threshold');
|
||||
console.log("Threshold Nodes" + thresholdNodes.length);
|
||||
var runwayNodes = xml.find('PropertyList/runway');
|
||||
console.log("Threshold Nodes" + runwayNodes.length);
|
||||
|
||||
var merged = new Array();
|
||||
|
||||
var nodesLookup = {};
|
||||
featureLookup = [];
|
||||
|
||||
var index = 0;
|
||||
runwayNodes.map(r => {
|
||||
var thresholds = r.find('threshold');
|
||||
thresholds.map(n => {
|
||||
var icon = threshold(n);
|
||||
icon.index = index;
|
||||
icon.addTo(layerGroup);
|
||||
// Width in m
|
||||
var runwayWidth = 20;
|
||||
var latlon = convert(n.find('lat/text()').text() + " " + n.find('lon/text()').text());
|
||||
var displ_m = Number(n.find('displ-m/text()').text());
|
||||
var pointMiddle = new LatLonEllipsoidal(latlon.decimalLatitude, latlon.decimalLongitude);
|
||||
var heading = Number(n.find('hdg-deg/text()').text());
|
||||
var point1 = pointMiddle.destinationPoint(displ_m, heading);
|
||||
var point2 = pointMiddle.destinationPoint(displ_m + 80, heading);
|
||||
|
||||
thresholdNodes.map(n => {
|
||||
var circle = threshold(n, layerGroup);
|
||||
features.push(circle);
|
||||
var runwayPoints = [];
|
||||
runwayPoints.push(point1.destinationPoint(runwayWidth / 2, (heading + 90)));
|
||||
runwayPoints.push(point2.destinationPoint(runwayWidth / 2, (heading + 90)));
|
||||
runwayPoints.push(point2.destinationPoint(runwayWidth / 2, (heading - 90)));
|
||||
runwayPoints.push(point1.destinationPoint(runwayWidth / 2, (heading - 90)));
|
||||
|
||||
var runwayPoly = takeoffPadPoly(runwayPoints);
|
||||
runwayPoly.addTo(layerGroup);
|
||||
}
|
||||
)
|
||||
|
||||
index+=1;
|
||||
}).sort();
|
||||
|
||||
return layerGroup;
|
||||
|
120
src/renderer/loaders/threshold_writer.js
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
Copyright 2021 Keith Paterson
|
||||
|
||||
This file is part of FG Airports.
|
||||
|
||||
FG Airports is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
FG Airports is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with FG Airports. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
/* eslint-disable */
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const store = require('../store');
|
||||
|
||||
const util = require('util');
|
||||
|
||||
const mathjs = require('mathjs');
|
||||
|
||||
var builder = require('xmlbuilder');
|
||||
|
||||
|
||||
|
||||
var writeThresholdXML = function (fDir, icao, coordinates) {
|
||||
try {
|
||||
try { fs.mkdirSync(path.join(fDir), { recursive: true })} catch (err) { }
|
||||
try { fs.mkdirSync(path.join(fDir, icao[0]),{ recursive: true })} catch (err) { }
|
||||
try { fs.mkdirSync(path.join(fDir, icao[0], icao[1]), { recursive: true })} catch (err) { }
|
||||
try { fs.mkdirSync(path.join(fDir, icao[0], icao[1], icao[2]), { recursive: true })} catch (err) { }
|
||||
|
||||
var f = path.join(fDir, icao[0], icao[1], icao[2], icao + '.threshold.new.xml');
|
||||
var fBak = path.join(fDir, icao[0], icao[1], icao[2], icao + '.threshold.bak.xml');
|
||||
|
||||
if( fs.existsSync(f) ) {
|
||||
fs.copyFileSync(f, fBak);
|
||||
}
|
||||
if (f == null)
|
||||
return;
|
||||
var xmlObj = { PropertyList: { runway: map(coordinates) } };
|
||||
|
||||
xmlString = builder.create(xmlObj).end({ pretty: true });
|
||||
fs.writeFileSync(f, xmlString);
|
||||
console.debug(xmlString);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var map = function (o) {
|
||||
console.debug(o);
|
||||
|
||||
/**
|
||||
<?xml version='1.0' encoding='ISO-8859-1'?>
|
||||
<PropertyList>
|
||||
<runway>
|
||||
<threshold>
|
||||
<lon>13.485025</lon>
|
||||
<lat>52.367689</lat>
|
||||
<rwy>07</rwy>
|
||||
<hdg-deg>68.75</hdg-deg>
|
||||
<displ-m>0.0</displ-m>
|
||||
<stopw-m>300.0</stopw-m>
|
||||
</threshold>
|
||||
<threshold>
|
||||
<lon>13.526097</lon>
|
||||
<lat>52.377431</lat>
|
||||
<rwy>25</rwy>
|
||||
<hdg-deg>248.78</hdg-deg>
|
||||
<displ-m>0.0</displ-m>
|
||||
<stopw-m>300.0</stopw-m>
|
||||
</threshold>
|
||||
</runway>
|
||||
<runway>
|
||||
<threshold>
|
||||
<lon>13.517142</lon>
|
||||
<lat>52.380125</lat>
|
||||
<rwy>07L</rwy>
|
||||
<hdg-deg>68.77</hdg-deg>
|
||||
<displ-m>0.0</displ-m>
|
||||
<stopw-m>160.0</stopw-m>
|
||||
</threshold>
|
||||
<threshold>
|
||||
<lon>13.554253</lon>
|
||||
<lat>52.388919</lat>
|
||||
<rwy>25R</rwy>
|
||||
<hdg-deg>248.80</hdg-deg>
|
||||
<displ-m>0.0</displ-m>
|
||||
<stopw-m>300.0</stopw-m>
|
||||
</threshold>
|
||||
</runway>
|
||||
</PropertyList>
|
||||
*/
|
||||
var ret = [];
|
||||
Object.keys(o).forEach(key => {
|
||||
ret.push({ threshold: mapThreshold(o[key])});
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* <latitude>58.106924</latitude>
|
||||
<longitude>6.610419</longitude>
|
||||
<index>0</index>
|
||||
<rwy>14</rwy>
|
||||
<heading>131.16</heading>
|
||||
<displacement>273</displacement>
|
||||
<stopw_m>0.0</stopw_m>
|
||||
|
||||
* @param {*} t
|
||||
*/
|
||||
|
||||
var mapThreshold = function (t) {
|
||||
return t.map( t => {return {lon: t.longitude, lat: t.latitude, rwy: t.rwy, 'hdg-deg': t.heading, 'displ-m': t.displacement, 'stopw-m': t.stopw_m}});
|
||||
}
|
||||
|
||||
export { writeThresholdXML };
|
78
src/renderer/loaders/tower_loader.js
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
Copyright 2020 Keith Paterson
|
||||
|
||||
This file is part of FG Airports.
|
||||
|
||||
FG Airports is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
FG Airports is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with FG Airports. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
/* eslint-disable */
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
var xamel = require('xamel');
|
||||
const convert = require('geo-coordinates-parser');
|
||||
|
||||
const store = require('../store');
|
||||
|
||||
const util = require('util');
|
||||
|
||||
const tower = require('./Tower.js');
|
||||
|
||||
|
||||
var $ = require('jquery');
|
||||
|
||||
exports.readTowerXML = function (fDir, icao, force) {
|
||||
try {
|
||||
var layerGroup = L.layerGroup();
|
||||
layerGroup.maxId = 0;
|
||||
var f = path.join(fDir, icao[0], icao[1], icao[2], icao + '.twr.xml');
|
||||
var fNew = path.join(fDir, icao[0], icao[1], icao[2], icao + '.twr.new.xml');
|
||||
|
||||
if (f == null || !fs.existsSync(f))
|
||||
return;
|
||||
if (fNew != null && fs.existsSync(fNew) && !force) {
|
||||
f = fNew;
|
||||
}
|
||||
|
||||
var features = new Array();
|
||||
|
||||
// map.on("editable:vertex:new", function (event) {
|
||||
// log.console("Add vertex " + event);
|
||||
// });
|
||||
|
||||
var xmlGroundnet = fs.readFileSync(f, 'utf8').toString();
|
||||
xamel.parse(xmlGroundnet, function (err, xml) {
|
||||
console.debug("parsed " + path.basename(f));
|
||||
if (err !== null) {
|
||||
console.error("Error in " + airline);
|
||||
throw err;
|
||||
}
|
||||
|
||||
var towerNodes = xml.find('PropertyList/tower/twr');
|
||||
console.log("Towers " + towerNodes.length);
|
||||
|
||||
towerNodes.map(n => {
|
||||
var towerIcon = tower(n, layerGroup);
|
||||
towerIcon['icao'] = icao
|
||||
towerIcon.addTo(layerGroup);
|
||||
/*
|
||||
//DEBUG Code
|
||||
var latlon = convert(n.find('lat/text()').text() + " " + n.find('lon/text()').text());
|
||||
var marker = new L.Circle([latlon.decimalLatitude, latlon.decimalLongitude], 5);
|
||||
marker.addTo(layerGroup);
|
||||
*/
|
||||
features.push(towerIcon);
|
||||
}).sort();
|
||||
|
||||
return layerGroup;
|
||||
});
|
||||
// var jsonAirports = JSON.parse(geoJSON);
|
||||
// return jsonAirports;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
return layerGroup;
|
||||
};
|
63
src/renderer/loaders/tower_writer.js
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
Copyright 2021 Keith Paterson
|
||||
|
||||
This file is part of FG Airports.
|
||||
|
||||
FG Airports is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
FG Airports is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with FG Airports. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
/* eslint-disable */
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const store = require('../store');
|
||||
|
||||
const util = require('util');
|
||||
|
||||
const mathjs = require('mathjs');
|
||||
|
||||
var builder = require('xmlbuilder');
|
||||
|
||||
var featureLookup = [];
|
||||
var parkings = [];
|
||||
var pushBackNodeLookup = [];
|
||||
|
||||
|
||||
exports.writeTowerXML = function (fDir, icao, coordinates) {
|
||||
try {
|
||||
try { fs.mkdirSync(path.join(fDir), { recursive: true })} catch (err) { }
|
||||
try { fs.mkdirSync(path.join(fDir, icao[0]),{ recursive: true })} catch (err) { }
|
||||
try { fs.mkdirSync(path.join(fDir, icao[0], icao[1]), { recursive: true })} catch (err) { }
|
||||
try { fs.mkdirSync(path.join(fDir, icao[0], icao[1], icao[2]), { recursive: true })} catch (err) { }
|
||||
|
||||
var f = path.join(fDir, icao[0], icao[1], icao[2], icao + '.twr.new.xml');
|
||||
var fBak = path.join(fDir, icao[0], icao[1], icao[2], icao + '.twr.bak.xml');
|
||||
|
||||
if( fs.existsSync(f) ) {
|
||||
fs.copyFileSync(f, fBak);
|
||||
}
|
||||
if (f == null)
|
||||
return;
|
||||
var xmlObj = { PropertyList: { tower: { twr: map(coordinates)} } };
|
||||
|
||||
xmlString = builder.create(xmlObj).end({ pretty: true });
|
||||
fs.writeFileSync(f, xmlString);
|
||||
console.debug(xmlString);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var map = function (o) {
|
||||
console.debug(o);
|
||||
/**
|
||||
<lon>-1.6286902</lon>
|
||||
<lat>59.53396633</lat>
|
||||
<elev-m>3.05</elev-m>
|
||||
*/
|
||||
return { lon: o.longitude, lat: o.latitude, 'elev-m': o.height};
|
||||
}
|
123
src/renderer/loaders/traffic_loader.js
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
Copyright 2021 Keith Paterson
|
||||
|
||||
This file is part of FG Airports.
|
||||
|
||||
FG Airports is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
FG Airports is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with FG Airports. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
/* eslint-disable */
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
var xamel = require('xamel');
|
||||
|
||||
const store = require('../store');
|
||||
|
||||
const util = require('util');
|
||||
|
||||
exports.readTrafficXML = function (f) {
|
||||
try {
|
||||
var ret = [];
|
||||
var xmlTraffic = fs.readFileSync(f, 'utf8').toString();
|
||||
xamel.parse(xmlTraffic, function (err, xml) {
|
||||
console.debug("parsed " + path.basename(f));
|
||||
if (err !== null) {
|
||||
console.error("Error in " + airline);
|
||||
throw err;
|
||||
}
|
||||
|
||||
var requiredAircraft = xml.find('trafficlist/aircraft');
|
||||
console.log("Aircraft " + requiredAircraft.length);
|
||||
|
||||
ret.concat(requiredAircraft);
|
||||
var flights = xml.find('trafficlist/flight');
|
||||
console.log("Flights " + flights.length);
|
||||
ret.concat(flights);
|
||||
console.log(ret.length);
|
||||
ret = ret.concat(flights.map(flightMapper)).concat(requiredAircraft.map(aircraftMapper))
|
||||
return ret;
|
||||
});
|
||||
return ret;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* <flight>
|
||||
<callsign>Hebridean_1047</callsign>
|
||||
<required-aircraft>HBR_BN_2</required-aircraft>
|
||||
<fltrules>VFR</fltrules>
|
||||
<departure>
|
||||
<port>EGPU</port>
|
||||
<time>4/14:50:00</time>
|
||||
</departure>
|
||||
<cruise-alt>50</cruise-alt>
|
||||
<arrival>
|
||||
<port>EGEO</port>
|
||||
<time>4/15:50:00</time>
|
||||
</arrival>
|
||||
<repeat>WEEK</repeat>
|
||||
</flight>
|
||||
*/
|
||||
|
||||
function flightMapper(params) {
|
||||
return {
|
||||
id: `${btoa(buildId(params))}`,
|
||||
callsign: params.find('callsign').text(),
|
||||
'required-aircraft': params.find('required-aircraft').text(),
|
||||
arrival: {
|
||||
port: params.find('arrival/port').text(),
|
||||
time: params.find('arrival/time').text()
|
||||
},
|
||||
departure: {
|
||||
port: params.find('departure/port').text(),
|
||||
time: params.find('departure/time').text()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function buildId(params) {
|
||||
return `${params.find('callsign').text()}_`+
|
||||
`${params.find('arrival/port').text()}_`+
|
||||
`${params.find('arrival/time').text()}_`+
|
||||
`${params.find('departure/port').text()}_` +
|
||||
`${params.find('departure/time').text()}`;
|
||||
}
|
||||
|
||||
/*
|
||||
<aircraft>
|
||||
<model>Aircraft/BN-2/BN-2-Hebridean.xml</model>
|
||||
<livery>HBR</livery>
|
||||
<airline>HBR</airline>
|
||||
<home-port>EGEO</home-port>
|
||||
<required-aircraft>HBR_BN_2</required-aircraft>
|
||||
<actype>BN2</actype>
|
||||
<offset>0</offset>
|
||||
<radius>8</radius>
|
||||
<flighttype>gate</flighttype>
|
||||
<performance-class>turboprop_transport</performance-class>
|
||||
<registration>G-HEBO</registration>
|
||||
<heavy>false</heavy>
|
||||
</aircraft>
|
||||
*/
|
||||
|
||||
function aircraftMapper(params) {
|
||||
return {
|
||||
model: params.find('model').text(),
|
||||
livery: params.find('livery').text(),
|
||||
airline: params.find('airline').text(),
|
||||
'home-port': params.find('home-port').text(),
|
||||
'required-aircraft': params.find('required-aircraft').text(),
|
||||
actype: params.find('actype').text(),
|
||||
offset: params.find('offset').text(),
|
||||
radius: params.find('radius').text(),
|
||||
flighttype: params.find('flighttype').text(),
|
||||
'performance-class': params.find('performance-class').text(),
|
||||
'registration': params.find('registration').text(),
|
||||
'heavy': params.find('heavy').text(),
|
||||
};
|
||||
}
|
180
src/renderer/loaders/traffic_writer.js
Normal file
@ -0,0 +1,180 @@
|
||||
/*
|
||||
Copyright 2021 Keith Paterson
|
||||
|
||||
This file is part of FG Airports.
|
||||
|
||||
FG Airports is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
FG Airports is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with FG Airports. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
/* eslint-disable */
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const store = require('../store');
|
||||
|
||||
const util = require('util');
|
||||
|
||||
const mathjs = require('mathjs');
|
||||
|
||||
var builder = require('xmlbuilder');
|
||||
|
||||
var parkingStats = (acc, cur) => {
|
||||
if (!acc[cur.radius]) {
|
||||
acc[cur.radius] = { count: 0, radius: cur.radius }
|
||||
}
|
||||
acc[cur.radius].count += 1
|
||||
return acc
|
||||
};
|
||||
|
||||
/**
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<trafficlist xmlns:xi="http://www.w3.org/2001/XInclude"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="traffic.xsd">
|
||||
<aircraft>
|
||||
<model>Aircraft/BN-2/BN-2-Hebridean.xml</model>
|
||||
<livery>HBR</livery>
|
||||
<airline>HBR</airline>
|
||||
<home-port>EGEO</home-port>
|
||||
<required-aircraft>HBR_BN_2</required-aircraft>
|
||||
<actype>BN2</actype>
|
||||
<offset>0</offset>
|
||||
<radius>8</radius>
|
||||
<flighttype>gate</flighttype>
|
||||
<performance-class>turboprop_transport</performance-class>
|
||||
<registration>G-HEBS</registration>
|
||||
<heavy>false</heavy>
|
||||
</aircraft>
|
||||
<flight>
|
||||
<callsign>Hebridean_1047</callsign>
|
||||
<required-aircraft>HBR_BN_2</required-aircraft>
|
||||
<fltrules>VFR</fltrules>
|
||||
<departure>
|
||||
<port>EGPU</port>
|
||||
<time>4/14:50:00</time>
|
||||
</departure>
|
||||
<cruise-alt>50</cruise-alt>
|
||||
<arrival>
|
||||
<port>EGEO</port>
|
||||
<time>4/15:50:00</time>
|
||||
</arrival>
|
||||
<repeat>WEEK</repeat>
|
||||
</flight>
|
||||
</trafficlist>
|
||||
*/
|
||||
|
||||
var writeTrafficXML = function (fDir, parkings, aircraft) {
|
||||
try {
|
||||
var icao = store.default.state.Airports.currentAirport.icao;
|
||||
var aircraftList = aircraft;
|
||||
|
||||
try { fs.mkdirSync(path.join(fDir), { recursive: true }) } catch (err) { }
|
||||
try { fs.mkdirSync(path.join(fDir, 'TST'), { recursive: true }) } catch (err) { }
|
||||
|
||||
var f = path.join(fDir, 'TST', icao + '.xml');
|
||||
|
||||
|
||||
var parkingData = parkings.reduce(parkingStats, {});
|
||||
|
||||
/*
|
||||
*
|
||||
<flight>
|
||||
<callsign>Hebridean_1001</callsign>
|
||||
<required-aircraft>HBR_BN_2</required-aircraft>
|
||||
<fltrules>VFR</fltrules>
|
||||
<departure>
|
||||
<port>EGEO</port>
|
||||
<time>2/14:10:00</time>
|
||||
</departure>
|
||||
<cruise-alt>50</cruise-alt>
|
||||
<arrival>
|
||||
<port>EGEY</port>
|
||||
<time>2/15:20:00</time>
|
||||
</arrival>
|
||||
<repeat>WEEK</repeat>
|
||||
</flight>
|
||||
*/
|
||||
|
||||
var flightMapper = function (pStat) {
|
||||
var ret = [];
|
||||
var blockSize = Math.min( pStat[1].count/6, 6);
|
||||
for (let index = 0; index < pStat[1].count; index++) {
|
||||
var aircraft = this[index];
|
||||
var minutes = `${Math.floor(index/blockSize)}`.padStart(2, '0');
|
||||
var seconds = `${index}`.padStart(2, '0');
|
||||
for (let weekday = 0; weekday < 7; weekday++) {
|
||||
ret.push({
|
||||
callsign: `Test_${index}_${weekday}`,
|
||||
'required-aircraft': aircraft['required-aircraft'],
|
||||
fltrules: 'VFR',
|
||||
departure: {
|
||||
port: icao,
|
||||
time: `${weekday}/12:${minutes}:${seconds}`
|
||||
},
|
||||
'cruise-alt': 50,
|
||||
arrival: {
|
||||
port: icao,
|
||||
time: `${weekday}/13:${minutes}:${seconds}`
|
||||
},
|
||||
repeat: 'WEEK'
|
||||
});
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
<aircraft>
|
||||
<model>Aircraft/BN-2/BN-2-Hebridean.xml</model>
|
||||
<livery>HBR</livery>
|
||||
<airline>HBR</airline>
|
||||
<home-port>EGEO</home-port>
|
||||
<required-aircraft>HBR_BN_2</required-aircraft>
|
||||
<actype>BN2</actype>
|
||||
<offset>0</offset>
|
||||
<radius>8</radius>
|
||||
<flighttype>gate</flighttype>
|
||||
<performance-class>turboprop_transport</performance-class>
|
||||
<registration>G-HEBO</registration>
|
||||
<heavy>false</heavy>
|
||||
</aircraft>
|
||||
|
||||
*/
|
||||
var aircraftMapper = function (pStat) {
|
||||
var ret = [];
|
||||
if (typeof this === 'undefined') {
|
||||
return;
|
||||
}
|
||||
var possibleAircraft = this.filter(a => a.radius <= pStat[1].radius);
|
||||
|
||||
for (let index = 0; index < pStat[1].count; index++) {
|
||||
var aircraft = possibleAircraft[Math.floor(Math.random() * possibleAircraft.length)];
|
||||
aircraft['required-aircraft'] = `GG-${index}`;
|
||||
aircraft.registration = `GG-${index}`;
|
||||
aircraft['home-port'] = icao;
|
||||
ret.push(aircraft);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
var aircraftList = Object.entries(parkingData).flatMap(aircraftMapper, aircraft).sort();
|
||||
var flightList = Object.entries(parkingData).flatMap(flightMapper, aircraftList).sort();
|
||||
|
||||
var xmlObj = { trafficList: { aircraft: aircraftList, flight: flightList } };
|
||||
|
||||
var xmlString = builder.create(xmlObj).end({ pretty: true });
|
||||
fs.writeFileSync(f, xmlString);
|
||||
console.debug(xmlString);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
export { writeTrafficXML as writeTrafficXML };
|
@ -14,6 +14,10 @@ Vue.config.productionTip = false
|
||||
|
||||
Vue.use(ElementUI)
|
||||
|
||||
Vue.config.errorHandler = (err, vm, info) => {
|
||||
console.error(err)
|
||||
}
|
||||
|
||||
/* eslint-disable no-new */
|
||||
new Vue({
|
||||
components: { App },
|
||||
|
@ -264,5 +264,5 @@ function mapSGPropertyNode(node) {
|
||||
}));
|
||||
|
||||
export function aiLayer(options) {
|
||||
return new L.AILayer(null, options);
|
||||
return undefined //new L.AILayer(null, options);
|
||||
}
|
||||
|
@ -1,15 +1,28 @@
|
||||
/**
|
||||
Copyright 2020 Keith Paterson
|
||||
|
||||
This file is part of FG Airports.
|
||||
|
||||
FG Airports is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
FG Airports is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with FG Airports. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
import Vue from 'vue'
|
||||
|
||||
const state = {
|
||||
type: 'none',
|
||||
index: 'none',
|
||||
editing: false,
|
||||
data: {airports: {}, parking: {}, arc: {}, node: {}, runway: {}}
|
||||
data: {airports: {}, parking: {}, arc: {}, multiarc: {}, node: {}, runway: {}, threshold: {}, tower: {}}
|
||||
}
|
||||
|
||||
const SET_EDIT_AIRPORT = 'SET_EDIT_AIRPORT'
|
||||
const SET_EDIT_PARKING = 'SET_EDIT_PARKING'
|
||||
const SET_EDIT_ARC = 'SET_EDIT_ARC'
|
||||
const SET_EDIT_MULTI_ARC = 'SET_EDIT_MULTI_ARC'
|
||||
const SET_EDIT_RUNWAY = 'SET_EDIT_RUNWAY'
|
||||
|
||||
const mutations = {
|
||||
@ -25,7 +38,6 @@ const mutations = {
|
||||
state.type = 'airport'
|
||||
},
|
||||
SET_EDIT_PARKING (state, parking) {
|
||||
Vue.set(state, 'data', {})
|
||||
var p = Object.assign({}, parking)
|
||||
Vue.set(state.data, 'parking', p)
|
||||
Vue.set(state, 'index', p.index)
|
||||
@ -35,15 +47,11 @@ const mutations = {
|
||||
if (node === undefined) {
|
||||
return
|
||||
}
|
||||
if (!state.data || state.type !== 'node') {
|
||||
Vue.set(state, 'data', {})
|
||||
}
|
||||
Vue.set(state.data, 'node', node)
|
||||
Vue.set(state, 'index', node.index)
|
||||
Vue.set(state, 'type', 'node')
|
||||
},
|
||||
SET_EDIT_RUNWAY (state, runway) {
|
||||
Vue.set(state, 'data', {})
|
||||
Vue.set(state.data, 'node', runway)
|
||||
Vue.set(state, 'index', runway.index)
|
||||
Vue.set(state, 'type', 'runway')
|
||||
@ -52,9 +60,6 @@ const mutations = {
|
||||
if (arc === undefined) {
|
||||
return
|
||||
}
|
||||
if (!state.data || state.type !== 'arc') {
|
||||
Vue.set(state, 'data', {})
|
||||
}
|
||||
Vue.set(state.data, 'arc', arc)
|
||||
if (state.data.arc.name === undefined) {
|
||||
Vue.set(state.data.arc, 'name', '')
|
||||
@ -62,6 +67,31 @@ const mutations = {
|
||||
Vue.set(state, 'index', arc.index)
|
||||
Vue.set(state, 'type', 'arc')
|
||||
},
|
||||
SET_EDIT_MULTI_ARC (state, arc) {
|
||||
if (arc === undefined) {
|
||||
return
|
||||
}
|
||||
Vue.set(state.data.multiarc, 'isPushBackRoute', arc.isPushBackRoute)
|
||||
Vue.set(state.data.multiarc, 'direction', arc.direction)
|
||||
if (state.data.multiarc.name === undefined) {
|
||||
Vue.set(state.data.multiarc, 'name', '')
|
||||
}
|
||||
Vue.set(state, 'index', arc.index)
|
||||
|
||||
Vue.set(state, 'type', 'multiarc')
|
||||
},
|
||||
'SET_EDIT_MULTI_ARC_IDS' (state, arcs) {
|
||||
if (arcs === undefined) {
|
||||
return
|
||||
}
|
||||
if (!state.data || state.type !== 'multiarc') {
|
||||
return
|
||||
}
|
||||
if (state.data.multiarc.ids === undefined) {
|
||||
state.data.multiarc.ids = []
|
||||
}
|
||||
state.data.multiarc.ids = state.data.multiarc.ids.concat(arcs.filter(n => n).filter((v, i, a) => a.indexOf(v) === i))
|
||||
},
|
||||
'SET_EDIT_PARKING_NAME' (state, parkingName) {
|
||||
Vue.set(state.data.parking, 'name', parkingName)
|
||||
},
|
||||
@ -90,14 +120,29 @@ const mutations = {
|
||||
'SET_EDIT_PARKING_COORDS' (state, coords) {
|
||||
Vue.set(state.data.parking, 'coords', coords)
|
||||
},
|
||||
'SET_EDIT_PARKING_NOSE_COORDS' (state, coords) {
|
||||
Vue.set(state.data.parking, 'nosecoords', coords)
|
||||
},
|
||||
'SET_EDIT_ARC_NAME' (state, arcName) {
|
||||
if (state.type === 'arc') {
|
||||
Vue.set(state.data.arc, 'name', arcName)
|
||||
} else {
|
||||
Vue.set(state.data.multiarc, 'name', arcName)
|
||||
}
|
||||
},
|
||||
'SET_EDIT_PUSHBACK' (state, isPushBackRoute) {
|
||||
Vue.set(state.data.arc, 'isPushBackRoute', isPushBackRoute)
|
||||
if (state.type === 'arc') {
|
||||
Vue.set(state.data.arc, 'isPushBackRoute', Number(isPushBackRoute))
|
||||
} else {
|
||||
Vue.set(state.data.multiarc, 'isPushBackRoute', Number(isPushBackRoute))
|
||||
}
|
||||
},
|
||||
'SET_EDIT_DIRECTION' (state, direction) {
|
||||
if (state.type === 'arc') {
|
||||
Vue.set(state.data.arc, 'direction', direction)
|
||||
} else {
|
||||
Vue.set(state.data.multiarc, 'direction', direction)
|
||||
}
|
||||
},
|
||||
'SET_EDIT_HOLDPOINTTYPE' (state, holdPointType) {
|
||||
Vue.set(state.data.node, 'holdPointType', holdPointType)
|
||||
@ -105,6 +150,28 @@ const mutations = {
|
||||
'SET_EDIT_NODE_COORDS' (state, coords) {
|
||||
Vue.set(state.data.node, 'coords', coords)
|
||||
},
|
||||
'SET_EDIT_TOWER_COORDS' (state, coords) {
|
||||
state.type = 'tower'
|
||||
if (!state.data.tower) {
|
||||
state.data.tower = {}
|
||||
}
|
||||
if (!state.data.tower.coords) {
|
||||
state.data.tower.coords = {}
|
||||
}
|
||||
Vue.set(state.data.tower.coords, 'latitude', coords.split(' ')[0])
|
||||
Vue.set(state.data.tower.coords, 'longitude', coords.split(' ')[1])
|
||||
},
|
||||
'SET_EDIT_TOWER_HEIGHT' (state, height) {
|
||||
Vue.set(state.data.tower, 'height', height)
|
||||
},
|
||||
'SET_EDIT_THRESHOLD_COORDS' (state, threshold) {
|
||||
state.type = 'threshold'
|
||||
Vue.set(state.data.threshold, 'runway', threshold.rwy)
|
||||
Vue.set(state.data.threshold, 'displacement', threshold.displacement)
|
||||
},
|
||||
'SET_EDIT_THRESHOLD_DISPLACEMENT' (state, displacement) {
|
||||
Vue.set(state.data.threshold, 'displacement', displacement)
|
||||
},
|
||||
'SET_EDIT_ISONRUNWAY' (state, isOnRunway) {
|
||||
Vue.set(state.data.node, 'isOnRunway', isOnRunway)
|
||||
}
|
||||
@ -129,12 +196,33 @@ const actions = {
|
||||
async setParkingCoords (context, coords) {
|
||||
context.commit('SET_EDIT_PARKING_COORDS', coords)
|
||||
},
|
||||
async setParkingNoseCoords (context, coords) {
|
||||
context.commit('SET_EDIT_PARKING_NOSE_COORDS', coords)
|
||||
},
|
||||
async setArc (context, arc) {
|
||||
context.commit(SET_EDIT_ARC, arc)
|
||||
},
|
||||
async setMultiArc (context, arc) {
|
||||
context.commit(SET_EDIT_MULTI_ARC, arc)
|
||||
},
|
||||
async setMultiArcIds (context, arc) {
|
||||
context.commit('SET_EDIT_MULTI_ARC_IDS', arc)
|
||||
},
|
||||
async setNode (context, node) {
|
||||
context.commit('SET_EDIT_NODE', node.attributes)
|
||||
context.commit('SET_EDIT_NODE_COORDS', node.lat.toFixed(6) + ' ' + node.lng.toFixed(6))
|
||||
},
|
||||
async setTowerCoords (context, node) {
|
||||
context.commit('SET_EDIT_TOWER_COORDS', node)
|
||||
},
|
||||
async setTowerHeight (context, height) {
|
||||
context.commit('SET_EDIT_TOWER_HEIGHT', height)
|
||||
},
|
||||
async setThreshold (context, node) {
|
||||
context.commit('SET_EDIT_THRESHOLD_COORDS', node)
|
||||
},
|
||||
async setDisplacement (context, displacement) {
|
||||
context.commit('SET_EDIT_THRESHOLD_DISPLACEMENT', displacement)
|
||||
}
|
||||
}
|
||||
|
||||
|
51
src/renderer/store/modules/Loading.js
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
Copyright 2020 Keith Paterson
|
||||
|
||||
This file is part of FG Airports.
|
||||
|
||||
FG Airports is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
FG Airports is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with FG Airports. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
import Vue from 'vue'
|
||||
|
||||
const state = { icao: '', groundnetLoaded: false, pavementLoaded: false }
|
||||
|
||||
const mutations = {
|
||||
SET_ICAO_LOADING (state, icao) {
|
||||
Vue.set(state, 'icao', icao)
|
||||
},
|
||||
SET_GROUNDNET_LOADED (state, loaded) {
|
||||
Vue.set(state, 'groundnetLoaded', loaded)
|
||||
},
|
||||
SET_PAVEMENT_LOADED (state, loaded) {
|
||||
Vue.set(state, 'pavementLoaded', loaded)
|
||||
}
|
||||
}
|
||||
|
||||
const actions = {
|
||||
async setIcaoLoading (context, p) {
|
||||
context.commit('SET_ICAO_LOADING', p)
|
||||
},
|
||||
async setGroundnetLoaded (context, p) {
|
||||
if (typeof p !== 'boolean') {
|
||||
console.error('Not Boolean')
|
||||
}
|
||||
context.commit('SET_GROUNDNET_LOADED', p)
|
||||
},
|
||||
async setPavementLoaded (context, p) {
|
||||
if (typeof p !== 'boolean') {
|
||||
console.error('Not Boolean')
|
||||
}
|
||||
context.commit('SET_PAVEMENT_LOADED', p)
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
state,
|
||||
mutations,
|
||||
actions
|
||||
}
|
@ -1,3 +1,15 @@
|
||||
/*
|
||||
Copyright 2020 Keith Paterson
|
||||
|
||||
This file is part of FG Airports.
|
||||
|
||||
FG Airports is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
FG Airports is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with FG Airports. If not, see http://www.gnu.org/licenses/.
|
||||
*/
|
||||
|
||||
import Vue from 'vue'
|
||||
|
||||
const state = { items: [] }
|
||||
@ -31,7 +43,7 @@ const mutations = {
|
||||
|
||||
const actions = {
|
||||
async addParking (context, p) {
|
||||
context.commit('ADD_FREADD_PARKINGQUENCY', p)
|
||||
context.commit('ADD_PARKING', p)
|
||||
},
|
||||
async updatedParking (context, p) {
|
||||
context.commit('UPDATE_PARKING', p)
|
||||
|
@ -1,6 +1,9 @@
|
||||
/* eslint-disable */
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
const state = {
|
||||
settings: { flightgearDirectory: '.', testDirectory: '.', email: 'flightgearairports@example.org', name: 'unknown', phi_url: 'http://localhost:8080' },
|
||||
settings: { numberOfSaves: 1, flightgearDirectory: '.', testDirectory: '.', email: 'flightgearairports@example.org', name: 'unknown', phi_url: 'http://localhost:8080' },
|
||||
zoom: 14,
|
||||
center: [47.413220, -1.219482],
|
||||
bounds: undefined,
|
||||
@ -8,41 +11,55 @@ const state = {
|
||||
}
|
||||
|
||||
const mutations = {
|
||||
'DELETE_INDEXED_DB' () { },
|
||||
'FLIGHTGEAR_DIRECTORY' (state, flightgearDirectory) {
|
||||
'DELETE_INDEXED_DB'() { },
|
||||
'FLIGHTGEAR_DIRECTORY'(state, flightgearDirectory) {
|
||||
try {
|
||||
fs.accessSync(flightgearDirectory)
|
||||
state.settings.flightgearDirectory = flightgearDirectory
|
||||
state.settings.flightgearDirectory_ai = flightgearDirectory + '/data/AI'
|
||||
state.settings.flightgearDirectory_traffic = flightgearDirectory + '/data/AI/Traffic'
|
||||
state.settings.flightgearDirectory_apt = flightgearDirectory + '/data/Airports/apt.dat.gz'
|
||||
} catch (err) {
|
||||
try {
|
||||
fs.accessSync(flightgearDirectory.replace(/\.App/, ''))
|
||||
state.settings.flightgearDirectory = flightgearDirectory.replace(/\.App/, '')
|
||||
} catch (error) {
|
||||
console.warn(error)
|
||||
}
|
||||
}
|
||||
|
||||
state.settings.flightgearDirectory_ai = flightgearDirectory + path.sep + 'AI'
|
||||
state.settings.flightgearDirectory_traffic = path.join(flightgearDirectory, 'AI', 'Traffic');
|
||||
state.settings.flightgearDirectory_apt = path.join(flightgearDirectory, 'Airports', 'apt.dat.gz');
|
||||
},
|
||||
'AIPORTS_DIRECTORY' (state, airportsDirectory) {
|
||||
'AIPORTS_DIRECTORY'(state, airportsDirectory) {
|
||||
state.settings.airportsDirectory = airportsDirectory
|
||||
},
|
||||
'TEST_DIRECTORY' (state, testDirectory) {
|
||||
'TEST_DIRECTORY'(state, testDirectory) {
|
||||
state.settings.testDirectory = testDirectory
|
||||
},
|
||||
'ZOOM' (state, zoom) {
|
||||
'ZOOM'(state, zoom) {
|
||||
state.zoom = zoom
|
||||
},
|
||||
'CENTER' (state, center) {
|
||||
'CENTER'(state, center) {
|
||||
state.center = center
|
||||
},
|
||||
'BOUNDS' (state, bounds) {
|
||||
'BOUNDS'(state, bounds) {
|
||||
state.bounds = bounds
|
||||
},
|
||||
'SET_EMAIL' (state, email) {
|
||||
'SET_EMAIL'(state, email) {
|
||||
state.settings.email = email
|
||||
},
|
||||
'SET_NAME' (state, name) {
|
||||
'SET_NAME'(state, name) {
|
||||
state.settings.name = name
|
||||
},
|
||||
'SET_PHI_URL' (state, phi_url) {
|
||||
'SET_NUMBER_OF_SAVES'(state, numberOfSaves) {
|
||||
state.settings.numberOfSaves = numberOfSaves
|
||||
},
|
||||
'SET_PHI_URL'(state, phi_url) {
|
||||
state.settings.phi_url = phi_url
|
||||
},
|
||||
'SET_SCAN_LOGGING' (state, scanLogging) {
|
||||
'SET_SCAN_LOGGING'(state, scanLogging) {
|
||||
state.settings.scanLogging = scanLogging
|
||||
},
|
||||
'ADD_WIP' (state, airport) {
|
||||
'ADD_WIP'(state, airport) {
|
||||
const item = state.wip.find((e) => e.icao === airport.icao)
|
||||
airport.time = Date.now()
|
||||
if (item === null || item === undefined) {
|
||||
@ -52,12 +69,12 @@ const mutations = {
|
||||
}
|
||||
state.wip.sort((w1, w2) => w1.time - w2.time)
|
||||
},
|
||||
'UPLOAD_WIP' (state, icao) {
|
||||
'UPLOAD_WIP'(state, icao) {
|
||||
const item = state.wip.find((e) => e.icao === icao)
|
||||
item.upload = Date.now()
|
||||
state.wip.sort((p, p2) => { return p.time - p2.time })
|
||||
},
|
||||
'REMOVE_WIP' (state, icao) {
|
||||
'REMOVE_WIP'(state, icao) {
|
||||
const item = state.wip.find((e) => e.icao === icao)
|
||||
const index = state.wip.indexOf(item)
|
||||
if (index > -1) {
|
||||
@ -69,21 +86,21 @@ const mutations = {
|
||||
const plugins = []
|
||||
|
||||
const actions = {
|
||||
async setZoom (context, zoom) {
|
||||
async setZoom(context, zoom) {
|
||||
context.commit('ZOOM', zoom)
|
||||
},
|
||||
async setCenter (context, center) {
|
||||
if( center.lat !== context.state.center.lat || center.lng !== context.state.center.lng) {
|
||||
async setCenter(context, center) {
|
||||
if (center.lat !== context.state.center.lat || center.lng !== context.state.center.lng) {
|
||||
context.commit('CENTER', center)
|
||||
}
|
||||
},
|
||||
async setBounds (context, bounds) {
|
||||
async setBounds(context, bounds) {
|
||||
context.commit('BOUNDS', bounds)
|
||||
},
|
||||
async addWip (context, airport) {
|
||||
async addWip(context, airport) {
|
||||
context.commit('ADD_WIP', airport)
|
||||
},
|
||||
async removeWip (context, icao) {
|
||||
async removeWip(context, icao) {
|
||||
context.commit('REMOVE_WIP', icao)
|
||||
}
|
||||
}
|
||||
|
@ -8,9 +8,14 @@ const fs = require('fs');
|
||||
//debugger;
|
||||
var turf;
|
||||
|
||||
if(process.env.NODE_ENV === 'development') {
|
||||
var check_msg;
|
||||
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
importScripts('../../../node_modules/dijkstrajs/dijkstra.js');
|
||||
turf = require('./node_modules/@turf/turf');
|
||||
} else if (process.env.NODE_ENV === 'mocha') {
|
||||
importScripts('../../../node_modules/dijkstrajs/dijkstra.js');
|
||||
turf = require('../../../node_modules/@turf/turf')
|
||||
} else {
|
||||
importScripts('dijkstra.js');
|
||||
turf = require('@turf/turf')
|
||||
@ -38,89 +43,141 @@ onmessage = function (event) {
|
||||
).catch(result => {
|
||||
console.error('Crashed');
|
||||
console.error(result);
|
||||
postMessage(['DONE', []]);
|
||||
postMessage(['DONE', [{ id: -1, message: ['Crashed', result] }]]);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Implements the checks of the groundnet
|
||||
* @param {*} data
|
||||
*/
|
||||
|
||||
async function checkGroundnet(data) {
|
||||
var promise = new Promise(function (resolve, reject) {
|
||||
try {
|
||||
const fName = process.env.NODE_ENV === 'development'
|
||||
? './src/renderer/utils/check_msg.json'
|
||||
: path.join(`${process.resourcesPath}`, 'workers', 'check_msg.json');
|
||||
check_msg = JSON.parse(fs.readFileSync(fName, 'utf8').toString());
|
||||
//debugger;
|
||||
var parkings = data.map(mapParkings).filter(n => n !== undefined);
|
||||
var runwayNodes = data.map(mapRunwayNodes).filter(n => n !== undefined);
|
||||
var runwayNodeIDs = data.map(mapRunwayNodeId).filter(n => n !== undefined);
|
||||
var runwayNodes = data.map(mapRunwayNode).filter(n => n !== undefined);
|
||||
var pushbackNodes = data.map(mapPushbackNodes).filter(n => n !== undefined);
|
||||
var edges = data.map(mapEdges).filter(n => n !== undefined);
|
||||
|
||||
this.max = 4 * parkings.length * runwayNodes.length +
|
||||
3 * parkings.length;
|
||||
var normalNodes = data.map(mapEdges).filter(n => n !== undefined)
|
||||
.flatMap(m => m.latLngs).filter(n => runwayNodeIDs.indexOf(Number(n.index)) < 0);
|
||||
|
||||
var takeoffPads = data.map(mapTakeoffPads).filter(n => n !== undefined);
|
||||
|
||||
this.max = 30;
|
||||
this.postMessage(['max', this.max]);
|
||||
|
||||
var boxes = {};
|
||||
//debugger;
|
||||
data.forEach(element => {
|
||||
//debugger;
|
||||
if(element.box!==undefined && element.box!==null) {
|
||||
boxes[element.index] = element.box[0].map(latlng => [latlng.lat, latlng.lng] );
|
||||
if (element.box !== undefined && element.box !== null) {
|
||||
boxes[element.index] = element.box[0].map(latlng => [latlng.lat, latlng.lng]);
|
||||
boxes[element.index].push(boxes[element.index][0]);
|
||||
}
|
||||
});
|
||||
var graph = {};
|
||||
var directionalGraph = {};
|
||||
var bidirectionalGraph = {};
|
||||
|
||||
console.debug(parkings);
|
||||
parkings.forEach(element => {
|
||||
graph[element] = {};
|
||||
directionalGraph[element] = {};
|
||||
bidirectionalGraph[element] = {};
|
||||
});
|
||||
runwayNodes.forEach(element => {
|
||||
graph[element] = {};
|
||||
runwayNodeIDs.forEach(element => {
|
||||
directionalGraph[element] = {};
|
||||
bidirectionalGraph[element] = {};
|
||||
});
|
||||
var notOkNodes = [];
|
||||
//debugger;
|
||||
|
||||
console.debug(edges);
|
||||
if (edges === undefined) {
|
||||
resolve([{ id: -1, message: check_msg.NO_EDGES }]);
|
||||
}
|
||||
this.postMessage(['progress', 1]);
|
||||
//debugger;
|
||||
if (takeoffPads.length === 0) {
|
||||
resolve([{ id: -1, message: check_msg.NO_RUNWAYS }]);
|
||||
}
|
||||
this.postMessage(['progress', 1]);
|
||||
edges.forEach(edge => {
|
||||
graph[edge.start] = {};
|
||||
graph[edge.end] = {};
|
||||
directionalGraph[edge.start] = {};
|
||||
bidirectionalGraph[edge.start] = {};
|
||||
directionalGraph[edge.end] = {};
|
||||
bidirectionalGraph[edge.end] = {};
|
||||
if (edge.latLngs !== undefined) {
|
||||
// Check if there are segments > 2km
|
||||
edge.latLngs.forEach((latLng, index, arr) => {
|
||||
if (index>0) {
|
||||
var d = distance([arr[index-1].lng, arr[index-1].lat], [latLng.lng, latLng.lat]);
|
||||
if(d>2000) {
|
||||
notOkNodes.push({ id: Number(arr[index-1].index), message: `Start of long route ${d.toFixed(2)}` });
|
||||
notOkNodes.push({ id: Number(arr[index].index), message: `End of long route ${d.toFixed(2)}` });
|
||||
if (index > 0) {
|
||||
var d = distance([arr[index - 1].lng, arr[index - 1].lat], [latLng.lng, latLng.lat]);
|
||||
if (d > 2000) {
|
||||
notOkNodes.push({ id: Number(arr[index - 1].index), message: check_msg.LONG_ROUTE_START });
|
||||
notOkNodes.push({ id: Number(arr[index].index), message: check_msg.LONG_ROUTE_END });
|
||||
}
|
||||
//console.log(d);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
this.postMessage(['progress', 1]);
|
||||
this.postMessage(['progress', 1]);
|
||||
// Add edges to graphs
|
||||
edges.forEach(element => {
|
||||
var node1 = graph[element.start];
|
||||
var node1 = directionalGraph[element.start];
|
||||
var node2 = directionalGraph[element.end];
|
||||
if (element.direction === undefined) {
|
||||
notOkNodes.push({ id: Number(element._leaflet_id), message: check_msg.EDGE_MISSING_DIRECTION });
|
||||
}
|
||||
if (element.direction === 'bi-directional' || element.direction === 'forward') {
|
||||
node1[Number(element.end)] = 1;
|
||||
var node2 = graph[element.end];
|
||||
}
|
||||
if (element.direction === 'bi-directional' || element.direction === 'backward') {
|
||||
node2[Number(element.start)] = 1;
|
||||
}
|
||||
|
||||
var node3 = bidirectionalGraph[element.start];
|
||||
var node4 = bidirectionalGraph[element.end];
|
||||
node3[Number(element.end)] = 1;
|
||||
node4[Number(element.start)] = 1;
|
||||
});
|
||||
var isLegitEnd = function(v) {
|
||||
if( Object.keys(graph[v]).length <= 1 ) {
|
||||
this.postMessage(['progress', 1]);
|
||||
var isLegitEnd = function (v) {
|
||||
if (bidirectionalGraph[v] === undefined) {
|
||||
debugger;
|
||||
}
|
||||
if (Object.keys(bidirectionalGraph[v]).length <= 1) {
|
||||
return true;
|
||||
}
|
||||
return Object.keys(graph[v]).filter( v => runwayNodes[v]).length === 0;
|
||||
return Object.keys(bidirectionalGraph[v]).filter(v => runwayNodeIDs[v]).length === 0;
|
||||
}
|
||||
//debugger;
|
||||
runwayNodes = runwayNodes.filter(
|
||||
runwayNodeIDs = runwayNodeIDs.filter(
|
||||
(v, i) => isLegitEnd(v)
|
||||
);
|
||||
// Check if there is a route from every parking to every runway node
|
||||
var okNodes = [];
|
||||
logger('info', graph);
|
||||
logger('info', directionalGraph);
|
||||
parkings.forEach(parkingNode => {
|
||||
runwayNodes.forEach(runwayNode => {
|
||||
var ok = checkRoute(graph, parkingNode, runwayNode);
|
||||
runwayNodeIDs.forEach(runwayNode => {
|
||||
var ok = checkRoute(directionalGraph, parkingNode, runwayNode);
|
||||
if (ok) {
|
||||
okNodes.push(parkingNode);
|
||||
okNodes.push(runwayNode);
|
||||
} else {
|
||||
console.log(`No route from Parking ${parkingNode} to Runwaynode ${runwayNode}`);
|
||||
}
|
||||
this.postMessage(['progress', 1]);
|
||||
|
||||
});
|
||||
});
|
||||
// Build pushback graph
|
||||
// Build pushback directionalGraph
|
||||
var noPushbackGraph = {};
|
||||
parkings.forEach(element => {
|
||||
noPushbackGraph[element] = {};
|
||||
@ -144,99 +201,133 @@ async function checkGroundnet(data) {
|
||||
var okPushbacks = [];
|
||||
// Check pushback
|
||||
var multiplePushbackRoutes = {};
|
||||
//debugger;
|
||||
parkings.forEach(parkingNode => {
|
||||
pushbackNodes.forEach(pushbackNode => {
|
||||
var numRoutes = checkRoute(noPushbackGraph, parkingNode, pushbackNode);
|
||||
if (numRoutes===0) {
|
||||
/*
|
||||
if(parkingNode===14) {
|
||||
debugger;
|
||||
}
|
||||
*/
|
||||
if (multiplePushbackRoutes[parkingNode]===undefined &&
|
||||
Object.keys(noPushbackGraph[parkingNode])>0) {
|
||||
if (numRoutes === 0) {
|
||||
if (multiplePushbackRoutes[parkingNode] === undefined &&
|
||||
Object.keys(noPushbackGraph[parkingNode]) > 0) {
|
||||
// Only when there is a edge leaving
|
||||
multiplePushbackRoutes[parkingNode] = [];
|
||||
}
|
||||
} else if (numRoutes===1){
|
||||
if (multiplePushbackRoutes[parkingNode]===undefined) {
|
||||
} else if (numRoutes === 1) {
|
||||
if (multiplePushbackRoutes[parkingNode] === undefined) {
|
||||
multiplePushbackRoutes[parkingNode] = [pushbackNode];
|
||||
} else {
|
||||
multiplePushbackRoutes[parkingNode].push(pushbackNode);
|
||||
}
|
||||
} else if (numRoutes>1){
|
||||
if (multiplePushbackRoutes[parkingNode]===undefined) {
|
||||
} else if (numRoutes > 1) {
|
||||
if (multiplePushbackRoutes[parkingNode] === undefined) {
|
||||
multiplePushbackRoutes[parkingNode] = [pushbackNode];
|
||||
} else {
|
||||
multiplePushbackRoutes[parkingNode].push(pushbackNode);
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
var notConnectedToPushback = pushbackNodes.map(
|
||||
id => {
|
||||
var normalRoutes = bidirectionalGraph[id];
|
||||
var pushbackRoutes = noPushbackGraph[id];
|
||||
if (Object.keys(pushbackRoutes).length < 1)
|
||||
return { id: id, message: check_msg.PUSHBACK_NOT_CONNECTED }
|
||||
}).filter(n => n !== undefined);
|
||||
this.postMessage(['progress', 1]);
|
||||
var multipleTaxiRoutes = pushbackNodes.map(
|
||||
id => {
|
||||
var normalRoutes = bidirectionalGraph[id];
|
||||
var pushbackRoutes = noPushbackGraph[id];
|
||||
if (normalRoutes !== undefined) {
|
||||
var nonPushbackRoutes = Object.keys(normalRoutes).filter(r => pushbackRoutes[r] === undefined);
|
||||
if (nonPushbackRoutes.length > 1)
|
||||
return { id: id, message: check_msg.TO_MANY_PUSHBACK_TAXI_ROUTES }
|
||||
}
|
||||
}).filter(n => n !== undefined);
|
||||
this.postMessage(['progress', 1]);
|
||||
var pushbackExitNotBidirectional = pushbackNodes.map(
|
||||
id => {
|
||||
var normalRoutes = bidirectionalGraph[id];
|
||||
var pushbackRoutes = noPushbackGraph[id];
|
||||
if (normalRoutes !== undefined) {
|
||||
var nonPushbackRoutes = Object.keys(normalRoutes).filter(r => pushbackRoutes[r] === undefined);
|
||||
if(nonPushbackRoutes.length > 0) {
|
||||
var returnRoute = Object.keys(bidirectionalGraph[nonPushbackRoutes[0]]).map(id => Number(id)).filter(retId =>id === retId);
|
||||
if (returnRoute.length === 0)
|
||||
return { id: id, message: check_msg.PUSHBACK_EXIT_NOT_BIDRECTIONAL }
|
||||
}
|
||||
}
|
||||
}).filter(n => n !== undefined);
|
||||
this.postMessage(['progress', 1]);
|
||||
});
|
||||
});
|
||||
var rogueHoldPoints = pushbackNodes.map(
|
||||
id => {
|
||||
var routes = noPushbackGraph[id];
|
||||
if(Object.keys(routes).length<1)
|
||||
return { id: id, message: 'Unconnected Pushbacknode' }
|
||||
if (Object.keys(routes).length < 1)
|
||||
return { id: id, message: check_msg.UNCONNECTED_PUSHBACK }
|
||||
/*
|
||||
else if(Object.keys(routes).length>1)
|
||||
return { id: id, message: 'Multiple connected pushback node' }
|
||||
*/
|
||||
}
|
||||
).filter(n => n !== undefined);
|
||||
this.postMessage(['progress', 1]);
|
||||
var wrongPushbackRoutes = parkings.filter(
|
||||
function (e) {
|
||||
//debugger;
|
||||
return this[e] != undefined && this[e].length != 1;
|
||||
}
|
||||
, multiplePushbackRoutes).map(
|
||||
id => {
|
||||
var endPoints = multiplePushbackRoutes[id];
|
||||
if( endPoints.length<1)
|
||||
return { id: id, message: 'No way to pushback holdpoint' }
|
||||
if (endPoints.length < 1)
|
||||
return { id: id, message: check_msg.NO_WAY_TO_HOLDPOINT }
|
||||
else
|
||||
return { id: id, message: 'Multiple connected pushback points' }
|
||||
return { id: id, message: check_msg.MULTIPLE_PUSHBACK }
|
||||
}
|
||||
);
|
||||
wrongPushbackRoutes =wrongPushbackRoutes.concat(multiplePushbackRoutes);
|
||||
|
||||
|
||||
this.postMessage(['progress', 1]);
|
||||
okNodes = okNodes.filter((v, i) => okNodes.indexOf(v) === i);
|
||||
var notOkNodesParkings = parkings.filter(
|
||||
(v, i) => okNodes.indexOf(v) < 0
|
||||
).map(
|
||||
id => { return { id: id, message: 'No way from parking to each runway' } }
|
||||
id => { return { id: id, message: check_msg.NO_RUNWAY_ROUTE } }
|
||||
);
|
||||
var notOkNodesRunways = runwayNodes.filter(
|
||||
this.postMessage(['progress', 1]);
|
||||
|
||||
var notOkNodesRunways = runwayNodeIDs.filter(
|
||||
(v, i) => okNodes.indexOf(v) < 0
|
||||
).map(
|
||||
id => { return { id: id, message: 'No way from runway to each parking' } }
|
||||
id => { return { id: id, message: check_msg.NO_PARKING_ROUTE } }
|
||||
);
|
||||
this.postMessage(['progress', 1]);
|
||||
|
||||
if (parkings.length === 0) {
|
||||
notOkNodes.push({ id: 0, message: 'No parkings' });
|
||||
notOkNodes.push({ id: -2, message: check_msg.NO_PARKINGS });
|
||||
}
|
||||
if (runwayNodes.length === 0) {
|
||||
notOkNodes.push({ id: 0, message: 'No Runwaynodes' });
|
||||
this.postMessage(['progress', 1]);
|
||||
if (runwayNodeIDs.length === 0) {
|
||||
notOkNodes.push({ id: -2, message: check_msg.NO_RUNWAY_NODES });
|
||||
}
|
||||
var allEnds = Object.entries(graph).filter(
|
||||
this.postMessage(['progress', 1]);
|
||||
var allEnds = Object.entries(bidirectionalGraph).filter(
|
||||
(v, i) => Object.keys(v[1]).length <= 1
|
||||
);
|
||||
// Ends that are not on Runway and not a Parking or Pushback
|
||||
var allLegitimateEndNodes = parkings.concat(runwayNodes).concat(pushbackNodes);
|
||||
var allLegitimateEndNodes = parkings.concat(runwayNodeIDs).concat(pushbackNodes);
|
||||
var danglingEnds = allEnds.filter(
|
||||
(v, i) => allLegitimateEndNodes.indexOf(Number(v[0])) < 0
|
||||
).map(
|
||||
v => { return { id: Number(v[0]), message: 'Node not a legimate end' } }
|
||||
v => { return { id: Number(v[0]), message: check_msg.NOT_LEGIT_END } }
|
||||
);
|
||||
this.postMessage(['progress', 1]);
|
||||
|
||||
var parkingNodes = data.map(mapParkingNode).filter(n => n !== undefined);
|
||||
|
||||
var overlappingParkings = [];
|
||||
parkingNodes.forEach(parkingNode => {
|
||||
if (boxes[parkingNode.index] === undefined) {
|
||||
overlappingParkings.push({ id: parkingNode.index, message: 'Unknown radius' });
|
||||
overlappingParkings.push({ id: parkingNode.index, message: check_msg.UNKNOWN_RADIUS });
|
||||
}
|
||||
});
|
||||
// Check for intersecting radii
|
||||
@ -248,78 +339,106 @@ async function checkGroundnet(data) {
|
||||
[parkingNode1.lng, parkingNode1.lat]);
|
||||
if (d < parkingNode.radius + parkingNode1.radius + 10) {
|
||||
// If bigger circles intersect we should check the boxes
|
||||
//debugger;
|
||||
if( boxes[parkingNode.index] !== null && boxes[parkingNode1.index] !== null &&
|
||||
if (boxes[parkingNode.index] !== null && boxes[parkingNode1.index] !== null &&
|
||||
boxes[parkingNode.index] !== undefined && boxes[parkingNode1.index] !== undefined) {
|
||||
var poly1 = turf.polygon([boxes[parkingNode.index]]);
|
||||
|
||||
var poly2 = turf.polygon([boxes[parkingNode1.index]]);
|
||||
|
||||
var intersection = turf.intersect(poly1, poly2);
|
||||
if( intersection !== null ) {
|
||||
overlappingParkings.push({ id: parkingNode.index, message: 'Overlapping parkings' });
|
||||
if (intersection !== null) {
|
||||
overlappingParkings.push({ id: parkingNode.index, message: check_msg.OVERLAPPING_PARKINGS });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
this.postMessage(['progress', 1]);
|
||||
});
|
||||
});
|
||||
var invalidParkings = [];
|
||||
// Check for name
|
||||
parkingNodes.forEach(parkingNode => {
|
||||
if (!parkingNode.name || /^\s*$/.test(parkingNode.name)) {
|
||||
invalidParkings.push({ id: parkingNode.index, message: 'Name empty' });
|
||||
this.postMessage(['progress', 1]);
|
||||
invalidParkings.push({ id: parkingNode.index, message: check_msg.NAME_EMPTY });
|
||||
|
||||
}
|
||||
if (!parkingNode.type) {
|
||||
invalidParkings.push({ id: parkingNode.index, message: 'Parking type empty' });
|
||||
this.postMessage(['progress', 1]);
|
||||
invalidParkings.push({ id: parkingNode.index, message: check_msg.TYPE_EMPTY });
|
||||
|
||||
}
|
||||
if (['ga','cargo', 'gate', 'mil-fighter', 'mil-cargo' ].indexOf(parkingNode.parkingType)<0) {
|
||||
//debugger;
|
||||
invalidParkings.push({ id: parkingNode.index, message: `Parking type ${parkingNode.parkingType} not valid` });
|
||||
this.postMessage(['progress', 1]);
|
||||
if (['ga', 'cargo', 'gate', 'mil-fighter', 'mil-cargo'].indexOf(parkingNode.parkingType) < 0) {
|
||||
invalidParkings.push({ id: parkingNode.index, message: check_msg.PARKING_TYPE_INVALID });
|
||||
}
|
||||
});
|
||||
this.postMessage(['progress', 1]);
|
||||
this.postMessage(['progress', 1]);
|
||||
|
||||
//Check for dual pushback/runway nodes
|
||||
runwayNodes.forEach(runwayNode => {
|
||||
runwayNodeIDs.forEach(runwayNode => {
|
||||
if (pushbackNodes.indexOf(runwayNode) >= 0) {
|
||||
notOkNodes.push({ id: runwayNode, message: 'Dual runway/ pushback node' });
|
||||
notOkNodes.push({ id: runwayNode, message: check_msg.DUAL_PUSHBACK });
|
||||
}
|
||||
});
|
||||
this.postMessage(['progress', 1]);
|
||||
//Check if runwaynodes are on runway
|
||||
runwayNodes.forEach(runwayNode => {
|
||||
// debugger;
|
||||
if (takeoffPads.filter(r => turf.booleanContains(r, latToTurf(runwayNode))).length === 0) {
|
||||
notOkNodes.push({ id: runwayNode.index, message: check_msg.RUNWAY_NODE_NOT_ON_RUNWAY });
|
||||
}
|
||||
});
|
||||
this.postMessage(['progress', 1]);
|
||||
|
||||
//Check if nodes no normal nodes are on runway
|
||||
normalNodes.forEach(normalNode => {
|
||||
//debugger;
|
||||
if (takeoffPads.filter(r => turf.booleanContains(r, latToTurf(normalNode))).length > 0) {
|
||||
notOkNodes.push({ id: normalNode.index, message: check_msg.NON_RUNWAYNODE_ON_RUNWAY });
|
||||
}
|
||||
});
|
||||
this.postMessage(['progress', 1]);
|
||||
|
||||
var doubleEdges = edges.filter((v, i, a) => a.findIndex(t => (t.start === v.start && t.end === v.end) ) !== i);
|
||||
doubleEdges.forEach(e => {
|
||||
notOkNodes.push({ id: e.id, message: check_msg.DOUBLE_EDGE });
|
||||
});
|
||||
|
||||
// debugger;
|
||||
|
||||
notOkNodes = notOkNodes.concat(invalidParkings);
|
||||
if (invalidParkings.length===0) {
|
||||
notOkNodes.push({id:-1, message: 'Parkings valid'});
|
||||
if (invalidParkings.length === 0) {
|
||||
notOkNodes.push({ id: -1, message: check_msg.PARKINGS_VALID });
|
||||
}
|
||||
notOkNodes = notOkNodes.concat(overlappingParkings);
|
||||
if (overlappingParkings.length===0) {
|
||||
notOkNodes.push({id:-1, message: 'No parkings overlapping'});
|
||||
if (overlappingParkings.length === 0) {
|
||||
notOkNodes.push({ id: -1, message: check_msg.NO_OVERLAPPING_PARKINGS });
|
||||
}
|
||||
notOkNodes = notOkNodes.concat(danglingEnds);
|
||||
if (danglingEnds.length===0) {
|
||||
notOkNodes.push({id:-1, message: 'No invalid ends'});
|
||||
if (danglingEnds.length === 0) {
|
||||
notOkNodes.push({ id: -1, message: check_msg.NO_INVALID_ENDS });
|
||||
}
|
||||
notOkNodes = notOkNodes.concat(notOkNodesParkings).concat(rogueHoldPoints);
|
||||
if (notOkNodesParkings.length===0 && rogueHoldPoints===0) {
|
||||
notOkNodes.push({id:-1, message: 'Routes from parkings OK'});
|
||||
if (notOkNodesParkings.length === 0 && rogueHoldPoints === 0) {
|
||||
notOkNodes.push({ id: -1, message: check_msg.ROUTES_FROM_PARKINGS_OK });
|
||||
}
|
||||
|
||||
notOkNodes = notOkNodes.concat(notOkNodesRunways);
|
||||
if (notOkNodesRunways.length===0) {
|
||||
notOkNodes.push({id:-1, message: 'Routes from runways OK'});
|
||||
if (notOkNodesRunways.length === 0) {
|
||||
notOkNodes.push({ id: -1, message: check_msg.ROUTES_FROM_RUNWAYS_OK });
|
||||
}
|
||||
notOkNodes = notOkNodes.concat(wrongPushbackRoutes);
|
||||
if (wrongPushbackRoutes.length===0) {
|
||||
notOkNodes.push({id:-1, message: 'Pushback routes OK'});
|
||||
notOkNodes = notOkNodes.concat(notConnectedToPushback);
|
||||
notOkNodes = notOkNodes.concat(multipleTaxiRoutes);
|
||||
notOkNodes = notOkNodes.concat(pushbackExitNotBidirectional);
|
||||
if (wrongPushbackRoutes.length === 0 &&
|
||||
notConnectedToPushback.length === 0 &&
|
||||
multipleTaxiRoutes.length === 0 &&
|
||||
pushbackExitNotBidirectional.length === 0
|
||||
) {
|
||||
notOkNodes.push({ id: -1, message: check_msg.PUSHBACK_ROUTES_OK });
|
||||
}
|
||||
// check1(graph);
|
||||
// check2();
|
||||
// this.postMessage(['progress', 1]);
|
||||
resolve(notOkNodes);
|
||||
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
@ -327,9 +446,9 @@ async function checkGroundnet(data) {
|
||||
return promise;
|
||||
}
|
||||
|
||||
function checkRoute(graph, from, to) {
|
||||
function checkRoute(directionalGraph, from, to) {
|
||||
try {
|
||||
var pathD = this.dijkstra.find_path(graph, from, to);
|
||||
var pathD = this.dijkstra.find_path(directionalGraph, from, to);
|
||||
if (pathD.length > 0) {
|
||||
console.log(pathD);
|
||||
return pathD.length;
|
||||
@ -341,8 +460,8 @@ function checkRoute(graph, from, to) {
|
||||
}
|
||||
}
|
||||
|
||||
function check1(graph) {
|
||||
var graph1 = {
|
||||
function check1(directionalGraph) {
|
||||
var directionalGraph1 = {
|
||||
a: { b: 1, d: 1 },
|
||||
b: { a: 1, c: 1, e: 1 },
|
||||
c: { b: 1, f: 1 },
|
||||
@ -353,7 +472,7 @@ function check1(graph) {
|
||||
h: { e: 1, g: 1, i: 1 },
|
||||
i: { f: 1, h: 1 }
|
||||
};
|
||||
var path = this.dijkstra.find_path(graph, 'a', 'i');
|
||||
var path = this.dijkstra.find_path(directionalGraph, 'a', 'i');
|
||||
console.log(path);
|
||||
}
|
||||
|
||||
@ -385,18 +504,44 @@ var mapBoxes = function (o) {
|
||||
return { index: o.index };
|
||||
}
|
||||
|
||||
var mapRunwayNodes = function (o) {
|
||||
var mapRunwayNodeId = function (o) {
|
||||
if (o.type === 'runway')
|
||||
return o.index;
|
||||
console.debug(o);
|
||||
}
|
||||
|
||||
var mapRunwayNode = function (o) {
|
||||
if (o.type === 'runway') {
|
||||
return { index: o.index, lat: o.lat, lng: o.lng };
|
||||
}
|
||||
}
|
||||
|
||||
var mapTakeoffPads = function (o) {
|
||||
if (o.type === 'takeoffpad_poly') {
|
||||
var pts = o.pavement[0].map(latLngToArray);
|
||||
pts.push(pts[0]);
|
||||
return turf.polygon([pts]);
|
||||
}
|
||||
}
|
||||
|
||||
var mapEdges = function (o) {
|
||||
if (o.type === 'poly')
|
||||
// debugger;
|
||||
return {
|
||||
start: o.start, end: o.end, isPushBackRoute: o.isPushBackRoute !== undefined &&
|
||||
o.isPushBackRoute !== 0, latLngs: o.latLngs
|
||||
id: o._leaflet_id, start: o.start, end: o.end, isPushBackRoute: o.isPushBackRoute !== undefined &&
|
||||
o.isPushBackRoute !== 0, direction: o.direction, latLngs: o.latLngs
|
||||
};
|
||||
console.debug(o);
|
||||
}
|
||||
|
||||
var latToTurf = function (turfPoint) {
|
||||
return turf.point([turfPoint.lng, turfPoint.lat]);
|
||||
};
|
||||
|
||||
var latLngToArray = function (turfPoint) {
|
||||
//debugger;
|
||||
|
||||
return [turfPoint.lng, turfPoint.lat];
|
||||
};
|
||||
|
||||
var turfToLatLng = function (turfPoint) {
|
||||
return '' + turfPoint.geometry.coordinates[1].toFixed(6) + ',' + turfPoint.geometry.coordinates[0].toFixed(6);
|
||||
};
|
||||
|
33
src/renderer/utils/check_msg.json
Normal file
@ -0,0 +1,33 @@
|
||||
{
|
||||
"LONG_ROUTE_START" : ["Start of long route", "Route segments of >2km are Taxidraw artefacts"],
|
||||
"LONG_ROUTE_END": ["End of long route", "Route segments of >2km are Taxidraw artefacts"],
|
||||
"EDGE_MISSING_DIRECTION": ["Edge missing direction", "Each edge must have a direction (forward, backward, bi-directional)"],
|
||||
"NO_RUNWAY_ROUTE": ["No way from parking to each runway", "There must be a route from each parking to each runway."],
|
||||
"NO_PARKING_ROUTE": ["No way from runway to each parking", "There must be a route from each runway to each parking."],
|
||||
"NO_PARKINGS": ["No parkings", ""],
|
||||
"NO_RUNWAY_NODES": ["No Runwaynodes", "Fine for parking only"],
|
||||
"NOT_LEGIT_END": ["Node not a legimate end", "Taxiroutes must end either at a parking or on a runway"],
|
||||
"UNKNOWN_RADIUS" :["Unknown radius", "Radii must be one from the list"],
|
||||
"OVERLAPPING_PARKINGS" :["Overlapping parkings", "Parkings must not overlap"],
|
||||
"NAME_EMPTY" :["Name empty", "Name of parking must not be empty"],
|
||||
"TYPE_EMPTY" :["Parking type empty", "The parking type must not be empty"],
|
||||
"PARKING_TYPE_INVALID" :["Parking type not valid", "The type of parking must be one of ()"],
|
||||
"DUAL_PUSHBACK": ["Dual runway/ pushback node", "A runway node can not be a hold node at the same time"],
|
||||
"RUNWAY_NODE_NOT_ON_RUNWAY" : ["Runwaynode not in takeoff pad", ""],
|
||||
"NON_RUNWAYNODE_ON_RUNWAY": ["Non Runwaynode in takeoff pad", ""],
|
||||
"PARKINGS_VALID": ["Parkings valid", "All Ok"],
|
||||
"NO_OVERLAPPING_PARKINGS": ["No parkings overlapping", "Parking positions may not overlap. Reduce the radius or move."],
|
||||
"NO_INVALID_ENDS": ["No invalid ends", ""],
|
||||
"ROUTES_FROM_PARKINGS_OK": ["Routes from parkings OK", ""],
|
||||
"ROUTES_FROM_RUNWAYS_OK": ["Routes from runways OK", ""],
|
||||
"PUSHBACK_ROUTES_OK": ["Pushback routes OK", ""],
|
||||
"UNCONNECTED_PUSHBACK": ["Unconnected Pushbacknode", ""],
|
||||
"NO_WAY_TO_HOLDPOINT":["No way to pushback holdpoint", "There is no route from the parking to the pushback hold point-"],
|
||||
"MULTIPLE_PUSHBACK": ["Multiple connected pushback points", "There are more than one possible pushback holdpoint routes."],
|
||||
"PUSHBACK_NOT_CONNECTED": ["Pushback Holding Point not Connected to Pushback Route", ""],
|
||||
"TO_MANY_PUSHBACK_TAXI_ROUTES": ["Too many Taxi routes from Pushback Holding Point", "There must be only one pushback point reachable from the parking."],
|
||||
"PUSHBACK_EXIT_NOT_BIDRECTIONAL": ["Pushback Holding Point Exit route is not bidirectional", ""],
|
||||
"NO_EDGES": ["No Edges", "No checks are run if there are no edges present"],
|
||||
"NO_RUNWAYS": ["No Runways", "No checks are run if there are no runways present. APT layer visible?"],
|
||||
"DOUBLE_EDGE": ["No Double Edges", "This edge is doubled"]
|
||||
}
|
@ -1,29 +1,40 @@
|
||||
var util = require("util");
|
||||
/* eslint-disable no-unused-vars */
|
||||
var util = require('util');
|
||||
|
||||
const d = new Date();
|
||||
|
||||
const fName = 'scan_' + d.getFullYear()
|
||||
+ d.getMonth()
|
||||
+ d.getDay()
|
||||
+ d.getHours()
|
||||
+ d.getMinutes()
|
||||
+ d.getSeconds()
|
||||
+ d.getMilliseconds() + '.log';
|
||||
const fName = 'scan_' + d.getFullYear() +
|
||||
d.getMonth() +
|
||||
d.getDay() +
|
||||
d.getHours() +
|
||||
d.getMinutes() +
|
||||
d.getSeconds() +
|
||||
d.getMilliseconds() + '.log';
|
||||
|
||||
var logStream = null;
|
||||
|
||||
var loggerInit = function (logging) {
|
||||
if (logging) {
|
||||
logStream = require('fs').createWriteStream( fName, {autoClose: true});
|
||||
try {
|
||||
const homedir = require('os').homedir();
|
||||
const logFileName = require('path').join(homedir, fName);
|
||||
logStream = require('fs').createWriteStream( logFileName, {autoClose: true});
|
||||
} catch (error) {
|
||||
console.error('Logging not possible ' + error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var logger = function (level, msg, o) {
|
||||
var d = new Date();
|
||||
if(logStream!==null) {
|
||||
try {
|
||||
if (logStream !== null) {
|
||||
logStream.write(d.toUTCString() + '|' + level + ' | ' + msg + '\r\n');
|
||||
}
|
||||
if (o != undefined && logStream!==null) {
|
||||
logStream.write( util.inspect(o,{depth: 2}) + '\r\n');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Logging not possible ' + error);
|
||||
}
|
||||
}
|
@ -16,6 +16,8 @@ You should have received a copy of the GNU General Public License along with FG
|
||||
* @param {*} callback
|
||||
*/
|
||||
|
||||
const { Debugger } = require("electron");
|
||||
|
||||
async function asyncForEach(array, callback) {
|
||||
logger('info', "AsyncForEach Len " + array.length);
|
||||
for (let index = 0; index < array.length; index++) {
|
||||
@ -46,7 +48,7 @@ async function scanGroundnetFiles(p, features) {
|
||||
try {
|
||||
logger('info', 'Start Groundnets ' + p);
|
||||
var files = traverseDir(p);
|
||||
this.postMessage(['max', files.length]);
|
||||
this.postMessage(['max', files.length*2]);
|
||||
logger('info', files);
|
||||
|
||||
asyncForEach(files, async f => {
|
||||
@ -184,6 +186,9 @@ function scanTrafficIntoDB(p, features) {
|
||||
|
||||
function traverseDir(dir) {
|
||||
var result = [];
|
||||
if(!fs.existsSync(dir)) {
|
||||
return result;
|
||||
}
|
||||
fs.readdirSync(dir).forEach(file => {
|
||||
let fullPath = path.join(dir, file);
|
||||
if (fs.lstatSync(fullPath).isDirectory()) {
|
||||
@ -239,26 +244,57 @@ function readAI(f, apts) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
const aircraftLookup = {};
|
||||
|
||||
dat.trafficlist.aircraft.map(n => {
|
||||
try {
|
||||
if(aircraftLookup[n['required-aircraft']] === undefined) {
|
||||
aircraftLookup[n['required-aircraft']] = [];
|
||||
}
|
||||
aircraftLookup[n['required-aircraft']].push(n.airline);
|
||||
aircraftLookup[n['required-aircraft']] = aircraftLookup[n['required-aircraft']].filter((v, i, a) => a.indexOf(v) === i);
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
//debugger;
|
||||
});
|
||||
|
||||
|
||||
logger('info', 'Traffic', dat.trafficlist.flight);
|
||||
|
||||
logger('info', "Departure flights " + dat.trafficlist.flight.length);
|
||||
|
||||
var merged = new Array();
|
||||
// Flat list. Each flight departing or landing counts as one.
|
||||
var merged = [];
|
||||
|
||||
var airports = {};
|
||||
|
||||
|
||||
dat.trafficlist.flight.map(n => {
|
||||
merged.push(n.departure.port);
|
||||
merged.push(n.arrival.port);
|
||||
|
||||
if(airports[n.departure.port] === undefined) {
|
||||
airports[n.departure.port] = [];
|
||||
}
|
||||
if(airports[n.arrival.port] === undefined) {
|
||||
airports[n.arrival.port] = [];
|
||||
}
|
||||
airports[n.departure.port] = airports[n.departure.port].concat(aircraftLookup[n['required-aircraft']]);
|
||||
airports[n.departure.port] = airports[n.departure.port].filter((v, i, a) => a.indexOf(v) === i)
|
||||
airports[n.arrival.port] = airports[n.arrival.port].concat(aircraftLookup[n['required-aircraft']]);
|
||||
airports[n.arrival.port] = airports[n.arrival.port].filter((v, i, a) => a.indexOf(v) === i)
|
||||
}).sort();
|
||||
|
||||
//debugger;
|
||||
var counts = {};
|
||||
for (var i = 0; i < merged.length; i++) {
|
||||
counts[merged[i]] = 1 + (counts[merged[i]] || 0);
|
||||
}
|
||||
|
||||
asyncForEach(Object.keys(counts), async key => {
|
||||
logger('info', key);
|
||||
await store(key, airline[1], counts[key]);
|
||||
asyncForEach(Object.keys(counts), async icao => {
|
||||
logger('info', icao);
|
||||
await store(icao, airports[icao], counts[icao]);
|
||||
}).then(t => {
|
||||
logger('info', "Finished");
|
||||
resolve();
|
||||
@ -290,7 +326,7 @@ function readAI(f, apts) {
|
||||
* @param {*} value
|
||||
*/
|
||||
|
||||
function store(icao, airline, value) {
|
||||
function store(icao, airlines, value) {
|
||||
var promise = new Promise(function (resolve, reject) {
|
||||
logger('info', "Airport " + icao + " has " + value + " new flights");
|
||||
// Make a request to get a record by key from the object store
|
||||
@ -300,18 +336,18 @@ function store(icao, airline, value) {
|
||||
var objectStoreRequest = index.get(icao);
|
||||
|
||||
objectStoreRequest.onsuccess = function (event) {
|
||||
logger('info', 'Stored ', event);
|
||||
logger('info', 'Store Request', event);
|
||||
var feature = objectStoreRequest.result;
|
||||
if (!feature) {
|
||||
feature = createFeature(icao);
|
||||
}
|
||||
feature.properties.flights += value;
|
||||
logger('info', "Airline : ", airline);
|
||||
if (!feature.properties.airlines.includes(airline)) {
|
||||
feature.properties.airlines.push(airline);
|
||||
feature.properties.airlines.sort();
|
||||
}
|
||||
logger('info', "ICAO : " + feature.properties.icao + " Flights : " + feature.properties.flights);
|
||||
logger('info', "Airlines : ", JSON.stringify(airlines));
|
||||
//debugger;
|
||||
feature.properties.airlines = feature.properties.airlines.concat(airlines);
|
||||
feature.properties.airlines = feature.properties.airlines.filter((v, i, a) => a.indexOf(v) === i)
|
||||
feature.properties.airlines.sort()
|
||||
// Create another request that inserts the item back into the database
|
||||
var updateAirportRequest = objectStore.put(feature);
|
||||
|
||||
@ -320,16 +356,16 @@ function store(icao, airline, value) {
|
||||
|
||||
// When this new request succeeds, run the displayData() function again to update the display
|
||||
updateAirportRequest.onsuccess = function (event) {
|
||||
logger('info', "Stored", event);
|
||||
logger('info', "Updated Success", event);
|
||||
resolve();
|
||||
};
|
||||
updateAirportRequest.onerror = function (event) {
|
||||
logger('info', "Error storing ", event);
|
||||
logger('info', "Error updating ", event);
|
||||
reject(event);
|
||||
};
|
||||
};
|
||||
objectStoreRequest.onerror = function (event) {
|
||||
logger('info', "Error " + event);
|
||||
logger('info', "Error reading" + event);
|
||||
reject(event);
|
||||
};
|
||||
});
|
||||
@ -345,6 +381,7 @@ function store(icao, airline, value) {
|
||||
async function readGroundnet(f, features) {
|
||||
var promise = new Promise(function (resolve, reject) {
|
||||
try {
|
||||
var thisPostMessage = this.postMessage;
|
||||
var filename = path.basename(f).match('^([^.]+)\\.([^.]+)(\\.new)?\\.([^.]+)');
|
||||
if (filename == null) {
|
||||
resolve("File didn't match");
|
||||
@ -439,12 +476,10 @@ async function readGroundnet(f, features) {
|
||||
}
|
||||
if(filename [3] === '.new') {
|
||||
feature['properties']['wipgroundnet'] = nodes && nodes.node ? nodes.node.length : 0;
|
||||
//debugger;
|
||||
feature['properties']['wipparking'] = parkingnodes && parkingnodes.Parking ? parkingnodes.Parking.length : 0;
|
||||
|
||||
} else {
|
||||
feature['properties']['groundnet'] = nodes && nodes.node ? nodes.node.length : 0;
|
||||
//debugger;
|
||||
feature['properties']['parking'] = parkingnodes && parkingnodes.Parking ? parkingnodes.Parking.length : 0;
|
||||
}
|
||||
}
|
||||
@ -459,6 +494,7 @@ async function readGroundnet(f, features) {
|
||||
// report on the success of the transaction completing, when everything is done
|
||||
transaction.oncomplete = function (event) {
|
||||
logger('info', 'Write Transaction complete ' + event);
|
||||
thisPostMessage(['progress', 1]);
|
||||
resolve("Stored " + filename[1]);
|
||||
};
|
||||
|
||||
@ -481,7 +517,7 @@ async function readGroundnet(f, features) {
|
||||
};
|
||||
}
|
||||
objectStoreRequest.onerror = function (event) {
|
||||
logger('info', "Read Errpr : " + event);
|
||||
logger('info', "Read Error : " + event);
|
||||
resolve(event);
|
||||
}
|
||||
}
|
||||
|
2
static/FGA_ACT_A_GA.svg
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="150mm" height="150mm" version="1.1" viewBox="0 0 150 150" xmlns="http://www.w3.org/2000/svg"><g transform="translate(-1.6394e-5 -147)"><g transform="translate(-512.5 -153)"><path d="m587.5 347.75c-0.32736 0-0.75863 2.023-0.97757 3.043 0 0-8.7023-0.47356-8.7023 0.14107 0 0.61461 8.733 0.36873 8.733 0.36873 0.0812 0.14151 0.22163 0.15914 0.368 0.18528v0.21306c-0.57176 0.16009-1.4739 0.31231-2.5099 0.41186-1.036 0.0995-1.1332 0.93371-1.1332 0.93371-0.70455 4.8918-0.96276 10.026-1.2071 14.632-0.012 0.0118-0.0165 1.6e-4 -0.0369 9e-3l-20.112 2e-3 -27.221 1.9869c-2.1208 0.16639-2.2014 1.5529-2.2014 3.2272v8.0906l29.858 3.5196 19.67 0.0146c1.2567 9.6974 3.6713 28.109 3.6713 28.109l-12.803 2.1075c-0.75926 0.18181-1.8746 0.23703-2.1181 1.0313-0.3756 1.9795-0.35641 4.2182-0.24741 6.0605 0.0369 0.68858 0.16248 1.2114 0.8672 1.354l13.439 2.401c0.39078 0.0865 0.49893-0.13326 0.58873-0.48422l1.3408-4.2669s-0.081 7.3888 0.73272 9.0111c0.81369-1.6224 0.73271-9.0111 0.73271-9.0111l1.3412 4.2669c0.0898 0.35096 0.19795 0.57077 0.58874 0.48422l13.439-2.401c0.70472-0.14253 0.83032-0.6654 0.8672-1.354 0.10899-1.8424 0.12819-4.081-0.24741-6.0605-0.24351-0.79425-1.3589-0.84947-2.1181-1.0313l-12.803-2.1075s2.4149-18.412 3.6716-28.109l19.67-0.0146 29.859-3.5196v-8.0906c5.8e-4 -1.6743-0.081-3.0608-2.2018-3.2272l-27.221-1.9869-20.112-2e-3c-0.0204-9e-3 -0.0249 3e-3 -0.0369-9e-3 -0.2443-4.6057-0.50251-9.7399-1.2071-14.632 0 0-0.0972-0.83417-1.1332-0.93371-1.036-0.0996-1.9381-0.25177-2.5099-0.41186v-0.21307c0.14636-0.0262 0.28682-0.0438 0.368-0.18528 0 0 8.733 0.24589 8.733-0.36873s-8.7023-0.14106-8.7023-0.14106c-0.21894-1.0201-0.65058-3.0431-0.97793-3.0431zm0 9.0766c0.34605 0 0.71407-1.3e-4 0.71408 0.5394v2.36c0 0.54212-0.36803 0.54196-0.71408 0.54196-0.34606 0-0.7192 1.6e-4 -0.7192-0.54196v-2.36c-1e-5 -0.53953 0.37314-0.5394 0.7192-0.5394zm-12.73 16.475c0.34605 0 0.71407-1.3e-4 0.71407 0.5394v2.36c0 0.54211-0.36802 0.54196-0.71407 0.54196-0.34606 0-0.7192 1.5e-4 -0.7192-0.54196v-2.36c0-0.53953 0.37314-0.5394 0.7192-0.5394zm25.474 0c0.34606 0 0.71408-1.3e-4 0.71408 0.5394v2.36c0 0.54211-0.36802 0.54196-0.71408 0.54196-0.34605 0-0.71919 1.5e-4 -0.71919-0.54196v-2.36c-1e-5 -0.53953 0.37314-0.5394 0.71919-0.5394z" fill="#3296ff"/><circle cx="587.5" cy="375" r="74.595" fill="none" stroke="#3296ff" stroke-linecap="square" stroke-linejoin="round" stroke-width=".811" style="paint-order:normal"/></g></g></svg>
|
After Width: | Height: | Size: 2.4 KiB |
2
static/FGA_ACT_B_PROP.svg
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="280mm" height="282.66mm" version="1.1" viewBox="0 0 280 282.66" xmlns="http://www.w3.org/2000/svg"><g transform="translate(35 -7.171)"><g transform="translate(-7.6294e-6 7.3444)"><g transform="matrix(4.5516 0 0 4.5516 -372.53 -527.39)" fill="#3296ff"><path transform="matrix(.26458 0 0 .26458 -7.9725e-5 4.7925e-5)" d="m396.53 449.99c-6.703 0-12.091 16.285-12.119 29.002l-0.17578 54.354-2.8828 7.209-14.512-0.18945c0.6477-4.764 1.2976-11.043-1.4473-15.457l-0.0469-1.3477 14.395 0.83985 0.16797-1.9668-14.578 0.97461c0-1.4239-1.0254-4.1602-2.3457-4.1602-1.4366 0-2.2472 2.4804-2.4375 4.1211l-14.088-1.1582-4e-3 2.4609 14.047-0.9668-0.1914 1.3164c-2.3109 4.8272-1.8613 10.199-0.92774 15.412-46.681 3.307-70.422 5.1355-71.252 5.2051-0.82972 0.0695-1.8463 0.90433-1.9707 2.293-0.0556 0.59954-0.16605 0.90065-0.33008 0.90039-0.16479-1e-3 -0.35633 0.0276-0.57422 0.082-0.21808 0.0533-0.43767 0.32575-0.6582 0.81641-0.67616 2.9741-0.27076 5.9302-0.0977 8.7734 0.0552 0.10885 12.16 0.73137 36.314 1.8672 24.156 1.1349 36.316 1.7029 36.48 1.7031 0.16403 3.7e-4 6.0384 0.17301 24.84 0.20703l2.123 5.0859c-0.0302 21.998 0.0965 58.62 7.0059 86.129-15.285 2.3628-23.055 3.6526-23.314 3.8594-2.0877 2.7596-2.3172 6.879-1.8203 9.998 0.0556 1e-3 4.4001 0.33632 13.033 1.0059l13.115 0.92578c0.10923-0.0544 1.4785-2.0469 1.4785-2.0469 0.21947 1.7517 0.2277 5.2639 2.7734 5.2676h2e-3c2.5457-4e-3 2.552-3.5159 2.7715-5.2676 0 0 1.3693 1.9924 1.4785 2.0469l13.115-0.92578c8.6331-0.66954 12.978-1.0047 13.033-1.0059 0.49693-3.119 0.26734-7.2384-1.8203-9.998-0.25928-0.20674-8.0293-1.4966-23.314-3.8594 6.9093-27.509 7.0361-64.131 7.0059-86.129l2.123-5.0859c18.801-0.034 24.678-0.20666 24.842-0.20703 0.16404-2.3e-4 12.323-0.56825 36.479-1.7031 24.155-1.1358 36.259-1.7583 36.314-1.8672 0.17311-2.8432 0.5785-5.7993-0.0976-8.7734-0.22035-0.49066-0.44013-0.76312-0.65821-0.81641-0.21807-0.0544-0.40943-0.0832-0.57421-0.082-0.16404 2.6e-4 -0.27257-0.30085-0.32813-0.90039-0.12435-1.3886-1.141-2.2234-1.9707-2.293-0.82972-0.0695-24.573-1.8981-71.254-5.2051 0.93358-5.2134 1.3832-10.585-0.92773-15.412l-0.19141-1.3164 14.047 0.9668-4e-3 -2.4609-14.088 1.1582c-0.19049-1.6407-1.0009-4.1211-2.4375-4.1211-1.3203 0-2.3457 2.7363-2.3457 4.1602l-14.576-0.97461 0.16602 1.9668 14.395-0.83985-0.0469 1.3477c-2.7449 4.4137-2.095 10.693-1.4473 15.457l-14.512 0.18945-2.8809-7.209-0.17578-54.354c0-12.782-5.4181-29.002-12.121-29.002zm-2.207 19.031h1.6133v4.8184h-1.6133zm2.8008 0h1.6133v4.8184h-1.6133zm-20.578 81.467h2.7774v7.1152h-2.7774zm3.8789 0h2.7773v7.1152h-2.7773zm29.434 0h2.7774v7.1152h-2.7774zm3.8789 0h2.7773v7.1152h-2.7773z" fill="#3296ff"/></g><circle cx="105" cy="139.83" r="139.18" fill="none" stroke="#3296ff" stroke-linecap="square" stroke-linejoin="round" stroke-width="1.6438" style="paint-order:normal"/></g></g></svg>
|
After Width: | Height: | Size: 2.8 KiB |
2
static/FGA_ACT_B_SHORTEN.svg
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="280mm" height="311.54mm" version="1.1" viewBox="0 0 280 311.54" xmlns="http://www.w3.org/2000/svg"><g transform="translate(-6.4969e-6 14.543)"><circle cx="140" cy="141.28" r="139.36" fill="none" stroke="#3296ff" stroke-linecap="square" stroke-linejoin="round" stroke-miterlimit="4.3333" stroke-width="1.2759" style="paint-order:normal"/><path d="m152.63 24.911c-0.0267-25.744-10.66-39.454-12.634-39.454h1e-5c-1.9741 0-12.608 13.71-12.634 39.454l0.0182 79.957-1.6403 1.3481s-84.993 49.186-89.398 51.752-4.5756 5.1873-4.5756 5.1873-7.5179 14.841-7.7484 15.302c-0.23052 0.4615-0.27144 1.1507-0.27144 1.1507l0.1078 2.3443s6.6825-7.4591 6.8393-7.6432c0.1568-0.18415 0.32861-0.34095 0.7442-0.33769 0.41558 3e-3 1.0215 0.0362 1.4196-0.32729 0.93562-1.1932 2.1371-2.6676 3.9093-3.1924 1.7722-0.52482 39.634-11.689 59.608-17.581l31.015-1.8624v47.86l-0.95849 1.5429h-1.3832c-0.24979-1.7755-0.85068-1.9326-0.85068-1.9326l-11.633 0.12468s-1.2585 0.79803-1.2585 6.6315c0 10.609 1.3118 13.973 1.3118 13.973s0.30131 0.16754 1.2416 0.16754l2.5625 10.064s0.46106 0.0701 0.9494 0.0701l1.7637 5.2665 0.71822-0.0351 1.3923-5.3548c0.55067 0 0.99225-0.16884 0.99225-0.16884l0.0714-0.44288 9.2212 6.0198 5.3548 27.175s-33.731 22.555-34.623 23.158c-0.89108 0.60283-1.4159 2.6639-1.565 4.3768l-0.65199 7.4952 38.872-12.307 1.0494 5.3873 1.1104-5.3873 38.871 12.307-0.65198-7.4952c-0.14909-1.7129-0.67393-3.774-1.565-4.3768-0.8911-0.60285-34.623-23.158-34.623-23.158l5.3561-27.175 9.2199-6.0198 0.0714 0.44288s0.4429 0.16884 0.99356 0.16884l1.391 5.3548 0.71822 0.0351 1.765-5.2665c0.48833 0 0.9481-0.0701 0.9481-0.0701l2.5625-10.064c0.9403 0 1.2416-0.16754 1.2416-0.16754s1.3118-3.3645 1.3118-13.973c0-5.8335-1.2585-6.6315-1.2585-6.6315l-11.633-0.12468s-0.6009 0.15707-0.8507 1.9326h-1.3832l-0.95719-1.5429v-47.86l31.013 1.8624c19.974 5.8921 57.836 17.057 59.608 17.581 1.7722 0.5248 2.9749 1.9992 3.9106 3.1924 0.39808 0.36352 1.0027 0.33031 1.4182 0.32729 0.4156-3e-3 0.58741 0.15355 0.74421 0.33769 0.1568 0.18415 6.8393 7.6432 6.8393 7.6432l0.10781-2.3443s-0.0397-0.68921-0.27015-1.1507c-0.23051-0.4615-7.7497-15.302-7.7497-15.302s-0.16886-2.6209-4.5743-5.1873c-4.4054-2.5664-89.399-51.752-89.399-51.752l-1.639-1.3481 0.0169-79.957m-34.454 111.65c0.78911 0 1.6055 0.23981 1.6053 1.2949v6.738c2.3e-4 0.93982-0.81617 1.2949-1.6053 1.2949-0.78909 0-1.6053-0.35505-1.6053-1.2949v-6.738c0-1.0551 0.81618-1.2949 1.6053-1.2949zm5.0002 0c0.78909 0 1.6055 0.23981 1.6053 1.2949v6.738c2.4e-4 0.93982-0.81619 1.2949-1.6053 1.2949s-1.6053-0.35505-1.6053-1.2949v-6.738c0-1.0551 0.81618-1.2949 1.6053-1.2949zm33.577 0c0.78909 0 1.6053 0.23981 1.6053 1.2949v6.738c0 0.93982-0.81618 1.2949-1.6053 1.2949-0.7891 0-1.6055-0.35505-1.6053-1.2949v-6.738c-2.4e-4 -1.055 0.81618-1.2949 1.6053-1.2949zm5.0002 0c0.78909 1e-5 1.6053 0.2398 1.6053 1.2949v6.738c0 0.93982-0.81618 1.2949-1.6053 1.2949s-1.6055-0.35505-1.6053-1.2949v-6.738c-2.4e-4 -1.0551 0.81619-1.2949 1.6053-1.2949z" fill="#3296ff"/></g></svg>
|
After Width: | Height: | Size: 2.9 KiB |
3
static/FGA_ACT_C.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg width="360mm" height="369.09mm" version="1.1" viewBox="0 0 360 369.09" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><metadata><rdf:RDF><cc:Work rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/><dc:title/></cc:Work></rdf:RDF></metadata><g transform="translate(75 36.046)"><g transform="translate(-65.5 -28.331)"><path d="m170.5-0.026086c-7.0846 9.35e-6 -19.026 24.031-19.062 58.205l0.0362 54.388-1.9176 10.818s-0.10598 1.4555-0.99653 1.9124-25.868 13.39-25.868 13.39c0.89235-6.9871 2.094-27.847-0.25947-27.847h-15.911c-3.162 1e-5 -2.337 31.287-0.34733 31.287h1.0188l1.163 3.968-94.45 48.717c-4.8538 2.6647-11.085 6.7435-12.179 12.611l-1.7264 14.181v2.7208l1.8819-8.6075c0.26207-1.101 1.0968-1.7912 2.1833-2.0856l48.418-14.553 1.5222 5.4184 1.2943-6.2934 32.906-10.202 1.2591 4.6033 1.4023-5.4184-0.02378-0.0238 17.489-5.4184h13.63v0.0238l1.1754 4.6751 1.1268-4.6989 27.248-0.014 0.0594 84.392c0.23612 14.268 3.6729 28.282 6.066 42.28 0 0-0.48489 3.4026-4.915 6.2216 0 0-36.324 23.321-38.756 24.91-2.4318 1.5884-3.5142 3.8978-3.5142 8.6897l0.0961 5.1067 52.194-11.616c1.3933 6.3589 5.2092 17.812 5.3703 18.305 0.16114 0.49226 0.88696 1.043 0.88696 1.043s0.44043 0.31323 0.75567 0.31323h1.486c0.31524 0 0.75567-0.31323 0.75567-0.31323s0.72582-0.55079 0.88695-1.043c0.16114-0.49225 3.977-11.946 5.3703-18.305l52.194 11.616 0.0956-5.1067c0-4.7918-1.0819-7.1013-3.5137-8.6897s-38.756-24.91-38.756-24.91c-4.4301-2.8189-4.915-6.2216-4.915-6.2216 2.3931-13.998 5.8299-28.012 6.066-42.28l0.06-84.392 27.248 0.014 1.1273 4.6989 1.1748-4.6751v-0.0238h13.63l17.49 5.4184-0.0238 0.0238 1.4023 5.4184 1.2586-4.6033 32.906 10.202 1.2948 6.2934 1.5222-5.4184 48.418 14.553c1.0865 0.29433 1.9212 0.98458 2.1833 2.0856l1.8824 8.6075v-2.7208l-1.7263-14.181c-1.0936-5.8671-7.3253-9.946-12.179-12.611l-94.45-48.717 1.163-3.968h1.0188c1.9896 0 2.8147-31.287-0.34734-31.287h-15.911c-2.3535 0-1.1518 20.86-0.25947 27.847 0 0-24.977-12.933-25.867-13.39-0.89055-0.45697-0.99705-1.9124-0.99705-1.9124l-1.9176-10.818 0.0362-54.388c-0.03593-34.174-11.977-58.205-19.062-58.205zm-2.373 45.661c0.8389 4.8e-5 1.0544 0.39604 1.0544 1.0673v3.692c0 0.68329-0.21552 1.0792-1.0544 1.0792-0.8389-6e-6 -1.0441-0.39594-1.0441-1.0792v-3.692c0-0.6713 0.20519-1.0673 1.0441-1.0673zm4.7454 0c0.8389 4.8e-5 1.0446 0.39604 1.0446 1.0673v3.692c0 0.68329-0.2057 1.0792-1.0446 1.0792-0.8389-6e-6 -1.0539-0.39594-1.0539-1.0792v-3.692c0-0.6713 0.215-1.0673 1.0539-1.0673zm-46.369 122.62c0.87915-2e-3 1.44 0.52759 1.44 1.4746v5.0349c0 0.82604-0.55805 1.4757-1.44 1.4757-0.88197 0-1.4379-0.64964-1.4379-1.4757v-5.0349c-2e-5 -0.93514 0.55878-1.4724 1.4379-1.4746zm87.992 0c0.87916 2e-3 1.4385 0.5395 1.4385 1.4746v5.0349c0 0.82604-0.55649 1.4757-1.4385 1.4757s-1.44-0.64964-1.44-1.4757v-5.0349c5e-5 -0.94705 0.56085-1.4766 1.44-1.4746zm-81.29 0.0476c0.87915-2e-3 1.4394 0.52759 1.4395 1.4746v5.0349c0 0.82603-0.55752 1.4757-1.4395 1.4757s-1.4385-0.64964-1.4385-1.4757v-5.0349c-2e-5 -0.93514 0.5593-1.4724 1.4385-1.4746zm74.589 0c0.87915 2e-3 1.4385 0.5395 1.4384 1.4746v5.0349c0 0.82603-0.55649 1.4757-1.4384 1.4757-0.88197 0-1.44-0.64964-1.44-1.4757v-5.0349c5e-5 -0.94705 0.56085-1.4766 1.44-1.4746z" fill="#3296ff" fill-rule="evenodd"/><circle cx="170.5" cy="172.29" r="179.31" fill="none" stroke="#3296ff" stroke-linecap="square" stroke-linejoin="round" stroke-miterlimit="3" stroke-width="1.371" style="paint-order:normal"/></g></g></svg>
|
After Width: | Height: | Size: 3.6 KiB |
2
static/FGA_ACT_D.svg
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="5203mm" height="5463.5mm" version="1.1" viewBox="0 0 5203 5463.5" xmlns="http://www.w3.org/2000/svg"><g transform="translate(2496.5 2583.2)"><path d="m103.62-2580.1c-130.08 0-255.75 434.93-255.75 588.23l-0.125 1240.4s-55.621 87.016-114.96 127.88c-59.342 40.86-294.12 203.78-294.12 203.78l12.788-24.751s2e-4 -204.6 0-255.75c-1e-4 -51.151-12.788-63.938-25.575-63.938-12.787 1e-4 -204.6 0-204.6 0-25.575 0-38.363 12.788-38.363 63.938 0 0-0.399 257.75 0 281.33 0.399 23.577 12.788 51.151 12.788 51.151h25.575l-0.62501 98.405s-1405.1 961.43-1444.4 988.54c-39.261 27.115-51.15 42.459-51.15 63.938v217.39l575.44-242.96 869.56-306.9 179.03-51.151 498.74-62.464s-0.736 1167.2-0.02 1290.1c0.706 122.92 63.489 432.48 63.489 432.48l-702.87 539.38-38.363 51.15v166.24l869.78-212.97 12.563 46.73 25.575 89.513 12.788 102.3 12.788 38.363 12.788-38.363 12.788-102.3 25.575-89.513 12.563-46.73 869.78 212.97v-166.24l-38.363-51.15-702.87-539.38s62.783-309.56 63.488-432.48c0.711-122.92-0.05-1290.1-0.05-1290.1l498.77 62.464 179.03 51.151 869.56 306.9 575.44 242.96v-217.39c0-21.479-11.889-36.823-51.151-63.938-39.261-27.115-1444.4-988.54-1444.4-988.54l-0.60001-98.405h25.575s12.389-27.573 12.788-51.151c0.399-23.577 0-281.33 0-281.33 0-51.15-12.788-63.938-38.363-63.938 0 0-191.81 1e-4 -204.6 0-12.788-1e-4 -25.575 12.788-25.575 63.938-2e-4 51.151 0 255.75 0 255.75l12.788 24.751s-234.77-162.92-294.12-203.78c-59.342-40.86-114.99-127.88-114.99-127.88l-0.104-1240.4c-1e-4 -153.3-125.68-588.23-255.75-588.23zm-38.363 409.2c6.347 2e-4 12.787 5.5342 12.787 11.064v67.809c0 5.4289-6.4405 10.865-12.787 10.864-6.3906 2e-4 -12.788-5.4355-12.788-10.864v-67.809c1e-4 -5.5302 6.3971-11.013 12.788-11.064zm76.726 0c6.3906 0.05 12.788 5.5342 12.788 11.064v67.809c-1e-4 5.4289-6.397 10.865-12.788 10.864-6.347 2e-4 -12.788-5.4355-12.788-10.864v-67.809c0-5.5302 6.4406-11.064 12.788-11.064zm-575.44 2186.7h25.575c6.347 2.01e-4 12.788 6.393 12.788 12.788v76.726c0 6.3929-6.4406 12.788-12.788 12.788h-25.575c-6.3906 1e-4 -12.787-6.3947-12.788-12.788v-76.726c1e-4 -6.3947 6.397-12.736 12.788-12.788zm115.09 0h25.575c6.347 2.01e-4 12.788 6.393 12.788 12.788v76.726c0 6.3929-6.4406 12.788-12.788 12.788h-25.575c-6.3906 1e-4 -12.787-6.3947-12.788-12.788v-76.726c2e-4 -6.3947 6.3971-12.736 12.788-12.788zm818.41 0h25.575c6.3907 0.05 12.788 6.393 12.788 12.788v76.726c-2e-4 6.3929-6.397 12.788-12.788 12.788h-25.575c-6.347 1e-4 -12.788-6.3947-12.788-12.788v-76.726c0-6.3947 6.4406-12.787 12.788-12.788zm115.09 0h25.575c6.3906 0.05 12.788 6.393 12.788 12.788v76.726c-1e-4 6.3929-6.3971 12.788-12.788 12.788h-25.575c-6.347 1e-4 -12.788-6.3947-12.788-12.788v-76.726c0-6.3947 6.4406-12.787 12.788-12.788zm-1048.6 140.66h25.575c6.347 1e-4 12.788 6.3929 12.788 12.787v76.726c0 6.3929-6.4406 12.788-12.788 12.788h-25.575c-6.3906 1e-4 -12.787-6.3947-12.788-12.788v-76.726c1e-4 -6.3946 6.397-12.736 12.788-12.787zm115.09 0h25.575c6.347 1e-4 12.788 6.3929 12.788 12.787v76.726c0 6.3929-6.4406 12.788-12.788 12.788h-25.575c-6.3906 1e-4 -12.787-6.3947-12.788-12.788v-76.726c2e-4 -6.3946 6.3971-12.736 12.788-12.787zm818.41 0h25.575c6.3907 0.05 12.788 6.3929 12.788 12.787v76.726c-2e-4 6.3929-6.397 12.788-12.788 12.788h-25.575c-6.347 1e-4 -12.788-6.3947-12.788-12.788v-76.726c0-6.3946 6.4406-12.787 12.788-12.787zm115.09 0h25.575c6.3906 0.05 12.788 6.3929 12.788 12.787v76.726c-1e-4 6.3929-6.3971 12.788-12.788 12.788h-25.575c-6.347 1e-4 -12.788-6.3947-12.788-12.788v-76.726c0-6.3946 6.4406-12.787 12.788-12.787z" fill="#3296ff" fill-rule="evenodd"/><circle cx="105" cy="135.8" r="2582.6" fill="none" stroke="#3296ff" stroke-linecap="square" stroke-linejoin="round" stroke-width="37.746" style="paint-order:normal"/></g></svg>
|
After Width: | Height: | Size: 3.6 KiB |
2
static/FGA_ACT_E.svg
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="660mm" height="735.62mm" version="1.1" viewBox="0 0 660 735.62" xmlns="http://www.w3.org/2000/svg"><g transform="translate(227.07 219.31)"><g transform="translate(-220.16 -219.35)"><path d="m323.98 0.041596c-12.621 1.1404-32.35 58.556-32.35 95.304v172.91l-46.402 31.844c1.7124-7.7226 3.623-25.137-0.66208-43.984h-33.315c-3.6679 12.285-5.2993 33.094 0.0391 51.47l3.3026 0.0898 3.0428 11.261c-67.538 46.949-135.82 92.856-204.08 138.75-2.0153 1.3847-2.119 1.8573-2.119 1.8573l-11.437 22.93v8.1344l26.342-17.935 71.254-28.565 34-11.466 0.69527 3.201 1.5605-3.992 51.247-17.319 1.0976 3.6346 1.041-4.3845 29.414-9.9624 21.011-3.2655 0.82027 6e-3 1.3632 4.7322 1.7772-4.7341 50.009-0.0273s-0.0109 126.27 0 148.94c0.0156 32.451 7.5281 73.581 8.5445 79.039s3.3484 11.282-3.1483 16.589c-6.4967 5.3071-71.763 58.406-77.1 62.77-5.3362 4.364-4.9704 10.253-4.7556 11.913s1.9276 15.884 1.9276 15.884l98.173-36.949 7.8414 28.559 1.7675 4e-3 7.8414-28.559 98.171 36.949s1.7128-14.223 1.9276-15.884 0.58251-7.5514-4.7536-11.915c-5.3362-4.3639-70.605-57.461-77.102-62.768-6.4967-5.3071-4.1647-11.131-3.1483-16.589s8.5308-46.587 8.5464-79.039c0.0109-22.668 0-148.94 0-148.94l50.007 0.0273 1.7773 4.7341 1.3632-4.7322 0.82222-8e-3 21.011 3.2674 29.413 9.9624 1.041 4.3826 1.0976-3.6326 51.249 17.319 1.5605 3.992 0.69331-3.201 34.002 11.464 71.252 28.567 26.344 17.935-2e-3 -8.1344-11.435-22.93s-0.1057-0.47265-2.121-1.8573c-68.258-45.89-136.54-91.8-204.08-138.75l3.0409-11.259 3.3045-0.0918c5.3383-18.376 3.705-39.185 0.0371-51.47h-33.315c-4.2851 18.847-2.3726 36.264-0.66013 43.986l-46.402-31.846v-172.91c0-36.748-19.762-94.167-32.383-95.308zm-4.3806 54.566h2.0546c0.8995-7e-6 1.2851 0.38391 1.2851 1.2812v7.5582c-4e-5 0.89669-0.38558 1.2812-1.2851 1.2812h-2.0546c-0.89949-9e-6 -1.2246-0.38449-1.2206-1.2812v-7.5582c-4e-3 -0.89728 0.32117-1.2812 1.2206-1.2812zm6.6422 0h2.0546c0.8995-7e-6 1.2851 0.38391 1.2851 1.2812v7.5582c-4e-5 0.89669-0.38558 1.2812-1.2851 1.2812h-2.0546c-0.89948-9e-6 -1.2246-0.38449-1.2206-1.2812v-7.5582c-4e-3 -0.89728 0.32117-1.2812 1.2206-1.2812zm43.543 294.97h2.5057c0.89954-6e-5 1.2851 0.38451 1.2851 1.2812v8.8394c2e-5 0.89668-0.38553 1.2812-1.2851 1.2812h-2.5057c-0.89957-5e-5 -1.2852-0.38456-1.2851-1.2812v-8.8394c-7e-5 -0.89676 0.38559-1.2813 1.2851-1.2812zm13.968 0h2.5057c0.89954-6e-5 1.2851 0.38451 1.2851 1.2812v8.8394c2e-5 0.89668-0.38553 1.2812-1.2851 1.2812h-2.5057c-0.89958-5e-5 -1.2852-0.38456-1.2851-1.2812v-8.8394c-7e-5 -0.89676 0.38559-1.2813 1.2851-1.2812zm-122 0.0488h2.5057c0.89954-6e-5 1.2851 0.38451 1.2851 1.2812v8.8394c2e-5 0.89667-0.38553 1.2812-1.2851 1.2812h-2.5057c-0.89957-5e-5 -1.2852-0.38456-1.2851-1.2812v-8.8394c-8e-5 -0.89675 0.38559-1.2813 1.2851-1.2812zm13.97 0h2.5057c0.89955-6e-5 1.2851 0.38451 1.2851 1.2812v8.8394c2e-5 0.89667-0.38553 1.2812-1.2851 1.2812h-2.5057c-0.89957-5e-5 -1.2852-0.38456-1.2851-1.2812v-8.8394c-7e-5 -0.89675 0.38558-1.2813 1.2851-1.2812zm94.048 13.818h2.5057c0.89954-6e-5 1.2851 0.38451 1.2851 1.2812v8.8394c2e-5 0.89668-0.38552 1.2812-1.2851 1.2812h-2.5057c-0.89957-5e-5 -1.2852-0.38456-1.2851-1.2812v-8.8394c-7e-5 -0.89675 0.38559-1.2813 1.2851-1.2812zm13.97 0h2.5057c0.89954-6e-5 1.2851 0.38451 1.2851 1.2812v8.8394c2e-5 0.89668-0.38553 1.2812-1.2851 1.2812h-2.5057c-0.89957-5e-5 -1.2852-0.38456-1.2851-1.2812v-8.8394c-7e-5 -0.89675 0.38559-1.2813 1.2851-1.2812zm-122 0.0488h2.5057c0.89955-6e-5 1.2851 0.38451 1.2851 1.2812v8.8394c2e-5 0.89667-0.38553 1.2812-1.2851 1.2812h-2.5057c-0.89957-5e-5 -1.2852-0.38456-1.2851-1.2812v-8.8394c-7e-5 -0.89675 0.38559-1.2813 1.2851-1.2812zm13.97 0h2.5057c0.89954-6e-5 1.2851 0.38451 1.2851 1.2812v8.8394c2e-5 0.89667-0.38553 1.2812-1.2851 1.2812h-2.5057c-0.89957-5e-5 -1.2852-0.38456-1.2851-1.2812v-8.8394c-7e-5 -0.89675 0.38558-1.2813 1.2851-1.2812zm97.866 6.2614h8.8667zm-108.03 0.0488h8.8667zm104.23 7.5406h2.5057c0.89954-6e-5 1.2851 0.38451 1.2851 1.2812v8.8394c2e-5 0.89667-0.38552 1.2792-1.2851 1.2792h-2.5057c-0.89957-5e-5 -1.2852-0.38261-1.2851-1.2792v-8.8394c-7e-5 -0.89675 0.38559-1.2813 1.2851-1.2812zm13.97 0h2.5057c0.89954-6e-5 1.2831 0.38451 1.2831 1.2812v8.8394c2e-5 0.89667-0.38357 1.2792-1.2831 1.2792h-2.5057c-0.89957-5e-5 -1.2852-0.38261-1.2851-1.2792v-8.8394c-7e-5 -0.89675 0.38559-1.2813 1.2851-1.2812zm-122 0.0488h2.5057c0.89955-6e-5 1.2851 0.38451 1.2851 1.2812v8.8394c1e-5 0.89667-0.38553 1.2812-1.2851 1.2812h-2.5057c-0.89957-5e-5 -1.2852-0.38456-1.2851-1.2812v-8.8394c-7e-5 -0.89675 0.38559-1.2813 1.2851-1.2812zm13.97 0h2.5057c0.89954-6e-5 1.2851 0.38451 1.2851 1.2812v8.8394c2e-5 0.89667-0.38553 1.2812-1.2851 1.2812h-2.5057c-0.89957-5e-5 -1.2852-0.38456-1.2851-1.2812v-8.8394c-7e-5 -0.89675 0.38558-1.2813 1.2851-1.2812z" fill="#3296ff"/><circle cx="323.1" cy="368.73" r="328.11" fill="none" stroke="#3296ff" stroke-width="3.7896" style="paint-order:normal"/></g></g></svg>
|
After Width: | Height: | Size: 4.8 KiB |
17
static/FGA_ACT_F.svg
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg width="211.67mm" height="211.67mm" version="1.1" viewBox="0 0 211.67 211.67" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
||||
<metadata>
|
||||
<rdf:RDF>
|
||||
<cc:Work rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
|
||||
<dc:title/>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g transform="translate(953.33 -995.17)">
|
||||
<path d="m-742.19 1101c0 27.929-11.095 54.714-30.844 74.463-19.749 19.749-46.534 30.844-74.463 30.844-27.929 0-54.714-11.095-74.463-30.844-19.749-19.749-30.844-46.534-30.844-74.463 0-27.929 11.095-54.714 30.844-74.463 19.749-19.749 46.534-30.844 74.463-30.844 27.929 0 54.714 11.095 74.463 30.844 19.749 19.749 30.844 46.534 30.844 74.463z" fill="none" stroke="#3296ff" stroke-linejoin="round" stroke-width="1.0531"/>
|
||||
<path d="m-847.5 1004.7c-7.4097 0-9.4794 27.242-9.4556 35.842v13.103l-1.2407 2.0809-2.6718 3.1116-5.7373 4.7856-15.217 12.445c0.26327-2.4217 0.81772-10.57-0.18346-11.848l-8.6782 0.072c-0.70678 0.8906-1.6381 10.501 0.13788 15.728h1.1029l0.38829 1.823-21.816 16.071c0.5494-2.3946 1.2496-11.314 0.25043-13.182l-8.8583 0.014c-1.0492 4.8589-1.1533 10.88-0.0459 15.696l1.2043 0.04 0.50012 2.5271s-28.608 21.118-31.045 22.91c-2.4373 1.7913-3.8489 5.5589-3.8729 8.2254-0.0241 2.6665-0.0401 5.2116-0.0401 5.2116l35.659-15.492 0.65645 4.4375 1.1948-5.2253 9.3938-3.722 0.4792 5.7045 1.5361-6.4857 9.1575-3.7024 0.83374 5.6914 1.1619-6.4791 8.8095-3.6302 0.53827 2.4748 1.0438-3.1115 9.1247-2.9869 0.64327 2.4748 0.93875-2.9147 12.853-3.4791 0.32163 5.0153 1.4704 10.352 0.033 19.858c0.17362 4.5575 0.64186 9.1069 1.287 13.621l1.477 6.7877c0.23946 1.6304-0.74861 3.3195-1.8528 4.424 0 0-27.318 20.921-28.298 21.678-0.98046 0.7565-1.2339 2.0863-1.2339 2.0863l-2.2479 10.338 25.84-9.5902 11.73-4.0193 2.1403 6.7961 0.58694 6.9848 0.58694-6.9848 2.1403-6.7961 11.73 4.0193 25.84 9.5902-2.2479-10.338s-0.25346-1.3298-1.2339-2.0863c-0.98047-0.7566-28.298-21.678-28.298-21.678-1.1042-1.1045-2.0923-2.7936-1.8528-4.4239l1.477-6.7877c0.64515-4.5145 1.1134-9.0639 1.287-13.621l0.033-19.858 1.4705-10.352 0.32163-5.0153 12.853 3.4791 0.93876 2.9147 0.64326-2.4748 9.1247 2.9869 1.0438 3.1115 0.53826-2.4748 8.8095 3.6302 1.1619 6.4791 0.83375-5.6914 9.1575 3.7024 1.5361 6.4857 0.4792-5.7045 9.3938 3.722 1.1948 5.2253 0.65644-4.4375 35.659 15.492s-0.016-2.5452-0.0401-5.2117-1.4357-6.4341-3.8729-8.2254c-2.4373-1.7912-31.045-22.91-31.045-22.91l0.50013-2.5271 1.2043-0.04c1.1074-4.816 1.0033-10.837-0.0459-15.696l-8.8583-0.014c-0.99921 1.8687-0.29898 10.788 0.25042 13.182l-21.816-16.071 0.3883-1.8229h1.1029c1.776-5.2277 0.84466-14.838 0.13787-15.728l-8.6782-0.072c-1.0012 1.2776-0.44672 9.4259-0.18345 11.848l-15.217-12.445-5.7373-4.7856-2.6718-3.1116-1.2407-2.0809v-13.103c0.0237-8.6006-2.046-35.842-9.4556-35.842zm-2.0804 12.256h1.3916v3.5317h-1.3916zm2.8227 0h1.4048v3.5317h-1.4048zm-19.766 73.142h1.3982v3.5317h-1.3982zm3.5777 0h1.3917v3.5317h-1.3917zm29.501 0h1.3916v3.5317h-1.3916zm3.5645 0h1.4048v3.5317h-1.4048zm-36.643 4.2932h1.3982v3.5251h-1.3982zm3.5777 0h1.3917v3.5251h-1.3917zm29.501 0h1.3916v3.5251h-1.3916zm3.5645 0h1.4048v3.5251h-1.4048zm-27.426 2.0481h1.3983v3.5186h-1.3983zm14.015 0h1.4048v3.5186h-1.4048zm-9.919 0.01h1.3983v3.5251h-1.3983zm14.015 0h1.4048v3.5251h-1.4048zm-18.112 4.4901h1.3983v3.5251h-1.3983zm4.0962 0h1.3983v3.5251h-1.3983zm9.919 0h1.4048v3.5251h-1.4048zm4.0963 0h1.4048v3.5251h-1.4048zm-18.112 4.5033h1.3983v3.5316h-1.3983zm4.0962 0h1.3983v3.5316h-1.3983zm9.919 0h1.4048v3.5316h-1.4048zm4.0963 0h1.4048v3.5316h-1.4048z" fill="#3296ff"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.7 KiB |
89
static/FGA_THR.svg
Normal file
@ -0,0 +1,89 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="64"
|
||||
height="64"
|
||||
version="1.1"
|
||||
viewBox="0 0 64 64"
|
||||
id="svg16"
|
||||
sodipodi:docname="FGA_THR.svg"
|
||||
inkscape:version="0.92.1 r15371">
|
||||
<metadata
|
||||
id="metadata22">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs20" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1147"
|
||||
id="namedview18"
|
||||
showgrid="false"
|
||||
inkscape:zoom="4"
|
||||
inkscape:cx="-31.957369"
|
||||
inkscape:cy="57.205794"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg16"
|
||||
units="px" />
|
||||
<g
|
||||
transform="matrix(0.48381287,0,0,0.48380165,-18.79736,-39.8415)"
|
||||
id="g14">
|
||||
<g
|
||||
transform="matrix(1.0265,0,0,1.0265,-2.7864,-3.9408)"
|
||||
id="g12"
|
||||
style="fill-rule:evenodd">
|
||||
<path
|
||||
transform="matrix(0.26458,0,0,0.26458,38.854,82.354)"
|
||||
d="m 294.7,489.09 -44.15,-72.041 -44.803,72.281 c 14.546,2.7042 29.306,4.1868 44.131,4.209 15.063,-0.066 30.057,-1.6154 44.822,-4.4492 z"
|
||||
style="paint-order:normal"
|
||||
id="path2"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
transform="matrix(0.26458,0,0,0.26458,38.854,82.354)"
|
||||
d="M 318.85,483.12 250.557,371.68 181.289,483.43 c 1.3922,0.41046 2.7334,0.92574 4.1367,1.3125 6.7072,1.8521 13.5,3.3069 20.328,4.5762 l 44.803,-72.281 44.15,72.041 c 6.3642,-1.2214 12.699,-2.6112 18.957,-4.3398 1.7592,-0.47721 3.4438,-1.1087 5.1855,-1.623 z"
|
||||
style="fill:#fffc00;paint-order:normal"
|
||||
id="path4"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
transform="matrix(0.26458,0,0,0.26458,38.854,82.354)"
|
||||
d="m 7.793,274.15 c 9.8503,98.716 78.612,181.32 173.49,209.29 l 69.268,-111.75 68.293,111.44 c 94.698,-27.966 163.41,-110.38 173.36,-208.98 z"
|
||||
style="paint-order:normal"
|
||||
id="path6"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 105,84.064 a 64.436,64.436 0 0 0 -6.9536,0.45217 v 63.984 H 91.068 v -62.829 a 64.436,64.436 0 0 0 -3.4644,0.79478 v 62.034 h -6.9784 v -59.598 a 64.436,64.436 0 0 0 -3.4644,1.5503 v 58.048 h -6.9784 v -54.219 a 64.436,64.436 0 0 0 -3.4644,2.4774 v 51.742 h -6.9784 v -45.829 a 64.436,64.436 0 0 0 -3.4644,3.7192 v 42.11 h -6.9784 v -32.27 a 64.436,64.436 0 0 0 -3.4644,6.8011 v 25.469 H 40.564 a 64.436,64.436 0 0 0 0.08992,2.5476 h 128.65 a 64.436,64.436 0 0 0 0.12764,-2.5476 h -5.2684 v -25.336 a 64.436,64.436 0 0 0 -3.4644,-6.8952 v 32.232 h -6.9784 v -42.046 a 64.436,64.436 0 0 0 -3.4644,-3.7445 v 45.79 h -6.9784 v -51.738 a 64.436,64.436 0 0 0 -3.4644,-2.4035 v 54.141 h -6.9784 v -58.023 a 64.436,64.436 0 0 0 -3.4644,-1.5885 v 59.611 h -6.9784 v -61.978 a 64.436,64.436 0 0 0 -3.4644,-0.8847 v 62.863 h -6.9784 v -64.035 a 64.436,64.436 0 0 0 -6.9536,-0.40049 z"
|
||||
style="paint-order:normal"
|
||||
id="path8"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m 86.789,198.81 18.357,-29.616 18.149,29.615 h 7.3544 l -25.503,-41.615 -25.796,41.617 h 7.4388"
|
||||
style="fill:#fffc00;paint-order:normal"
|
||||
id="path10"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 4.0 KiB |
146
static/tower.svg
Normal file
@ -0,0 +1,146 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
|
||||
sodipodi:docname="FGA Tower Icon.svg"
|
||||
viewBox="0 0 248.26501 249.26443"
|
||||
height="32"
|
||||
width="32"
|
||||
id="svg833"
|
||||
version="1.1">
|
||||
<metadata
|
||||
id="metadata839">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs837" />
|
||||
<sodipodi:namedview
|
||||
inkscape:current-layer="layer1"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:window-y="-9"
|
||||
inkscape:window-x="-9"
|
||||
inkscape:cy="131.18309"
|
||||
inkscape:cx="130.09189"
|
||||
inkscape:zoom="2.8284272"
|
||||
fit-margin-bottom="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-top="0"
|
||||
showgrid="false"
|
||||
id="namedview835"
|
||||
inkscape:window-height="1361"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0"
|
||||
guidetolerance="10"
|
||||
gridtolerance="10"
|
||||
objecttolerance="10"
|
||||
borderopacity="1"
|
||||
bordercolor="#666666"
|
||||
pagecolor="#ffffff"
|
||||
inkscape:document-rotation="0"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:snap-bbox-midpoints="true"
|
||||
inkscape:object-paths="true"
|
||||
inkscape:snap-intersection-paths="true"
|
||||
inkscape:snap-smooth-nodes="true"
|
||||
inkscape:snap-midpoints="true"
|
||||
inkscape:snap-global="true" />
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer2"
|
||||
inkscape:label="Background" />
|
||||
<g
|
||||
transform="translate(7.706459,7.9160461)"
|
||||
inkscape:label="Headset"
|
||||
id="layer1"
|
||||
inkscape:groupmode="layer">
|
||||
<g
|
||||
id="g962">
|
||||
<circle
|
||||
r="124.1325"
|
||||
cy="116.21645"
|
||||
cx="116.42604"
|
||||
id="path1622"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="sccsccs"
|
||||
d="m 88.489103,214.89893 c 0,-5.21922 4.23103,-9.45026 9.450184,-9.45033 l 36.986813,-6e-5 c 5.20585,0 9.43688,4.23103 9.43688,9.45026 0,5.21922 -4.23103,9.45026 -9.43688,9.45012 l -36.986813,7e-5 c -5.219154,2e-4 -9.450184,-4.23083 -9.450184,-9.45006 z"
|
||||
style="fill:#000000;fill-opacity:1;stroke:#00a8b2;stroke-width:0.0994765;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path849-5" />
|
||||
<g
|
||||
style="fill:#000000;fill-opacity:1"
|
||||
transform="translate(-3.4175518e-4)"
|
||||
id="g1992">
|
||||
<path
|
||||
id="path849-5-5"
|
||||
style="fill:#000000;fill-opacity:1;stroke:#00a8b2;stroke-width:0.150978;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 226.14123,79.658933 c -7.92132,0 -14.34375,6.421246 -14.34375,14.322266 v 56.134771 c 1e-4,7.92121 6.42243,14.34377 14.34375,14.34375 1.77942,0 3.47461,-0.33935 5.04687,-0.93164 a 124.1325,124.1325 0 0 0 9.29492,-43.01367 v -8.59961 a 124.1325,124.1325 0 0 0 -4.2207,-28.076179 c -2.59403,-2.582096 -6.16991,-4.179688 -10.12109,-4.179688 z" />
|
||||
<path
|
||||
id="path849-5-5-8"
|
||||
style="fill:#000000;fill-opacity:1;stroke:#00a8b2;stroke-width:0.150978;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 6.711542,79.658933 c -3.950201,0 -7.5252386,1.596784 -10.1191409,4.177734 A 124.1325,124.1325 0 0 0 -7.6302551,111.8855 v 8.66211 a 124.1325,124.1325 0 0 0 9.2949219,42.98047 c 1.5722702,0.59229 3.2674492,0.93164 5.0468752,0.93164 7.92132,0 14.34406,-6.42254 14.34375,-14.34375 V 93.981199 c 2.1e-4,-7.901011 -6.42245,-14.322266 -14.34375,-14.322266 z" />
|
||||
</g>
|
||||
<g
|
||||
id="g916"
|
||||
style="stroke:#00989a;stroke-opacity:1">
|
||||
<path
|
||||
id="rect1605"
|
||||
style="fill:none;fill-opacity:1;stroke:#00989a;stroke-width:2;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 53.844354,143.81714 v 79.60352 a 124.1325,124.1325 0 0 0 62.582026,16.92773 124.1325,124.1325 0 0 0 63.28907,-17.34766 v -79.18359 z" />
|
||||
<polygon
|
||||
style="fill:#00989a;fill-opacity:1;stroke:#00989a;stroke-opacity:1"
|
||||
id="polygon986"
|
||||
points="89.486,243.876 71.941,139.481 26.677,139.481 61.767,243.876 "
|
||||
transform="matrix(0.75835957,0,0,0.75835957,6.0968618,-47.492855)" />
|
||||
<polygon
|
||||
style="fill:#00989a;fill-opacity:1;stroke:#00989a;stroke-opacity:1"
|
||||
id="polygon988"
|
||||
points="151.484,139.481 151.484,243.876 189.314,243.876 206.859,139.481 "
|
||||
transform="matrix(0.75835957,0,0,0.75835957,6.0968618,-47.492855)" />
|
||||
<polygon
|
||||
style="fill:#00989a;fill-opacity:1;stroke:#00989a;stroke-opacity:1"
|
||||
id="polygon990"
|
||||
points="84.109,139.481 101.654,243.876 139.484,243.876 139.484,139.481 "
|
||||
transform="matrix(0.75835957,0,0,0.75835957,6.0968618,-47.492855)" />
|
||||
<polygon
|
||||
style="fill:#00989a;fill-opacity:1;stroke:#00989a;stroke-opacity:1"
|
||||
id="polygon992"
|
||||
points="201.482,243.876 229.201,243.876 264.291,139.481 219.027,139.481 "
|
||||
transform="matrix(0.75835957,0,0,0.75835957,6.0968618,-47.492855)" />
|
||||
<rect
|
||||
y="42.483017"
|
||||
x="44.615604"
|
||||
height="9.8302555"
|
||||
width="143.62088"
|
||||
id="rect1605-7"
|
||||
style="fill:#00989a;fill-opacity:1;stroke:#00989a;stroke-width:2.50089;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
id="path1761"
|
||||
d="m 221.22133,163.59357 c -16.80353,25.19128 -43.642,43.64367 -76.66957,51.11645"
|
||||
style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
id="path913"
|
||||
d="M 6.8856252,81.848629 C 21.611214,33.687043 66.066978,0.7936943 116.42946,0.79583065 c 50.36251,0.00213 94.81547,32.89923835 109.537,81.06206135"
|
||||
style="fill:none;stroke:#000000;stroke-width:5;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 6.6 KiB |
18
test/mocha/index.js
Normal file
@ -0,0 +1,18 @@
|
||||
'use strict'
|
||||
|
||||
// Set BABEL_ENV to use proper env config
|
||||
process.env.BABEL_ENV = 'test'
|
||||
|
||||
// Enable use of ES6+ on required files
|
||||
require('babel-register')({
|
||||
ignore: /node_modules/
|
||||
})
|
||||
|
||||
// Attach Chai APIs to global scope
|
||||
const { expect, should, assert } = require('chai')
|
||||
global.expect = expect
|
||||
global.should = should
|
||||
global.assert = assert
|
||||
|
||||
// Require all JS files in `./specs` for Mocha to consume
|
||||
require('require-dir')('./specs')
|
228
test/mocha/specs/check.spec.js
Normal file
@ -0,0 +1,228 @@
|
||||
var assert = require('chai').assert;
|
||||
var Worker = require("tiny-worker");
|
||||
|
||||
process.chdir('src/renderer/utils');
|
||||
|
||||
describe("Test Check", function () {
|
||||
describe("Routing Checks", function () {
|
||||
it("Not legitimate End", function (done) {
|
||||
var data = [
|
||||
{ 'start': 1, 'end': 2, '_leaflet_id': 1, 'type': 'poly', 'isPushBackRoute': true }
|
||||
];
|
||||
var worker = new Worker('check.js');
|
||||
worker.onmessage = function (e) {
|
||||
if (e.data === 'checkStarted') {
|
||||
} else if (e.data[0] === 'DONE') {
|
||||
console.log('DONE')
|
||||
worker.terminate()
|
||||
if (e.data[1].length === 0) {
|
||||
done('Crashed')
|
||||
} else {
|
||||
console.log(e.data[1]);
|
||||
console.log(e.data[1].filter(m => m.id === 1));
|
||||
assert.lengthOf(e.data[1].filter(m => m.id === 1).filter(m => m.message === 'Node not a legimate end'), 1);
|
||||
assert.lengthOf(e.data[1].filter(m => m.id === 2).filter(m => m.message === 'Node not a legimate end'), 1);
|
||||
assert.lengthOf(e.data[1].filter(m => m.message === 'No invalid ends'), 0);
|
||||
|
||||
done()
|
||||
}
|
||||
} else if (e.data.length > 0) {
|
||||
}
|
||||
};
|
||||
worker.postMessage(['check', data]);
|
||||
});
|
||||
it("Legitimate End Runway", function (done) {
|
||||
var data = [
|
||||
{ 'start': 1, 'end': 2, '_leaflet_id': 1, 'type': 'poly', 'isPushBackRoute': true, 'direction': 'bi-directional' },
|
||||
{ 'index': 1, '_leaflet_id': 2, 'type': 'runway' }
|
||||
];
|
||||
var worker = new Worker('check.js');
|
||||
worker.onmessage = function (e) {
|
||||
if (e.data === 'checkStarted') {
|
||||
} else if (e.data[0] === 'DONE') {
|
||||
console.log('DONE')
|
||||
worker.terminate()
|
||||
if (e.data[1].length === 0) {
|
||||
done('Crashed')
|
||||
} else {
|
||||
console.log(e.data[1]);
|
||||
console.log(e.data[1].filter(m => m.id === 1));
|
||||
assert.lengthOf(e.data[1].filter(m => m.id === 1).filter(m => m.message === 'No way from runway to each parking'), 1);
|
||||
assert.lengthOf(e.data[1].filter(m => m.id === 2).filter(m => m.message === 'Node not a legimate end'), 1);
|
||||
assert.lengthOf(e.data[1].filter(m => m.message === 'No invalid ends'), 0);
|
||||
done()
|
||||
}
|
||||
} else if (e.data.length > 0) {
|
||||
}
|
||||
};
|
||||
worker.postMessage(['check', data]);
|
||||
});
|
||||
|
||||
it("From Parking to Runway bi-directional", function (done) {
|
||||
var data = [
|
||||
{ 'start': 1, 'end': 2, '_leaflet_id': 1, 'type': 'poly', 'isPushBackRoute': true, direction: 'bi-directional' },
|
||||
{ 'index': 1, '_leaflet_id': 2, 'type': 'runway' },
|
||||
{ 'index': 2, '_leaflet_id': 3, 'name': 'name', parkingType: 'gate', 'type': 'parking' }
|
||||
];
|
||||
var worker = new Worker('check.js');
|
||||
worker.onmessage = function (e) {
|
||||
if (e.data === 'checkStarted') {
|
||||
} else if (e.data[0] === 'DONE') {
|
||||
console.log('DONE')
|
||||
worker.terminate()
|
||||
if (e.data[1].length === 0) {
|
||||
done('Crashed')
|
||||
} else {
|
||||
console.log(e.data[1]);
|
||||
console.log(e.data[1].filter(m => m.id === 1));
|
||||
assert.lengthOf(e.data[1].filter(m => m.id === -1).filter(m => m.message === 'Routes from runways OK'), 1);
|
||||
assert.lengthOf(e.data[1].filter(m => m.message === 'No invalid ends'), 1);
|
||||
done()
|
||||
}
|
||||
} else if (e.data.length > 0) {
|
||||
}
|
||||
};
|
||||
worker.postMessage(['check', data]);
|
||||
});
|
||||
|
||||
it("From Parking to Runway forward OK", function (done) {
|
||||
var data = [
|
||||
{ 'start': 1, 'end': 2, '_leaflet_id': 1, 'type': 'poly', 'isPushBackRoute': true, direction: 'forward' },
|
||||
{ 'index': 1, '_leaflet_id': 3, 'name': 'name', parkingType: 'gate', 'type': 'parking' },
|
||||
{ 'index': 2, '_leaflet_id': 2, 'type': 'runway' }
|
||||
];
|
||||
var worker = new Worker('check.js');
|
||||
worker.onmessage = function (e) {
|
||||
if (e.data === 'checkStarted') {
|
||||
} else if (e.data[0] === 'DONE') {
|
||||
console.log('DONE')
|
||||
worker.terminate()
|
||||
|
||||
if (e.data[1].length === 0) {
|
||||
done('Crashed')
|
||||
} else {
|
||||
console.log(e.data[1]);
|
||||
console.log(e.data[1].filter(m => m.id === 1));
|
||||
assert.lengthOf(e.data[1].filter(m => m.id === -1).filter(m => m.message === 'Routes from runways OK'), 1);
|
||||
assert.lengthOf(e.data[1].filter(m => m.message === 'No invalid ends'), 1);
|
||||
done()
|
||||
}
|
||||
} else if (e.data.length > 0) {
|
||||
}
|
||||
};
|
||||
worker.postMessage(['check', data]);
|
||||
});
|
||||
|
||||
it("From Parking to Runway forward Not Ok", function (done) {
|
||||
var data = [
|
||||
{ 'start': 1, 'end': 2, '_leaflet_id': 1, 'type': 'poly', 'isPushBackRoute': true, direction: 'forward' },
|
||||
{ 'index': 2, '_leaflet_id': 3, 'name': 'name', parkingType: 'gate', 'type': 'parking' },
|
||||
{ 'index': 1, '_leaflet_id': 2, 'type': 'runway' }
|
||||
];
|
||||
var worker = new Worker('check.js');
|
||||
worker.onmessage = function (e) {
|
||||
if (e.data === 'checkStarted') {
|
||||
} else if (e.data[0] === 'DONE') {
|
||||
console.log('DONE')
|
||||
worker.terminate()
|
||||
|
||||
if (e.data[1].length === 0) {
|
||||
done('Crashed')
|
||||
} else {
|
||||
console.log(e.data[1]);
|
||||
console.log(e.data[1].filter(m => m.id === 1));
|
||||
assert.lengthOf(e.data[1].filter(m => m.id === -1).filter(m => m.message === 'Routes from runways OK'), 0);
|
||||
assert.lengthOf(e.data[1].filter(m => m.message === 'No invalid ends'), 1);
|
||||
done()
|
||||
}
|
||||
} else if (e.data.length > 0) {
|
||||
}
|
||||
};
|
||||
worker.postMessage(['check', data]);
|
||||
});
|
||||
|
||||
it("From Parking to Runway reverse OK", function (done) {
|
||||
var data = [
|
||||
{ 'start': 1, 'end': 2, '_leaflet_id': 1, 'type': 'poly', 'isPushBackRoute': true, direction: 'backward' },
|
||||
{ 'index': 2, '_leaflet_id': 3, 'name': 'name', parkingType: 'gate', 'type': 'parking' },
|
||||
{ 'index': 1, '_leaflet_id': 2, 'type': 'runway' }
|
||||
];
|
||||
var worker = new Worker('check.js');
|
||||
worker.onmessage = function (e) {
|
||||
if (e.data === 'checkStarted') {
|
||||
} else if (e.data[0] === 'DONE') {
|
||||
console.log('DONE')
|
||||
worker.terminate()
|
||||
if (e.data[1].length === 0) {
|
||||
done('Crashed')
|
||||
} else {
|
||||
console.log(e.data[1]);
|
||||
console.log(e.data[1].filter(m => m.id === 1));
|
||||
assert.lengthOf(e.data[1].filter(m => m.id === -1).filter(m => m.message === 'Routes from runways OK'), 1);
|
||||
assert.lengthOf(e.data[1].filter(m => m.message === 'No invalid ends'), 1);
|
||||
done()
|
||||
}
|
||||
} else if (e.data.length > 0) {
|
||||
}
|
||||
};
|
||||
worker.postMessage(['check', data]);
|
||||
});
|
||||
|
||||
it("From Parking to Runway reverse Not OK", function (done) {
|
||||
var data = [
|
||||
{ 'start': 1, 'end': 2, '_leaflet_id': 1, 'type': 'poly', 'isPushBackRoute': true, direction: 'backward' },
|
||||
{ 'index': 1, '_leaflet_id': 3, 'name': 'name', parkingType: 'gate', 'type': 'parking' },
|
||||
{ 'index': 2, '_leaflet_id': 2, 'type': 'runway' }
|
||||
];
|
||||
var worker = new Worker('check.js');
|
||||
worker.onmessage = function (e) {
|
||||
if (e.data === 'checkStarted') {
|
||||
} else if (e.data[0] === 'DONE') {
|
||||
console.log('DONE')
|
||||
worker.terminate()
|
||||
if (e.data[1].length === 0) {
|
||||
done('Crashed')
|
||||
} else {
|
||||
console.log(e.data[1]);
|
||||
console.log(e.data[1].filter(m => m.id === 1));
|
||||
assert.lengthOf(e.data[1].filter(m => m.id === -1).filter(m => m.message === 'Routes from runways OK'), 0, 'No Routes from Runway');
|
||||
assert.lengthOf(e.data[1].filter(m => m.message === 'No invalid ends'), 1, 'No invalid ends');
|
||||
done()
|
||||
}
|
||||
} else if (e.data.length > 0) {
|
||||
}
|
||||
};
|
||||
worker.postMessage(['check', data]);
|
||||
});
|
||||
});
|
||||
describe("Routing Checks", function () {
|
||||
it("Runway Node not on Runway", function (done) {
|
||||
var data = [
|
||||
{ 'index': 2, '_leaflet_id': 2, 'type': 'runway' },
|
||||
{ 'name': 'R29', 'type': 'runway_area', 'polygon': [] }
|
||||
];
|
||||
var worker = new Worker('check.js');
|
||||
worker.onmessage = function (e) {
|
||||
if (e.data === 'checkStarted') {
|
||||
} else if (e.data[0] === 'DONE') {
|
||||
console.log('DONE')
|
||||
worker.terminate()
|
||||
if (e.data[1].length === 0) {
|
||||
done('Crashed')
|
||||
} else {
|
||||
console.log(e.data[1]);
|
||||
console.log(e.data[1].filter(m => m.id === 1));
|
||||
assert.lengthOf(e.data[1].filter(m => m.id === -1).filter(m => m.message === 'Routes from runways OK'), 0, 'No Routes from Runway');
|
||||
assert.lengthOf(e.data[1].filter(m => m.message === 'No invalid ends'), 1, 'No invalid ends');
|
||||
done()
|
||||
}
|
||||
} else if (e.data.length > 0) {
|
||||
}
|
||||
};
|
||||
worker.postMessage(['check', data]);
|
||||
});
|
||||
});
|
||||
describe("", function () {
|
||||
|
||||
});
|
||||
});
|
@ -1,13 +0,0 @@
|
||||
import Vue from 'vue'
|
||||
Vue.config.devtools = false
|
||||
Vue.config.productionTip = false
|
||||
|
||||
// require all test files (files that ends with .spec.js)
|
||||
const testsContext = require.context('./specs', true, /\.spec$/)
|
||||
testsContext.keys().forEach(testsContext)
|
||||
|
||||
// require all src files except main.js for coverage.
|
||||
// you can also change this to match only the subset of files that
|
||||
// you want coverage for.
|
||||
const srcContext = require.context('../../src/renderer', true, /^\.\/(?!main(\.js)?$)/)
|
||||
srcContext.keys().forEach(srcContext)
|
@ -1,62 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const merge = require('webpack-merge')
|
||||
const webpack = require('webpack')
|
||||
|
||||
const baseConfig = require('../../.electron-vue/webpack.renderer.config')
|
||||
const projectRoot = path.resolve(__dirname, '../../src/renderer')
|
||||
|
||||
// Set BABEL_ENV to use proper preset config
|
||||
process.env.BABEL_ENV = 'test'
|
||||
|
||||
let webpackConfig = merge(baseConfig, {
|
||||
devtool: '#inline-source-map',
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
'process.env.NODE_ENV': '"testing"'
|
||||
})
|
||||
]
|
||||
})
|
||||
|
||||
// don't treat dependencies as externals
|
||||
delete webpackConfig.entry
|
||||
delete webpackConfig.externals
|
||||
delete webpackConfig.output.libraryTarget
|
||||
|
||||
// apply vue option to apply isparta-loader on js
|
||||
webpackConfig.module.rules
|
||||
.find(rule => rule.use.loader === 'vue-loader').use.options.loaders.js = 'babel-loader'
|
||||
|
||||
module.exports = config => {
|
||||
config.set({
|
||||
browsers: ['visibleElectron'],
|
||||
client: {
|
||||
useIframe: false
|
||||
},
|
||||
coverageReporter: {
|
||||
dir: './coverage',
|
||||
reporters: [
|
||||
{ type: 'lcov', subdir: '.' },
|
||||
{ type: 'text-summary' }
|
||||
]
|
||||
},
|
||||
customLaunchers: {
|
||||
'visibleElectron': {
|
||||
base: 'Electron',
|
||||
flags: ['--show']
|
||||
}
|
||||
},
|
||||
frameworks: ['mocha', 'chai'],
|
||||
files: ['./index.js'],
|
||||
preprocessors: {
|
||||
'./index.js': ['webpack', 'sourcemap']
|
||||
},
|
||||
reporters: ['spec', 'coverage'],
|
||||
singleRun: true,
|
||||
webpack: webpackConfig,
|
||||
webpackMiddleware: {
|
||||
noInfo: true
|
||||
}
|
||||
})
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
import Vue from 'vue'
|
||||
import LandingPage from '@/components/LandingPage'
|
||||
|
||||
describe('LandingPage.vue', () => {
|
||||
it('should render correct contents', () => {
|
||||
const vm = new Vue({
|
||||
el: document.createElement('div'),
|
||||
render: h => h(LandingPage)
|
||||
}).$mount()
|
||||
|
||||
expect(vm.$el.querySelector('.title').textContent).to.contain('Welcome to your new project!')
|
||||
})
|
||||
})
|