diff --git a/build/installer.nsh b/build/installer.nsh new file mode 100644 index 0000000..9886d3d --- /dev/null +++ b/build/installer.nsh @@ -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 diff --git a/src/renderer/components/ArcEditMulti.vue b/src/renderer/components/ArcEditMulti.vue new file mode 100644 index 0000000..753eafc --- /dev/null +++ b/src/renderer/components/ArcEditMulti.vue @@ -0,0 +1,106 @@ + + + + diff --git a/src/renderer/components/DirectorySelect.vue b/src/renderer/components/DirectorySelect.vue index dde7b6b..64dbfab 100644 --- a/src/renderer/components/DirectorySelect.vue +++ b/src/renderer/components/DirectorySelect.vue @@ -3,7 +3,7 @@
...
- + @@ -20,9 +20,15 @@ methods: { handleFileChange (e) { - var first = e.target.files[0].webkitRelativePath.split("/")[0]; - var webkitdirectoryPath = e.target.files[0].path.split(first)[0] + first; - this.$emit('input', webkitdirectoryPath) + 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) + } } } } @@ -39,6 +45,8 @@ text-align: center; font-weight: bold; + width: 28px; + height: 28px; } .directory-select > input[type="file"] { diff --git a/src/renderer/components/EditLayer.vue b/src/renderer/components/EditLayer.vue index 8f7c026..6f15642 100644 --- a/src/renderer/components/EditLayer.vue +++ b/src/renderer/components/EditLayer.vue @@ -41,11 +41,7 @@ You should have received a copy of the GNU General Public License along with FG props: [], created () { - console.log(LMap) - console.log(LMarker) - console.log(L) - console.log(LEdit) - console.log(L2) + [LMap, LMarker, L, LEdit, L2] console.log('Created Editlayer') // console.log(LSymbol) }, @@ -72,6 +68,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; @@ -125,12 +131,18 @@ You should have received a copy of the GNU General Public License along with FG this.icao = icao this.groundnetLayerGroup = readGroundnetXML(this.$store.state.Settings.settings.airportsDirectory, icao, force) 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() + l.addListeners() + } + if (l.updateArrows !== undefined) { + l.updateArrows(this.$store.state.Settings.zoom) } }) console.log(this.groundnetLayerGroup.maxId) @@ -659,6 +671,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); @@ -666,6 +679,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); + 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 = this.$store.state.Editable.data.multiarc.direction + arc.options.attributes.name = this.$store.state.Editable.data.multiarc.name + arc.options.attributes.isPushBackRoute = this.$store.state.Editable.data.multiarc.isPushBackRoute + arc.updateStyle(); + } + }); + }, //Update Node editedNode() { if (this.$store.state.Editable.index === undefined || @@ -825,11 +859,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 } diff --git a/src/renderer/components/FlightgearMap.vue b/src/renderer/components/FlightgearMap.vue index 7002f4d..ca6eade 100644 --- a/src/renderer/components/FlightgearMap.vue +++ b/src/renderer/components/FlightgearMap.vue @@ -30,8 +30,6 @@ You should have received a copy of the GNU General Public License along with FG - - + + + @@ -60,6 +61,7 @@ You should have received a copy of the GNU General Public License along with FG import ToolBar from './ToolBar' import EditLayer from './EditLayer' import ToolLayer from './ToolLayer' + import TowerLayer from './TowerLayer' import PavementLayer from './PavementLayer' import ThresholdLayer from './ThresholdLayer' @@ -75,7 +77,7 @@ 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, LeafletSidebar, AiLayer, EditBar, ToolBar, EditLayer, TowerLayer, PavementLayer, LLayerGroup, LControl, ThresholdLayer, ToolLayer }, props: [], created () { this.loadingInstance = null @@ -85,7 +87,7 @@ You should have received a copy of the GNU General Public License along with FG }, (newValue, oldValue) => { // debugger - console.log('setIcaoLoading ' + oldValue + ' => ' + newValue + ' ' + this.groundnetLoaded + ' ' + this.pavementLoaded + ' ' + this.loadingInstance) + 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)) { @@ -105,7 +107,7 @@ You should have received a copy of the GNU General Public License along with FG }, (newValue, oldValue) => { // debugger - console.log('groundnetLoaded ' + oldValue + ' => ' + newValue + ' ' + this.groundnetLoaded + ' ' + this.pavementLoaded + ' ' + this.loadingInstance) + console.log('groundnetLoaded ' + oldValue + ' => ' + newValue + ' groundnetLoaded ' + this.groundnetLoaded + ' pavementLoaded ' + this.pavementLoaded + ' ' + this.loadingInstance) if (newValue !== oldValue) { this.groundnetLoaded = newValue if (this.groundnetLoaded && @@ -160,6 +162,9 @@ You should have received a copy of the GNU General Public License along with FG this.$refs.pavementLayer.load(airportsToLoad[0]) this.$refs.editLayer.load(airportsToLoad[0]) this.$refs.thresholdLayer.load(airportsToLoad[0]) + if (this.$refs.towerLayer) { + this.$refs.towerLayer.load(airportsToLoad[0]) + } this.editingAirport = airportsToLoad[0] }) } @@ -169,7 +174,6 @@ 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) } }) @@ -208,16 +212,34 @@ 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) { 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') } } + 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') + } + } }, onSelectedPolygon (ring) { var parkings = this.$refs.editLayer.getParkings(ring) @@ -234,6 +256,7 @@ You should have received a copy of the GNU General Public License along with FG this.$refs.map.mapObject.options.minZoom = 1 } this.$refs.editLayer.enableEdit() + this.$refs.towerLayer.enableEdit() this.$refs.editBar.setEditing(event) this.$refs.toolBar.setEditing(event) this.$refs.sidebar.setEditing(event) @@ -317,13 +340,36 @@ 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) } + 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.$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) } }, diff --git a/src/renderer/components/Help.vue b/src/renderer/components/Help.vue index 5118886..582e14a 100644 --- a/src/renderer/components/Help.vue +++ b/src/renderer/components/Help.vue @@ -1,7 +1,18 @@ + @@ -51,7 +60,9 @@ }, computed: { - + version: function () { + return ' Flightgear Airports ' + require('electron').remote.app.getVersion() + } } } diff --git a/src/renderer/components/LeafletSidebar.vue b/src/renderer/components/LeafletSidebar.vue index 746190d..967de5b 100644 --- a/src/renderer/components/LeafletSidebar.vue +++ b/src/renderer/components/LeafletSidebar.vue @@ -38,6 +38,7 @@ You should have received a copy of the GNU General Public License along with FG
+ @@ -74,6 +75,7 @@ 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 ArcEditMulti from './ArcEditMulti' import CheckPanel from './CheckPanel' import FileSelect from './FileSelect' import Help from './Help' @@ -89,7 +91,7 @@ You should have received a copy of the GNU General Public License along with FG export default { name: 'leaflet-sidebar', - components: { Help, AirportEdit, ArcEdit, CheckPanel, NodeEdit, ParkingEdit, ParkingGroupEdit, RunScan, FileSelect, SettingsPanel, Search, Upload, WorkInProgress }, + components: { Help, AirportEdit, ArcEdit, ArcEditMulti, CheckPanel, NodeEdit, ParkingEdit, ParkingGroupEdit, RunScan, FileSelect, SettingsPanel, Search, Upload, WorkInProgress }, props: [], created () { window.addEventListener('keydown', this.doCommand) diff --git a/src/renderer/components/SettingsPanel.vue b/src/renderer/components/SettingsPanel.vue index ee3ea39..d3c8789 100644 --- a/src/renderer/components/SettingsPanel.vue +++ b/src/renderer/components/SettingsPanel.vue @@ -11,17 +11,25 @@ Airports Directory - {{ airports_directory }} - - + {{ airports_directory }} + + + + Flightgear Data Directory - {{ flightgear_directory }} - + {{ flightgear_directory }} + - Traffic Directory - {{ Traffic_directory }} + Traffic Directory + + + {{ Traffic_directory }} - APT File - {{ apt_file }} + APT File + + + {{ apt_file }} Export Directory - {{ test_directory }} + {{ test_directory }} @@ -194,6 +206,14 @@ 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 }, @@ -222,9 +242,25 @@ 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 () { @@ -247,14 +283,14 @@ border-radius: 4px; } .label { - padding: 10px; + padding: 5px; font-weight: bold; } -.file-label { - padding: 10px; +.file_label { + padding: 5px; } .invalid { - padding: 10px; + padding: 5px; background-color: red; } diff --git a/src/renderer/components/ThresholdLayer.vue b/src/renderer/components/ThresholdLayer.vue index a6f75e7..545186a 100644 --- a/src/renderer/components/ThresholdLayer.vue +++ b/src/renderer/components/ThresholdLayer.vue @@ -31,6 +31,10 @@ load (icao) { // Callback for add this.layerGroup = readThresholdXML(this.$store.state.Settings.settings.airportsDirectory, icao, this.read) + if (!this.layerGroup) { + console.warn('Threshold for ICAO not loaded ' + icao) + return + } this.layerGroup.addTo(this.$parent.mapObject) this.visible = true this.icao = icao @@ -58,13 +62,21 @@ this.visible = visible } } + }, + zoomUpdated () { + 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') } } } diff --git a/src/renderer/components/TowerLayer.vue b/src/renderer/components/TowerLayer.vue new file mode 100644 index 0000000..3718b94 --- /dev/null +++ b/src/renderer/components/TowerLayer.vue @@ -0,0 +1,104 @@ + + + + + + diff --git a/src/renderer/loaders/TaxiwaySegmentExtender.js b/src/renderer/loaders/TaxiwaySegmentExtender.js index 041b2e6..073cac5 100644 --- a/src/renderer/loaders/TaxiwaySegmentExtender.js +++ b/src/renderer/loaders/TaxiwaySegmentExtender.js @@ -4,6 +4,7 @@ const Vue = require('vue'); var L = require('leaflet'); const store = require('../store'); const util = require('util'); +const assign = require('core-js/fn/object/assign'); const extendTaxiSegment = function (taxiwaySegment) { taxiwaySegment.__proto__.begin; @@ -36,7 +37,7 @@ const extendTaxiSegment = function (taxiwaySegment) { this.editLayer = editLayer; this._latlngs[0].glueindex = this.begin; this._latlngs.slice(-1)[0].glueindex = this.end; - if(this.featureLookup) { + if (this.featureLookup) { if (typeof this.featureLookup[this.begin] === 'undefined') { this.featureLookup[this.begin] = new Array(); } @@ -45,7 +46,7 @@ const extendTaxiSegment = function (taxiwaySegment) { } this.featureLookup[this.begin].push(this); this.featureLookup[this.end].push(this); - this.bidirectional = true; + this.bidirectional = true; } }; taxiwaySegment.__proto__.select = function () { @@ -53,50 +54,50 @@ const extendTaxiSegment = function (taxiwaySegment) { this.updateStyle(); }; taxiwaySegment.__proto__.selectVertex = function (index) { - this.getLatLngs().forEach( element => { - if (Number(element.glueindex) === index) { - if (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'); - } else if (this.icon != null) { - if (this.icon.style != null) { - this.icon.style['background-color'] = 'white'; - } else { - this.setStyle({ color: 'white' }) + this.getLatLngs().forEach(element => { + if (Number(element.glueindex) === index) { + if (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'); + } else if (this.icon != null) { + if (this.icon.style != null) { + this.icon.style['background-color'] = 'white'; + } else { + this.setStyle({ color: 'white' }) + } + } else if (this.options.icon != null) { + if (this.options.icon.style != null) { + this.options.icon.style['background-color'] = 'white'; + } else { + this.options.icon._setIconStyles({ color: 'white' }) + } + } } - } else if (this.options.icon != null) { - if (this.options.icon.style != null) { - this.options.icon.style['background-color'] = 'white'; + 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'; } else { - this.options.icon._setIconStyles({ color: 'white' }) + element.__vertex.setStyle({ color: 'red' }) } - } + } else if (element.__vertex.options.icon != null) { + if (element.__vertex.options.icon.style != null) { + element.__vertex.options.icon.style['background-color'] = 'red'; + } else { + element.__vertex.options.icon._setIconStyles({ 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'; - } else { - element.__vertex.setStyle({ color: 'red' }) - } - } else if (element.__vertex.options.icon != null) { - if (element.__vertex.options.icon.style != null) { - element.__vertex.options.icon.style['background-color'] = 'red'; - } else { - element.__vertex.options.icon._setIconStyles({ color: 'red' }) - } - } - } - }); + }); }; 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) { @@ -111,128 +112,170 @@ const extendTaxiSegment = function (taxiwaySegment) { } else { element.__vertex.options.icon._setIconStyles({ color: 'white' }) } - } + } } }); }; taxiwaySegment.__proto__.addListeners = function () { this.on('click', function (event) { - if (Number(store.default.state.Editable.index) >= 0 && - this.featureLookup[store.default.state.Editable.index] !== undefined) { + 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 => { element.deselect(); }); } event.target.select(); - console.log("Click : " + event.target); - if (store.default.state.Editable.data.arc === undefined || - store.default.state.Editable.data.arc !== event.target.options.attributes) { - if (event.target.options.attributes === undefined) { - event.target.options.attributes = {}; - } - event.target.options.attributes.index = event.target._leaflet_id; + 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) { + 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; - store.default.dispatch('setArc', event.target.options.attributes); - } + this.editLayer.featureLookup[event.target._leaflet_id] = []; + this.featureLookup[event.target._leaflet_id].push(this); + 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); + } + multiarc.isPushBackRoute = assign(event.target.options.attributes.isPushBackRoute); + 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) { this.selectVertex(dragIndex); - console.log('GlueDrag : '+ dragIndex + '\t' + event.target.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.debug('editable:vertex:new ' + event.vertex.getIndex() + '\t' + event.vertex.getLastIndex() + '\t'); - // Find nearest node - let closest = this.editLayer.closestLayerSnap(event.latlng, 5) - let taxiwaySegment = event.latlng.__vertex.editor.feature; - if (taxiwaySegment.options.attributes === undefined) { - taxiwaySegment.options.attributes = { direction: 'bi-directional' }; - } - taxiwaySegment.updateStyle(); - if(event.vertex.getIndex() !== 0 && event.vertex.getIndex() !== event.vertex.getLastIndex()) { - var nextIndex = ++taxiwaySegment.editLayer.groundnetLayerGroup.maxId; - var splitOffNodes = taxiwaySegment.getLatLngs().splice(-1); - var remainingNodes = taxiwaySegment.getLatLngs(); - splitOffNodes.unshift(L.latLng(remainingNodes[1].lat, remainingNodes[1].lng, remainingNodes[1].alt)); - remainingNodes[1]['glueindex'] = nextIndex; - remainingNodes[1].attributes = { index: nextIndex, isOnRunway: 0 }; - taxiwaySegment.options.attributes.end = nextIndex; - splitOffNodes[0]['glueindex'] = nextIndex; - splitOffNodes[0].attributes = { index: nextIndex, isOnRunway: 0 }; - 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.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); + }), + this.on('editable:vertex:new', event => { + console.debug('editable:vertex:new ' + event.vertex.getIndex() + '\t' + event.vertex.getLastIndex() + '\t'); + // Find nearest node + let closest = this.editLayer.closestLayerSnap(event.latlng, 5) + let taxiwaySegment = event.latlng.__vertex.editor.feature; + if (taxiwaySegment.options.attributes === undefined) { + taxiwaySegment.options.attributes = { direction: 'bi-directional' }; } - } 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 }; - // Push Vertex to lookup - this.editLayer.featureLookup[event.latlng.glueindex].push(event.latlng.__vertex); - if (taxiwaySegment.options.attributes.begin === undefined) { - taxiwaySegment.options.attributes.begin = event.latlng['glueindex'] - } else { - taxiwaySegment.options.attributes.end = event.latlng['glueindex'] - } - if (taxiwaySegment.getLatLngs().length === 1) { - taxiwaySegment.begin = closest.glueindex; - } - taxiwaySegment.end = closest.glueindex; - console.log(`Closest : ${closest}`) - } else { - event.vertex.latlng['glueindex'] = ++this.editLayer.groundnetLayerGroup.maxId; - event.vertex.latlng.attributes = { index: event.vertex.latlng.glueindex, isOnRunway: 0 }; - 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); - // taxiwaySegment.editor.refresh(); + taxiwaySegment.updateStyle(); + if (event.vertex.getIndex() !== 0 && event.vertex.getIndex() !== event.vertex.getLastIndex()) { + var nextIndex = ++taxiwaySegment.editLayer.groundnetLayerGroup.maxId; + var splitOffNodes = taxiwaySegment.getLatLngs().splice(-1); + var remainingNodes = taxiwaySegment.getLatLngs(); + splitOffNodes.unshift(L.latLng(remainingNodes[1].lat, remainingNodes[1].lng, remainingNodes[1].alt)); + remainingNodes[1]['glueindex'] = nextIndex; + remainingNodes[1].attributes = { index: nextIndex, isOnRunway: 0 }; + taxiwaySegment.options.attributes.end = nextIndex; + splitOffNodes[0]['glueindex'] = nextIndex; + splitOffNodes[0].attributes = { index: nextIndex, isOnRunway: 0 }; + taxiwaySegment.setLatLngs(remainingNodes); + //taxiwaySegment.editor.refresh(); //taxiwaySegment.editor.reset(); - if (taxiwaySegment.options.attributes.begin === undefined) { - taxiwaySegment.options.attributes.begin = event.vertex.latlng['glueindex'] - taxiwaySegment.begin = event.vertex.latlng.glueindex; - } else if (taxiwaySegment.options.attributes.end === undefined || - (taxiwaySegment.getLatLngs()[taxiwaySegment.getLatLngs().length - 1].glueindex && - Number(taxiwaySegment.getLatLngs()[taxiwaySegment.getLatLngs().length - 1].glueindex) !== taxiwaySegment.options.attributes.end)) { - taxiwaySegment.options.attributes.end = event.vertex.latlng['glueindex'] - taxiwaySegment.end = Number(event.vertex.latlng.glueindex); + 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.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 { + // 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 }; + // Push Vertex to lookup + this.editLayer.featureLookup[event.latlng.glueindex].push(event.latlng.__vertex); + if (taxiwaySegment.options.attributes.begin === undefined) { + taxiwaySegment.options.attributes.begin = event.latlng['glueindex'] + } else { + taxiwaySegment.options.attributes.end = event.latlng['glueindex'] + } + if (taxiwaySegment.getLatLngs().length === 1) { + taxiwaySegment.begin = closest.glueindex; + } + taxiwaySegment.end = closest.glueindex; + console.log(`Closest : ${closest}`) + } else { + event.vertex.latlng['glueindex'] = ++this.editLayer.groundnetLayerGroup.maxId; + event.vertex.latlng.attributes = { index: event.vertex.latlng.glueindex, isOnRunway: 0 }; + 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); + // taxiwaySegment.editor.refresh(); + //taxiwaySegment.editor.reset(); + if (taxiwaySegment.options.attributes.begin === undefined) { + taxiwaySegment.options.attributes.begin = event.vertex.latlng['glueindex'] + taxiwaySegment.begin = event.vertex.latlng.glueindex; + } else if (taxiwaySegment.options.attributes.end === undefined || + (taxiwaySegment.getLatLngs()[taxiwaySegment.getLatLngs().length - 1].glueindex && + Number(taxiwaySegment.getLatLngs()[taxiwaySegment.getLatLngs().length - 1].glueindex) !== taxiwaySegment.options.attributes.end)) { + taxiwaySegment.options.attributes.end = event.vertex.latlng['glueindex'] + taxiwaySegment.end = Number(event.vertex.latlng.glueindex); + } } } - } - //this.splitShape(taxiwaySegment.getLatLngs(), ) - }); + //this.splitShape(taxiwaySegment.getLatLngs(), ) + }); this.on('editable:vertex:deleted', event => { console.debug('editable:vertex:deleted') }); @@ -251,7 +294,7 @@ const extendTaxiSegment = function (taxiwaySegment) { 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(); } }); @@ -268,7 +311,7 @@ const extendTaxiSegment = function (taxiwaySegment) { this.editLayer.featureLookup[event.vertex.latlng.glueindex].forEach store.default.dispatch('setNode', event.vertex.latlng) this.selectVertex(store.default.state.Editable.index) - } + } } }); var dragIndex = -1; @@ -282,7 +325,7 @@ const extendTaxiSegment = function (taxiwaySegment) { 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(); } }); @@ -297,7 +340,7 @@ const extendTaxiSegment = function (taxiwaySegment) { parking[0].selectParking(); } else { this.selectVertex(Number(dragIndex)) - } + } } }); this.on('editable:vertex:dragend', function (event) { @@ -316,29 +359,79 @@ const extendTaxiSegment = function (taxiwaySegment) { 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) { + this.featureLookup[store.default.state.Editable.index] !== undefined) { + this.featureLookup[store.default.state.Editable.index].forEach(element => { + if (element.deselect !== undefined) { element.deselect(); } }); - } - store.default.dispatch('setNode', event.vertex.latlng) + } + store.default.dispatch('setNode', event.vertex.latlng) } var lines = this.featureLookup[event.vertex.latlng.glueindex].filter(n => n instanceof L.Polyline); Vue.default.nextTick(function () { - lines.forEach( line => { + lines.forEach(line => { line.selectVertex(store.default.state.Editable.index) }); }) - } + } } catch (error) { console.error(error); } }); }; + + 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; + } + /** * */ @@ -392,8 +485,38 @@ const 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__.updateStyle = function () { var style = {}; + if(!this.options.attributes) { + return; + } if (this.options.attributes.selected) { style.color = 'red'; } else if (this.options.attributes.isPushBackRoute) { @@ -403,18 +526,18 @@ const extendTaxiSegment = function (taxiwaySegment) { style.color = '#3388ff'; } 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;' } }) + 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); } - - } + + } }; }; diff --git a/src/renderer/loaders/Threshold.js b/src/renderer/loaders/Threshold.js index 9038342..27d3e57 100644 --- a/src/renderer/loaders/Threshold.js +++ b/src/renderer/loaders/Threshold.js @@ -1,141 +1,85 @@ +/* +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 store = require('../store'); +const fs = require('fs'); +const path = require('path'); -var $ = require('jquery'); -L.Threshold = L.Circle.extend({ - select() { - var style = {}; - style['color'] = 'red'; - this.setStyle(style); - }, - 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); +/**http://wiki.openstreetmap.org/wiki/Zoom_levels*/ + + +L.Threshold = L.Marker.extend({ + options: { + zIndexOffset: 20000, + }, + 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 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: `
${this.svg}
`, + })); + + this.update(this.getLatLng()); + console.debug(); + 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(); - } - } - , - { - 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; - }, - () => { - event.target.setStyle({color : '#3388ff'}); - this.unwatch(); - } - , - { - deep: true //add this if u need to watch object properties change etc. - } - ); + } + }, + onAdd : function(map) { + var metersPP = this.metersPerPixel(map.getCenter().lat, map.getZoom()); + this.updateIcon(map); + }, + metersPerPixel: function (latitude, zoomLevel) { + var earthCircumference = 40075017; + var latitudeRadians = latitude * (Math.PI / 180); + return earthCircumference * Math.cos(latitudeRadians) / Math.pow(2, zoomLevel + 8); + }, - } - - }); - - this.on('editable:disable', function (event) { - event.target.removeDirection(); - }); - }, - updateStyle: function () { - - }, - 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] = []; - } - this.featureLookup[this.id].push(this); - }, - - _getLatRadius: function () { - return this._mRadius; - }, - - _getLngRadius: function () { - return this._mRadius; + pixelValue: function (latitude, meters, zoomLevel) { + return meters / metersPerPixel(latitude, zoomLevel); }, + }); -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(); - }); - /* - -*/ - //circle.attributes = { type: n.attr('type'), name: n.attr('name'), radius: Number(n.attr('radius')), airlineCodes: n.attr('airlineCodes'), heading: Number(n.attr('heading')) }; +L.Threshold.addInitHook(function(){ + this.svg = this.stripSVG('FGA_THR.svg'); + this.iconSize = 500; +}); - $.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; +//Builds a marker for a ai or multiplayer aircraft +var threshold = function (n, options) { + var latlon = convert(n.find('lat/text()').text() + " " + n.find('lon/text()').text()); + var heading = n.find('hdg-deg/text()').text(); + + var marker = new L.Threshold([latlon.decimalLatitude, latlon.decimalLongitude], {heading: heading}); + return marker; } -module.exports = threshold; \ No newline at end of file +module.exports = threshold; diff --git a/src/renderer/loaders/Tower.js b/src/renderer/loaders/Tower.js new file mode 100644 index 0000000..0180eac --- /dev/null +++ b/src/renderer/loaders/Tower.js @@ -0,0 +1,84 @@ +/* +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'); + +/**http://wiki.openstreetmap.org/wiki/Zoom_levels*/ + + +L.TowerMarker = L.Marker.extend({ + options: { + zIndexOffset: 10000, + }, + + initialize: function (latlng, options) { + L.Marker.prototype.initialize(latlng, options); + L.Util.setOptions(this, options); + this.svg = this.stripSVG('tower.svg'); + + this.isDragging = false; + }, + updateProperties: function(properties) { + this.heading = properties.heading; + this.updateIcon(); + }, + 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) { + if(map !== null) { + var metersPP = this.metersPerPixel(map.getCenter().lat, map.getZoom()); + if(this._metersPP != metersPP) { + console.debug('Meters per pixel ' + metersPP); + var pixelSize = 32 / metersPP; + var scale = pixelSize/64; + var offset = -(64/2); + this.setIcon(L.divIcon({ + iconSize: 64, + className: 'tower-marker-icon', + html: `
${this.svg}
`, + })); + this._metersPP = metersPP; + } + } + }, + onAdd : function(map) { + var metersPP = this.metersPerPixel(map.getCenter().lat, map.getZoom()); + console.debug('Meters per pixel ' + metersPP); + this.updateIcon(map); + }, + 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); + }, + + +}); + +//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()); + return new L.TowerMarker([latlon.decimalLatitude, latlon.decimalLongitude], options); +} + +module.exports = tower; diff --git a/src/renderer/loaders/groundnet_writer.js b/src/renderer/loaders/groundnet_writer.js index 5fa6463..4fc2c74 100644 --- a/src/renderer/loaders/groundnet_writer.js +++ b/src/renderer/loaders/groundnet_writer.js @@ -60,6 +60,11 @@ function walkPushbackRoute (index, walkedNodes, pushBackNodes) { 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 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'); @@ -201,7 +206,12 @@ var mapParkings = function (o) { 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; } diff --git a/src/renderer/loaders/threshold_loader.js b/src/renderer/loaders/threshold_loader.js index 9b6b5da..31ae532 100644 --- a/src/renderer/loaders/threshold_loader.js +++ b/src/renderer/loaders/threshold_loader.js @@ -50,8 +50,16 @@ exports.readThresholdXML = function (fDir, icao, force) { thresholdNodes.map(n => { - var circle = threshold(n, layerGroup); - features.push(circle); + var icon = threshold(n); + icon.addTo(layerGroup); + + 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(circle); }).sort(); return layerGroup; diff --git a/src/renderer/loaders/tower_loader.js b/src/renderer/loaders/tower_loader.js new file mode 100644 index 0000000..e898bd1 --- /dev/null +++ b/src/renderer/loaders/tower_loader.js @@ -0,0 +1,83 @@ +/* +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("Tower " + towerNodes.length); + + var merged = new Array(); + + var nodesLookup = {}; + featureLookup = []; + + + towerNodes.map(n => { + var towerIcon = tower(n, layerGroup); + towerIcon.addTo(layerGroup); + 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; +}; \ No newline at end of file diff --git a/src/renderer/store/modules/Editable.js b/src/renderer/store/modules/Editable.js index 1c10641..45270bf 100644 --- a/src/renderer/store/modules/Editable.js +++ b/src/renderer/store/modules/Editable.js @@ -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: {}} } 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 = { @@ -62,6 +75,34 @@ const mutations = { Vue.set(state, 'index', arc.index) Vue.set(state, 'type', 'arc') }, + SET_EDIT_MULTI_ARC (state, arc) { + if (arc === undefined) { + return + } + if (!state.data || state.type !== 'multiarc') { + Vue.set(state, 'data', {multiarc: {}}) + } + 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) }, @@ -91,13 +132,25 @@ const mutations = { Vue.set(state.data.parking, 'coords', coords) }, 'SET_EDIT_ARC_NAME' (state, arcName) { - Vue.set(state.data.arc, 'name', 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', Number(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) { - Vue.set(state.data.arc, 'direction', 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) @@ -132,6 +185,12 @@ const actions = { 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)) diff --git a/src/renderer/store/modules/Loading.js b/src/renderer/store/modules/Loading.js index 75a16ee..d6cc7bf 100644 --- a/src/renderer/store/modules/Loading.js +++ b/src/renderer/store/modules/Loading.js @@ -31,9 +31,15 @@ const actions = { 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) } } diff --git a/src/renderer/utils/scan.js b/src/renderer/utils/scan.js index dd951e0..303bfc0 100644 --- a/src/renderer/utils/scan.js +++ b/src/renderer/utils/scan.js @@ -186,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()) { diff --git a/static/FGA_ACT_A_GA.svg b/static/FGA_ACT_A_GA.svg new file mode 100644 index 0000000..ea3bfb2 --- /dev/null +++ b/static/FGA_ACT_A_GA.svg @@ -0,0 +1,2 @@ + + diff --git a/static/FGA_ACT_B_PROP.svg b/static/FGA_ACT_B_PROP.svg new file mode 100644 index 0000000..cfb1b14 --- /dev/null +++ b/static/FGA_ACT_B_PROP.svg @@ -0,0 +1,2 @@ + + diff --git a/static/FGA_ACT_B_SHORTEN.svg b/static/FGA_ACT_B_SHORTEN.svg new file mode 100644 index 0000000..9fffc0e --- /dev/null +++ b/static/FGA_ACT_B_SHORTEN.svg @@ -0,0 +1,2 @@ + + diff --git a/static/FGA_ACT_C.svg b/static/FGA_ACT_C.svg new file mode 100644 index 0000000..1353d30 --- /dev/null +++ b/static/FGA_ACT_C.svg @@ -0,0 +1,3 @@ + + +image/svg+xml diff --git a/static/FGA_ACT_D.svg b/static/FGA_ACT_D.svg new file mode 100644 index 0000000..87895c4 --- /dev/null +++ b/static/FGA_ACT_D.svg @@ -0,0 +1,2 @@ + + diff --git a/static/FGA_ACT_E.svg b/static/FGA_ACT_E.svg new file mode 100644 index 0000000..502a9a4 --- /dev/null +++ b/static/FGA_ACT_E.svg @@ -0,0 +1,2 @@ + + diff --git a/static/FGA_ACT_F.svg b/static/FGA_ACT_F.svg new file mode 100644 index 0000000..fee4f5e --- /dev/null +++ b/static/FGA_ACT_F.svg @@ -0,0 +1,17 @@ + + + + + + +image/svg+xml + + + + + + + + + + diff --git a/static/FGA_THR.svg b/static/FGA_THR.svg new file mode 100644 index 0000000..aa41794 --- /dev/null +++ b/static/FGA_THR.svg @@ -0,0 +1,89 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/static/tower.svg b/static/tower.svg new file mode 100644 index 0000000..93d5265 --- /dev/null +++ b/static/tower.svg @@ -0,0 +1,78 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + +