This commit is contained in:
portree_kid 2020-03-01 21:50:16 +01:00
parent bff3af2c52
commit ad3bd57448
10 changed files with 360 additions and 114 deletions

5
package-lock.json generated
View File

@ -6395,6 +6395,11 @@
"randombytes": "^2.0.0"
}
},
"dijkstrajs": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.1.tgz",
"integrity": "sha1-082BIh4+pAdCz83lVtTpnpjdxxs="
},
"dir-glob": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz",

View File

@ -58,6 +58,7 @@
"dependencies": {
"@turf/turf": "^5.1.6",
"axios": "^0.18.0",
"dijkstrajs": "^1.0.1",
"electron-debug": "^3.0.1",
"element-ui": "^2.12.0",
"file-url": "^3.0.0",

View File

@ -0,0 +1,46 @@
<template>
<div>
<h1 class="leaflet-sidebar-header">
Check Result
<div class="leaflet-sidebar-close">
<i class="fa fa-caret-left"></i>
</div>
</h1>
<div id="panel" width="100%">
<el-row v-for="(result,idx) in results" :key="idx">
<el-col :span="7">{{ result.id }}</el-col>
<el-col :span="15">{{ result.message }}</el-col>
</el-row>
</div>
</div>
</template>
<script lang="js">
export default {
name: 'settings-panel',
components: {},
props: [],
mounted () {
},
data () {
return {
}
},
methods: {
},
computed: {
results: function () {
return this.$store.state.Check.results
}
}
}
</script>
<style>
.el-row {
margin-bottom: 1px;
}
.el-col {
border-radius: 1px;
}
</style>

View File

@ -1,7 +1,12 @@
<template>
<div id="EditBar">
<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>
<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>
<span slot="footer" class="dialog-footer">
@ -14,9 +19,25 @@
</el-dialog>
<EditButton icon="fas fa-save" v-on:click="save" :show="editing" tooltip="Save"></EditButton>
<EditButton icon="fas fa-draw-polygon" v-on:click="drawPolyline" :show="editing" tooltip="Draw Taxiline"></EditButton>
<EditButton icon="fas fa-parking" v-on:click="drawParking" :show="editing" tooltip="Draw Parking"></EditButton>
<EditButton
icon="fas fa-draw-polygon"
v-on:click="drawPolyline"
:show="editing"
tooltip="Draw Taxiline"
></EditButton>
<EditButton
icon="fas fa-parking"
v-on:click="drawParking"
:show="editing"
tooltip="Draw Parking"
></EditButton>
<EditButton icon="fas fa-trash-alt" v-on:click="deleteFeature" :show="editing" tooltip="Remove"></EditButton>
<EditButton icon="far fa-check-square" v-on:click="showCheck" :show="editing" tooltip="Check"></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>
</div>
</template>
@ -24,10 +45,14 @@
/* eslint-disable */
import EditButton from './EditButton'
import Vue from 'vue'
import fileUrl from 'file-url'
const path = require('path')
export default {
components: { EditButton },
data () {
return {isEditing: false, centerDialogVisible: false, saveDialogVisible: false}
return {isEditing: false, centerDialogVisible: false, saveDialogVisible: false, checkDialogVisible: false, checking: false, progress: 0, max: 0}
},
created () {
},
@ -58,6 +83,75 @@
Vue.set(this, 'saveDialogVisible', false)
}, this)
},
pollData () {
var workery = this.worker
var view = this
workery.polling = setInterval(() => {
if (workery != null) {
view.max = Number(workery.max)
view.progress = Number(workery.progress)
view.scanning = Boolean(workery.checking)
workery.view = view
}
}, 1000)
},
check () {
try {
this.scanning = true
const winURL = process.env.NODE_ENV === 'development'
? `http://localhost:9080/src/renderer/utils/check.js`
: `file://${__dirname}/check.js`
console.log('make a worker: ', path.resolve(__dirname, 'check.js'))
const worker = new Worker(winURL)
console.log(fileUrl('src/renderer/utils/check.js'))
worker.checking = this.checking
worker.max = this.max
worker.view = this
worker.editLayer = this.$parent.$parent.$refs.editLayer
worker.progress = 0
// var worker = new Worker(fileUrl('src/renderer/utils/worker.js'))
this.worker = worker
var xml = []
this.$parent.$parent.$refs.editLayer.groundnetLayerGroup.eachLayer(l => {
console.log(l)
xml.push(l)
})
var features = xml.map(this.featuresMapper).filter(n => n)
worker.postMessage(['check', features ] )
this.pollData()
// the reply
var store = this.$store
worker.onmessage = function (e) {
if (e.data === 'checkStarted') {
this.progress = 0
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
clearInterval(this.polling)
this.checking = false
} else if (e.data.length > 0) {
if (e.data[0] === 'max') {
this.max = e.data[1]
}
if (e.data[0] === 'progress') {
this.progress += e.data[1]
}
}
// console.log(e.data)
}
} catch (err) {
console.error(err)
}
},
drawPolyline () {
this.$parent.$parent.$refs.editLayer.drawPolyline()
},
@ -66,6 +160,24 @@
},
deleteFeature () {
this.$parent.$parent.$refs.editLayer.deleteFeature()
},
showCheck() {
Vue.set(this, 'checkDialogVisible', true)
this.check()
},
featuresMapper(o) {
if (o instanceof L.ParkingSpot) {
return { 'index': Number(o['id']), '_leaflet_id': o._leaflet_id, 'type': 'parking', 'name': o.options.attributes.name, 'radius': String(o.options.attributes.radius) };
} 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.Polyline) {
console.log(o)
return { 'start': Number(o['begin']), 'end': Number(o['end']), '_leaflet_id': o._leaflet_id, 'type': 'poly' };
} else {
console.log('Unknown Type ')
console.log(typeof o)
}
}
},
computed: {

View File

@ -1,7 +1,4 @@
<template>
<section class="edit-layer">
<h1>edit-layer Component</h1>
</section>
</template>
<script lang="js">
@ -13,11 +10,13 @@
import {extendTaxiSegment} from '../loaders/TaxiwaySegmentExtender'
import {writeGroundnetXML} from '../loaders/groundnet_writer'
import L2 from 'leaflet-textpath'
import Vue from 'vue'
// import {LSymbol} from 'leaflet-polylinedecorator'
export default {
name: 'edit-layer',
components: {},
props: [],
created () {
console.log(LMap)
@ -66,15 +65,14 @@
},
data () {
return {
maxId: 1, icao: String
maxId: 1, icao: String, checking: false
}
},
methods: {
load (icao, force) {
if (this.groundnetLayerGroup !== undefined) {
this.groundnetLayerGroup.removeFrom(this.$parent.mapObject)
}
}
this.icao = icao
this.groundnetLayerGroup = readGroundnetXML(this.$store.state.Settings.settings.airportsDirectory, icao, force)
@ -129,6 +127,9 @@
this.deferredMountedTo(this.$parent.mapObject)
}
},
showCheck() {
Vue.set(this, 'checking', true)
},
enableEdit () {
this.editable = true
this.featureLookup = [];
@ -264,14 +265,14 @@
if (element instanceof L.RunwayNode) {
if (isOnRunway === 0) {
// We shouldn't have a RunwayNode
element.removeFrom(layerGroup);
element.removeFrom(this.groundnetLayerGroup);
this.featureLookup[nIndex].splice(index,1);
}
hasRunwayNode = true;
} else if (element instanceof L.HoldNode) {
if (!isHoldPoint) {
// We shouldn't have a RunwayNode
element.removeFrom(layerGroup);
element.removeFrom(this.groundnetLayerGroup);
this.featureLookup[nIndex].splice(index,1);
} else {
var fa_icon;
@ -322,9 +323,11 @@
});
const node = new L.RunwayNode(latlng, { icon: icon });
node.glueindex = nIndex;
node.addTo(layerGroup);
node.addTo(this.groundnetLayerGroup);
this.featureLookup[nIndex].push(node);
node.featureLookup = this.featureLookup;
node.addListeners();
node.extensions();
}
if (!hasHoldPointNode && isHoldPoint) {
var fa_icon = null;
@ -341,9 +344,11 @@
});
const node = new L.HoldNode(latlng, { icon: icon });
node.glueindex = nIndex;
node.addTo(layerGroup);
node.addTo(this.groundnetLayerGroup);
node.featureLookup = this.featureLookup;
this.featureLookup[nIndex].push(node);
node.addListeners();
node.extensions();
}
},
closestLayerSnap (eventLatlng, snap) {
@ -398,6 +403,7 @@
const circle = new L.ParkingSpot(event.latlng, {attributes: {radius: 20, heading: 0}})
circle.id = (++this.groundnetLayerGroup.maxId)
circle.addTo(this.groundnetLayerGroup)
circle.featureLookup = this.featureLookup
circle.enableEdit()
circle.extensions()
circle.addListeners()

View File

@ -7,6 +7,7 @@
<li><a href="#edit" role="tab"><i class="fas fa-edit"></i></a></li>
<li><a href="#search" role="tab"><i class="fa fa-search"></i></a></li>
<li><a href="#scan" role="tab"><i class="fa fa-sync"></i></a></li>
<li><a href="#check" role="tab"><i class="far fa-check-square"></i></a></li>
</ul>
<ul role="tablist"> <!-- bottom aligned tabs -->
@ -42,6 +43,9 @@
<div class="leaflet-sidebar-pane" id="settings">
<SettingsPanel></SettingsPanel>
</div>
<div class="leaflet-sidebar-pane" id="check">
<CheckPanel></CheckPanel>
</div>
</div>
</div>
</template>
@ -52,17 +56,18 @@
import {} from 'leaflet-sidebar-v2'
import L from 'leaflet'
import AirportEdit from './AirportEdit'
import CheckPanel from './CheckPanel'
import ParkingEdit from './ParkingEdit'
import ArcEdit from './ArcEdit'
import NodeEdit from './NodeEdit'
import SettingsPanel from './SettingsPanel'
import RunScan from './RunScan'
import Search from './Search'
import FileSelect from './FileSelect'
import NodeEdit from './NodeEdit'
import RunScan from './RunScan'
import SettingsPanel from './SettingsPanel'
import Search from './Search'
export default {
name: 'leaflet-sidebar',
components: { AirportEdit, ArcEdit, NodeEdit, ParkingEdit, SettingsPanel, RunScan, FileSelect, Search },
components: { AirportEdit, ArcEdit, CheckPanel, NodeEdit, ParkingEdit, SettingsPanel, RunScan, FileSelect, Search },
props: [],
mounted () {
this.add()

View File

@ -43,6 +43,7 @@ L.RunwayNode = L.Marker.extend({
});
},
extensions: function (editLayer) {
this.options.attributes = {};
if (typeof this.featureLookup[this.glueindex] === 'undefined') {
this.featureLookup[this.glueindex] = new Array();
}

View File

@ -0,0 +1,24 @@
const state = {
results: []
}
const mutations = {
'CHECK_RESULTS' (state, results) {
state.results = results
}
}
const plugins = []
const actions = {
async setResults (context, results) {
context.commit('CHECK_RESULTS', results)
}
}
export default {
state,
mutations,
actions,
plugins
}

View File

@ -1,95 +0,0 @@
/* eslint-disable */
const loki = require('lokijs');
const fs = require('fs');
var db = new loki('airports_DB.json');
var features = null;
export async function init() {
var promise = new Promise(function (resolve, reject) {
console.log("Init " + (features == null));
if (features == null) {
console.log("Loading DB");
db.loadDatabase({}, function (err) {
if (err) {
console.error("Error loading DB");
console.error(err);
db.addCollection('features', {
unique: ["properties.icao"], autoupdate: true
});
features = db.getCollection('features');
}
features = db.getCollection('features');
if( features == null ){
db.addCollection('features', {
unique: ["properties.icao"], autoupdate: true
});
features = db.getCollection('features');
}
console.log("Loaded " + features.count() + " features");
resolve(features);
});
}
else {
resolve(features);
}
});
return promise;
}
export function getAirport(apts, icao) {
console.log("Getting Airport " + icao);
var results = apts.where(function (f) {
return f.properties['icao'] === icao;
});
var feature;
if (results.length == 0) {
feature = {
"type": "Feature",
'properties': { 'icao': icao, 'twr': false, 'threshold': false, 'flights': 0 },
'geometry': {
"type": "Point"
}
};
feature = apts.insert(feature);
// apts.update(feature);
console.log("Added New");
console.log(JSON.stringify(feature));
return feature;
}
else {
console.debug("retrieved " + JSON.stringify(results[0]));
return results[0];
}
}
export function save() {
if (!features || !features.data)
return;
var mappedData = features.data.map(function (f) {
delete f.meta;
delete f.$loki;
if(f.properties.airlines) {
f.properties.airlines = f.properties.airlines.join(' ');
}
else {
f.properties.airlines = [];
}
return f;
});
mappedData = mappedData.filter(feature => feature.properties['twr'] || feature.properties['threshold']);
//console.log(mappedData);
var featureCollection = { type: "FeatureCollection", features: mappedData };
let data = JSON.stringify(featureCollection, null, 2);
fs.writeFileSync('airports.json', data);
db.saveDatabase(function (err) {
if (err) {
console.error(err);
}
});
}

141
src/renderer/utils/check.js Normal file
View File

@ -0,0 +1,141 @@
/* eslint-disable */
const winURL = process.env.NODE_ENV === 'development'
? `http://localhost:9080/src/renderer/utils/`
: `file://D:/GIT/flightgear-airports/src/renderer/utils/`
var path = require('path');
const fs = require('fs');
importScripts('../../../node_modules/dijkstrajs/dijkstra.js');
const homedir = require('os').homedir();
importScripts('logger.js');
function errorReceiver(event) {
throw event.data;
}
onmessage = function (event) {
postMessage('checkStarted');
logger('info', 'Check Started');
console.log(event.data);
if (event.data[0] === 'check') {
checkGroundnet(event.data[1]).then(result => {
console.log("DONE Checking");
postMessage(['DONE', result]);
// event.origin.webContents.send('scanFinished');
}
).catch(result => {
console.log('Crashed');
console.log(result);
postMessage('DONE');
});
}
};
async function checkGroundnet(data) {
var promise = new Promise(function (resolve, reject) {
this.max = 4;
debugger;
var parkings = data.map(mapParkings).filter(n => n !== undefined);
var runwayNodes = data.map(mapRunwayNodes).filter(n => n !== undefined);
var edges = data.map(mapEdges).filter(n => n !== undefined);
var graph = {};
parkings.forEach(element => {
graph[element] = {};
});
runwayNodes.forEach(element => {
graph[element] = {};
});
edges.forEach(element => {
graph[element.start] = {};
graph[element.end] = {};
});
edges.forEach(element => {
var node1 = graph[element.start];
node1[element.end] = 1;
var node2 = graph[element.end];
node2[element.start] = 1;
});
var okNodes = [];
logger('info', graph);
parkings.forEach(parkingNode => {
runwayNodes.forEach(runwayNode => {
var ok = checkRoute(graph, parkingNode, runwayNode);
if(ok) {
okNodes.push(parkingNode);
okNodes.push(runwayNode);
}
this.progress += 1;
});
});
okNodes = okNodes.filter((v,i) => okNodes.indexOf(v) === i);
var allNodes = parkings.concat(runwayNodes);
var notOkNodes = allNodes.filter((v,i) => okNodes.indexOf(v) < 0).map(id => {return {id:id, message:'Node not connected'}});
if (parkings.length === 0) {
notOkNodes.push({id:0, message:'No parkings'});
}
if (runwayNodes.length === 0) {
notOkNodes.push({id:0, message:'No Runwaynodes'});
}
// check1(graph);
// check2();
// this.progress += 1;
resolve(notOkNodes);
});
return promise;
}
function checkRoute(graph, from, to) {
try {
var pathD = this.dijkstra.find_path(graph, from, to);
if (pathD.length>0) {
console.log(pathD);
}
return true;
} catch (error) {
console.log('No route from ' + from + ' to ' + to);
return false;
}
}
function check1(graph) {
var graph1 = {
a: {b: 1, d: 1},
b: {a: 1, c: 1, e: 1},
c: {b: 1, f: 1},
d: {a: 1, e: 1, g: 1},
e: {b: 1, d: 1, f: 1, h: 1},
f: {c: 1, e: 1, i: 1},
g: {d: 1, h: 1},
h: {e: 1, g: 1, i: 1},
i: {f: 1, h: 1}
};
var path = this.dijkstra.find_path(graph, 'a', 'i');
console.log(path);
}
function check2(params) {
}
var mapParkings = function (o) {
if(o.type === 'parking')
return o.index;
console.log(o);
}
var mapRunwayNodes = function (o) {
if(o.type === 'runway')
return o.index;
console.log(o);
}
var mapEdges = function (o) {
if(o.type === 'poly')
return {start: o.start, end: o.end};
console.log(o);
}