This commit is contained in:
portree_kid 2020-04-16 08:35:43 +02:00
parent 304269b996
commit 826781647e
11 changed files with 2195 additions and 528 deletions

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"C_Cpp.default.configurationProvider": "go2sh.cmake-integration"
}

2204
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,37 @@
<template>
<section class="ai-layer">
<h1>ai-layer Component</h1>
</section>
</template>
<script lang="js">
import {aiLayer} from '../phi/AILayer'
export default {
/* eslint-disable */
name: 'ai-layer',
props: [],
mounted () {
this.aiLayer = aiLayer({url: this.$store.state.Settings.settings.phi_url})
this.aiLayer.addTo(this.$parent.mapObject)
},
data () {
return {
}
},
methods: {
},
computed: {
}
}
</script>
<style scoped lang="scss">
.ai-layer {
}
</style>

View File

@ -16,6 +16,7 @@
<!--<l-marker :lat-lng="marker"></l-marker>--> <!--<l-marker :lat-lng="marker"></l-marker>-->
<LeafletSidebar></LeafletSidebar> <LeafletSidebar></LeafletSidebar>
<EditBar></EditBar> <EditBar></EditBar>
<AiLayer ref="aiLayer"></AiLayer>
<PavementLayer ref="pavementLayer"></PavementLayer> <PavementLayer ref="pavementLayer"></PavementLayer>
<ThresholdLayer ref="thresholdLayer"></ThresholdLayer> <ThresholdLayer ref="thresholdLayer"></ThresholdLayer>
<l-layer-group layerType="overlay" name="airports" ref="airportLayer"> <l-layer-group layerType="overlay" name="airports" ref="airportLayer">
@ -37,6 +38,7 @@
import 'leaflet/dist/leaflet.css' import 'leaflet/dist/leaflet.css'
import { LMap, LTileLayer, LMarker, LCircle, LLayerGroup, LControl } from 'vue2-leaflet' import { LMap, LTileLayer, LMarker, LCircle, LLayerGroup, LControl } from 'vue2-leaflet'
import LeafletSidebar from './LeafletSidebar' import LeafletSidebar from './LeafletSidebar'
import AiLayer from './AiLayer'
import EditBar from './EditBar' import EditBar from './EditBar'
import EditLayer from './EditLayer' import EditLayer from './EditLayer'
import PavementLayer from './PavementLayer' import PavementLayer from './PavementLayer'
@ -53,7 +55,7 @@
}) })
export default { export default {
name: 'flightgear-map', name: 'flightgear-map',
components: { LMap, LTileLayer, LMarker, LCircle, LeafletSidebar, EditBar, EditLayer, PavementLayer, LLayerGroup, LControl, ThresholdLayer }, components: { LMap, LTileLayer, LMarker, LCircle, LeafletSidebar, AiLayer, EditBar, EditLayer, PavementLayer, LLayerGroup, LControl, ThresholdLayer },
props: [], props: [],
mounted () { mounted () {
this.$store.dispatch('getAirports') this.$store.dispatch('getAirports')

View File

@ -50,6 +50,14 @@
<directory-select @input="testDirectorySelect"></directory-select> <directory-select @input="testDirectorySelect"></directory-select>
</el-col> </el-col>
</el-row> </el-row>
<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-row>
<el-col :span="7" class="label">Author : </el-col> <el-col :span="7" class="label">Author : </el-col>
<el-col :span="17"> <el-col :span="17">
@ -99,6 +107,16 @@
this.$store.commit('SET_EMAIL', newValue) this.$store.commit('SET_EMAIL', newValue)
} }
}, },
phi_url: {
// getter
get: function () {
return this.$store.state.Settings.settings.phi_url
},
// setter
set: function (newValue) {
this.$store.commit('SET_PHI_URL', newValue)
}
},
flightgear_directory: function () { flightgear_directory: function () {
return this.$store.state.Settings.settings.flightgearDirectory return this.$store.state.Settings.settings.flightgearDirectory
}, },

View File

@ -39,8 +39,8 @@ exports.readGroundnetXML = function (fDir, icao, force) {
var f = path.join(fDir, icao[0], icao[1], icao[2], icao + '.groundnet.xml'); 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'); var fNew = path.join(fDir, icao[0], icao[1], icao[2], icao + '.groundnet.new.xml');
if (f == null || !fs.existsSync(f)) if (f == null || (!fs.existsSync(f) && force)|| (!fs.existsSync(f) && !fs.existsSync(fNew) ))
return; return layerGroup;
if (fNew != null && fs.existsSync(fNew) && !force) { if (fNew != null && fs.existsSync(fNew) && !force) {
f = fNew; f = fNew;
} }

268
src/renderer/phi/AILayer.js Normal file
View File

@ -0,0 +1,268 @@
/* eslint-disable */
const $ = require('jquery');
const aiAircraftMarker = require('./AircraftMarker').default;
var aiLayerLookup = {};
/**http://wiki.openstreetmap.org/wiki/Zoom_levels*/
var metersPerPixel = function (latitude, zoomLevel) {
var earthCircumference = 40075017;
var latitudeRadians = latitude * (Math.PI / 180);
return earthCircumference * Math.cos(latitudeRadians) / Math.pow(2, zoomLevel + 8);
};
var pixelValue = function (latitude, meters, zoomLevel) {
return meters / metersPerPixel(latitude, zoomLevel);
};
function mapSGPropertyNode(node) {
var o = {};
node.children.forEach(child => {
if (child.nChildren > 0) {
o[child['name']] = mapSGPropertyNode(child);
} else {
switch (child.type) {
case "string":
o[child['name']] = child.value;
break;
case "bool":
o[child['name']] = Boolean(child.value);
break;
case "double":
case "int":
o[child['name']] = child.value;
break;
default:
break;
}
}
});
o.name = node.name;
o.index = node.index;
o.path = node.path;
return o;
}
(function (factory) {
if (typeof define === "function" && define.amd) {
// AMD. Register as an anonymous module.
define([
'knockout', 'leaflet', 'props'
], factory);
} else {
// Browser globals
factory();
}
}(function (ko, leaflet, SGPropertyNode) {
var AITypeToCssClassMap = {
aircraft: "ai-aircraft-marker-icon",
multiplayer: "mp-aircraft-marker-icon"
}
function formatFL(num) {
return "F" + ("000" + (num / 100).toFixed(0)).substr(-3, 3);
}
function ViewModel(h, l) {
var self = this;
self.heading = h;
self.labelLines = l;
}
L.AILayer = L.GeoJSON.extend({
options: {
pointToLayer: function (feature, latlng) {
var options = {
title: feature.properties.callsign,
alt: feature.properties.callsign,
riseOnHover: true,
draggable: true,
};
var aiMarker = null;
if (feature.properties.type == "aircraft") {
if (aiLayerLookup[feature.id] === undefined) {
aiMarker = aiAircraftMarker(latlng, feature.properties);
aiMarker.on('add', function (e) {
});
aiMarker.options.draggable = true;
//We can't drag multiplayer
if (feature.properties.type == "aircraft") {
aiMarker.on('dragstart', function (evt) {
evt.target.isDragging = true;
});
aiMarker.on('dragend', function (evt) {
if (evt.target !== this)
return;
var pos = evt.target.getLatLng();
var props = {
name: "position",
children: [
{
name: "latitude-deg",
value: pos.lat,
}, {
name: "longitude-deg",
value: pos.lng,
},
],
};
$.post("json" + feature.properties.path, JSON.stringify(props));
evt.target.isDragging = false;
});
}
aiLayerLookup[feature.id] = aiMarker;
return aiMarker;
} else {
var aiMarker = aiLayerLookup[feature.id];
aiMarker.setLatLng({lat: feature.geometry.coordinates[1],
lng: feature.geometry.coordinates[0]});
aiMarker.updateProperties(feature.properties);
return aiMarker;
}
}
},
// onEachFeature : function(feature, layer) {
// },
},
onAdd: function (map) {
L.GeoJSON.prototype.onAdd.call(this, map);
this.update(++this.updateId);
},
onRemove: function (map) {
this.updateId++;
L.GeoJSON.prototype.onRemove.call(this, map);
},
stop: function () {
this.updateId++;
},
// Refresh method called every 10s to reload other aircraft
updateId: 0,
update: function (id) {
var self = this;
if (self.updateId != id)
return;
var url = this.options.url + "/json/ai/models?d=99";
var jqxhr = $.get(url).done(function (data) {
try {
self.clearLayers();
self.addData(self.aiPropsToGeoJson(data, [
"aircraft", "multiplayer", "carrier"
], self._map.getBounds()));
} catch (error) {
console.error(error);
}
}).fail(function (a, b) {
self.updateId++;
// alert('failed to load AI data');
}).always(function () {
});
if (self.updateId == id) {
setTimeout(function () {
self.update(id)
}, 10000);
}
},
// Builds the GeoJSON representation of AI, Multiplayer and Carriers
aiPropsToGeoJson: function (props, types, bounds) {
var geoJSON = {
type: "FeatureCollection",
features: [],
};
types.forEach(function (type) {
props.children.filter(childObject => childObject.path.includes(type))
.map(mapSGPropertyNode)
.forEach(function (child) {
if (!child["valid"])
return;
var path = child.path;
var position = child.position;
var orientation = child.orientation;
var velocities = child.velocities;
var lon = position["longitude-deg"];
var lat = position["latitude-deg"];
if (false == bounds.contains(L.latLng(lat, lon))) {
return;
}
var alt = position["altitude-ft"];
var heading = orientation["true-heading-deg"];
var id = child.id;
var callsign = "";
var name = "";
var speed = 0;
var departureAirportId = "";
var arrivalAirportId = "";
if (type == "multiplayer") {
name = child["sim"]["model"]["path"];
}
if (type == "carrier") {
callsign = child["sign"];
name = child["name"];
speed = velocities["speed-kts"];
} else {
callsign = child["callsign"];
speed = velocities["true-airspeed-kt"];
departureAirportId = child["departure-airport-id"];
arrivalAirportId = child["arrival-airport-id"];
}
geoJSON.features.push({
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
lon, lat, alt.toFixed(0)
],
},
"id": id,
"properties": {
"path": path,
"type": type,
"heading": heading.toFixed(0),
"speed": speed.toFixed(0),
"callsign": callsign,
"name": name,
"departureAirportId": departureAirportId,
"arrivalAirportId": arrivalAirportId,
},
});
});
});
return geoJSON;
},
});
L.aiLayer = function (options) {
return new L.AILayer(null, options);
}
}));
export function aiLayer(options) {
return new L.AILayer(null, options);
}

