From 7fe712c94b998dfab240791edbf4896677a94b4d Mon Sep 17 00:00:00 2001 From: portree_kid Date: Mon, 20 Jan 2020 21:53:53 +0100 Subject: [PATCH] Export/Save --- package-lock.json | 5 + package.json | 3 +- src/renderer/assets/global.css | 37 +++++++ src/renderer/components/AirportLayer.vue | 3 - src/renderer/components/EditLayer.vue | 22 +++- src/renderer/loaders/RunwayNode.js | 37 +++++++ src/renderer/loaders/TaxiwaySegment.js | 8 +- src/renderer/loaders/groundnet_loader.js | 13 ++- src/renderer/loaders/groundnet_writer.js | 134 +++++++++++++++++++++++ src/renderer/main.js | 1 + 10 files changed, 253 insertions(+), 10 deletions(-) create mode 100644 src/renderer/assets/global.css create mode 100644 src/renderer/loaders/RunwayNode.js create mode 100644 src/renderer/loaders/groundnet_writer.js diff --git a/package-lock.json b/package-lock.json index 575abcc..eb0a788 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20008,6 +20008,11 @@ "resolved": "https://registry.npmjs.org/xml-writer/-/xml-writer-1.4.2.tgz", "integrity": "sha1-7/wpYGXi5T27WkSR60LV41VP42w=" }, + "xmlbuilder": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-13.0.2.tgz", + "integrity": "sha512-Eux0i2QdDYKbdbA6AM6xE4m6ZTZr4G4xF9kahI2ukSEMCzwce2eX9WlTI5J3s+NU7hpasFsr8hWIONae7LluAQ==" + }, "xmlhttprequest-ssl": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", diff --git a/package.json b/package.json index 38ad060..d368510 100644 --- a/package.json +++ b/package.json @@ -86,7 +86,8 @@ "vuex-persist": "^2.2.0", "vuex-persistedstate": "^2.7.0", "worker-threads": "^1.0.0", - "xamel": "^0.3.1" + "xamel": "^0.3.1", + "xmlbuilder": "^13.0.2" }, "devDependencies": { "@fortawesome/fontawesome-free": "^5.12.0", diff --git a/src/renderer/assets/global.css b/src/renderer/assets/global.css new file mode 100644 index 0000000..d8847c0 --- /dev/null +++ b/src/renderer/assets/global.css @@ -0,0 +1,37 @@ +.marker-pin { + width: 30px; + height: 30px; + border-radius: 50% 50% 50% 0; + background: #c30b82; + position: absolute; + transform: rotate(-45deg); + left: 50%; + top: 50%; + margin: -15px 0 0 -15px; + } + + .marker-pin::after { + content: ''; + width: 24px; + height: 24px; + margin: 3px 0 0 3px; + background: #fff; + position: absolute; + border-radius: 50%; + } + + .custom-div-icon i { + position: absolute; + width: 12px; + font-size: 12px; + left: 0; + right: 0; + margin: 12px auto; + text-align: center; + } + + .custom-div-icon i.awesome { + margin: 8px auto; + font-size: 12px; + } + \ No newline at end of file diff --git a/src/renderer/components/AirportLayer.vue b/src/renderer/components/AirportLayer.vue index 5332941..faab752 100644 --- a/src/renderer/components/AirportLayer.vue +++ b/src/renderer/components/AirportLayer.vue @@ -48,7 +48,4 @@ diff --git a/src/renderer/components/EditLayer.vue b/src/renderer/components/EditLayer.vue index b227dc8..564994e 100644 --- a/src/renderer/components/EditLayer.vue +++ b/src/renderer/components/EditLayer.vue @@ -9,6 +9,7 @@ import L from 'leaflet' import LEdit from 'leaflet-editable/src/Leaflet.Editable.js' import {readGroundnetXML, addFeature} from '../loaders/groundnet_loader' + import {writeGroundnetXML} from '../loaders/groundnet_writer' import L2 from 'leaflet-textpath' // import {LSymbol} from 'leaflet-polylinedecorator' @@ -38,7 +39,12 @@ if (this.groundnetLayerGroup !== undefined) { this.groundnetLayerGroup.removeFrom(this.$parent.mapObject) } + this.icao = icao this.groundnetLayerGroup = readGroundnetXML(this.$store.state.Settings.settings.airportsDirectory, icao) + if (this.groundnetLayerGroup === undefined) { + console.console.error('ICAO not loaded ' + icao) + return + } /* this.groundnetLayerGroup.eachLayer(l => { if (l instanceof L.TaxiwaySegment) { @@ -60,6 +66,7 @@ }, visible (feature) { let bounds = this.$store.state.Settings.bounds + let coordinates = feature.geometry.coordinates let ret = bounds.getNorthEast().lat > Number(coordinates[1]) && bounds.getNorthEast().lng > Number(coordinates[0]) @@ -87,7 +94,9 @@ if (typeof l.extensions === 'function') { l.extensions() } - l.bringToFront() + if (typeof l.bringToFront === 'function') { + l.bringToFront() + } }) }, disableEdit () { @@ -104,6 +113,9 @@ drawPolyline () { var polyLine = this.$parent.mapObject.editTools.startPolyline() polyLine.addTo(this.groundnetLayerGroup) + polyLine.on('editable:drawing:end', event => { + console.log(event) + }) }, drawParking () { this.$parent.mapObject.on('click', this.addParking) @@ -131,7 +143,11 @@ this.load(this.icao) }, save () { - + var xml = [] + this.groundnetLayerGroup.eachLayer(l => { + xml.push(l) + }) + writeGroundnetXML(this.$store.state.Settings.settings.airportsDirectory, this.icao, xml) } }, computed: { @@ -145,5 +161,5 @@ } - diff --git a/src/renderer/loaders/RunwayNode.js b/src/renderer/loaders/RunwayNode.js new file mode 100644 index 0000000..830837d --- /dev/null +++ b/src/renderer/loaders/RunwayNode.js @@ -0,0 +1,37 @@ +/* eslint-disable */ +const convert = require('geo-coordinates-parser'); +const leaflet = require('leaflet'); +const turf = require('@turf/turf'); +const util = require('util'); +const store = require('../store'); + +var $ = require('jquery'); +L.RunwayNode = L.Marker.extend({ + addListeners: function () { + this.on('editable:drawing:move', function (event) { + console.log("Move : ", event); + // Is it the edit vertex (Middle) moving? + follow(event.target.id, event); + }); + } +}); + +var runwayNode = function (n, layerGroup) { + //console.log(n.attr('lat') + " " + n.attr('lon')); + var latlon = convert(n.attr('lat') + " " + n.attr('lon')); + //console.log(latlon.decimalLatitude); + //console.log(convert(n.attr('lat') + " " + n.attr('lon')).decimalLongitude); + const icon = new L.DivIcon({ + className: 'custom-div-icon', + html: "
", + iconSize: [30, 42], + iconAnchor: [15, 42] + }); + const node = new L.RunwayNode([latlon.decimalLatitude, latlon.decimalLongitude], { icon: icon }); + node.id = n.attr('index'); + node.addTo(layerGroup); + node.addListeners(); + return node; +} + +module.exports = runwayNode; \ No newline at end of file diff --git a/src/renderer/loaders/TaxiwaySegment.js b/src/renderer/loaders/TaxiwaySegment.js index bb48ee4..1a78068 100644 --- a/src/renderer/loaders/TaxiwaySegment.js +++ b/src/renderer/loaders/TaxiwaySegment.js @@ -12,10 +12,14 @@ L.TaxiwaySegment = L.Polyline.extend({ bidirectional: Boolean, updateBeginVertex : function (latlng) { - this._latlngs[0].__vertex.setLatLng(latlng); + if (this._latlngs[0].__vertex) { + this._latlngs[0].__vertex.setLatLng(latlng); + } }, updateEndVertex : function (latlng) { - this._latlngs[1].__vertex.setLatLng(latlng); + if(this._latlngs[1].__vertex){ + this._latlngs[1].__vertex.setLatLng(latlng); + } }, updateMiddle: function () { diff --git a/src/renderer/loaders/groundnet_loader.js b/src/renderer/loaders/groundnet_loader.js index e9fbe54..7bf4b7c 100644 --- a/src/renderer/loaders/groundnet_loader.js +++ b/src/renderer/loaders/groundnet_loader.js @@ -8,6 +8,7 @@ const markers = require('./MagneticVertex'); const TaxiwaySegment = require('./TaxiwaySegment'); const parkingSpot = require('./ParkingSpot.js'); +const runwayNode = require('./RunwayNode.js'); const store = require('../store'); @@ -68,6 +69,13 @@ exports.readGroundnetXML = function (fDir, icao) { layerGroup.maxId = Math.max(layerGroup.maxId, Number(n.attr('index'))) nodesLookup[n.attr('index')] = n; + if (n.attr('isOnRunway') === '1') { + var rNode = runwayNode(n, layerGroup); + if(featureLookup[rNode.id] === undefined) { + featureLookup[rNode.id] = []; + } + featureLookup[rNode.id].push(rNode); + } }).sort(); @@ -194,7 +202,10 @@ exports.readGroundnetXML = function (fDir, icao) { follow = function (dragIndex, event) { featureLookup[dragIndex].forEach(element => { if(element !== event.target){ - if (element instanceof L.ParkingSpot) { + if (element instanceof L.RunwayNode) { + element.setLatLng(event.latlng); + } + else if (element instanceof L.ParkingSpot) { // element.disableEdit(); element.setLatLng(event.latlng); // element.enableEdit(); diff --git a/src/renderer/loaders/groundnet_writer.js b/src/renderer/loaders/groundnet_writer.js new file mode 100644 index 0000000..877c1f1 --- /dev/null +++ b/src/renderer/loaders/groundnet_writer.js @@ -0,0 +1,134 @@ +/* eslint-disable */ +const fs = require('fs'); +const path = require('path'); + +const markers = require('./MagneticVertex'); +const TaxiwaySegment = require('./TaxiwaySegment'); + +const parkingSpot = require('./ParkingSpot.js'); + +const store = require('../store'); + +const util = require('util'); + +const mathjs = require('mathjs'); + +var builder = require('xmlbuilder'); + + +exports.writeGroundnetXML = function (fDir, icao, featureList) { + try { + var f = path.join(fDir, icao[0], icao[1], icao[2], icao + '.groundnet.new.xml'); + + if (f == null) + return; + + console.log(featureList); + + var parkings = featureList.map(mapParkings).filter(n => n); + + var nodes = []; + featureList.filter(o => o instanceof L.TaxiwaySegment).filter(n => n).forEach(element => { + var begin = mapBeginNode(element); + nodes[begin['@index']] = begin; + var end = mapEndNode(element); + nodes[end['@index']] = end; + }); + + // delete the parkings + parkings.forEach( n => { + nodes[n['@index']] = null; + } ); + nodes = nodes.filter(n => n); + + nodes.sort((p, p2) => {return p['@index']- p2['@index'] }); + var uniqueNodes = nodes.filter( (v, i, a) => a.indexOf(v) === i ); + + var maxId = uniqueNodes.slice(-1)[0]['@index']; + + var arcList = []; + featureList.filter(o => o instanceof L.TaxiwaySegment).filter(n => n).forEach(element => { + + if (element.getLatLngs().length > 2) { + let middlePoints = element.getLatLngs().slice(1,-1); + let startIndex = element.begin; + middlePoints.forEach(latlng => { + uniqueNodes.push({'@index': String(++maxId), '@lat': convertLat(latlng), '@lon': convertLon(latlng)}); + arc = {'@begin': startIndex, '@end': String(maxId)}; + arcList.push(arc); + arc = {'@begin': String(maxId), '@end': startIndex}; + arcList.push(arc); + startIndex = maxId; + }); + arc = {'@begin': String(startIndex), '@end': element.end}; + arcList.push(arc); + arc = {'@begin': element.end, '@end': String(startIndex)}; + arcList.push(arc); + console.log('We have a edited line'); + } + else { + arc = {'@begin': element.begin, '@end': element.end }; + arcList.push(arc); + if (element.bidirectional) { + arc = {'@begin': element.end, '@end': element.begin }; + arcList.push(arc); + } + } + // + }); + + + var xmlObj = {groundnet: {version:1, parkingList:{ Parking: parkings }, TaxiNodes: { node: uniqueNodes}, TaxiWaySegments: { arc: arcList}}}; + + xmlString = builder.create(xmlObj).end({ pretty: true}); + fs.writeFileSync(f,xmlString); + console.log(xmlString); + } catch (error) { + console.error(error); + } + return layerGroup; +} + +var mapParkings = function( o ) { + console.log(o); + if (o instanceof L.ParkingSpot) { + var lat = convertLat(o.getLatLng()); + var lon = convertLon(o.getLatLng()); + // + return {'@index': String(o['id']), '@type': o.options.attributes.type, '@name': o.options.attributes.name, '@lat': lat, '@lon': lon, '@heading': Number(o.options.attributes.heading), '@radius': String(o.options.radius)}; + } +} + +var mapBeginNode = function( o ) { + if (o instanceof L.TaxiwaySegment) { + console.log(o); + // + return {'@index': String(o['begin']), '@lat': convertLat(o._latlngs[0]), '@lon': convertLon(o._latlngs[0])}; + } +} + +var mapEndNode = function( o ) { + if (o instanceof L.TaxiwaySegment) { + console.log(o); + // + return {'@index': String(o['end']), '@lat': convertLat(o._latlngs[1]), '@lon': convertLon(o._latlngs[1])}; + } +} + +var convertLat = function( latlng ) { + console.log(latlng.lat); + var NS = latlng.lat>0?'N':'S'; + var deg = mathjs.abs(mathjs.floor(latlng.lat)); + var min = (mathjs.abs(latlng.lat) - deg) * 60; + // console.log(NS + deg + " " + min); + return NS + String(deg).padStart(2, '0') + " " + mathjs.round( min, 3 ); +} + +var convertLon = function( latlng ) { + console.log(latlng.lng); + var NS = latlng.lat<0?'E':'W'; + var deg = mathjs.floor(mathjs.abs(latlng.lng)); + var min = (mathjs.abs(latlng.lng) - deg) * 60; + // console.log(NS + deg + " " + min); + return NS + String(deg).padStart(2, '0') + " " + mathjs.round( min, 3 ); +} \ No newline at end of file diff --git a/src/renderer/main.js b/src/renderer/main.js index 9ab3dc5..e1b6b03 100644 --- a/src/renderer/main.js +++ b/src/renderer/main.js @@ -2,6 +2,7 @@ import Vue from 'vue' import axios from 'axios' import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' +import '@/assets/global.css' import App from './App' import router from './router'