View File

@ -0,0 +1,87 @@
/* eslint-disable */
const fs = require('fs');
const path = require('path');
/**http://wiki.openstreetmap.org/wiki/Zoom_levels*/
var metersPerPixel = function (latitude, zoomLevel) {
var earthCircumference = 40075017;
var latitudeRadians = latitude * (Math.PI / 180);
return earthCircumference * Math.cos(latitudeRadians) / Math.pow(2, zoomLevel + 8);
};
var pixelValue = function (latitude, meters, zoomLevel) {
return meters / metersPerPixel(latitude, zoomLevel);
};
function stripSVG(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];
}
const airLinerSVG = stripSVG('Airplane_silhouette.svg');
const gaSVG = stripSVG('Black_aircraft_icon.svg');
L.AircraftMarker = L.Marker.extend({
options: {
zIndexOffset: 10000,
},
initialize: function (latlng, options) {
L.Marker.prototype.initialize(latlng, options);
L.Util.setOptions(this, options);
this.heading = options.heading;
this.updateIcon();
this.isDragging = false;
},
updateProperties: function(properties) {
this.heading = properties.heading;
this.updateIcon();
},
updateIcon : function() {
if(this._map !== undefined && this._map !== null) {
var metersPP = metersPerPixel(this._map.getCenter().lat, this._map.getZoom());
console.log(metersPP);
var scale = 0.07 / metersPP;
this.setIcon(L.divIcon({
iconSize: null,
className: 'aircraft-marker-icon',
html: `<div style=\'transform: translateX(-10px) translateY(-10px); height: 20px; width: 20px; border: 1px red\'>${airLinerSVG}</div>`,
}));
this.getElement().children.item(0).children.item(0).style = `transform: translateX(-200px) translateY(-200px) scale(${scale},${scale}) rotate(${(this.heading)-45}deg)`;
}
else {
this.setIcon(L.divIcon({
iconSize: null,
className: 'aircraft-marker-icon',
html: `<div style=\'transform: rotate(${this.heading}deg) scale(0.001,0.001) \'>${airLinerSVG}</div>`,
}));
}
},
onAdd : function(map) {
var metersPP = metersPerPixel(map.getCenter().lat, map.getZoom());
console.log(metersPP);
console.log(this);
this.updateIcon();
},
});
//Builds a marker for a ai or multiplayer aircraft
module.exports.default = function (latlng, options) {
return new L.AircraftMarker(latlng, options);
}
/*
var l1 = feature.properties.callsign,
l2 = feature.properties.heading + 'T ' + feature.properties.speed + 'KTAS ' +
formatFL(feature.geometry.coordinates[2]),
l3 = feature.properties.departureAirportId + ' -> ' + feature.properties.arrivalAirportId;
*/

View File

@ -1,5 +1,6 @@
/* eslint-disable */
const state = { const state = {
settings: { flightgearDirectory: '.', testDirectory: '.', email: 'x' }, settings: { flightgearDirectory: '.', testDirectory: '.', email: 'x', phi_url: 'http://localhost:8080' },
zoom: 14, zoom: 14,
center: [47.413220, -1.219482], center: [47.413220, -1.219482],
bounds: undefined, bounds: undefined,
@ -32,10 +33,13 @@ const mutations = {
'SET_EMAIL' (state, email) { 'SET_EMAIL' (state, email) {
state.settings.email = email state.settings.email = email
}, },
'SET_PHI_URL' (state, phi_url) {
state.settings.phi_url = phi_url
},
'ADD_WIP' (state, airport) { 'ADD_WIP' (state, airport) {
const item = state.wip.find((e) => e.icao === airport.icao) const item = state.wip.find((e) => e.icao === airport.icao)
airport.time = Date.now() airport.time = Date.now()
if (item === null) { if (item === null || item === undefined) {
state.wip.push(airport) state.wip.push(airport)
} else { } else {
Object.assign(item, airport) Object.assign(item, airport)

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.0"
width="400"
height="400">
<defs
id="defs4" />
<g
transform="translate(-147.06733,-109.44716)">
<path
d="M 157.98695,184.38488 L 173.37483,168.20017 C 182.38616,159.18884 197.56012,162.31477 197.56012,162.31477 L 242.58958,168.47612 L 265.39575,146.16045 C 277.41087,134.35989 288.26269,152.4142 283.54247,158.63631 L 271.83305,172.24635 L 320.32641,181.22794 L 336.78707,162.03882 C 354.38063,141.01237 367.47041,159.95529 359.53185,171.11218 L 348.89521,184.56906 L 421.75804,194.07153 C 484.40828,133.78139 509.98537,108.77262 526.46939,123.63021 C 543.05967,138.5836 513.71315,168.38877 456.64135,227.17701 L 467.00204,302.24678 L 482.26714,289.52597 C 491.27847,282.01653 507.27901,294.06392 490.75822,309.72648 L 469.76089,329.52825 L 478.61969,378.66527 L 491.73923,368.58052 C 503.32523,359.35463 517.39476,371.55518 501.7322,388.29052 L 480.88803,409.28786 C 480.02981,409.93153 487.69305,452.38631 487.69305,452.38631 C 492.41327,473.19821 480.67347,480.80195 480.67347,480.80195 L 466.35838,493.27782 L 411.97962,339.67439 C 407.47395,326.15738 396.0546,311.47862 376.97351,313.22076 C 366.8894,314.29354 341.41552,331.49026 337.98263,335.56682 L 279.00579,392.27531 C 277.5039,393.34809 288.07915,465.99635 288.07915,465.99635 C 288.07915,468.14191 269.38054,492.66454 269.38054,492.66454 L 232.01433,426.14725 L 213.56128,434.7301 L 224.35108,417.93211 L 157.06733,379.9526 L 182.29502,361.49956 C 194.31014,364.28878 257.3034,371.36975 258.59073,370.72608 C 258.59073,370.72608 309.88762,319.85344 312.81633,316.77643 C 329.76623,298.96831 335.46935,292.31456 338.04402,283.51778 C 340.6208,274.71377 336.23117,261.81195 309.62838,245.4769 C 272.93937,222.94855 157.98695,184.38488 157.98695,184.38488 z"
id="path3166"
style="fill:#000000;stroke:none;" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -0,0 +1,68 @@
<?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"
version="1.0"
width="20"
height="20"
id="svg2"
sodipodi:version="0.32"
inkscape:version="0.46"
sodipodi:docname="Aero-stub_img.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape">
<metadata
id="metadata16">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
inkscape:window-height="675"
inkscape:window-width="640"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
guidetolerance="10.0"
gridtolerance="10.0"
objecttolerance="10.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base"
showgrid="false"
inkscape:zoom="11.55"
inkscape:cx="16.576935"
inkscape:cy="10.772134"
inkscape:window-x="110"
inkscape:window-y="110"
inkscape:current-layer="svg2" />
<defs
id="defs4">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 10 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="20 : 10 : 1"
inkscape:persp3d-origin="10 : 6.6666667 : 1"
id="perspective18" />
<filter
id="filter">
<feGaussianBlur
stdDeviation="0.4858"
id="feGaussianBlur7" />
</filter>
</defs>
<path
style="fill:#000000"
id="path13"
d="M 4.7932777,4.7812376 C 4.7259064,4.8486085 4.7323964,4.9347702 4.9650313,5.4373336 C 4.9924894,5.4966515 5.1453716,5.7138571 5.1453716,5.7138571 C 5.1453723,5.7138561 5.0426847,5.8268489 5.0148394,5.8546943 C 4.9610053,5.9085284 4.9361984,6.0293335 4.958161,6.1243469 C 5.026297,6.4191302 5.8480608,7.5947712 6.3081405,8.0548517 C 6.593652,8.3403629 6.7408456,8.5354068 6.730653,8.6147666 C 6.7220521,8.6817367 6.6138788,8.9698607 6.4901987,9.2536889 C 6.2719706,9.7544933 6.1902268,9.8530093 3.7284084,12.592571 C 1.7788774,14.76205 1.1823532,15.462131 1.1469587,15.620578 C 1.0488216,16.059908 1.4289737,16.468046 2.4110617,16.977428 L 2.9177343,17.24021 C 2.9177343,17.24021 10.306553,11.950215 10.306553,11.950215 L 14.736066,15.314858 L 14.634732,15.495198 C 14.578751,15.594046 14.11587,16.171307 13.60593,16.778194 C 13.095992,17.385083 12.673006,17.939029 12.666441,18.009665 C 12.640049,18.293626 13.777085,19.186772 13.947719,19.016137 C 14.217037,18.74682 15.346696,17.884968 15.441971,17.875697 C 15.509995,17.869079 16.481025,17.128624 16.810843,16.798805 C 17.140662,16.468987 17.881117,15.497956 17.887735,15.429933 C 17.897006,15.334658 18.758859,14.204999 19.028176,13.93568 C 19.198811,13.765045 18.305664,12.62801 18.021702,12.654403 C 17.951067,12.660967 17.397123,13.083953 16.790233,13.593891 C 16.183346,14.103831 15.606085,14.566712 15.507236,14.622693 L 15.326897,14.724027 L 11.962253,10.294514 C 11.962253,10.294514 17.252249,2.9056938 17.25225,2.9056938 L 16.989466,2.3990218 C 16.480084,1.416933 16.071947,1.0367811 15.632617,1.1349189 C 15.474169,1.1703136 14.774089,1.7668355 12.60461,3.7163677 C 9.8650471,6.1781859 9.7665321,6.2599294 9.2657298,6.4781579 C 8.9819013,6.601838 8.6937782,6.7100098 8.6268071,6.7186131 C 8.5474478,6.7288044 8.352405,6.5816098 8.0668925,6.2960996 C 7.6068129,5.8360191 6.4311712,5.0142561 6.1363875,4.9461203 C 6.0413739,4.9241577 5.92057,4.9489642 5.8667352,5.0027982 C 5.8388891,5.0306446 5.7276147,5.1316136 5.7276147,5.1316136 C 5.7276147,5.1316136 5.5104099,4.9787304 5.4510923,4.9512732 C 4.9485278,4.7186391 4.8606505,4.7138647 4.7932777,4.7812376 z" />
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB