'use strict' ;
const path = require ( 'path' ) ;
const fs = require ( 'fs' ) ;
const ol = require ( 'openlayers' ) ;
const xml2js = require ( 'xml2js' ) ;
const Store = require ( 'electron-store' ) ;
const store = new Store ( ) ;
const { dialog } = require ( "@electron/remote" ) ;
const MSPChainerClass = require ( './../js/msp/MSPchainer' ) ;
const mspHelper = require ( './../js/msp/MSPHelper' ) ;
const MSPCodes = require ( './../js/msp/MSPCodes' ) ;
const MSP = require ( './../js/msp' ) ;
const mspQueue = require ( './../js/serial_queue' ) ;
const { GUI , TABS } = require ( './../js/gui' ) ;
const FC = require ( './../js/fc' ) ;
const CONFIGURATOR = require ( './../js/data_storage' ) ;
const i18n = require ( './../js/localization' ) ;
const { globalSettings } = require ( './../js/globalSettings' ) ;
const MWNP = require ( './../js/mwnp' ) ;
const Waypoint = require ( './../js/waypoint' )
const WaypointCollection = require ( './../js/waypointCollection' ) ;
const Safehome = require ( './../js/safehome' ) ;
const SafehomeCollection = require ( './../js/safehomeCollection' ) ;
const { ApproachDirection , FwApproach } = require ( './../js/fwApproach' ) ;
const FwApproachCollection = require ( './../js/fwApproachCollection' ) ;
const SerialBackend = require ( './../js/serial_backend' ) ;
const { distanceOnLine , wrap _360 , calculate _new _cooridatnes } = require ( './../js/helpers' ) ;
const Plotly = require ( './../js/libraries/plotly-latest.min' ) ;
const interval = require ( './../js/intervals' ) ;
var MAX _NEG _FW _LAND _ALT = - 2000 ; // cm
// Dictionary of Parameter 1,2,3 definition depending on type of action selected (refer to MWNP.WPTYPE)
var dictOfLabelParameterPoint = {
1 : { parameter1 : 'Speed (cm/s)' , parameter2 : '' , parameter3 : 'Sea level Ref' } ,
2 : { parameter1 : '' , parameter2 : '' , parameter3 : '' } ,
3 : { parameter1 : 'Wait time (s)' , parameter2 : 'Speed (cm/s)' , parameter3 : 'Sea level Ref' } ,
4 : { parameter1 : 'Force land (non zero)' , parameter2 : '' , parameter3 : '' } ,
5 : { parameter1 : '' , parameter2 : '' , parameter3 : '' } ,
6 : { parameter1 : 'Target WP number' , parameter2 : 'Number of repeat (-1: infinite)' , parameter3 : '' } ,
7 : { parameter1 : 'Heading (deg)' , parameter2 : '' , parameter3 : '' } ,
8 : { parameter1 : '' , parameter2 : '' , parameter3 : 'Sea level Ref' }
} ;
var waypointOptions = [ 'JUMP' , 'SET_HEAD' , 'RTH' ] ;
////////////////////////////////////
//
// Tab mission control block
//
////////////////////////////////////
TABS . mission _control = { } ;
TABS . mission _control . isYmapLoad = false ;
TABS . mission _control . initialize = function ( callback ) {
let cursorInitialized = false ;
let curPosStyle ;
let curPosGeo ;
let rthGeo ;
let breadCrumbLS ;
let breadCrumbFeature ;
let breadCrumbStyle ;
let breadCrumbSource ;
let breadCrumbVector ;
let textStyle ;
let textFeature ;
var textGeom ;
let isOffline = false ;
let selectedSafehome ;
let $safehomeContentBox ;
let $waypointOptionsTableBody ;
let settings = { speed : 0 , alt : 5000 , safeRadiusSH : 50 , fwApproachAlt : 60 , fwLandAlt : 5 , maxDistSH : 0 , fwApproachLength : 0 , fwLoiterRadius : 0 , bingDemModel : false } ;
if ( GUI . active _tab != 'mission_control' ) {
GUI . active _tab = 'mission_control' ;
}
if ( CONFIGURATOR . connectionValid ) {
var loadChainer = new MSPChainerClass ( ) ;
loadChainer . setChain ( [
mspHelper . getMissionInfo ,
//mspHelper.loadWaypoints,
mspHelper . loadSafehomes ,
mspHelper . loadFwApproach ,
function ( callback ) {
mspHelper . getSetting ( "nav_fw_land_approach_length" ) . then ( ( data ) => {
settings . fwApproachLength = parseInt ( data . value ) ;
} ) . then ( callback ) ;
} ,
function ( callback ) {
mspHelper . getSetting ( "safehome_max_distance" ) . then ( ( data ) => {
settings . maxDistSH = parseInt ( data . value ) / 100 ;
} ) . then ( callback ) ;
} ,
function ( callback ) {
mspHelper . getSetting ( ( "nav_fw_loiter_radius" ) ) . then ( ( data ) => {
settings . fwLoiterRadius = parseInt ( data . value ) ;
} ) . then ( callback ) ;
}
] ) ;
loadChainer . setExitPoint ( loadHtml ) ;
loadChainer . execute ( ) ;
} else {
// FC not connected, load page anyway
loadHtml ( ) ;
if ( ! FC . FW _APPROACH ) {
FC . FW _APPROACH = new FwApproachCollection ( ) ;
}
if ( ! FC . SAFEHOMES ) {
FC . SAFEHOMES = new SafehomeCollection ( ) ;
}
for ( let i = 0 ; i < FC . FW _APPROACH . getMaxFwApproachCount ( ) ; i ++ ) {
FC . FW _APPROACH . put ( new FwApproach ( i ) ) ;
}
}
function loadHtml ( ) {
GUI . load ( path . join ( _ _dirname , "mission_control.html" ) , process _html ) ;
}
function process _html ( ) {
// set GUI for offline operations
if ( ! CONFIGURATOR . connectionValid ) {
$ ( '#infoAvailablePoints' ) . hide ( ) ;
$ ( '#infoMissionValid' ) . hide ( ) ;
$ ( '#loadMissionButton' ) . hide ( ) ;
$ ( '#saveMissionButton' ) . hide ( ) ;
$ ( '#loadEepromMissionButton' ) . hide ( ) ;
$ ( '#saveEepromMissionButton' ) . hide ( ) ;
isOffline = true ;
}
$safehomeContentBox = $ ( '#SafehomeContentBox' ) ;
$waypointOptionsTableBody = $ ( '#waypointOptionsTableBody' ) ;
if ( typeof require !== "undefined" ) {
loadSettings ( ) ;
// let the dom load finish, avoiding the resizing of the map
setTimeout ( initMap , 200 ) ;
if ( ! isOffline ) {
setTimeout ( ( ) => {
if ( FC . SAFEHOMES . safehomeCount ( ) >= 1 ) {
updateSelectedShAndFwAp ( 0 ) ;
} else {
selectedSafehome = null ;
selectedFwApproachSh = null ;
}
renderSafehomesOnMap ( ) ;
updateSafehomeInfo ( ) ;
} , 500 ) ;
}
} else {
$ ( '#missionMap, #missionControls' ) . hide ( ) ;
$ ( '#notLoadMap' ) . show ( ) ;
}
i18n . localize ( ) ;
function get _raw _gps _data ( ) {
MSP . send _message ( MSPCodes . MSP _RAW _GPS , false , false , get _comp _gps _data ) ;
}
function get _comp _gps _data ( ) {
MSP . send _message ( MSPCodes . MSP _COMP _GPS , false , false , get _altitude _data ) ;
}
function get _altitude _data ( ) {
MSP . send _message ( MSPCodes . MSP _ALTITUDE , false , false , get _attitude _data ) ;
}
function get _attitude _data ( ) {
MSP . send _message ( MSPCodes . MSP _ATTITUDE , false , false , update _gpsTrack ) ;
}
function update _gpsTrack ( ) {
let lat = FC . GPS _DATA . lat / 10000000 ;
let lon = FC . GPS _DATA . lon / 10000000 ;
//Update map
if ( FC . GPS _DATA . fix >= 2 ) {
if ( ! cursorInitialized ) {
cursorInitialized = true ;
/////////////////////////////////////
//create layer for current position
curPosStyle = new ol . style . Style ( {
image : new ol . style . Icon ( ( {
anchor : [ 0.5 , 0.5 ] ,
opacity : 1 ,
scale : 0.6 ,
src : './images/icons/icon_mission_airplane.png'
} ) )
} ) ;
let currentPositionLayer ;
curPosGeo = new ol . geom . Point ( ol . proj . fromLonLat ( [ lon , lat ] ) ) ;
let curPosFeature = new ol . Feature ( {
geometry : curPosGeo
} ) ;
curPosFeature . setStyle ( curPosStyle ) ;
let vectorSource = new ol . source . Vector ( {
features : [ curPosFeature ]
} ) ;
currentPositionLayer = new ol . layer . Vector ( {
source : vectorSource
} ) ;
///////////////////////////
//create layer for RTH Marker
let rthStyle = new ol . style . Style ( {
image : new ol . style . Icon ( ( {
anchor : [ 0.5 , 1.0 ] ,
opacity : 1 ,
scale : 0.5 ,
src : './images/icons/cf_icon_RTH.png'
} ) )
} ) ;
rthGeo = new ol . geom . Point ( ol . proj . fromLonLat ( [ 90 , 0 ] ) ) ;
let rthFeature = new ol . Feature ( {
geometry : rthGeo
} ) ;
rthFeature . setStyle ( rthStyle ) ;
let rthVector = new ol . source . Vector ( {
features : [ rthFeature ]
} ) ;
let rthLayer = new ol . layer . Vector ( {
source : rthVector
} ) ;
//////////////////////////////
//create layer for bread crumbs
breadCrumbLS = new ol . geom . LineString ( [ ol . proj . fromLonLat ( [ lon , lat ] ) , ol . proj . fromLonLat ( [ lon , lat ] ) ] ) ;
breadCrumbStyle = new ol . style . Style ( {
stroke : new ol . style . Stroke ( {
color : '#ffcc33' ,
width : 6
} )
} ) ;
breadCrumbFeature = new ol . Feature ( {
geometry : breadCrumbLS
} ) ;
breadCrumbFeature . setStyle ( breadCrumbStyle ) ;
breadCrumbSource = new ol . source . Vector ( {
features : [ breadCrumbFeature ]
} ) ;
breadCrumbVector = new ol . layer . Vector ( {
source : breadCrumbSource
} ) ;
/////////////////////////////
//create layer for heading, alt, groundspeed
textGeom = new ol . geom . Point ( [ 0 , 0 ] ) ;
textStyle = new ol . style . Style ( {
text : new ol . style . Text ( {
font : 'bold 35px Calibri,sans-serif' ,
fill : new ol . style . Fill ( { color : '#fff' } ) ,
offsetX : map . getSize ( ) [ 0 ] - 260 ,
offsetY : 80 ,
textAlign : 'left' ,
backgroundFill : new ol . style . Fill ( { color : '#000' } ) ,
stroke : new ol . style . Stroke ( {
color : '#fff' , width : 2
} ) ,
text : 'H: XXX\nAlt: XXXm\nSpeed: XXXcm/s'
} )
} ) ;
textFeature = new ol . Feature ( {
geometry : textGeom
} ) ;
textFeature . setStyle ( textStyle ) ;
var textSource = new ol . source . Vector ( {
features : [ textFeature ]
} ) ;
var textVector = new ol . layer . Vector ( {
source : textSource
} ) ;
map . addLayer ( rthLayer ) ;
map . addLayer ( breadCrumbVector ) ;
map . addLayer ( currentPositionLayer ) ;
map . addControl ( textVector ) ;
}
let gpsPos = ol . proj . fromLonLat ( [ lon , lat ] ) ;
curPosGeo . setCoordinates ( gpsPos ) ;
breadCrumbLS . appendCoordinate ( gpsPos ) ;
var coords = breadCrumbLS . getCoordinates ( ) ;
if ( coords . length > 100 )
{
coords . shift ( ) ;
breadCrumbLS . setCoordinates ( coords ) ;
}
curPosStyle . getImage ( ) . setRotation ( ( FC . SENSOR _DATA . kinematics [ 2 ] / 360.0 ) * 6.28318 ) ;
//update data text
textGeom . setCoordinates ( map . getCoordinateFromPixel ( [ 0 , 0 ] ) ) ;
let tmpText = textStyle . getText ( ) ;
tmpText . setText ( ' \n' +
'H: ' + FC . SENSOR _DATA . kinematics [ 2 ] +
'\nAlt: ' + FC . SENSOR _DATA . altitude +
'm\nSpeed: ' + FC . GPS _DATA . speed + 'cm/s\n' +
'Dist: ' + FC . GPS _DATA . distanceToHome + 'm' ) ;
}
}
/ *
* enable data pulling if not offline
* Refreshing data at 5 Hz ... Could slow this down if we have performance issues
* /
if ( ! isOffline )
{
interval . add ( 'gps_pull' , function gps _update ( ) {
// avoid usage of the GPS commands until a GPS sensor is detected for targets that are compiled without GPS support.
if ( ! SerialBackend . have _sensor ( FC . CONFIG . activeSensors , 'gps' ) ) {
update _gpsTrack ( ) ;
return ;
}
get _raw _gps _data ( ) ;
} , 200 ) ;
}
GUI . content _ready ( callback ) ;
}
///////////////////////////////////////////////
//
// define & init parameters
//
///////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////
// define & init parameters for Map Layer
//////////////////////////////////////////////////////////////////////////////////////////////
var markers = [ ] ; // Layer for Waypoints
var lines = [ ] ; // Layer for lines between waypoints
var safehomeMarkers = [ ] ; // layer for Safehome points
var safehomeMarkers = [ ] ; // layer for Safehome points
var approachLayers = [ ] // Layers for FW approach
var safehomeMarkers = [ ] ; // layer for Safehome points
var approachLayers = [ ] // Layers for FW approach
var map ;
//////////////////////////////////////////////////////////////////////////////////////////////
// define & init parameters for Selected Marker
//////////////////////////////////////////////////////////////////////////////////////////////
var selectedMarker = null ;
var selectedFeature = null ;
var tempMarker = null ;
var disableMarkerEdit = false ;
var selectedFwApproachWp = null ;
var selectedFwApproachSh = null ;
var lockShExclHeading = false ;
//////////////////////////////////////////////////////////////////////////////////////////////
// define & init parameters for default Settings
//////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////
// define & init Waypoints parameters
//////////////////////////////////////////////////////////////////////////////////////////////
var mission = new WaypointCollection ( ) ;
//////////////////////////////////////////////////////////////////////////////////////////////
// define & init Multi Mission parameters
//////////////////////////////////////////////////////////////////////////////////////////////
var multimission = new WaypointCollection ( ) ;
var multimissionCount = 0 ;
var maxMultimissionCount = 9 ;
//////////////////////////////////////////////////////////////////////////////////////////////
// define & init home parameters
//////////////////////////////////////////////////////////////////////////////////////////////
var HOME = new Waypoint ( 0 , 0 , 0 , 0 ) ;
var homeMarkers = [ ] ; // layer for home point
//////////////////////////////////////////////////////////////////////////////////////////////
// define & init Safehome parameters
//////////////////////////////////////////////////////////////////////////////////////////////
//var FC.SAFEHOMES = new SafehomeCollection(); // TO COMMENT FOR RELEASE : DECOMMENT FOR DEBUG
//FC.SAFEHOMES.inflate(); // TO COMMENT FOR RELEASE : DECOMMENT FOR DEBUG
//var safehomeRangeRadius = 200; //meters
//var safehomeSafeRadius = 50; //meters
/////////////////////////////////////////////
//
// Reinit Jquery Form
//
/////////////////////////////////////////////
function clearEditForm ( ) {
$ ( '#pointLat' ) . val ( '' ) ;
$ ( '#pointLon' ) . val ( '' ) ;
$ ( '#pointAlt' ) . val ( '' ) ;
$ ( '#pointP1' ) . val ( '' ) ;
$ ( '#pointP2' ) . val ( '' ) ;
$ ( '#pointP3Alt' ) . val ( '' ) ;
$ ( '#missionDistance' ) . text ( 0 ) ;
$ ( '#MPeditPoint' ) . fadeOut ( 300 ) ;
}
function clearFilename ( ) {
$ ( '#missionFilename' ) . text ( '' ) ;
}
/////////////////////////////////////////////
//
// Manage Settings
//
/////////////////////////////////////////////
function loadSettings ( ) {
var missionPlannerSettings = store . get ( 'missionPlannerSettings' , false ) ;
if ( missionPlannerSettings ) {
if ( ! missionPlannerSettings . fwApproachLength && settings . fwApproachLength ) {
missionPlannerSettings . fwApproachLength = settings . fwApproachLength ;
missionPlannerSettings . maxDistSH = settings . maxDistSH ;
missionPlannerSettings . fwLoiterRadius = settings . fwLoiterRadius ;
}
saveSettings ( ) ;
settings = missionPlannerSettings ;
}
refreshSettings ( ) ;
}
function saveSettings ( ) {
store . set ( 'missionPlannerSettings' , settings ) ;
}
function refreshSettings ( ) {
$ ( '#MPdefaultPointAlt' ) . val ( String ( settings . alt ) ) ;
$ ( '#MPdefaultPointSpeed' ) . val ( String ( settings . speed ) ) ;
$ ( '#MPdefaultSafeRangeSH' ) . val ( String ( settings . safeRadiusSH ) ) ;
$ ( '#MPdefaultFwApproachAlt' ) . val ( String ( settings . fwApproachAlt ) ) ;
$ ( '#MPdefaultLandAlt' ) . val ( String ( settings . fwLandAlt ) ) ;
}
function closeSettingsPanel ( ) {
$ ( '#missionPlannerSettings' ) . hide ( ) ;
}
/////////////////////////////////////////////
//
// Manage Safehome
//
/////////////////////////////////////////////
function closeSafehomePanel ( ) {
$ ( '#missionPlannerSafehome' ) . hide ( ) ;
cleanSafehomeLayers ( ) ;
}
function checkApproachAltitude ( altitude , isSeaLevelRef , sealevel ) {
if ( altitude - ( isSeaLevelRef ? sealevel * 100 : 0 ) < 0 ) {
GUI . alert ( i18n . getMessage ( 'MissionPlannerAltitudeChangeReset' ) ) ;
return false ;
}
return true ;
}
function checkLandingAltitude ( altitude , isSeaLevelRef , sealevel ) {
if ( altitude - ( isSeaLevelRef ? sealevel * 100 : 0 ) < MAX _NEG _FW _LAND _ALT ) {
GUI . alert ( i18n . getMessage ( 'MissionPlannerFwLAndingAltitudeChangeReset' ) ) ;
return false ;
}
return true ;
}
function updateSafehomeInfo ( ) {
let freeSamehomes = FC . SAFEHOMES . getMaxSafehomeCount ( ) - FC . SAFEHOMES . safehomeCount ( )
$ ( '#availableSafehomes' ) . text ( freeSamehomes + '/' + FC . SAFEHOMES . getMaxSafehomeCount ( ) ) ;
}
function renderSafehomesOnMap ( ) {
/ *
* Process safehome on Map
* /
FC . SAFEHOMES . get ( ) . forEach ( safehome => {
addFwApproach ( safehome . getLonMap ( ) , safehome . getLatMap ( ) , FC . FW _APPROACH . get ( ) [ safehome . getNumber ( ) ] , safehomeMarkers ) ;
} ) ;
FC . SAFEHOMES . get ( ) . forEach ( safehome => {
addSafehomeCircles ( safehome ) ;
addSafeHomeMarker ( safehome ) ;
} ) ;
}
function cleanSafehomeLayers ( ) {
for ( var i in safehomeMarkers ) {
map . removeLayer ( safehomeMarkers [ i ] ) ;
}
safehomeMarkers = [ ] ;
}
function getSafehomeIcon ( safehome ) {
/ *
* Process Safehome Icon
* /
return new ol . style . Style ( {
image : new ol . style . Icon ( ( {
anchor : [ 0.5 , 1 ] ,
opacity : 1 ,
scale : 0.5 ,
src : './images/icons/cf_icon_safehome' + ( safehome . isUsed ( ) ? '_used' : '' ) + '.png'
} ) ) ,
text : new ol . style . Text ( ( {
text : String ( Number ( safehome . getNumber ( ) ) + 1 ) ,
font : '12px sans-serif' ,
offsetY : - 15 ,
offsetX : - 2 ,
fill : new ol . style . Fill ( {
color : '#FFFFFF'
} ) ,
stroke : new ol . style . Stroke ( {
color : '#FFFFFF'
} ) ,
} ) )
} ) ;
}
function paintApproachLine ( pos1 , pos2 , color , layers )
{
var line = new ol . geom . LineString ( [ ol . proj . fromLonLat ( [ pos1 . lon , pos1 . lat ] ) , ol . proj . fromLonLat ( [ pos2 . lon , pos2 . lat ] ) ] ) ;
var feature = new ol . Feature ( {
geometry : line
} ) ;
var styles = [ new ol . style . Style ( {
stroke : new ol . style . Stroke ( {
color : color ,
width : 3 ,
} ) ,
} )
] ;
var geometry = feature . getGeometry ( ) ;
geometry . forEachSegment ( function ( start , end ) {
var dx = end [ 0 ] - start [ 0 ] ;
var dy = end [ 1 ] - start [ 1 ] ;
var rotation = Math . atan2 ( dy , dx ) ;
styles . push ( new ol . style . Style ( {
geometry : new ol . geom . Point ( distanceOnLine ( start , end , - 8 ) ) ,
image : new ol . style . RegularShape ( {
fill : new ol . style . Fill ( { color } ) ,
points : 3 ,
radius : 8 ,
rotation : - rotation ,
angle : Math . PI / 2 // rotate -90°
} )
} ) ) ;
} ) ;
feature . setStyle ( styles ) ;
var vectorSource = new ol . source . Vector ( {
features : [ feature ]
} ) ;
var vectorLayer = new ol . layer . Vector ( {
source : vectorSource
} ) ;
vectorLayer . kind = "approachline" ;
vectorLayer . selection = false ;
approachLayers . push ( vectorLayer ) ;
approachLayers . push ( vectorLayer ) ;
map . addLayer ( vectorLayer ) ;
layers . push ( vectorLayer ) ;
return vectorLayer ;
}
function paintApproach ( landCoord , approachLength , bearing , approachDirection , layers ) {
var pos1 = calculate _new _cooridatnes ( landCoord , bearing , approachLength ) ;
let direction ;
if ( approachDirection == ApproachDirection . LEFT ) {
direction = wrap _360 ( bearing + 90 ) ;
} else {
direction = wrap _360 ( bearing - 90 ) ;
}
var pos2 = calculate _new _cooridatnes ( pos1 , direction , Math . max ( settings . fwLoiterRadius * 4 , settings . fwApproachLength / 2 ) ) ;
paintApproachLine ( landCoord , pos2 , '#0025a1' , layers ) ;
paintApproachLine ( pos2 , pos1 , '#0025a1' , layers ) ;
paintApproachLine ( pos1 , landCoord , '#f78a05' , layers ) ;
}
function addFwApproach ( lon , lat , fwApproach , layers )
{
if ( fwApproach . getLandHeading1 ( ) != 0 ) {
let bearing = wrap _360 ( Math . abs ( fwApproach . getLandHeading1 ( ) ) + 180 ) ;
paintApproach ( { lat : lat , lon : lon } , settings . fwApproachLength , bearing , fwApproach . getApproachDirection ( ) , layers ) ;
}
if ( fwApproach . getLandHeading1 ( ) > 0 ) {
let direction = fwApproach . getApproachDirection ( ) == ApproachDirection . LEFT ? ApproachDirection . RIGHT : ApproachDirection . LEFT ;
paintApproach ( { lat : lat , lon : lon } , settings . fwApproachLength , fwApproach . getLandHeading1 ( ) , direction , layers ) ;
}
if ( fwApproach . getLandHeading2 ( ) != 0 ) {
let bearing = wrap _360 ( Math . abs ( fwApproach . getLandHeading2 ( ) ) + 180 ) ;
paintApproach ( { lat : lat , lon : lon } , settings . fwApproachLength , bearing , fwApproach . getApproachDirection ( ) , layers ) ;
}
if ( fwApproach . getLandHeading2 ( ) > 0 ) {
let direction = fwApproach . getApproachDirection ( ) == ApproachDirection . LEFT ? ApproachDirection . RIGHT : ApproachDirection . LEFT ;
paintApproach ( { lat : lat , lon : lon } , settings . fwApproachLength , fwApproach . getLandHeading2 ( ) , direction , layers ) ;
}
}
function addSafehomeCircles ( safehome ) {
/ *
* add safehome on Map
* /
let coord = ol . proj . fromLonLat ( [ safehome . getLonMap ( ) , safehome . getLatMap ( ) ] ) ;
var iconFeature = new ol . Feature ( {
geometry : new ol . geom . Point ( coord ) ,
name : 'safehome'
} ) ;
//iconFeature.setStyle(getSafehomeIcon(safehome, safehome.isUsed()));
let circleStyle = new ol . style . Style ( {
stroke : new ol . style . Stroke ( {
color : 'rgba(144, 12, 63, 0.5)' ,
width : 3 ,
lineDash : [ 10 ]
} ) ,
// fill: new ol.style.Fill({
// color: 'rgba(251, 225, 155, 0.1)'
// })
} ) ;
let circleSafeStyle = new ol . style . Style ( {
stroke : new ol . style . Stroke ( {
color : 'rgba(136, 204, 62, 1)' ,
width : 3 ,
lineDash : [ 10 ]
} ) ,
/ * f i l l : n e w o l . s t y l e . F i l l ( {
color : 'rgba(136, 204, 62, 0.1)'
} ) * /
} ) ;
var vectorLayer = new ol . layer . Vector ( {
source : new ol . source . Vector ( {
features : [ iconFeature ]
} ) ,
style : function ( iconFeature ) {
let styles = [ getSafehomeIcon ( safehome ) ] ;
if ( safehome . isUsed ( ) ) {
circleStyle . setGeometry ( new ol . geom . Circle ( iconFeature . getGeometry ( ) . getCoordinates ( ) , getProjectedRadius ( settings . maxDistSH ) ) ) ;
circleSafeStyle . setGeometry ( new ol . geom . Circle ( iconFeature . getGeometry ( ) . getCoordinates ( ) , getProjectedRadius ( Number ( settings . safeRadiusSH ) ) ) ) ;
styles . push ( circleSafeStyle ) ;
styles . push ( circleStyle ) ;
}
return styles ;
}
} ) ;
vectorLayer . kind = "safehome" ;
vectorLayer . number = safehome . getNumber ( ) ;
vectorLayer . selection = false ;
safehomeMarkers . push ( vectorLayer ) ;
map . addLayer ( vectorLayer ) ;
}
function addSafeHomeMarker ( safehome ) {
let coord = ol . proj . fromLonLat ( [ safehome . getLonMap ( ) , safehome . getLatMap ( ) ] ) ;
var iconFeature = new ol . Feature ( {
geometry : new ol . geom . Point ( coord ) ,
name : 'safehome'
} ) ;
var vectorLayer = new ol . layer . Vector ( {
source : new ol . source . Vector ( {
features : [ iconFeature ]
} ) ,
style : function ( iconFeature ) {
return [ getSafehomeIcon ( safehome ) ] ;
}
} ) ;
vectorLayer . kind = "safehome" ;
vectorLayer . number = safehome . getNumber ( ) ;
vectorLayer . selection = true ;
safehomeMarkers . push ( vectorLayer ) ;
map . addLayer ( vectorLayer ) ;
}
function getProjectedRadius ( radius ) {
let projection = map . getView ( ) . getProjection ( ) ;
let resolutionAtEquator = map . getView ( ) . getResolution ( ) ;
let resolutionRate = resolutionAtEquator / ol . proj . getPointResolution ( projection , resolutionAtEquator , map . getView ( ) . getCenter ( ) ) ;
let radiusProjected = ( radius / ol . proj . METERS _PER _UNIT . m ) * resolutionRate ;
return radiusProjected ;
}
/////////////////////////////////////////////
//
// Manage Take Off Home
//
/////////////////////////////////////////////
function closeHomePanel ( ) {
$ ( '#missionPlannerHome' ) . hide ( ) ;
$ ( '#missionPlannerElevation' ) . hide ( ) ;
cleanHomeLayers ( ) ;
}
function cleanHomeLayers ( ) {
for ( var i in homeMarkers ) {
map . removeLayer ( homeMarkers [ i ] ) ;
}
homeMarkers = [ ] ;
}
function renderHomeTable ( ) {
/ *
* Process home table UI
* /
$ ( ".home-lat" ) . val ( HOME . getLatMap ( ) ) . on ( 'change' , function ( ) {
HOME . setLat ( Math . round ( Number ( $ ( this ) . val ( ) ) * 10000000 ) ) ;
cleanHomeLayers ( ) ;
renderHomeOnMap ( ) ;
} ) ;
$ ( ".home-lon" ) . val ( HOME . getLonMap ( ) ) . on ( 'change' , function ( ) {
HOME . setLon ( Math . round ( Number ( $ ( this ) . val ( ) ) * 10000000 ) ) ;
cleanHomeLayers ( ) ;
renderHomeOnMap ( ) ;
} ) ;
if ( HOME . getLatMap ( ) == 0 && HOME . getLonMap ( ) == 0 ) {
HOME . setAlt ( "N/A" ) ;
} else {
( async ( ) => {
const elevationAtHome = await HOME . getElevation ( globalSettings ) ;
$ ( '#elevationValueAtHome' ) . text ( elevationAtHome + ' m' ) ;
HOME . setAlt ( elevationAtHome ) ;
} ) ( )
}
if ( globalSettings . mapProviderType == 'bing' ) {
$ ( '#elevationEarthModelclass' ) . fadeIn ( 300 ) ;
changeSwitchery ( $ ( '#elevationEarthModel' ) , settings . bingDemModel ) ;
} else {
$ ( '#elevationEarthModelclass' ) . fadeOut ( 300 ) ;
}
}
function renderHomeOnMap ( ) {
/ *
* Process home on Map
* /
map . addLayer ( addHomeMarker ( HOME ) ) ;
}
function addHomeMarker ( home ) {
/ *
* add safehome on Map
* /
let coord = ol . proj . fromLonLat ( [ home . getLonMap ( ) , home . getLatMap ( ) ] ) ;
var iconFeature = new ol . Feature ( {
geometry : new ol . geom . Point ( coord ) ,
name : 'home'
} ) ;
//iconFeature.setStyle(getSafehomeIcon(safehome, safehome.isUsed()));
var vectorLayer = new ol . layer . Vector ( {
source : new ol . source . Vector ( {
features : [ iconFeature ]
} ) ,
style : function ( iconFeature ) {
let styles = [ getHomeIcon ( home ) ] ;
return styles ;
}
} ) ;
vectorLayer . kind = "home" ;
vectorLayer . number = home . getNumber ( ) ;
vectorLayer . selection = false ;
homeMarkers . push ( vectorLayer ) ;
return vectorLayer ;
}
function getHomeIcon ( home ) {
/ *
* Process Safehome Icon
* /
return new ol . style . Style ( {
image : new ol . style . Icon ( ( {
anchor : [ 0.5 , 1 ] ,
opacity : 1 ,
scale : 0.5 ,
src : './images/icons/cf_icon_home.png'
} ) ) ,
} ) ;
}
function updateHome ( ) {
renderHomeTable ( ) ;
cleanHomeLayers ( ) ;
renderHomeOnMap ( ) ;
plotElevation ( ) ;
}
/////////////////////////////////////////////
//
// Manage Multi Mission
//
/////////////////////////////////////////////
/ * M u l t i M i s s i o n w o r k i n g m e t h o d :
* 'multimission' waypoint collection is a repository for all multi missions .
* 'mission' WP collection remains as the WP source for the map display .
* All missions can be displayed on the map or only a single mission . With all missions displayed 'mission' and
* 'multimission' are copies containing all missions . When a single mission is displayed 'multimission' contains all
* missions except the currently displayed mission .
* On update to display all missions the current dislayed mission is merged back into 'multimission' and 'mission'
* updated as a copy of 'multimission' .
* When all missions are displayed WP data can be viewed but mission edit is disabled .
* Mission WPs can be edited only when a single mission is loaded on the map . * /
var startWPCount = 0 ;
function renderMultimissionTable ( ) {
$ ( '#multimissionOptionList' ) . prop ( 'options' ) . length = 1 ;
for ( var i = 1 ; i <= multimissionCount ; i ++ ) {
$ ( '#multimissionOptionList' ) . append ( $ ( '<option>' , { value : i , text : i } ) ) ;
}
updateMultimissionState ( ) ;
$ ( '#activeNissionIndex' ) . text ( 1 ) ;
}
function updateMultimissionState ( ) {
setMultimissionEditControl ( false ) ;
if ( ! mission . isEmpty ( ) || multimissionCount ) {
if ( ( ! multimissionCount || ( multimissionCount && ! mission . isEmpty ( ) ) ) && multimissionCount < maxMultimissionCount ) {
$ ( "#addMultimissionButton" ) . removeClass ( 'disabled' ) ;
} else {
$ ( "#addMultimissionButton" ) . addClass ( 'disabled' ) ;
}
if ( multimissionCount ) {
let totalmultimissionWPs ;
if ( singleMissionActive ( ) ) {
totalmultimissionWPs = multimission . get ( ) . length + mission . get ( ) . length ;
$ ( "#updateMultimissionButton" ) . removeClass ( 'disabled' ) ;
$ ( "#setActiveMissionButton" ) . removeClass ( 'disabled' ) ;
$ ( '#missionPlannerElevation' ) . show ( ) ;
} else {
$ ( '#missionDistance' ) . text ( 'N/A' ) ;
totalmultimissionWPs = mission . get ( ) . length ;
$ ( "#editMission" ) . show ( ) ;
$ ( "#updateMultimissionButton" ) . addClass ( 'disabled' ) ;
$ ( "#setActiveMissionButton" ) . addClass ( 'disabled' ) ;
$ ( '#missionPlannerElevation' ) . hide ( ) ;
setMultimissionEditControl ( true ) ;
}
$ ( '#multimissionInfo' ) . text ( multimissionCount + ' missions (' + totalmultimissionWPs + '/' + mission . getMaxWaypoints ( ) + ' WPs)' ) ;
document . getElementById ( 'multimissionInfo' ) . style . color = totalmultimissionWPs > mission . getMaxWaypoints ( ) ? "#FF0000" : "#303030" ;
} else {
$ ( '#cancelMultimission' ) . trigger ( 'click' ) ;
$ ( '#multimissionInfo' ) . text ( 'No multi missions loaded' ) ;
$ ( "#updateMultimissionButton" ) . addClass ( 'disabled' ) ;
$ ( "#setActiveMissionButton" ) . addClass ( 'disabled' ) ;
}
} else {
$ ( "#addMultimissionButton" ) . addClass ( 'disabled' ) ;
$ ( "#setActiveMissionButton" ) . addClass ( 'disabled' ) ;
}
updateTotalInfo ( ) ;
}
// /* checks if single mission loaded on map */
function singleMissionActive ( ) {
return ! multimissionCount || Number ( $ ( '#multimissionOptionList' ) . val ( ) ) ;
}
function updateAllMultimission ( missionDelete = false , newMission = false ) {
// flag if new MM mission empty on update
let missionIsEmptyOnUpdate = mission . isEmpty ( ) ? true : false ;
/ * c o p y a c t i v e s i n g l e m i s s i o n i n t o M M o n u p d a t e s o M M c o n t a i n s a l l m i s s i o n s .
* active mission may be deleted by not copying back into MM on update * /
var i = startWPCount ;
if ( ! missionDelete ) {
mission . get ( ) . forEach ( function ( element ) {
multimission . get ( ) . splice ( i , 0 , element ) ;
i ++ ;
} ) ;
}
i = 0 ;
multimission . get ( ) . forEach ( function ( element ) { // renumber MM WPs
element . setNumber ( i ) ;
i ++ ;
} ) ;
multimission . update ( false ) ;
// multimission.missionDisplayDebug();
// if new mission added no need to redraw so return
if ( newMission ) return ;
mission . reinit ( ) ;
mission . copy ( multimission ) ;
mission . update ( false ) ;
// mission.missionDisplayDebug();
/ * R e m o v e e m p t y m i s s i o n s o n u p d a t e .
* Cancel MM if only 2 MM missions loaded and one mission is empty * /
if ( missionIsEmptyOnUpdate ) {
multimissionCount -= multimissionCount == 2 ? 2 : 1 ;
if ( ! multimissionCount ) {
multimissionCount = 0 ;
multimission . flush ( ) ;
}
renderMultimissionTable ( ) ;
}
selectedMarker = null ;
clearEditForm ( ) ;
setView ( 14 ) ;
refreshLayers ( ) ;
updateTotalInfo ( ) ;
}
/* selects single mission from MM repository */
function editMultimission ( ) {
var MMCount = 0 ;
var endWPCount = 0 ;
var found = false ;
startWPCount = 0 ;
mission . get ( ) . forEach ( function ( element ) {
if ( element . getEndMission ( ) == 0xA5 && ! found ) {
MMCount ++ ;
endWPCount = element . getNumber ( ) ;
if ( MMCount == Number ( $ ( '#multimissionOptionList' ) . val ( ) ) ) {
found = true ;
} else {
startWPCount = endWPCount + 1 ;
}
}
} ) ;
mission . reinit ( ) ;
var tempMissionData = multimission . get ( ) . slice ( startWPCount , endWPCount + 1 ) ; // copy selected single mission from MM
let i = 0 ;
tempMissionData . forEach ( function ( element ) { // write mission copy to active map mission
mission . put ( element ) ;
mission . get ( ) [ i ] . setNumber ( i ) ;
i ++ ;
} ) ;
mission . setMaxWaypoints ( multimission . getMaxWaypoints ( ) ) ;
multimission . get ( ) . splice ( startWPCount , ( endWPCount - startWPCount + 1 ) ) // cut current active map mission from MM
mission . update ( ) ;
updateMultimissionState ( ) ;
selectedMarker = null ;
clearEditForm ( ) ;
setView ( 14 ) ;
refreshLayers ( ) ;
updateTotalInfo ( ) ;
plotElevation ( ) ;
}
/* single mission selection using WP Edit panel button */
function mapSelectEditMultimission ( WPNumber ) {
let MMCount = 1 ;
mission . get ( ) . forEach ( function ( element ) {
if ( element . getEndMission ( ) == 0xA5 && element . getNumber ( ) < WPNumber ) {
MMCount ++ ;
}
} ) ;
$ ( '#multimissionOptionList' ) . val ( MMCount ) . trigger ( 'change' ) ;
}
function deleteMultimission ( ) {
updateAllMultimission ( true ) ;
multimissionCount -= multimissionCount == 2 ? 2 : 1 ;
if ( ! multimissionCount ) {
multimission . flush ( ) ;
}
renderMultimissionTable ( ) ;
}
function addMultimission ( ) {
if ( singleMissionActive ( ) || ! multimissionCount ) {
updateAllMultimission ( false , true ) ;
}
multimissionCount += ! multimissionCount ? 2 : 1 ;
renderMultimissionTable ( ) ;
$ ( '#multimissionOptionList' ) . val ( multimissionCount ) ;
removeAllWaypoints ( ) ;
startWPCount = multimission . get ( ) . length ;
updateMultimissionState ( ) ;
}
function removeAllMultiMissionCheck ( ) {
if ( ! multimissionCount ) {
return true ;
} else if ( singleMissionActive ( ) ) {
deleteMultimission ( ) ;
return false ;
}
multimissionCount = 0 ;
multimission . flush ( ) ;
renderMultimissionTable ( ) ;
return true ;
}
function fileLoadMultiMissionCheck ( ) {
if ( singleMissionActive ( ) ) {
return true ;
} else if ( confirm ( i18n . getMessage ( 'confirm_overwrite_multimission_file_load_option' ) ) ) {
var options = {
filters : [ { name : "Mission file" , extensions : [ 'mission' ] } ]
} ;
dialog . showOpenDialog ( options ) . then ( result => {
if ( result . canceled ) {
console . log ( 'No file selected' ) ;
return ;
}
if ( result . filePaths . length == 1 ) {
loadMissionFile ( result . filePaths [ 0 ] ) ;
multimissionCount = 0 ;
multimission . flush ( ) ;
renderMultimissionTable ( ) ;
}
} ) ;
}
return false ;
}
/* disable mission/WP edit when all missions displayed on map, true = edit disabled */
function setMultimissionEditControl ( enabled = true ) {
disableMarkerEdit = enabled ;
$ ( "*" , "#MPeditPoint" ) . prop ( 'disabled' , enabled ) ;
if ( enabled ) {
$ ( "#addOptionsPointButton" ) . addClass ( 'disabled' ) ;
$ ( "#removePointButton" ) . addClass ( 'disabled' ) ;
$ ( "#waypointOptionsTableBody" ) . fadeOut ( ) ;
} else {
$ ( "#addOptionsPointButton" ) . removeClass ( 'disabled' ) ;
$ ( "#removePointButton" ) . removeClass ( 'disabled' ) ;
$ ( "#waypointOptionsTableBody" ) . fadeIn ( ) ;
}
}
/////////////////////////////////////////////
//
// Manage Waypoint
//
/////////////////////////////////////////////
function removeAllWaypoints ( ) {
mission . reinit ( ) ;
refreshLayers ( ) ;
clearEditForm ( ) ;
updateTotalInfo ( ) ;
clearFilename ( ) ;
}
function addWaypointMarker ( waypoint , isEdit = false ) {
let coord = ol . proj . fromLonLat ( [ waypoint . getLonMap ( ) , waypoint . getLatMap ( ) ] ) ;
var iconFeature = new ol . Feature ( {
geometry : new ol . geom . Point ( coord ) ,
name : 'Null Island' ,
population : 4000 ,
rainfall : 500
} ) ;
iconFeature . setStyle ( getWaypointIcon ( waypoint , isEdit ) ) ;
var vectorSource = new ol . source . Vector ( {
features : [ iconFeature ]
} ) ;
var vectorLayer = new ol . layer . Vector ( {
source : vectorSource
} ) ;
vectorLayer . kind = "waypoint" ;
vectorLayer . number = waypoint . getNumber ( ) ;
vectorLayer . layerNumber = waypoint . getLayerNumber ( ) ;
markers . push ( vectorLayer ) ;
return vectorLayer ;
}
function getWaypointIcon ( waypoint , isEdit ) {
var dictofPointIcon = {
1 : 'WP' ,
2 : 'PH' ,
3 : 'PH' ,
5 : 'POI' ,
8 : 'LDG'
} ;
return new ol . style . Style ( {
image : new ol . style . Icon ( ( {
anchor : [ 0.5 , 1 ] ,
opacity : 1 ,
scale : 0.5 ,
src : './images/icons/cf_icon_position' + ( dictofPointIcon [ waypoint . getAction ( ) ] != '' ? '_' + dictofPointIcon [ waypoint . getAction ( ) ] : '' ) + ( isEdit ? '_edit' : '' ) + '.png'
} ) ) ,
text : new ol . style . Text ( ( {
text : String ( Number ( waypoint . getLayerNumber ( ) + 1 ) ) ,
font : '12px sans-serif' ,
offsetY : - 15 ,
offsetX : - 2 ,
fill : new ol . style . Fill ( {
color : '#FFFFFF'
} ) ,
stroke : new ol . style . Stroke ( {
color : '#FFFFFF'
} ) ,
} ) )
} ) ;
}
function repaintLine4Waypoints ( mission ) {
let oldPos ,
oldAction ,
poiList = [ ] ,
oldHeading ,
multiMissionWPNum = 0 ;
let activatePoi = false ;
let activateHead = false ;
$ ( '#missionDistance' ) . text ( 0 ) ;
cleanLines ( ) ;
mission . get ( ) . forEach ( function ( element ) {
if ( ! element . isAttached ( ) ) {
let coord = ol . proj . fromLonLat ( [ element . getLonMap ( ) , element . getLatMap ( ) ] ) ;
if ( element . getAction ( ) == 5 ) {
// If action is Set_POI, increment counter of POI
poiList . push ( element . getNumber ( ) ) ;
activatePoi = true ;
activateHead = false ;
}
else {
// If classic WPs, draw standard line in-between
if ( typeof oldPos !== 'undefined' && activatePoi != true && activateHead != true ) {
paintLine ( oldPos , coord , element . getNumber ( ) ) ;
}
// If one is POI, draw orange line in-between and modulate dashline each time a new POI is defined
else if ( typeof oldPos !== 'undefined' && activatePoi == true && activateHead != true ) {
if ( ( poiList . length % 2 ) == 0 ) {
paintLine ( oldPos , coord , element . getNumber ( ) , '#ffb725' , 5 ) ;
}
else {
paintLine ( oldPos , coord , element . getNumber ( ) , '#ffb725' ) ;
}
}
// If one is SET_HEAD, draw labelled line in-between with heading value
else if ( typeof oldPos !== 'undefined' && activatePoi != true && activateHead == true ) {
paintLine ( oldPos , coord , element . getNumber ( ) , '#1497f1' , 0 , String ( oldHeading ) + "°" ) ;
}
if ( element . getEndMission ( ) == 0xA5 ) {
oldPos = 'undefined' ;
activatePoi = false ;
activateHead = false ;
multiMissionWPNum = element . getNumber ( ) + 1 ;
} else {
oldPos = coord ;
}
}
}
else if ( element . isAttached ( ) ) {
if ( element . getAction ( ) == MWNP . WPTYPE . JUMP ) {
let jumpWPIndex = multiMissionWPNum + element . getP1 ( ) ;
let coord = ol . proj . fromLonLat ( [ mission . getWaypoint ( jumpWPIndex ) . getLonMap ( ) , mission . getWaypoint ( jumpWPIndex ) . getLatMap ( ) ] ) ;
paintLine ( oldPos , coord , element . getNumber ( ) , '#e935d6' , 5 , "Repeat x" + ( element . getP2 ( ) == - 1 ? " infinite" : String ( element . getP2 ( ) ) ) , false , true ) ;
}
// If classic WPs is defined with a heading = -1, change Boolean for POI to false. If it is defined with a value different from -1, activate Heading boolean
else if ( element . getAction ( ) == MWNP . WPTYPE . SET _HEAD ) {
if ( element . getP1 ( ) == - 1 ) {
activatePoi = false ;
activateHead = false ;
oldHeading = 'undefined'
}
else if ( typeof element . getP1 ( ) != 'undefined' && element . getP1 ( ) != - 1 ) {
activatePoi = false ;
activateHead = true ;
oldHeading = String ( element . getP1 ( ) ) ;
}
}
if ( element . getEndMission ( ) == 0xA5 ) {
oldPos = 'undefined' ;
activatePoi = false ;
activateHead = false ;
multiMissionWPNum = element . getNumber ( ) + 1 ;
}
}
if ( element . getAction ( ) == MWNP . WPTYPE . LAND ) {
addFwApproach ( element . getLonMap ( ) , element . getLatMap ( ) , FC . FW _APPROACH . get ( ) [ FC . SAFEHOMES . getMaxSafehomeCount ( ) + element . getMultiMissionIdx ( ) ] , lines ) ;
}
} ) ;
//reset text position
if ( textGeom ) {
textGeom . setCoordinates ( map . getCoordinateFromPixel ( [ 0 , 0 ] ) ) ;
}
let lengthMission = mission . getDistance ( true ) ;
if ( disableMarkerEdit ) {
$ ( '#missionDistance' ) . text ( 'N/A' ) ;
} else {
if ( lengthMission . length >= 1 ) {
$ ( '#missionDistance' ) . text ( lengthMission [ lengthMission . length - 1 ] . toFixed ( 1 ) ) ;
} else {
$ ( '#missionDistance' ) . text ( 'infinite' ) ;
}
}
}
function paintLine ( pos1 , pos2 , pos2ID , color = '#1497f1' , lineDash = 0 , lineText = "" , selection = true , arrow = false ) {
var line = new ol . geom . LineString ( [ pos1 , pos2 ] ) ;
var feature = new ol . Feature ( {
geometry : line
} ) ;
feature . setStyle (
new ol . style . Style ( {
stroke : new ol . style . Stroke ( {
color : color ,
width : 3 ,
lineDash : [ lineDash ]
} ) ,
text : new ol . style . Text ( {
text : lineText ,
font : '14px sans-serif' ,
placement : 'line' ,
textBaseline : 'ideographic' ,
stroke : new ol . style . Stroke ( {
color : color
} ) ,
} ) ,
} ) ,
) ;
if ( arrow ) {
let dx = pos2 [ 0 ] - pos1 [ 0 ] ;
let dy = pos2 [ 1 ] - pos1 [ 1 ] ;
let rotation = Math . atan2 ( dx , dy ) ;
var featureArrow = new ol . Feature ( {
geometry : new ol . geom . Point ( [ pos1 [ 0 ] + dx / 2 , pos1 [ 1 ] + dy / 2 ] )
} ) ;
featureArrow . setStyle (
new ol . style . Style ( {
image : new ol . style . Icon ( {
src : './images/icons/cf_icon_arrow.png' ,
scale : 0.3 ,
anchor : [ 0.5 , 0.5 ] ,
rotateWithView : true ,
rotation : rotation ,
} ) ,
} )
) ;
}
if ( arrow ) {
var vectorSource = new ol . source . Vector ( {
features : [ feature , featureArrow ]
} ) ;
}
else {
var vectorSource = new ol . source . Vector ( {
features : [ feature ]
} ) ;
}
var vectorLayer = new ol . layer . Vector ( {
source : vectorSource
} ) ;
vectorLayer . kind = "line" ;
vectorLayer . selection = selection ;
vectorLayer . number = pos2ID ;
lines . push ( vectorLayer ) ;
/ * v a r l e n g t h = o l . S p h e r e . g e t L e n g t h ( l i n e ) + p a r s e F l o a t ( $ ( ' # m i s s i o n D i s t a n c e ' ) . t e x t ( ) ) ;
$ ( '#missionDistance' ) . text ( length . toFixed ( 3 ) ) ; * /
map . addLayer ( vectorLayer ) ;
}
function refreshLayers ( ) {
cleanLayers ( ) ;
redrawLayers ( ) ;
}
function cleanLayers ( ) {
for ( var i in lines ) {
map . removeLayer ( lines [ i ] ) ;
}
lines = [ ] ;
for ( var i in markers ) {
map . removeLayer ( markers [ i ] ) ;
}
markers = [ ] ;
}
function cleanLines ( ) {
for ( var i in lines ) {
map . removeLayer ( lines [ i ] ) ;
}
lines = [ ] ;
}
function redrawLayers ( ) {
if ( ! mission . isEmpty ( ) ) {
repaintLine4Waypoints ( mission ) ;
mission . get ( ) . forEach ( function ( element ) {
if ( ! element . isAttached ( ) ) {
map . addLayer ( addWaypointMarker ( element ) ) ;
}
} ) ;
}
}
function redrawLayer ( ) {
repaintLine4Waypoints ( mission ) ;
if ( selectedFeature && selectedMarker ) {
selectedFeature . setStyle ( getWaypointIcon ( selectedMarker , true ) ) ;
}
}
function renderSafeHomeOptions ( ) {
if ( selectedSafehome && selectedFwApproachSh ) {
lockShExclHeading = true ;
if ( ! $ ( '#missionPlannerSafehome' ) . is ( ':visible' ) ) {
$ ( '#missionPlannerSafehome' ) . fadeIn ( 300 ) ;
}
$ ( '#SafehomeContentBox' ) . show ( ) ;
if ( selectedFwApproachSh . getLandHeading1 ( ) == 0 && selectedFwApproachSh . getLandHeading1 ( ) == 0 && selectedFwApproachSh . getApproachAltAsl ( ) == 0 && selectedFwApproachSh . getLandAltAsl ( ) == 0 ) {
selectedFwApproachSh . setApproachAltAsl ( settings . fwApproachAlt * 100 ) ;
selectedFwApproachSh . setLandAltAsl ( settings . fwLandAlt * 100 ) ;
}
if ( selectedFwApproachSh . getElevation ( ) == 0 ) {
( async ( ) => {
const elevation = await selectedFwApproachSh . getElevationFromServer ( selectedSafehome . getLonMap ( ) , selectedSafehome . getLatMap ( ) , globalSettings ) * 100 ;
selectedFwApproachSh . setElevation ( elevation ) ;
$ ( '#safehomeElevation' ) . text ( selectedFwApproachSh . getElevation ( ) / 100 + " m" ) ;
} ) ( ) ;
}
const $safehomeBox = $safehomeContentBox . find ( '.missionPlannerSafehomeBox:last-child' ) ;
$safehomeBox . find ( '.spacer_box_title' ) . text ( i18n . getMessage ( 'safehomeEdit' ) + ' ' + ( selectedSafehome . getNumber ( ) + 1 ) ) ;
$ ( '#safehomeLatitude' ) . val ( selectedSafehome . getLatMap ( ) ) ;
$ ( '#safehomeLongitude' ) . val ( selectedSafehome . getLonMap ( ) ) ;
changeSwitchery ( $ ( '#safehomeSeaLevelRef' ) , selectedFwApproachSh . getIsSeaLevelRef ( ) ) ;
$ ( '#safehomeApproachAlt' ) . val ( selectedFwApproachSh . getApproachAltAsl ( ) ) ;
$ ( '#safehomeLandAlt' ) . val ( selectedFwApproachSh . getLandAltAsl ( ) ) ;
$ ( '#geozoneApproachDirection' ) . val ( selectedFwApproachSh . getApproachDirection ( ) ) ;
$ ( '#safehomeLandHeading1' ) . val ( Math . abs ( selectedFwApproachSh . getLandHeading1 ( ) ) ) ;
changeSwitchery ( $ ( '#safehomeLandHeading1Excl' ) , selectedFwApproachSh . getLandHeading1 ( ) < 0 ) ;
$ ( '#safehomeLandHeading2' ) . val ( Math . abs ( selectedFwApproachSh . getLandHeading2 ( ) ) ) ;
changeSwitchery ( $ ( '#safehomeLandHeading2Excl' ) , selectedFwApproachSh . getLandHeading2 ( ) < 0 ) ;
$ ( '#safehomeLandAltM' ) . text ( selectedFwApproachSh . getLandAltAsl ( ) / 100 + " m" ) ;
$ ( '#safehomeApproachAltM' ) . text ( selectedFwApproachSh . getApproachAltAsl ( ) / 100 + " m" ) ;
lockShExclHeading = false ;
} else {
$ ( '#SafehomeContentBox' ) . hide ( ) ;
}
}
function renderWaypointOptionsTable ( waypoint ) {
/ *
* Process Waypoint Options table UI
* /
$waypointOptionsTableBody . empty ( ) ;
mission . getAttachedFromWaypoint ( waypoint ) . forEach ( function ( element ) {
$waypointOptionsTableBody . append ( ' \
< tr > \
< td > < div id = "deleteOptionsPoint" class = "btnTable btnTableIcon btnTable-danger" > \
< a class = "ic_cancel" data - role = "waypointOptions-delete" href = "#" style = "float: center" title = "Delete" > < / a > \
< / d i v > \
< / t d > \
< td > < span class = "waypointOptions-number" / > < / t d > \
< td > < select class = "waypointOptions-action" > < / s e l e c t > < / t d > \
< td > < input type = "number" class = "waypointOptions-p1" / > < / t d > \
< td > < input type = "number" class = "waypointOptions-p2" / > < / t d > \
< / t r > \
' ) ;
const $row = $waypointOptionsTableBody . find ( 'tr:last' ) ;
for ( var i = 1 ; i <= 3 ; i ++ ) {
if ( dictOfLabelParameterPoint [ element . getAction ( ) ] [ 'parameter' + String ( i ) ] != '' ) {
$row . find ( ".waypointOptions-p" + String ( i ) ) . prop ( "disabled" , false ) ;
$row . find ( ".waypointOptions-p" + String ( i ) ) . prop ( "title" , dictOfLabelParameterPoint [ element . getAction ( ) ] [ 'parameter' + String ( i ) ] ) ;
}
else {
$row . find ( ".waypointOptions-p" + String ( i ) ) . prop ( "disabled" , true ) ;
$row . find ( ".waypointOptions-p" + String ( i ) ) . prop ( "title" , "" ) ;
}
}
GUI . fillSelect ( $row . find ( ".waypointOptions-action" ) , waypointOptions , waypointOptions . indexOf ( MWNP . WPTYPE . REV [ element . getAction ( ) ] ) ) ;
$row . find ( ".waypointOptions-action" ) . val ( waypointOptions . indexOf ( MWNP . WPTYPE . REV [ element . getAction ( ) ] ) ) . on ( 'change' , function ( ) {
element . setAction ( MWNP . WPTYPE [ waypointOptions [ $ ( this ) . val ( ) ] ] ) ;
for ( var i = 1 ; i <= 3 ; i ++ ) {
if ( dictOfLabelParameterPoint [ element . getAction ( ) ] [ 'parameter' + String ( i ) ] != '' ) {
$row . find ( ".waypointOptions-p" + String ( i ) ) . prop ( "disabled" , false ) ;
$row . find ( ".waypointOptions-p" + String ( i ) ) . prop ( "title" , dictOfLabelParameterPoint [ element . getAction ( ) ] [ 'parameter' + String ( i ) ] ) ;
}
else {
$row . find ( ".waypointOptions-p" + String ( i ) ) . prop ( "disabled" , true ) ;
$row . find ( ".waypointOptions-p" + String ( i ) ) . prop ( "title" , "" ) ;
}
}
mission . updateWaypoint ( element ) ;
cleanLines ( ) ;
redrawLayer ( ) ;
} ) ;
$row . find ( ".waypointOptions-number" ) . text ( element . getAttachedNumber ( ) + 1 ) ;
$row . find ( ".waypointOptions-p1" ) . val ( ( MWNP . WPTYPE . REV [ element . getAction ( ) ] == "JUMP" ? element . getP1 ( ) + 1 : element . getP1 ( ) ) ) . on ( 'change' , function ( ) {
if ( MWNP . WPTYPE . REV [ element . getAction ( ) ] == "SET_HEAD" ) {
if ( $ ( this ) . val ( ) >= 360 || ( $ ( this ) . val ( ) < 0 && $ ( this ) . val ( ) != - 1 ) )
{
$ ( this ) . val ( - 1 ) ;
GUI . alert ( i18n . getMessage ( 'MissionPlannerHeadSettingsCheck' ) ) ;
}
}
else if ( MWNP . WPTYPE . REV [ element . getAction ( ) ] == "RTH" ) {
if ( $ ( this ) . val ( ) != 0 && $ ( this ) . val ( ) != 1 )
{
$ ( this ) . val ( 0 ) ;
GUI . alert ( i18n . getMessage ( 'MissionPlannerRTHSettingsCheck' ) ) ;
}
}
else if ( MWNP . WPTYPE . REV [ element . getAction ( ) ] == "JUMP" ) {
if ( $ ( this ) . val ( ) > mission . getNonAttachedList ( ) . length || $ ( this ) . val ( ) < 1 )
{
$ ( this ) . val ( 1 ) ;
GUI . alert ( i18n . getMessage ( 'MissionPlannerJumpSettingsCheck' ) ) ;
}
else if ( mission . getPoiList ( ) . length != 0 && mission . getPoiList ( ) ) {
if ( mission . getPoiList ( ) . includes ( mission . convertJumpNumberToWaypoint ( Number ( $ ( this ) . val ( ) ) - 1 ) ) ) {
$ ( this ) . val ( 1 ) ;
GUI . alert ( i18n . getMessage ( 'MissionPlannerJump3SettingsCheck' ) ) ;
}
}
}
element . setP1 ( ( MWNP . WPTYPE . REV [ element . getAction ( ) ] == "JUMP" ? mission . convertJumpNumberToWaypoint ( Number ( $ ( this ) . val ( ) ) - 1 ) : Number ( $ ( this ) . val ( ) ) ) ) ;
mission . updateWaypoint ( element ) ;
cleanLines ( ) ;
redrawLayer ( ) ;
} ) ;
$row . find ( ".waypointOptions-p2" ) . val ( element . getP2 ( ) ) . on ( 'change' , function ( ) {
if ( MWNP . WPTYPE . REV [ element . getAction ( ) ] == "JUMP" ) {
if ( $ ( this ) . val ( ) > 10 || ( $ ( this ) . val ( ) < 0 && $ ( this ) . val ( ) != - 1 ) )
{
$ ( this ) . val ( 0 ) ;
GUI . alert ( i18n . getMessage ( 'MissionPlannerJump2SettingsCheck' ) ) ;
}
}
element . setP2 ( Number ( $ ( this ) . val ( ) ) ) ;
mission . updateWaypoint ( element ) ;
cleanLines ( ) ;
redrawLayer ( ) ;
} ) ;
$row . find ( "[data-role='waypointOptions-delete']" ) . attr ( "data-index" , element . getAttachedNumber ( ) + 1 ) ;
} ) ;
GUI . switchery ( ) ;
i18n . localize ( ) ; ;
return waypoint ;
}
function setView ( zoom ) {
var coord = ol . proj . fromLonLat ( [ mission . getWaypoint ( 0 ) . getLonMap ( ) , mission . getWaypoint ( 0 ) . getLatMap ( ) ] ) ;
map . getView ( ) . setCenter ( coord ) ;
map . getView ( ) . setZoom ( zoom ) ;
}
/////////////////////////////////////////////
//
// Manage Map construction
//
/////////////////////////////////////////////
function initMap ( ) {
var app = { } ;
//////////////////////////////////////////////////////////////////////////////////////////////
// Drag behavior definition
//////////////////////////////////////////////////////////////////////////////////////////////
/ * *
* @ constructor
* @ extends { ol . interaction . Pointer }
* /
app . Drag = function ( ) {
ol . interaction . Pointer . call ( this , {
handleDownEvent : app . Drag . prototype . handleDownEvent ,
handleDragEvent : app . Drag . prototype . handleDragEvent ,
handleMoveEvent : app . Drag . prototype . handleMoveEvent ,
handleUpEvent : app . Drag . prototype . handleUpEvent
} ) ;
/ * *
* @ type { ol . Pixel }
* @ private
* /
this . coordinate _ = null ;
/ * *
* @ type { string | undefined }
* @ private
* /
this . cursor _ = 'pointer' ;
/ * *
* @ type { ol . Feature }
* @ private
* /
this . feature _ = null ;
/ * *
* @ type { string | undefined }
* @ private
* /
this . previousCursor _ = undefined ;
} ;
ol . inherits ( app . Drag , ol . interaction . Pointer ) ;
app . ConvertCentimetersToMeters = function ( val ) {
return parseInt ( val ) / 100 ;
} ;
/ * *
* @ constructor
* @ extends { ol . control . Control }
* @ param { Object = } opt _options Control options .
* /
app . PlannerSettingsControl = function ( opt _options ) {
var options = opt _options || { } ;
var button = document . createElement ( 'button' ) ;
button . innerHTML = ' ' ;
button . style = 'background: url(\'./images/CF_settings_white.svg\') no-repeat 1px -1px;background-color: rgba(0,60,136,.5);' ;
var handleShowSettings = function ( ) {
$ ( '#missionPlannerSettings' ) . fadeIn ( 300 ) ;
} ;
button . addEventListener ( 'click' , handleShowSettings , false ) ;
button . addEventListener ( 'touchstart' , handleShowSettings , false ) ;
var element = document . createElement ( 'div' ) ;
element . className = 'mission-control-settings ol-unselectable ol-control' ;
element . appendChild ( button ) ;
element . title = 'MP Settings' ;
ol . control . Control . call ( this , {
element : element ,
target : options . target
} ) ;
} ;
ol . inherits ( app . PlannerSettingsControl , ol . control . Control ) ;
/ * *
* @ constructor
* @ extends { ol . control . Control }
* @ param { Object = } opt _options Control options .
* /
app . PlannerSafehomeControl = function ( opt _options ) {
var options = opt _options || { } ;
var button = document . createElement ( 'button' ) ;
button . innerHTML = ' ' ;
button . style = 'background: url(\'./images/icons/cf_icon_safehome_white.svg\') no-repeat 1px -1px;background-color: rgba(0,60,136,.5);' ;
var handleShowSafehome = function ( ) {
$ ( '#missionPlannerSafehome' ) . fadeIn ( 300 ) ;
cleanSafehomeLayers ( ) ;
renderSafehomesOnMap ( ) ;
$ ( '#safeHomeMaxDistance' ) . text ( settings . maxDistSH ) ;
$ ( '#SafeHomeSafeDistance' ) . text ( settings . safeRadiusSH ) ;
} ;
button . addEventListener ( 'click' , handleShowSafehome , false ) ;
button . addEventListener ( 'touchstart' , handleShowSafehome , false ) ;
var element = document . createElement ( 'div' ) ;
element . className = 'mission-control-safehome ol-unselectable ol-control' ;
element . appendChild ( button ) ;
element . title = 'MP Safehome' ;
ol . control . Control . call ( this , {
element : element ,
target : options . target
} ) ;
} ;
ol . inherits ( app . PlannerSafehomeControl , ol . control . Control ) ;
/ * *
* @ constructor
* @ extends { ol . control . Control }
* @ param { Object = } opt _options Control options .
* /
app . PlannerElevationControl = function ( opt _options ) {
var options = opt _options || { } ;
var button = document . createElement ( 'button' ) ;
button . innerHTML = ' ' ;
button . style = 'background: url(\'./images/icons/cf_icon_elevation_white.svg\') no-repeat 1px -1px;background-color: rgba(0,60,136,.5);' ;
var handleShowSettings = function ( ) {
$ ( '#missionPlannerHome' ) . fadeIn ( 300 ) ;
cleanHomeLayers ( ) ;
renderHomeTable ( ) ;
renderHomeOnMap ( ) ;
$ ( '#missionPlannerElevation' ) . fadeIn ( 300 ) ;
plotElevation ( ) ;
} ;
button . addEventListener ( 'click' , handleShowSettings , false ) ;
button . addEventListener ( 'touchstart' , handleShowSettings , false ) ;
var element = document . createElement ( 'div' ) ;
element . className = 'mission-control-elevation ol-unselectable ol-control' ;
element . appendChild ( button ) ;
element . title = 'MP Elevation' ;
ol . control . Control . call ( this , {
element : element ,
target : options . target
} ) ;
} ;
ol . inherits ( app . PlannerElevationControl , ol . control . Control ) ;
// /**
// * @constructor
// * @extends {ol.control.Control}
// * @param {Object=} opt_options Control options.
// */
app . PlannerMultiMissionControl = function ( opt _options ) {
var options = opt _options || { } ;
var button = document . createElement ( 'button' ) ;
button . innerHTML = ' ' ;
button . style = 'background: url(\'./images/icons/cf_icon_multimission_white.svg\') no-repeat 1px -1px;background-color: rgba(0,60,136,.5);' ;
var handleShowSettings = function ( ) {
$ ( '#missionPlannerMultiMission' ) . fadeIn ( 300 ) ;
} ;
button . addEventListener ( 'click' , handleShowSettings , false ) ;
button . addEventListener ( 'touchstart' , handleShowSettings , false ) ;
var element = document . createElement ( 'div' ) ;
element . className = 'mission-control-multimission ol-unselectable ol-control' ;
element . appendChild ( button ) ;
element . title = 'MP MultiMission' ;
ol . control . Control . call ( this , {
element : element ,
target : options . target
} ) ;
} ;
ol . inherits ( app . PlannerMultiMissionControl , ol . control . Control ) ;
/ * *
* @ param { ol . MapBrowserEvent } evt Map browser event .
* @ return { boolean } ` true ` to start the drag sequence .
* /
app . Drag . prototype . handleDownEvent = function ( evt ) {
if ( disableMarkerEdit ) return false ;
var map = evt . map ;
var feature = map . forEachFeatureAtPixel ( evt . pixel ,
function ( feature , layer ) {
return feature ;
} ) ;
tempMarker = map . forEachFeatureAtPixel ( evt . pixel ,
function ( feature , layer ) {
return layer ;
} ) ;
if ( feature ) {
this . coordinate _ = evt . coordinate ;
this . feature _ = feature ;
this . layer _ = tempMarker ;
}
return ! ! feature ;
} ;
/ * *
* @ param { ol . MapBrowserEvent } evt Map browser event .
* /
app . Drag . prototype . handleDragEvent = function ( evt ) {
if ( tempMarker . kind == "safehomecircle" ) {
return ;
}
var map = evt . map ;
var feature = map . forEachFeatureAtPixel ( evt . pixel ,
function ( feature , layer ) {
return feature ;
} ) ;
var deltaX = evt . coordinate [ 0 ] - this . coordinate _ [ 0 ] ;
var deltaY = evt . coordinate [ 1 ] - this . coordinate _ [ 1 ] ;
var geometry = /** @type {ol.geom.SimpleGeometry} */
( this . feature _ . getGeometry ( ) ) ;
if ( tempMarker . kind == "waypoint" || tempMarker . kind == "safehome" || tempMarker . kind == "home" ) {
geometry . translate ( deltaX , deltaY ) ;
this . coordinate _ [ 0 ] = evt . coordinate [ 0 ] ;
this . coordinate _ [ 1 ] = evt . coordinate [ 1 ] ;
}
let coord = ol . proj . toLonLat ( geometry . getCoordinates ( ) ) ;
if ( tempMarker . kind == "waypoint" ) {
let tempWp = mission . getWaypoint ( tempMarker . number ) ;
tempWp . setLon ( Math . round ( coord [ 0 ] * 10000000 ) ) ;
tempWp . setLat ( Math . round ( coord [ 1 ] * 10000000 ) ) ;
if ( selectedMarker != null && tempMarker . number == selectedMarker . getLayerNumber ( ) ) {
$ ( '#pointLon' ) . val ( Math . round ( coord [ 0 ] * 10000000 ) / 10000000 ) ;
$ ( '#pointLat' ) . val ( Math . round ( coord [ 1 ] * 10000000 ) / 10000000 ) ;
}
mission . updateWaypoint ( tempWp ) ;
repaintLine4Waypoints ( mission ) ;
}
else if ( tempMarker . kind == "safehome" ) {
let tmpSafehome = FC . SAFEHOMES . get ( ) [ tempMarker . number ] ;
tmpSafehome . setLon ( Math . round ( coord [ 0 ] * 1e7 ) ) ;
tmpSafehome . setLat ( Math . round ( coord [ 1 ] * 1e7 ) ) ;
$ ( '#safeHomeLongitude' ) . val ( Math . round ( coord [ 0 ] * 1e7 ) ) ;
$ ( '#safeHomeLatitude' ) . val ( Math . round ( coord [ 1 ] * 1e7 ) ) ;
updateSelectedShAndFwAp ( tempMarker . number ) ;
renderSafeHomeOptions ( ) ;
cleanSafehomeLayers ( ) ;
renderSafehomesOnMap ( ) ;
}
else if ( tempMarker . kind == "home" ) {
HOME . setLon ( Math . round ( coord [ 0 ] * 10000000 ) ) ;
HOME . setLat ( Math . round ( coord [ 1 ] * 10000000 ) ) ;
$ ( '.home-lon' ) . val ( Math . round ( coord [ 0 ] * 10000000 ) / 10000000 ) ;
$ ( '.home-lat' ) . val ( Math . round ( coord [ 1 ] * 10000000 ) / 10000000 ) ;
}
} ;
/ * *
* @ param { ol . MapBrowserEvent } evt Event .
* /
app . Drag . prototype . handleMoveEvent = function ( evt ) {
if ( this . cursor _ ) {
var map = evt . map ;
var feature = map . forEachFeatureAtPixel ( evt . pixel ,
function ( feature , layer ) {
return feature ;
} ) ;
var element = evt . map . getTargetElement ( ) ;
if ( feature && feature . name != "circleFeature" && feature . name != "circleSafeFeature" ) {
if ( element . style . cursor != this . cursor _ ) {
this . previousCursor _ = element . style . cursor ;
element . style . cursor = this . cursor _ ;
}
} else if ( this . previousCursor _ !== undefined ) {
element . style . cursor = this . previousCursor _ ;
this . previousCursor _ = undefined ;
}
}
} ;
/ * *
* @ param { ol . MapBrowserEvent } evt Map browser event .
* @ return { boolean } ` false ` to stop the drag sequence .
* /
app . Drag . prototype . handleUpEvent = function ( evt ) {
if ( tempMarker . kind == "waypoint" ) {
if ( selectedMarker != null && tempMarker . number == selectedMarker . getLayerNumber ( ) ) {
( async ( ) => {
const elevationAtWP = await mission . getWaypoint ( tempMarker . number ) . getElevation ( globalSettings ) ;
$ ( '#elevationValueAtWP' ) . text ( elevationAtWP ) ;
const returnAltitude = checkAltElevSanity ( false , mission . getWaypoint ( tempMarker . number ) . getAlt ( ) , elevationAtWP , mission . getWaypoint ( tempMarker . number ) . getP3 ( ) ) ;
mission . getWaypoint ( tempMarker . number ) . setAlt ( returnAltitude ) ;
if ( mission . getWaypoint ( tempMarker . number ) . getAction ( ) == MWNP . WPTYPE . LAND ) {
let approach = FC . FW _APPROACH . get ( ) [ FC . SAFEHOMES . getMaxSafehomeCount ( ) + mission . getWaypoint ( tempMarker . number ) . getMultiMissionIdx ( ) ] ;
if ( approach . getIsSeaLevelRef ( ) ) {
if ( approach . getElevation ( ) != 0 ) {
approach . setApproachAltAsl ( approach . getApproachAltAsl ( ) - approach . getElevation ( ) + elevationAtWP * 100 ) ;
approach . setLandAltAsl ( approach . getLandAltAsl ( ) - approach . getElevation ( ) + elevationAtWP * 100 ) ;
}
approach . setElevation ( elevationAtWP * 100 ) ;
$ ( '#wpApproachAlt' ) . val ( approach . getApproachAltAsl ( ) ) ;
$ ( '#wpLandAlt' ) . val ( approach . getLandAltAsl ) ;
$ ( '#wpLandAltM' ) . text ( approach . getLandAltAsl ( ) / 100 + " m" ) ;
$ ( '#wpApproachAltM' ) . text ( approach . getApproachAltAsl ( ) / 100 + " m" ) ;
}
}
plotElevation ( ) ;
} ) ( )
}
}
else if ( tempMarker . kind == "home" ) {
( async ( ) => {
const elevationAtHome = await HOME . getElevation ( globalSettings ) ;
$ ( '#elevationValueAtHome' ) . text ( elevationAtHome + ' m' ) ;
HOME . setAlt ( elevationAtHome ) ;
plotElevation ( ) ;
} ) ( )
}
else if ( tempMarker . kind == "safehome" ) {
( async ( ) => {
let approach = FC . FW _APPROACH . get ( ) [ tempMarker . number ] ;
let safehome = FC . SAFEHOMES . get ( ) [ tempMarker . number ] ;
const elevation = await approach . getElevationFromServer ( safehome . getLonMap ( ) , safehome . getLatMap ( ) , globalSettings ) * 100 ;
$ ( '#safehomeElevation' ) . text ( elevation / 100 + " m" ) ;
if ( approach . getIsSeaLevelRef ( ) ) {
if ( approach . getElevation ( ) != 0 ) {
approach . setApproachAltAsl ( approach . getApproachAltAsl ( ) - approach . getElevation ( ) + elevation ) ;
approach . setLandAltAsl ( approach . getLandAltAsl ( ) - approach . getElevation ( ) + elevation ) ;
}
approach . setElevation ( elevation ) ;
}
renderSafeHomeOptions ( ) ;
} ) ( )
}
this . coordinate _ = null ;
this . feature _ = null ;
return false ;
} ;
var lat = ( FC . GPS _DATA ? ( FC . GPS _DATA . lat / 10000000 ) : 0 ) ;
var lon = ( FC . GPS _DATA ? ( FC . GPS _DATA . lon / 10000000 ) : 0 ) ;
let mapLayer ;
let control _list ;
if ( globalSettings . mapProviderType == 'bing' ) {
mapLayer = new ol . source . BingMaps ( {
key : globalSettings . mapApiKey ,
imagerySet : 'AerialWithLabels' ,
maxZoom : 19
} ) ;
} else if ( globalSettings . mapProviderType == 'mapproxy' ) {
mapLayer = new ol . source . TileWMS ( {
url : globalSettings . proxyURL ,
params : { 'LAYERS' : globalSettings . proxyLayer }
} )
} else {
mapLayer = new ol . source . OSM ( ) ;
}
if ( CONFIGURATOR . connectionValid ) {
control _list = [
new app . PlannerSettingsControl ( ) ,
new app . PlannerMultiMissionControl ( ) ,
new app . PlannerSafehomeControl ( ) ,
new app . PlannerElevationControl ( ) ,
]
}
else {
control _list = [
new app . PlannerSettingsControl ( ) ,
new app . PlannerMultiMissionControl ( ) ,
new app . PlannerElevationControl ( ) ,
//new app.PlannerSafehomeControl() // TO COMMENT FOR RELEASE : DECOMMENT FOR DEBUG
]
}
//////////////////////////////////////////////////////////////////////////////////////////////
// Map object definition
//////////////////////////////////////////////////////////////////////////////////////////////
map = new ol . Map ( {
controls : ol . control . defaults ( {
attributionOptions : {
collapsible : false
}
} ) . extend ( control _list ) ,
interactions : ol . interaction . defaults ( ) . extend ( [ new app . Drag ( ) ] ) ,
layers : [
new ol . layer . Tile ( {
source : mapLayer
} )
] ,
target : document . getElementById ( 'missionMap' ) ,
view : new ol . View ( {
center : ol . proj . fromLonLat ( [ lon , lat ] ) ,
zoom : 2
} )
} ) ;
//////////////////////////////////////////////////////////////////////////
// Set the attribute link to open on an external browser window, so
// it doesn't interfere with the configurator.
//////////////////////////////////////////////////////////////////////////
setTimeout ( function ( ) {
$ ( '.ol-attribution a' ) . attr ( 'target' , '_blank' ) ;
} , 100 ) ;
//////////////////////////////////////////////////////////////////////////
// save map view settings when user moves it
//////////////////////////////////////////////////////////////////////////
map . on ( 'moveend' , function ( evt ) {
store . set ( 'missionPlannerLastValues' , {
center : ol . proj . toLonLat ( map . getView ( ) . getCenter ( ) ) ,
zoom : map . getView ( ) . getZoom ( )
} ) ;
} ) ;
//////////////////////////////////////////////////////////////////////////
// load map view settings on startup
//////////////////////////////////////////////////////////////////////////
var missionPlannerLastValues = store . get ( 'missionPlannerLastValues' , false ) ;
if ( missionPlannerLastValues && missionPlannerLastValues . zoom && missionPlannerLastValues . center ) {
map . getView ( ) . setCenter ( ol . proj . fromLonLat ( missionPlannerLastValues . center ) ) ;
map . getView ( ) . setZoom ( missionPlannerLastValues . zoom ) ;
}
//////////////////////////////////////////////////////////////////////////
// Map on-click behavior definition
//////////////////////////////////////////////////////////////////////////
map . on ( 'click' , function ( evt ) {
var tempSelectedMarkerIndex = null ;
if ( selectedMarker != null && selectedFeature != null ) {
tempSelectedMarkerIndex = selectedMarker . getLayerNumber ( ) ;
try {
selectedFeature . setStyle ( getWaypointIcon ( selectedMarker , false ) ) ;
selectedMarker = null ;
selectedFeature = null ;
tempMarker = null ;
clearEditForm ( ) ;
} catch ( e ) {
console . log ( e ) ;
GUI . log ( i18n . getMessage ( 'notAWAYPOINT' ) ) ;
}
}
selectedFeature = map . forEachFeatureAtPixel ( evt . pixel ,
function ( feature , layer ) {
return feature ;
} ) ;
tempMarker = map . forEachFeatureAtPixel ( evt . pixel ,
function ( feature , layer ) {
return layer ;
} ) ;
if ( selectedFeature && tempMarker . kind == "waypoint" ) {
$ ( "#editMission" ) . hide ( ) ;
selectedMarker = mission . getWaypoint ( tempMarker . number ) ;
selectedFwApproachWp = FC . FW _APPROACH . get ( ) [ FC . SAFEHOMES . getMaxSafehomeCount ( ) + selectedMarker . getMultiMissionIdx ( ) ] ;
if ( selectedFwApproachWp . getLandHeading1 ( ) == 0 && selectedFwApproachWp . getLandHeading1 ( ) == 0 && selectedFwApproachWp . getApproachAltAsl ( ) == 0 && selectedFwApproachWp . getLandAltAsl ( ) == 0 ) {
selectedFwApproachWp . setApproachAltAsl ( settings . fwApproachAlt * 100 ) ;
selectedFwApproachWp . setLandAltAsl ( settings . fwLandAlt * 100 ) ;
}
var geometry = selectedFeature . getGeometry ( ) ;
var coord = ol . proj . toLonLat ( geometry . getCoordinates ( ) ) ;
selectedFeature . setStyle ( getWaypointIcon ( selectedMarker , true ) ) ;
let P3Value = selectedMarker . getP3 ( ) ;
changeSwitchery ( $ ( '#pointP3Alt' ) , TABS . mission _control . isBitSet ( P3Value , MWNP . P3 . ALT _TYPE ) ) ;
changeSwitchery ( $ ( '#pointP3UserAction1' ) , TABS . mission _control . isBitSet ( P3Value , MWNP . P3 . USER _ACTION _1 ) ) ;
changeSwitchery ( $ ( '#pointP3UserAction2' ) , TABS . mission _control . isBitSet ( P3Value , MWNP . P3 . USER _ACTION _2 ) ) ;
changeSwitchery ( $ ( '#pointP3UserAction3' ) , TABS . mission _control . isBitSet ( P3Value , MWNP . P3 . USER _ACTION _3 ) ) ;
changeSwitchery ( $ ( '#pointP3UserAction4' ) , TABS . mission _control . isBitSet ( P3Value , MWNP . P3 . USER _ACTION _4 ) ) ;
var altitudeMeters = app . ConvertCentimetersToMeters ( selectedMarker . getAlt ( ) ) ;
if ( selectedMarker . getAction ( ) == MWNP . WPTYPE . LAND ) {
$ ( '#wpFwLanding' ) . fadeIn ( 300 ) ;
} else {
$ ( '#wpFwLanding' ) . fadeOut ( 300 ) ;
}
if ( tempSelectedMarkerIndex == null || tempSelectedMarkerIndex != selectedMarker . getLayerNumber ( ) ) {
( async ( ) => {
const elevationAtWP = await selectedMarker . getElevation ( globalSettings ) ;
$ ( '#elevationValueAtWP' ) . text ( elevationAtWP ) ;
const returnAltitude = checkAltElevSanity ( false , selectedMarker . getAlt ( ) , elevationAtWP , P3Value ) ;
selectedMarker . setAlt ( returnAltitude ) ;
/ *
if ( TABS . mission _control . isBitSet ( P3Value , MWNP . P3 . ALT _TYPE ) ) {
if ( ! selectedFwApproachWp . getIsSeaLevelRef ( ) ) {
selectedFwApproachWp . setApproachDirection ( selectedFwApproachWp . getApproachDirection ( ) + elevationAtWP * 100 ) ;
selectedFwApproachWp . setLandAltAsl ( selectedFwApproachWp . getLandAltAsl ( ) + elevationAtWP * 100 ) ;
}
}
* /
selectedFwApproachWp . setIsSeaLevelRef ( TABS . mission _control . isBitSet ( P3Value , MWNP . P3 . ALT _TYPE ) ? 1 : 0 ) ;
$ ( '#wpApproachAlt' ) . val ( selectedFwApproachWp . getApproachAltAsl ( ) ) ;
$ ( '#wpLandAlt' ) . val ( selectedFwApproachWp . getLandAltAsl ) ;
$ ( '#wpLandAltM' ) . text ( selectedFwApproachWp . getLandAltAsl ( ) / 100 + " m" ) ;
$ ( '#wpApproachAltM' ) . text ( selectedFwApproachWp . getApproachAltAsl ( ) / 100 + " m" ) ;
plotElevation ( ) ;
} ) ( )
}
$ ( '#elevationAtWP' ) . fadeIn ( ) ;
$ ( '#groundClearanceAtWP' ) . fadeIn ( ) ;
$ ( '#altitudeInMeters' ) . text ( ` ${ altitudeMeters } m ` ) ;
$ ( '#pointLon' ) . val ( Math . round ( coord [ 0 ] * 10000000 ) / 10000000 ) ;
$ ( '#pointLat' ) . val ( Math . round ( coord [ 1 ] * 10000000 ) / 10000000 ) ;
$ ( '#pointAlt' ) . val ( selectedMarker . getAlt ( ) ) ;
$ ( '#pointType' ) . val ( selectedMarker . getAction ( ) ) ;
// Change SpeedValue to Parameter1, 2, 3
$ ( '#pointP1' ) . val ( selectedMarker . getP1 ( ) ) ;
$ ( '#pointP2' ) . val ( selectedMarker . getP2 ( ) ) ;
$ ( '#wpApproachDirection' ) . val ( selectedFwApproachWp . getApproachDirection ( ) ) ;
$ ( '#wpLandHeading1' ) . val ( Math . abs ( selectedFwApproachWp . getLandHeading1 ( ) ) ) ;
changeSwitchery ( $ ( '#wpLandHeading1Excl' ) , selectedFwApproachWp . getLandHeading1 ( ) < 0 ) ;
$ ( '#wpLandHeading2' ) . val ( Math . abs ( selectedFwApproachWp . getLandHeading2 ( ) ) ) ;
changeSwitchery ( $ ( '#wpLandHeading2Excl' ) , selectedFwApproachWp . getLandHeading2 ( ) < 0 ) ;
$ ( '#wpApproachDirection' ) . val ( selectedFwApproachWp . getApproachDirection ( ) ) ;
$ ( '#wpLandHeading1' ) . val ( Math . abs ( selectedFwApproachWp . getLandHeading1 ( ) ) ) ;
changeSwitchery ( $ ( '#wpLandHeading1Excl' ) , selectedFwApproachWp . getLandHeading1 ( ) < 0 ) ;
$ ( '#wpLandHeading2' ) . val ( Math . abs ( selectedFwApproachWp . getLandHeading2 ( ) ) ) ;
changeSwitchery ( $ ( '#wpLandHeading2Excl' ) , selectedFwApproachWp . getLandHeading2 ( ) < 0 ) ;
// Selection box update depending on choice of type of waypoint
for ( var j in dictOfLabelParameterPoint [ selectedMarker . getAction ( ) ] ) {
if ( dictOfLabelParameterPoint [ selectedMarker . getAction ( ) ] [ j ] != '' ) {
$ ( '#pointP' + String ( j ) . slice ( - 1 ) + 'class' ) . fadeIn ( 300 ) ;
$ ( 'label[for=pointP' + String ( j ) . slice ( - 1 ) + ']' ) . html ( dictOfLabelParameterPoint [ selectedMarker . getAction ( ) ] [ j ] ) ;
}
else { $ ( '#pointP' + String ( j ) . slice ( - 1 ) + 'class' ) . fadeOut ( 300 ) ; }
}
selectedMarker = renderWaypointOptionsTable ( selectedMarker ) ;
$ ( '#EditPointNumber' ) . text ( "Edit point " + String ( selectedMarker . getLayerNumber ( ) + 1 ) ) ;
$ ( '#MPeditPoint' ) . fadeIn ( 300 ) ;
$ ( '#pointP3UserActionClass' ) . fadeIn ( ) ;
redrawLayer ( ) ;
}
else if ( selectedFeature && tempMarker . kind == "line" && tempMarker . selection && ! disableMarkerEdit ) {
let tempWpCoord = ol . proj . toLonLat ( evt . coordinate ) ;
let tempWp = new Waypoint ( tempMarker . number , MWNP . WPTYPE . WAYPOINT , Math . round ( tempWpCoord [ 1 ] * 10000000 ) , Math . round ( tempWpCoord [ 0 ] * 10000000 ) , Number ( settings . alt ) , Number ( settings . speed ) ) ;
tempWp . setMultiMissionIdx ( mission . getWaypoint ( 0 ) . getMultiMissionIdx ( ) ) ;
if ( homeMarkers . length && HOME . getAlt ( ) != "N/A" ) {
( async ( ) => {
const elevationAtWP = await tempWp . getElevation ( globalSettings ) ;
tempWp . setAlt ( checkAltElevSanity ( false , settings . alt , elevationAtWP , false ) ) ;
mission . insertWaypoint ( tempWp , tempMarker . number ) ;
mission . update ( singleMissionActive ( ) ) ;
refreshLayers ( ) ;
plotElevation ( ) ;
} ) ( )
} else {
mission . insertWaypoint ( tempWp , tempMarker . number ) ;
mission . update ( singleMissionActive ( ) ) ;
refreshLayers ( ) ;
plotElevation ( ) ;
}
}
else if ( selectedFeature && tempMarker . kind == "safehome" && tempMarker . selection ) {
updateSelectedShAndFwAp ( tempMarker . number ) ;
//renderSafeHomeOptions();
}
else if ( selectedFeature && tempMarker . kind == "home" && tempMarker . selection ) {
selectedMarker = HOME ;
var geometry = selectedFeature . getGeometry ( ) ;
var coord = ol . proj . toLonLat ( geometry . getCoordinates ( ) ) ;
$ ( '.home-lon' ) . val ( Math . round ( coord [ 0 ] * 10000000 ) / 10000000 ) ;
$ ( '.home-lat' ) . val ( Math . round ( coord [ 1 ] * 10000000 ) / 10000000 ) ;
}
else if ( ! disableMarkerEdit ) {
let tempWpCoord = ol . proj . toLonLat ( evt . coordinate ) ;
let tempWp = new Waypoint ( mission . get ( ) . length , MWNP . WPTYPE . WAYPOINT , Math . round ( tempWpCoord [ 1 ] * 10000000 ) , Math . round ( tempWpCoord [ 0 ] * 10000000 ) , Number ( settings . alt ) , Number ( settings . speed ) ) ;
if ( mission . get ( ) . length == 0 ) {
tempWp . setMultiMissionIdx ( multimissionCount == 0 ? 0 : multimissionCount - 1 ) ;
FC . FW _APPROACH . clean ( FC . SAFEHOMES . getMaxSafehomeCount ( ) + tempWp . getMultiMissionIdx ( ) ) ;
} else {
tempWp . setMultiMissionIdx ( mission . getWaypoint ( mission . get ( ) . length - 1 ) . getMultiMissionIdx ( ) ) ;
}
if ( homeMarkers . length && HOME . getAlt ( ) != "N/A" ) {
( async ( ) => {
const elevationAtWP = await tempWp . getElevation ( globalSettings ) ;
tempWp . setAlt ( checkAltElevSanity ( false , settings . alt , elevationAtWP , false ) ) ;
mission . put ( tempWp ) ;
mission . update ( singleMissionActive ( ) ) ;
refreshLayers ( ) ;
plotElevation ( ) ;
} ) ( )
} else {
mission . put ( tempWp ) ;
mission . update ( singleMissionActive ( ) ) ;
refreshLayers ( ) ;
plotElevation ( ) ;
}
}
//mission.missionDisplayDebug();
updateMultimissionState ( ) ;
} ) ;
//////////////////////////////////////////////////////////////////////////
// change mouse cursor when over marker
//////////////////////////////////////////////////////////////////////////
$ ( map . getViewport ( ) ) . on ( 'mousemove' , function ( e ) {
var pixel = map . getEventPixel ( e . originalEvent ) ;
var name = "" ;
var hit = map . forEachFeatureAtPixel ( pixel , function ( feature , layer ) {
if ( feature ) {
name = feature . getProperties ( ) . name ;
}
return true ;
} ) ;
if ( hit && name != "safehomeDist" && name != "safehomeSafe" ) {
map . getTarget ( ) . style . cursor = 'pointer' ;
} else {
map . getTarget ( ) . style . cursor = '' ;
}
} ) ;
//////////////////////////////////////////////////////////////////////////
// handle map size on container resize
//////////////////////////////////////////////////////////////////////////
setInterval ( function ( ) {
let width = $ ( "#missionMap canvas" ) . width ( ) , height = $ ( "#missionMap canvas" ) . height ( ) ;
if ( ( map . width _ != width ) || ( map . height _ != height ) ) map . updateSize ( ) ;
map . width _ = width ; map . height _ = height ;
} , 200 ) ;
//////////////////////////////////////////////////////////////////////////
// Update Alt display in meters on ALT field keypress up
//////////////////////////////////////////////////////////////////////////
$ ( '#pointAlt' ) . on ( 'keyup' , ( ) => {
let altitudeMeters = app . ConvertCentimetersToMeters ( $ ( '#pointAlt' ) . val ( ) ) ;
$ ( '#altitudeInMeters' ) . text ( ` ${ altitudeMeters } m ` ) ;
} ) ;
/////////////////////////////////////////////
// Callback to show/hide menu boxes
/////////////////////////////////////////////
$ ( '#showHideActionButton' ) . on ( 'click' , function ( ) {
var src = ( $ ( this ) . children ( ) . attr ( 'class' ) === 'ic_hide' )
? 'ic_show'
: 'ic_hide' ;
$ ( this ) . children ( ) . attr ( 'class' , src ) ;
if ( $ ( this ) . children ( ) . attr ( 'class' ) === 'ic_hide' ) {
$ ( '#ActionContent' ) . fadeIn ( 300 ) ;
}
else {
$ ( '#ActionContent' ) . fadeOut ( 300 ) ;
}
} ) ;
$ ( '#showHideInfoButton' ) . on ( 'click' , function ( ) {
var src = ( $ ( this ) . children ( ) . attr ( 'class' ) === 'ic_hide' )
? 'ic_show'
: 'ic_hide' ;
$ ( this ) . children ( ) . attr ( 'class' , src ) ;
if ( $ ( this ) . children ( ) . attr ( 'class' ) === 'ic_hide' ) {
$ ( '#InfoContent' ) . fadeIn ( 300 ) ;
}
else {
$ ( '#InfoContent' ) . fadeOut ( 300 ) ;
}
} ) ;
$ ( '#showHideSafehomeButton' ) . on ( 'click' , function ( ) {
var src = ( $ ( this ) . children ( ) . attr ( 'class' ) === 'ic_hide' )
? 'ic_show'
: 'ic_hide' ;
$ ( this ) . children ( ) . attr ( 'class' , src ) ;
if ( $ ( this ) . children ( ) . attr ( 'class' ) === 'ic_hide' ) {
$ ( '#SafehomeContent' ) . fadeIn ( 300 ) ;
}
else {
$ ( '#SafehomeContent' ) . fadeOut ( 300 ) ;
}
} ) ;
$ ( '#showHideHomeButton' ) . on ( 'click' , function ( ) {
var src = ( $ ( this ) . children ( ) . attr ( 'class' ) === 'ic_hide' )
? 'ic_show'
: 'ic_hide' ;
$ ( this ) . children ( ) . attr ( 'class' , src ) ;
if ( $ ( this ) . children ( ) . attr ( 'class' ) === 'ic_hide' ) {
$ ( '#HomeContent' ) . fadeIn ( 300 ) ;
}
else {
$ ( '#HomeContent' ) . fadeOut ( 300 ) ;
}
} ) ;
$ ( '#showHideWPeditButton' ) . on ( 'click' , function ( ) {
var src = ( $ ( this ) . children ( ) . attr ( 'class' ) === 'ic_hide' )
? 'ic_show'
: 'ic_hide' ;
$ ( this ) . children ( ) . attr ( 'class' , src ) ;
if ( $ ( this ) . children ( ) . attr ( 'class' ) === 'ic_hide' ) {
$ ( '#WPeditContent' ) . fadeIn ( 300 ) ;
}
else {
$ ( '#WPeditContent' ) . fadeOut ( 300 ) ;
}
} ) ;
$ ( '#showHideMultimissionButton' ) . on ( 'click' , function ( ) {
var src = ( $ ( this ) . children ( ) . attr ( 'class' ) === 'ic_hide' )
? 'ic_show'
: 'ic_hide' ;
$ ( this ) . children ( ) . attr ( 'class' , src ) ;
if ( $ ( this ) . children ( ) . attr ( 'class' ) === 'ic_hide' ) {
$ ( '#multimissionContent' ) . fadeIn ( 300 ) ;
}
else {
$ ( '#multimissionContent' ) . fadeOut ( 300 ) ;
}
} ) ;
/////////////////////////////////////////////
// Callback for Waypoint edition
/////////////////////////////////////////////
$ ( '#pointType' ) . on ( 'change' , ( event ) => {
if ( selectedMarker ) {
if ( Number ( $ ( '#pointType' ) . val ( ) ) == MWNP . WPTYPE . LAND ) {
let found = false ;
mission . get ( ) . forEach ( wp => {
if ( wp . getAction ( ) == MWNP . WPTYPE . LAND ) {
GUI . alert ( i18n . getMessage ( 'MissionPlannerOnlyOneLandWp' ) ) ;
found = true ;
$ ( event . currentTarget ) . val ( selectedMarker . getAction ( ) ) ;
}
} ) ;
if ( ! found ) {
$ ( '#wpFwLanding' ) . fadeIn ( 300 ) ;
}
} else {
$ ( '#wpFwLanding' ) . fadeOut ( 300 ) ;
}
selectedMarker . setAction ( Number ( $ ( '#pointType' ) . val ( ) ) ) ;
if ( [ MWNP . WPTYPE . SET _POI , MWNP . WPTYPE . POSHOLD _TIME , MWNP . WPTYPE . LAND ] . includes ( selectedMarker . getAction ( ) ) ) {
selectedMarker . setP1 ( 0.0 ) ;
selectedMarker . setP2 ( 0.0 ) ;
}
for ( var j in dictOfLabelParameterPoint [ selectedMarker . getAction ( ) ] ) {
if ( dictOfLabelParameterPoint [ selectedMarker . getAction ( ) ] [ j ] != '' ) {
$ ( '#pointP' + String ( j ) . slice ( - 1 ) + 'class' ) . fadeIn ( 300 ) ;
$ ( 'label[for=pointP' + String ( j ) . slice ( - 1 ) + ']' ) . html ( dictOfLabelParameterPoint [ selectedMarker . getAction ( ) ] [ j ] ) ;
}
else { $ ( '#pointP' + String ( j ) . slice ( - 1 ) + 'class' ) . fadeOut ( 300 ) ; }
}
mission . updateWaypoint ( selectedMarker ) ;
mission . update ( singleMissionActive ( ) ) ;
redrawLayer ( ) ;
}
} ) ;
$ ( '#pointLat' ) . on ( 'change' , function ( event ) {
if ( selectedMarker ) {
selectedMarker . setLat ( Math . round ( Number ( $ ( '#pointLat' ) . val ( ) ) * 10000000 ) ) ;
mission . updateWaypoint ( selectedMarker ) ;
mission . update ( singleMissionActive ( ) ) ;
refreshLayers ( ) ;
selectedFeature = markers [ selectedMarker . getLayerNumber ( ) ] . getSource ( ) . getFeatures ( ) [ 0 ] ;
selectedFeature . setStyle ( getWaypointIcon ( selectedMarker , true ) ) ;
plotElevation ( ) ;
}
} ) ;
$ ( '#pointLon' ) . on ( 'change' , function ( event ) {
if ( selectedMarker ) {
selectedMarker . setLon ( Math . round ( Number ( $ ( '#pointLon' ) . val ( ) ) * 10000000 ) ) ;
mission . updateWaypoint ( selectedMarker ) ;
mission . update ( singleMissionActive ( ) ) ;
refreshLayers ( ) ;
selectedFeature = markers [ selectedMarker . getLayerNumber ( ) ] . getSource ( ) . getFeatures ( ) [ 0 ] ;
selectedFeature . setStyle ( getWaypointIcon ( selectedMarker , true ) ) ;
plotElevation ( ) ;
}
} ) ;
$ ( '#pointAlt' ) . on ( 'change' , function ( event ) {
if ( selectedMarker ) {
const elevationAtWP = Number ( $ ( '#elevationValueAtWP' ) . text ( ) ) ;
const returnAltitude = checkAltElevSanity ( true , Number ( $ ( '#pointAlt' ) . val ( ) ) , elevationAtWP , selectedMarker . getP3 ( ) ) ;
selectedMarker . setAlt ( returnAltitude ) ;
mission . updateWaypoint ( selectedMarker ) ;
mission . update ( singleMissionActive ( ) ) ;
redrawLayer ( ) ;
plotElevation ( ) ;
}
} ) ;
$ ( '#pointP1' ) . on ( 'change' , function ( event ) {
if ( selectedMarker ) {
selectedMarker . setP1 ( Number ( $ ( '#pointP1' ) . val ( ) ) ) ;
mission . updateWaypoint ( selectedMarker ) ;
mission . update ( singleMissionActive ( ) ) ;
redrawLayer ( ) ;
}
} ) ;
$ ( '#pointP2' ) . on ( 'change' , function ( event ) {
if ( selectedMarker ) {
selectedMarker . setP2 ( Number ( $ ( '#pointP2' ) . val ( ) ) ) ;
mission . updateWaypoint ( selectedMarker ) ;
mission . update ( singleMissionActive ( ) ) ;
redrawLayer ( ) ;
}
} ) ;
$ ( '#pointP3Alt' ) . on ( 'change' , function ( event ) {
if ( selectedMarker ) {
var P3Value = selectedMarker . getP3 ( ) ;
if ( disableMarkerEdit ) {
changeSwitchery ( $ ( '#pointP3Alt' ) , TABS . mission _control . isBitSet ( P3Value , MWNP . P3 . ALT _TYPE ) ) ;
}
P3Value = TABS . mission _control . setBit ( P3Value , MWNP . P3 . ALT _TYPE , $ ( '#pointP3Alt' ) . prop ( "checked" ) ) ;
( async ( ) => {
const elevationAtWP = await selectedMarker . getElevation ( globalSettings ) ;
$ ( '#elevationValueAtWP' ) . text ( elevationAtWP ) ;
var altitude = Number ( $ ( '#pointAlt' ) . val ( ) ) ;
if ( P3Value != selectedMarker . getP3 ( ) ) {
selectedMarker . setP3 ( P3Value ) ;
let groundClearance = 100 * Number ( $ ( '#groundClearanceValueAtWP' ) . text ( ) ) ;
if ( isNaN ( groundClearance ) ) {
groundClearance = settings . alt ; // use default altitude if no current ground clearance
}
if ( $ ( '#pointP3Alt' ) . prop ( "checked" ) ) {
selectedMarker . setAlt ( groundClearance + elevationAtWP * 100 ) ;
} else {
let elevationAtHome = HOME . getAlt ( ) ;
if ( isNaN ( elevationAtHome ) ) {
elevationAtHome = elevationAtWP ;
}
selectedMarker . setAlt ( groundClearance + 100 * ( elevationAtWP - elevationAtHome ) ) ;
}
if ( selectedMarker . getAction ( ) == MWNP . WPTYPE . LAND && selectedFwApproachWp && selectedFwApproachWp . getIsSeaLevelRef ( ) != $ ( '#pointP3Alt' ) . prop ( "checked" ) ) {
let oldElevation = 0 ;
if ( selectedFwApproachWp . getIsSeaLevelRef ( ) ) {
oldElevation = selectedFwApproachWp . getElevation ( ) ;
}
if ( $ ( '#pointP3Alt' ) . prop ( "checked" ) ) {
selectedFwApproachWp . setApproachAltAsl ( selectedFwApproachWp . getApproachAltAsl ( ) - oldElevation + elevationAtWP * 100 ) ;
selectedFwApproachWp . setLandAltAsl ( selectedFwApproachWp . getLandAltAsl ( ) - oldElevation + elevationAtWP * 100 ) ;
} else {
selectedFwApproachWp . setApproachAltAsl ( selectedFwApproachWp . getApproachAltAsl ( ) - elevationAtWP * 100 ) ;
selectedFwApproachWp . setLandAltAsl ( selectedFwApproachWp . getLandAltAsl ( ) - elevationAtWP * 100 ) ;
}
selectedFwApproachWp . setElevation ( elevationAtWP * 100 ) ;
selectedFwApproachWp . setIsSeaLevelRef ( $ ( '#pointP3Alt' ) . prop ( "checked" ) ? 1 : 0 ) ;
$ ( '#wpApproachAlt' ) . val ( selectedFwApproachWp . getApproachAltAsl ( ) ) ;
$ ( '#wpLandAlt' ) . val ( selectedFwApproachWp . getLandAltAsl ( ) ) ;
}
}
const returnAltitude = checkAltElevSanity ( false , selectedMarker . getAlt ( ) , elevationAtWP , selectedMarker . getP3 ( ) ) ;
selectedMarker . setAlt ( returnAltitude ) ;
$ ( '#pointAlt' ) . val ( selectedMarker . getAlt ( ) ) ;
let altitudeMeters = app . ConvertCentimetersToMeters ( selectedMarker . getAlt ( ) ) ;
$ ( '#altitudeInMeters' ) . text ( ` ${ altitudeMeters } m ` ) ;
$ ( '#wpLandAltM' ) . text ( selectedFwApproachWp . getLandAltAsl ( ) / 100 + " m" ) ;
$ ( '#wpApproachAltM' ) . text ( selectedFwApproachWp . getApproachAltAsl ( ) / 100 + " m" ) ;
if ( selectedFwApproachWp && selectedFwApproachWp . getIsSeaLevelRef ( ) != $ ( '#pointP3Alt' ) . prop ( "checked" ) ) {
selectedFwApproachWp . setIsSeaLevelRef ( $ ( '#pointP3Alt' ) . prop ( "checked" ) ) ;
selectedFwApproachWp . setElevation ( elevationAtWP * 100 ) ;
if ( $ ( '#pointP3Alt' ) . prop ( "checked" ) ) {
selectedFwApproachWp . setApproachAltAsl ( selectedFwApproachWp . getApproachAltAsl ( ) + elevationAtWP * 100 ) ;
selectedFwApproachWp . setLandAltAsl ( selectedFwApproachWp . getLandAltAsl ( ) + elevationAtWP * 100 ) ;
} else {
selectedFwApproachWp . setApproachAltAsl ( selectedFwApproachWp . getApproachAltAsl ( ) - elevationAtWP * 100 ) ;
selectedFwApproachWp . setLandAltAsl ( selectedFwApproachWp . getLandAltAsl ( ) - elevationAtWP * 100 ) ;
}
$ ( '#wpApproachAlt' ) . val ( selectedFwApproachWp . getApproachAltAsl ( ) ) ;
$ ( '#wpLandAlt' ) . val ( selectedFwApproachWp . getLandAltAsl ( ) ) ;
}
$ ( '#wpLandAltM' ) . text ( selectedFwApproachWp . getLandAltAsl ( ) / 100 + " m" ) ;
$ ( '#wpApproachAltM' ) . text ( selectedFwApproachWp . getApproachAltAsl ( ) / 100 + " m" ) ;
mission . updateWaypoint ( selectedMarker ) ;
mission . update ( singleMissionActive ( ) ) ;
redrawLayer ( ) ;
plotElevation ( ) ;
} ) ( ) ;
}
} ) ;
$ ( '#pointP3UserAction1' ) . on ( 'change' , function ( event ) {
if ( selectedMarker ) {
if ( disableMarkerEdit ) {
changeSwitchery ( $ ( '#pointP3UserAction1' ) , TABS . mission _control . isBitSet ( selectedMarker . getP3 ( ) , MWNP . P3 . USER _ACTION _1 ) ) ;
}
var P3Value = TABS . mission _control . setBit ( selectedMarker . getP3 ( ) , MWNP . P3 . USER _ACTION _1 , $ ( '#pointP3UserAction1' ) . prop ( "checked" ) ) ;
selectedMarker . setP3 ( P3Value ) ;
mission . updateWaypoint ( selectedMarker ) ;
mission . update ( singleMissionActive ( ) ) ;
redrawLayer ( ) ;
}
} ) ;
$ ( '#pointP3UserAction2' ) . on ( 'change' , function ( event ) {
if ( selectedMarker ) {
if ( disableMarkerEdit ) {
changeSwitchery ( $ ( '#pointP3UserAction2' ) , TABS . mission _control . isBitSet ( selectedMarker . getP3 ( ) , MWNP . P3 . USER _ACTION _2 ) ) ;
}
var P3Value = TABS . mission _control . setBit ( selectedMarker . getP3 ( ) , MWNP . P3 . USER _ACTION _2 , $ ( '#pointP3UserAction2' ) . prop ( "checked" ) ) ;
selectedMarker . setP3 ( P3Value ) ;
mission . updateWaypoint ( selectedMarker ) ;
mission . update ( singleMissionActive ( ) ) ;
redrawLayer ( ) ;
}
} ) ;
$ ( '#pointP3UserAction3' ) . on ( 'change' , function ( event ) {
if ( selectedMarker ) {
if ( disableMarkerEdit ) {
changeSwitchery ( $ ( '#pointP3UserAction3' ) , TABS . mission _control . isBitSet ( selectedMarker . getP3 ( ) , MWNP . P3 . USER _ACTION _3 ) ) ;
}
var P3Value = TABS . mission _control . setBit ( selectedMarker . getP3 ( ) , MWNP . P3 . USER _ACTION _3 , $ ( '#pointP3UserAction3' ) . prop ( "checked" ) ) ;
selectedMarker . setP3 ( P3Value ) ;
mission . updateWaypoint ( selectedMarker ) ;
mission . update ( singleMissionActive ( ) ) ;
redrawLayer ( ) ;
}
} ) ;
$ ( '#pointP3UserAction4' ) . on ( 'change' , function ( event ) {
if ( selectedMarker ) {
if ( disableMarkerEdit ) {
changeSwitchery ( $ ( '#pointP3UserAction4' ) , TABS . mission _control . isBitSet ( selectedMarker . getP3 ( ) , MWNP . P3 . USER _ACTION _4 ) ) ;
}
var P3Value = TABS . mission _control . setBit ( selectedMarker . getP3 ( ) , MWNP . P3 . USER _ACTION _4 , $ ( '#pointP3UserAction4' ) . prop ( "checked" ) ) ;
selectedMarker . setP3 ( P3Value ) ;
mission . updateWaypoint ( selectedMarker ) ;
mission . update ( singleMissionActive ( ) ) ;
redrawLayer ( ) ;
}
} ) ;
$ ( '#wpApproachAlt' ) . on ( 'change' , ( event ) => {
if ( selectedMarker && selectedFwApproachWp ) {
let altitude = Number ( $ ( event . currentTarget ) . val ( ) ) ;
if ( checkApproachAltitude ( altitude , $ ( '#pointP3Alt' ) . prop ( 'checked' ) , Number ( $ ( '#elevationValueAtWP' ) . text ( ) ) ) ) {
selectedFwApproachWp . setApproachAltAsl ( Number ( $ ( event . currentTarget ) . val ( ) ) ) ;
$ ( '#wpApproachAltM' ) . text ( selectedFwApproachWp . getApproachAltAsl ( ) / 100 + " m" ) ;
}
}
} ) ;
$ ( '#wpLandAlt' ) . on ( 'change' , ( event ) => {
if ( selectedMarker && selectedFwApproachWp ) {
let altitude = Number ( $ ( event . currentTarget ) . val ( ) ) ;
if ( checkLandingAltitude ( altitude , $ ( '#pointP3Alt' ) . prop ( 'checked' ) , Number ( $ ( '#elevationValueAtWP' ) . text ( ) ) ) ) {
selectedFwApproachWp . setLandAltAsl ( Number ( $ ( event . currentTarget ) . val ( ) ) ) ;
$ ( '#wpLandAltM' ) . text ( selectedFwApproachWp . getLandAltAsl ( ) / 100 + " m" ) ;
}
}
} ) ;
$ ( '#wpApproachDirection' ) . on ( 'change' , ( event ) => {
if ( selectedMarker && selectedFwApproachWp ) {
selectedFwApproachWp . setApproachDirection ( $ ( event . currentTarget ) . val ( ) ) ;
refreshLayers ( ) ;
}
} ) ;
$ ( '#wpLandHeading1' ) . on ( 'change' , ( event ) => {
if ( selectedMarker && selectedFwApproachWp ) {
let val = Number ( $ ( event . currentTarget ) . val ( ) ) ;
if ( val < 0 ) {
val = 360 ;
$ ( '#wpLandHeading1' ) . val ( 360 ) ;
}
if ( val > 360 ) {
val = 0 ;
$ ( '#wpLandHeading1' ) . val ( 0 ) ;
}
if ( $ ( '#wpLandHeading1Excl' ) . prop ( 'checked' ) ) {
val *= - 1 ;
}
selectedFwApproachWp . setLandHeading1 ( val ) ;
refreshLayers ( ) ;
}
} ) ;
$ ( '#wpLandHeading1Excl' ) . on ( 'change' , ( event ) => {
if ( selectedMarker && selectedFwApproachWp ) {
if ( disableMarkerEdit ) {
changeSwitchery ( $ ( '#wpLandHeading1Excl' ) , selectedFwApproachWp . getLandHeading1 ( ) < 0 ) ;
return ;
}
if ( $ ( '#wpLandHeading1Excl' ) . prop ( 'checked' ) ) {
selectedFwApproachWp . setLandHeading1 ( - Math . abs ( selectedFwApproachWp . getLandHeading1 ( ) ) ) ;
} else {
selectedFwApproachWp . setLandHeading1 ( Math . abs ( selectedFwApproachWp . getLandHeading1 ( ) ) ) ;
}
refreshLayers ( ) ;
}
} ) ;
$ ( '#wpLandHeading2' ) . on ( 'change' , ( event ) => {
if ( selectedMarker && selectedFwApproachWp ) {
let val = Number ( $ ( event . currentTarget ) . val ( ) ) ;
if ( val < 0 ) {
val = 360 ;
$ ( '#wpLandHeading2' ) . val ( 360 ) ;
}
if ( val > 360 ) {
val = 0 ;
$ ( '#wpLandHeading2' ) . val ( 0 ) ;
}
if ( $ ( '#wpLandHeading2Excl' ) . prop ( 'checked' ) ) {
val *= - 1 ;
}
selectedFwApproachWp . setLandHeading2 ( val ) ;
refreshLayers ( ) ;
}
} ) ;
$ ( '#wpLandHeading2Excl' ) . on ( 'change' , ( event ) => {
if ( selectedMarker && selectedFwApproachWp ) {
if ( disableMarkerEdit ) {
changeSwitchery ( $ ( '#wpLandHeading2Excl' ) , selectedFwApproachWp . getLandHeading2 ( ) < 0 ) ;
return ;
}
if ( $ ( '#wpLandHeading2Excl' ) . prop ( 'checked' ) ) {
selectedFwApproachWp . setLandHeading2 ( - Math . abs ( selectedFwApproachWp . getLandHeading2 ( ) ) ) ;
} else {
selectedFwApproachWp . setLandHeading2 ( Math . abs ( selectedFwApproachWp . getLandHeading2 ( ) ) ) ;
}
refreshLayers ( ) ;
}
} ) ;
/////////////////////////////////////////////
// Callback for Waypoint Options Table
/////////////////////////////////////////////
$waypointOptionsTableBody . on ( 'click' , "[data-role='waypointOptions-delete']" , function ( event ) {
if ( selectedMarker ) {
mission . dropAttachedFromWaypoint ( selectedMarker , $ ( event . currentTarget ) . attr ( "data-index" ) - 1 ) ;
renderWaypointOptionsTable ( selectedMarker ) ;
//cleanLines();
refreshLayers ( ) ;
selectedFeature = markers [ selectedMarker . getLayerNumber ( ) ] . getSource ( ) . getFeatures ( ) [ 0 ] ;
selectedFeature . setStyle ( getWaypointIcon ( selectedMarker , true ) ) ;
}
} ) ;
$ ( "[data-role='waypointOptions-add']" ) . on ( 'click' , function ( ) {
if ( selectedMarker ) {
mission . addAttachedFromWaypoint ( selectedMarker ) ;
renderWaypointOptionsTable ( selectedMarker ) ;
//cleanLines();
refreshLayers ( ) ;
selectedFeature = markers [ selectedMarker . getLayerNumber ( ) ] . getSource ( ) . getFeatures ( ) [ 0 ] ;
selectedFeature . setStyle ( getWaypointIcon ( selectedMarker , true ) ) ;
}
} ) ;
$ ( '#editMission' ) . on ( 'click' , function ( ) {
mapSelectEditMultimission ( selectedMarker . getNumber ( ) ) ;
} ) ;
/////////////////////////////////////////////
// Callback for SAFEHOMES
/////////////////////////////////////////////
$ ( '#addSafehome' ) . on ( 'click' , ( ) => {
if ( FC . SAFEHOMES . safehomeCount ( ) + 1 > FC . SAFEHOMES . getMaxSafehomeCount ( ) ) {
GUI . alert ( i18n . getMessage ( 'missionSafehomeMaxSafehomesReached' ) ) ;
return ;
}
let mapCenter = map . getView ( ) . getCenter ( ) ;
let midLon = Math . round ( ol . proj . toLonLat ( mapCenter ) [ 0 ] * 1e7 ) ;
let midLat = Math . round ( ol . proj . toLonLat ( mapCenter ) [ 1 ] * 1e7 ) ;
FC . SAFEHOMES . put ( new Safehome ( FC . SAFEHOMES . safehomeCount ( ) , 1 , midLat , midLon ) ) ;
updateSelectedShAndFwAp ( FC . SAFEHOMES . safehomeCount ( ) - 1 ) ;
renderSafeHomeOptions ( ) ;
cleanSafehomeLayers ( ) ;
renderSafehomesOnMap ( ) ;
updateSafehomeInfo ( ) ;
} ) ;
$ ( '#cancelSafehome' ) . on ( 'click' , function ( ) {
closeSafehomePanel ( ) ;
} ) ;
$ ( '#loadEepromSafehomeButton' ) . on ( 'click' , function ( ) {
$ ( this ) . addClass ( 'disabled' ) ;
GUI . log ( 'Start of getting Safehome points' ) ;
var loadChainer = new MSPChainerClass ( ) ;
loadChainer . setChain ( [
mspHelper . loadSafehomes ,
mspHelper . loadFwApproach ,
function ( ) {
if ( FC . SAFEHOMES . safehomeCount ( ) >= 1 ) {
updateSelectedShAndFwAp ( 0 ) ;
} else {
selectedSafehome = null ;
selectedFwApproachSh = null ;
}
renderSafeHomeOptions ( ) ;
cleanSafehomeLayers ( ) ;
renderSafehomesOnMap ( ) ;
updateSafehomeInfo ( ) ;
GUI . log ( i18n . getMessage ( 'endGettingSafehomePoints' ) ) ;
$ ( '#loadEepromSafehomeButton' ) . removeClass ( 'disabled' ) ;
}
] ) ;
loadChainer . execute ( ) ;
} ) ;
$ ( '#saveEepromSafehomeButton' ) . on ( 'click' , function ( ) {
$ ( this ) . addClass ( 'disabled' ) ;
GUI . log ( i18n . getMessage ( 'startSendingSafehomePoints' ) ) ;
var saveChainer = new MSPChainerClass ( ) ;
saveChainer . setChain ( [
mspHelper . saveSafehomes ,
mspHelper . saveFwApproach ,
function ( ) {
mspHelper . saveToEeprom ( ) ;
GUI . log ( i18n . getMessage ( 'endSendingSafehomePoints' ) ) ;
$ ( '#saveEepromSafehomeButton' ) . removeClass ( 'disabled' ) ;
}
] ) ;
saveChainer . execute ( ) ;
} ) ;
$ ( '#deleteSafehome' ) . on ( 'click' , ( ) => {
if ( selectedSafehome && selectedFwApproachSh ) {
var shNum = selectedSafehome . getNumber ( ) ;
FC . SAFEHOMES . drop ( shNum ) ;
FC . FW _APPROACH . clean ( shNum ) ;
if ( FC . SAFEHOMES . safehomeCount ( ) > 0 ) {
updateSelectedShAndFwAp ( FC . SAFEHOMES . safehomeCount ( ) - 1 ) ;
} else {
selectedSafehome = null ;
selectedFwApproachSh = null ;
}
renderSafeHomeOptions ( ) ;
cleanSafehomeLayers ( ) ;
renderSafehomesOnMap ( ) ;
updateSafehomeInfo ( ) ;
}
} ) ;
$ ( '#safehomeLatitude' ) . on ( 'change' , event => {
if ( selectedFwApproachSh ) {
selectedFwApproachSh . setLat ( Math . round ( Number ( $ ( event . currentTarget ) . val ( ) ) * 1e7 ) ) ;
renderSafeHomeOptions ( ) ;
cleanSafehomeLayers ( ) ;
renderSafehomesOnMap ( ) ;
}
} ) ;
$ ( '#safehomeLongitude' ) . on ( 'change' , event => {
if ( selectedFwApproachSh ) {
selectedFwApproachSh . setLon ( Math . round ( Number ( $ ( event . currentTarget ) . val ( ) ) * 1e7 ) ) ;
renderSafeHomeOptions ( ) ;
cleanSafehomeLayers ( ) ;
renderSafehomesOnMap ( ) ;
}
} ) ;
$ ( '#safehomeSeaLevelRef' ) . on ( 'change' , event => {
let isChecked = $ ( event . currentTarget ) . prop ( 'checked' ) ? 1 : 0 ;
if ( selectedSafehome && selectedFwApproachSh && isChecked != selectedFwApproachSh . getIsSeaLevelRef ( ) ) {
selectedFwApproachSh . setIsSeaLevelRef ( isChecked ) ;
( async ( ) => {
const elevation = await selectedFwApproachSh . getElevationFromServer ( selectedSafehome . getLonMap ( ) , selectedSafehome . getLatMap ( ) , globalSettings ) * 100 ;
selectedFwApproachSh . setElevation ( elevation ) ;
if ( isChecked ) {
selectedFwApproachSh . setApproachAltAsl ( selectedFwApproachSh . getApproachAltAsl ( ) + elevation ) ;
selectedFwApproachSh . setLandAltAsl ( selectedFwApproachSh . getLandAltAsl ( ) + elevation ) ;
} else {
selectedFwApproachSh . setApproachAltAsl ( selectedFwApproachSh . getApproachAltAsl ( ) - elevation ) ;
selectedFwApproachSh . setLandAltAsl ( selectedFwApproachSh . getLandAltAsl ( ) - elevation ) ;
}
$ ( '#safehomeElevation' ) . text ( elevation / 100 ) ;
$ ( '#safehomeApproachAlt' ) . val ( selectedFwApproachSh . getApproachAltAsl ( ) ) ;
$ ( '#safehomeLandAlt' ) . val ( selectedFwApproachSh . getLandAltAsl ( ) ) ;
$ ( '#safehomeLandAltM' ) . text ( selectedFwApproachSh . getLandAltAsl ( ) / 100 + " m" ) ;
$ ( '#safehomeApproachAltM' ) . text ( selectedFwApproachSh . getApproachAltAsl ( ) / 100 + " m" ) ;
renderSafeHomeOptions ( ) ;
} ) ( ) ;
}
} ) ;
$ ( '#safehomeApproachAlt' ) . on ( 'change' , event => {
if ( selectedFwApproachSh ) {
let altitude = Number ( $ ( event . currentTarget ) . val ( ) ) ;
if ( checkApproachAltitude ( altitude , $ ( '#safehomeSeaLevelRef' ) . prop ( 'checked' ) , Number ( $ ( '#safehomeElevation' ) . text ( ) ) ) ) {
selectedFwApproachSh . setApproachAltAsl ( Number ( $ ( event . currentTarget ) . val ( ) ) ) ;
$ ( '#safehomeApproachAltM' ) . text ( selectedFwApproachSh . getApproachAltAsl ( ) / 100 + " m" ) ;
cleanSafehomeLayers ( ) ;
renderSafehomesOnMap ( ) ;
renderHomeTable ( ) ;
}
$ ( '#safehomeApproachAlt' ) . val ( selectedFwApproachSh . getApproachAltAsl ( ) ) ;
}
} ) ;
$ ( '#safehomeLandAlt' ) . on ( 'change' , event => {
if ( selectedFwApproachSh ) {
let altitude = Number ( $ ( event . currentTarget ) . val ( ) ) ;
if ( checkLandingAltitude ( altitude , $ ( '#safehomeSeaLevelRef' ) . prop ( 'checked' ) , Number ( $ ( '#safehomeElevation' ) . text ( ) ) ) ) {
selectedFwApproachSh . setLandAltAsl ( altitude ) ;
$ ( '#safehomeLandAltM' ) . text ( selectedFwApproachSh . getLandAltAsl ( ) / 100 + " m" ) ;
cleanSafehomeLayers ( ) ;
renderSafehomesOnMap ( ) ;
renderHomeTable ( ) ;
} else {
$ ( '#safehomeLandAlt' ) . val ( selectedFwApproachSh . getLandAltAsl ( ) ) ;
}
}
} ) ;
$ ( '#geozoneApproachDirection' ) . on ( 'change' , event => {
if ( selectedFwApproachSh ) {
selectedFwApproachSh . setApproachDirection ( $ ( event . currentTarget ) . val ( ) ) ;
cleanSafehomeLayers ( ) ;
renderSafehomesOnMap ( ) ;
}
} ) ;
$ ( '#safehomeLandHeading1Excl' ) . on ( 'change' , event => {
if ( selectedFwApproachSh && ! lockShExclHeading ) {
selectedFwApproachSh . setLandHeading1 ( selectedFwApproachSh . getLandHeading1 ( ) * - 1 ) ;
cleanSafehomeLayers ( ) ;
renderSafehomesOnMap ( ) ;
}
} ) ;
$ ( '#safehomeLandHeading1' ) . on ( 'change' , event => {
if ( selectedFwApproachSh ) {
let val = Number ( $ ( event . currentTarget ) . val ( ) ) ;
if ( val < 0 ) {
val = 360 ;
$ ( '#safehomeLandHeading1' ) . val ( 360 ) ;
}
if ( val > 360 ) {
val = 0 ;
$ ( '#safehomeLandHeading1' ) . val ( 0 ) ;
}
if ( $ ( '#safehomeLandHeading1Excl' ) . prop ( 'checked' ) ) {
val *= - 1 ;
}
selectedFwApproachSh . setLandHeading1 ( val ) ;
cleanSafehomeLayers ( ) ;
renderSafehomesOnMap ( ) ;
}
} ) ;
$ ( '#safehomeLandHeading2Excl' ) . on ( 'change' , event => {
if ( selectedFwApproachSh && ! lockShExclHeading ) {
selectedFwApproachSh . setLandHeading2 ( selectedFwApproachSh . getLandHeading2 ( ) * - 1 ) ;
cleanSafehomeLayers ( ) ;
renderSafehomesOnMap ( ) ;
}
} ) ;
$ ( '#safehomeLandHeading2' ) . on ( 'change' , event => {
if ( selectedFwApproachSh ) {
let val = Number ( $ ( event . currentTarget ) . val ( ) ) ;
if ( val < 0 ) {
val = 360 ;
$ ( '#safehomeLandHeading2' ) . val ( 360 ) ;
}
if ( val > 360 ) {
val = 0 ;
$ ( '#safehomeLandHeading2' ) . val ( 0 ) ;
}
if ( $ ( '#safehomeLandHeading2Excl' ) . prop ( 'checked' ) ) {
val *= - 1 ;
}
selectedFwApproachSh . setLandHeading2 ( val ) ;
cleanSafehomeLayers ( ) ;
renderSafehomesOnMap ( ) ;
}
} ) ;
/////////////////////////////////////////////
// Callback for HOME Table
/////////////////////////////////////////////
$ ( '#homeTableBody' ) . on ( 'click' , "[data-role='home-center']" , function ( event ) {
let mapCenter = map . getView ( ) . getCenter ( ) ;
HOME . setLon ( Math . round ( ol . proj . toLonLat ( mapCenter ) [ 0 ] * 1e7 ) ) ;
HOME . setLat ( Math . round ( ol . proj . toLonLat ( mapCenter ) [ 1 ] * 1e7 ) ) ;
updateHome ( ) ;
} ) ;
$ ( '#cancelHome' ) . on ( 'click' , function ( ) {
closeHomePanel ( ) ;
} ) ;
$ ( '#cancelPlot' ) . on ( 'click' , function ( ) {
closeHomePanel ( ) ;
} ) ;
$ ( '#elevationEarthModel' ) . on ( 'change' , function ( event ) {
if ( globalSettings . mapProviderType == 'bing' ) {
( async ( ) => {
const elevationAtHome = await HOME . getElevation ( globalSettings ) ;
$ ( '#elevationValueAtHome' ) . text ( elevationAtHome + ' m' ) ;
HOME . setAlt ( elevationAtHome ) ;
if ( selectedMarker ) {
const elevationAtWP = await selectedMarker . getElevation ( globalSettings ) ;
$ ( '#elevationValueAtWP' ) . text ( elevationAtWP ) ;
const returnAltitude = checkAltElevSanity ( false , selectedMarker . getAlt ( ) , elevationAtWP , selectedMarker . getP3 ( ) ) ;
selectedMarker . setAlt ( returnAltitude ) ;
mission . updateWaypoint ( selectedMarker ) ;
}
redrawLayer ( ) ;
plotElevation ( ) ;
} ) ( )
settings . bingDemModel = $ ( '#elevationEarthModel' ) . prop ( "checked" ) ? true : false ;
saveSettings ( ) ;
}
} ) ;
/////////////////////////////////////////////
// Callback for MULTIMISSION Table
/////////////////////////////////////////////
$ ( '#multimissionOptionList' ) . on ( 'change' , function ( ) {
if ( singleMissionActive ( ) ) {
// updateAllMultimission only when a single mission is loaded on map
// or new mission is empty.
if ( mission . isEmpty ( ) ) {
updateAllMultimission ( ) ;
return ;
}
let missions = 0 ;
mission . get ( ) . forEach ( function ( element ) {
missions += element . getEndMission ( ) == 0xA5 ? 1 : 0 ;
} ) ;
if ( missions == 1 ) updateAllMultimission ( ) ;
editMultimission ( ) ;
} else {
updateAllMultimission ( ) ;
updateMultimissionState ( ) ;
}
} ) ;
$ ( '#addMultimissionButton' ) . on ( 'click' , function ( ) {
addMultimission ( ) ;
} ) ;
$ ( '#updateMultimissionButton' ) . on ( 'click' , function ( ) {
$ ( '#multimissionOptionList' ) . val ( '0' ) . trigger ( 'change' ) ;
} ) ;
$ ( '#cancelMultimission' ) . on ( 'click' , function ( ) {
$ ( '#missionPlannerMultiMission' ) . fadeOut ( 300 ) ;
} ) ;
$ ( '#setActiveMissionButton' ) . on ( 'click' , function ( ) {
$ ( '#activeNissionIndex' ) . text ( Number ( $ ( '#multimissionOptionList' ) . val ( ) ) ) ;
} ) ;
/////////////////////////////////////////////
// Callback for Remove buttons
/////////////////////////////////////////////
$ ( '#removeAllPoints' ) . on ( 'click' , function ( ) {
if ( markers . length && confirm ( i18n . getMessage ( 'confirm_delete_all_points' ) ) ) {
if ( removeAllMultiMissionCheck ( ) ) {
removeAllWaypoints ( ) ;
updateMultimissionState ( ) ;
}
for ( let i = FC . SAFEHOMES . getMaxSafehomeCount ( ) ; i < FC . FW _APPROACH . getMaxFwApproachCount ( ) ; i ++ ) {
FC . FW _APPROACH . clean ( i ) ;
}
plotElevation ( ) ;
}
} ) ;
$ ( '#removePoint' ) . on ( 'click' , function ( ) {
if ( selectedMarker ) {
if ( mission . isJumpTargetAttached ( selectedMarker ) ) {
GUI . alert ( i18n . getMessage ( 'MissionPlannerJumpTargetRemoval' ) ) ;
}
else if ( mission . getAttachedFromWaypoint ( selectedMarker ) && mission . getAttachedFromWaypoint ( selectedMarker ) . length != 0 ) {
if ( confirm ( i18n . getMessage ( 'confirm_delete_point_with_options' ) ) ) {
mission . getAttachedFromWaypoint ( selectedMarker ) . forEach ( function ( element ) {
if ( element . getAction ( ) == MWNP . WPTYPE . LAND ) {
FC . FW _APPROACH . clean ( element . getNumber ( ) ) ;
}
mission . dropWaypoint ( element ) ;
mission . update ( singleMissionActive ( ) ) ;
} ) ;
mission . dropWaypoint ( selectedMarker ) ;
selectedMarker = null ;
mission . update ( singleMissionActive ( ) ) ;
clearEditForm ( ) ;
refreshLayers ( ) ;
plotElevation ( ) ;
}
}
else {
mission . dropWaypoint ( selectedMarker ) ;
if ( selectedMarker . getAction ( ) == MWNP . WPTYPE . LAND ) {
FC . FW _APPROACH . clean ( selectedFwApproachWp . getNumber ( ) ) ;
}
selectedMarker = null ;
mission . update ( singleMissionActive ( ) ) ;
clearEditForm ( ) ;
refreshLayers ( ) ;
plotElevation ( ) ;
}
updateMultimissionState ( ) ;
}
} ) ;
/////////////////////////////////////////////
// Callback for Save/load buttons
/////////////////////////////////////////////
$ ( '#loadFileMissionButton' ) . on ( 'click' , function ( ) {
if ( ! fileLoadMultiMissionCheck ( ) ) return ;
if ( markers . length && ! confirm ( i18n . getMessage ( 'confirm_delete_all_points' ) ) ) return ;
var options = {
filters : [ { name : "Mission file" , extensions : [ 'mission' ] } ]
} ;
dialog . showOpenDialog ( options ) . then ( result => {
if ( result . canceled ) {
console . log ( 'No file selected' ) ;
return ;
}
if ( result . filePaths . length == 1 ) {
loadMissionFile ( result . filePaths [ 0 ] ) ;
}
} )
} ) ;
$ ( '#saveFileMissionButton' ) . on ( 'click' , function ( ) {
var options = {
filters : [ { name : "Mission file" , extensions : [ 'mission' ] } ]
} ;
dialog . showSaveDialog ( options ) . then ( result => {
if ( result . canceled ) {
return ;
}
saveMissionFile ( result . filePath ) ;
} ) ;
} ) ;
$ ( '#loadMissionButton' ) . on ( 'click' , function ( ) {
let message = multimissionCount ? 'confirm_overwrite_multimission_file_load_option' : 'confirm_delete_all_points' ;
if ( ( markers . length || multimissionCount ) && ! confirm ( i18n . getMessage ( message ) ) ) return ;
removeAllWaypoints ( ) ;
$ ( this ) . addClass ( 'disabled' ) ;
GUI . log ( i18n . getMessage ( 'startGetPoint' ) ) ;
getWaypointsFromFC ( false ) ;
} ) ;
$ ( '#saveMissionButton' ) . on ( 'click' , function ( ) {
if ( mission . isEmpty ( ) ) {
GUI . alert ( i18n . getMessage ( 'no_waypoints_to_save' ) ) ;
return ;
}
$ ( this ) . addClass ( 'disabled' ) ;
GUI . log ( i18n . getMessage ( 'startSendPoint' ) ) ;
sendWaypointsToFC ( false ) ;
} ) ;
$ ( '#loadEepromMissionButton' ) . on ( 'click' , function ( ) {
let message = multimissionCount ? 'confirm_overwrite_multimission_file_load_option' : 'confirm_delete_all_points' ;
if ( ( markers . length || multimissionCount ) && ! confirm ( i18n . getMessage ( message ) ) ) return ;
removeAllWaypoints ( ) ;
$ ( this ) . addClass ( 'disabled' ) ;
GUI . log ( i18n . getMessage ( 'startGetPoint' ) ) ;
getWaypointsFromFC ( true ) ;
} ) ;
$ ( '#saveEepromMissionButton' ) . on ( 'click' , function ( ) {
if ( mission . isEmpty ( ) ) {
GUI . alert ( i18n . getMessage ( 'no_waypoints_to_save' ) ) ;
return ;
}
$ ( this ) . addClass ( 'disabled' ) ;
GUI . log ( i18n . getMessage ( 'startSendPoint' ) ) ;
sendWaypointsToFC ( true ) ;
} ) ;
/////////////////////////////////////////////
// Callback for settings
/////////////////////////////////////////////
$ ( '#saveSettings' ) . on ( 'click' , function ( ) {
let oldSafeRadiusSH = settings . safeRadiusSH ;
// update only default settings
settings . alt = Number ( $ ( '#MPdefaultPointAlt' ) . val ( ) ) ;
settings . speed = Number ( $ ( '#MPdefaultPointSpeed' ) . val ( ) ) ;
settings . safeRadiusSH = Number ( $ ( '#MPdefaultSafeRangeSH' ) . val ( ) ) ;
settings . fwApproachAlt = Number ( $ ( '#MPdefaultFwApproachAlt' ) . val ( ) ) ;
settings . fwLandAlt = Number ( $ ( '#MPdefaultLandAlt' ) . val ( ) ) ;
saveSettings ( ) ;
if ( settings . safeRadiusSH != oldSafeRadiusSH && $ ( '#showHideSafehomeButton' ) . is ( ":visible" ) ) {
cleanSafehomeLayers ( ) ;
renderSafehomesOnMap ( ) ;
$ ( '#SafeHomeSafeDistance' ) . text ( settings . safeRadiusSH ) ;
}
closeSettingsPanel ( ) ;
} ) ;
$ ( '#cancelSettings' ) . on ( 'click' , function ( ) {
loadSettings ( ) ;
closeSettingsPanel ( ) ;
} ) ;
updateTotalInfo ( ) ;
}
/////////////////////////////////////////////
//
// Load/Save MWP File Toolbox
//
/////////////////////////////////////////////
function loadMissionFile ( filename ) {
for ( let i = FC . SAFEHOMES . getMaxSafehomeCount ( ) ; i < FC . FW _APPROACH . getMaxFwApproachCount ( ) ; i ++ ) {
FC . FW _APPROACH . clean ( i ) ;
}
fs . readFile ( filename , ( err , data ) => {
if ( err ) {
GUI . log ( i18n . getMessage ( 'errorReadingFile' ) ) ;
return console . error ( err ) ;
}
xml2js . Parser ( { 'explicitChildren' : true , 'preserveChildrenOrder' : true } ) . parseString ( data , ( err , result ) => {
if ( err ) {
GUI . log ( i18n . getMessage ( 'errorParsingFile' ) ) ;
return console . error ( err ) ;
}
// parse mission file
removeAllWaypoints ( ) ;
let missionEndFlagCount = 0 ;
var node = null ;
var nodemission = null ;
for ( var noderoot in result ) {
if ( ! nodemission && noderoot . match ( /mission/i ) ) {
nodemission = result [ noderoot ] ;
var missionIdx = - 1 ;
if ( nodemission . $$ && nodemission . $$ . length ) {
for ( var i = 0 ; i < nodemission . $$ . length ; i ++ ) {
node = nodemission . $$ [ i ] ;
if ( node [ '#name' ] . match ( /version/i ) && node . $ ) {
for ( var attr in node . $ ) {
if ( attr . match ( /value/i ) ) {
mission . setVersion ( node . $ [ attr ] ) ;
}
}
} else if ( node [ '#name' ] . match ( /meta/i ) || node [ '#name' ] . match ( /mwp/i ) && node . $ ) {
for ( var attr in node . $ ) {
if ( attr . match ( /mission/i ) ) {
missionIdx = parseInt ( node . $ [ attr ] ) - 1 ;
} else if ( attr . match ( /zoom/i ) ) {
mission . setCenterZoom ( parseInt ( node . $ [ attr ] ) ) ;
} else if ( attr . match ( /cx/i ) ) {
mission . setCenterLon ( parseFloat ( node . $ [ attr ] ) * 10000000 ) ;
} else if ( attr . match ( /cy/i ) ) {
mission . setCenterLat ( parseFloat ( node . $ [ attr ] ) * 10000000 ) ;
} else if ( attr . match ( /home\-x/i ) ) {
HOME . setLon ( Math . round ( parseFloat ( node . $ [ attr ] ) * 10000000 ) ) ;
} else if ( attr . match ( /home\-y/i ) ) {
HOME . setLat ( Math . round ( parseFloat ( node . $ [ attr ] ) * 10000000 ) ) ;
}
}
} else if ( node [ '#name' ] . match ( /missionitem/i ) && node . $ ) {
//var point = {};
var point = new Waypoint ( 0 , 0 , 0 , 0 ) ;
for ( var attr in node . $ ) {
if ( attr . match ( /no/i ) ) {
point . setNumber ( parseInt ( node . $ [ attr ] ) ) ;
} else if ( attr . match ( /action/i ) ) {
if ( node . $ [ attr ] . match ( /WAYPOINT/i ) ) {
point . setAction ( MWNP . WPTYPE . WAYPOINT ) ;
} else if ( node . $ [ attr ] . match ( /PH_UNLIM/i ) || node . $ [ attr ] . match ( /POSHOLD_UNLIM/i ) ) {
point . setAction ( MWNP . WPTYPE . POSHOLD _UNLIM ) ;
} else if ( node . $ [ attr ] . match ( /PH_TIME/i ) || node . $ [ attr ] . match ( /POSHOLD_TIME/i ) ) {
point . setAction ( MWNP . WPTYPE . POSHOLD _TIME ) ;
} else if ( node . $ [ attr ] . match ( /RTH/i ) ) {
point . setAction ( MWNP . WPTYPE . RTH ) ;
} else if ( node . $ [ attr ] . match ( /SET_POI/i ) ) {
point . setAction ( MWNP . WPTYPE . SET _POI ) ;
} else if ( node . $ [ attr ] . match ( /JUMP/i ) ) {
point . setAction ( MWNP . WPTYPE . JUMP ) ;
} else if ( node . $ [ attr ] . match ( /SET_HEAD/i ) ) {
point . setAction ( MWNP . WPTYPE . SET _HEAD ) ;
} else if ( node . $ [ attr ] . match ( /LAND/i ) ) {
point . setAction ( MWNP . WPTYPE . LAND ) ;
} else {
point . setAction ( 0 ) ;
}
} else if ( attr . match ( /lat/i ) ) {
point . setLat ( Math . round ( parseFloat ( node . $ [ attr ] ) * 10000000 ) ) ;
} else if ( attr . match ( /lon/i ) ) {
point . setLon ( Math . round ( parseFloat ( node . $ [ attr ] ) * 10000000 ) ) ;
} else if ( attr . match ( /alt/i ) ) {
point . setAlt ( ( parseInt ( node . $ [ attr ] ) * 100 ) ) ;
} else if ( attr . match ( /parameter1/i ) ) {
point . setP1 ( parseInt ( node . $ [ attr ] ) ) ;
} else if ( attr . match ( /parameter2/i ) ) {
point . setP2 ( parseInt ( node . $ [ attr ] ) ) ;
} else if ( attr . match ( /parameter3/i ) ) {
point . setP3 ( parseInt ( node . $ [ attr ] ) ) ;
} else if ( attr . match ( /flag/i ) ) {
point . setEndMission ( parseInt ( node . $ [ attr ] ) ) ;
if ( parseInt ( node . $ [ attr ] ) == 0xA5 ) {
missionEndFlagCount ++ ;
}
}
}
if ( missionIdx >= 0 ) {
point . setMultiMissionIdx ( missionIdx ) ;
}
mission . put ( point ) ;
} else if ( node [ '#name' ] . match ( /fwapproach/i ) && node . $ ) {
var fwApproach = new FwApproach ( 0 ) ;
var idx = - 1 ;
for ( var attr in node . $ ) {
if ( attr . match ( /index/i ) ) {
idx = parseInt ( node . $ [ attr ] ) ;
} else if ( attr . match ( /no/i ) ) {
fwApproach . setNumber ( parseInt ( node . $ [ attr ] ) ) ;
} else if ( attr . match ( /approach-alt/i ) ) {
fwApproach . setApproachAltAsl ( parseInt ( node . $ [ attr ] ) ) ;
} else if ( attr . match ( /land-alt/i ) ) {
fwApproach . setLandAltAsl ( parseInt ( node . $ [ attr ] ) ) ;
} else if ( attr . match ( /approach-direction/i ) ) {
fwApproach . setApproachDirection ( node . $ [ attr ] == 'left' ? 0 : 1 ) ;
} else if ( attr . match ( /landheading1/i ) ) {
fwApproach . setLandHeading1 ( parseInt ( node . $ [ attr ] ) ) ;
} else if ( attr . match ( /landheading2/i ) ) {
fwApproach . setLandHeading2 ( parseInt ( node . $ [ attr ] ) ) ;
} else if ( attr . match ( /sealevel-ref/i ) ) {
fwApproach . setIsSeaLevelRef ( parseBooleans ( node . $ [ attr ] ) ? 1 : 0 ) ;
}
}
FC . FW _APPROACH . insert ( fwApproach , FC . SAFEHOMES . getMaxSafehomeCount ( ) + idx ) ;
}
}
}
}
}
if ( missionEndFlagCount > 1 ) {
if ( multimissionCount && ! confirm ( i18n . getMessage ( 'confirm_multimission_file_load' ) ) ) {
mission . flush ( ) ;
return ;
} else {
/ * u p d a t e A t t a c h e d W a y p o i n t s ( i . e n o n M a p M a r k e r s )
* Ensure WPs numbered sequentially across all missions * /
i = 1 ;
mission . get ( ) . forEach ( function ( element ) {
element . setNumber ( i ) ;
i ++ ;
} ) ;
mission . update ( false , true ) ;
multimissionCount = missionEndFlagCount ;
multimission . reinit ( ) ;
multimission . copy ( mission ) ;
renderMultimissionTable ( ) ;
$ ( '#missionPlannerMultiMission' ) . fadeIn ( 300 ) ;
}
} else {
// update Attached Waypoints (i.e non Map Markers)
mission . update ( true , true ) ;
}
updateMultimissionState ( ) ;
if ( Object . keys ( mission . getCenter ( ) ) . length !== 0 ) {
var coord = ol . proj . fromLonLat ( [ mission . getCenter ( ) . lon / 10000000 , mission . getCenter ( ) . lat / 10000000 ] ) ;
map . getView ( ) . setCenter ( coord ) ;
if ( mission . getCenter ( ) . zoom ) {
map . getView ( ) . setZoom ( mission . getCenter ( ) . zoom ) ;
}
else {
map . getView ( ) . setZoom ( 16 ) ;
}
}
else {
setView ( 16 ) ;
}
redrawLayers ( ) ;
if ( ! ( HOME . getLatMap ( ) == 0 && HOME . getLonMap ( ) == 0 ) ) {
updateHome ( ) ;
}
updateTotalInfo ( ) ;
let sFilename = String ( filename . split ( '\\' ) . pop ( ) . split ( '/' ) . pop ( ) ) ;
GUI . log ( sFilename + i18n . getMessage ( 'loadedSuccessfully' ) ) ;
updateFilename ( sFilename ) ;
} ) ;
} ) ;
}
function saveMissionFile ( filename ) {
var center = ol . proj . toLonLat ( map . getView ( ) . getCenter ( ) ) ;
var zoom = map . getView ( ) . getZoom ( ) ;
let multimission = multimissionCount && ! singleMissionActive ( ) ;
let version = multimission ? '4.0.0' : '2.3-pre8' ;
var data = {
'version' : { $ : { 'value' : version } } ,
'mwp' : { $ : { 'cx' : ( Math . round ( center [ 0 ] * 10000000 ) / 10000000 ) ,
'cy' : ( Math . round ( center [ 1 ] * 10000000 ) / 10000000 ) ,
'home-x' : HOME . getLonMap ( ) ,
'home-y' : HOME . getLatMap ( ) ,
'zoom' : zoom } } ,
'missionitem' : [ ] ,
'fwapproach' : [ ]
} ;
let missionStartWPNumber = 0 ;
let missionNumber = 1 ;
mission . get ( ) . forEach ( function ( waypoint ) {
if ( waypoint . getNumber ( ) - missionStartWPNumber == 0 && multimission ) {
let meta = { $ : {
'mission' : missionNumber
} } ;
data . missionitem . push ( meta ) ;
}
var point = { $ : {
'no' : waypoint . getNumber ( ) - missionStartWPNumber + 1 ,
'action' : MWNP . WPTYPE . REV [ waypoint . getAction ( ) ] ,
'lat' : waypoint . getLatMap ( ) ,
'lon' : waypoint . getLonMap ( ) ,
'alt' : ( waypoint . getAlt ( ) / 100 ) ,
'parameter1' : ( MWNP . WPTYPE . REV [ waypoint . getAction ( ) ] == "JUMP" ? waypoint . getP1 ( ) + 1 : waypoint . getP1 ( ) ) ,
'parameter2' : waypoint . getP2 ( ) ,
'parameter3' : waypoint . getP3 ( ) ,
'flag' : waypoint . getEndMission ( ) ,
} } ;
data . missionitem . push ( point ) ;
if ( waypoint . getEndMission ( ) == 0xA5 ) {
missionStartWPNumber = waypoint . getNumber ( ) + 1 ;
missionNumber ++ ;
}
} ) ;
let approachIdx = 0 ;
for ( let i = FC . SAFEHOMES . getMaxSafehomeCount ( ) ; i < FC . FW _APPROACH . getMaxFwApproachCount ( ) ; i ++ ) {
let approach = FC . FW _APPROACH . get ( ) [ i ] ;
if ( approach . getLandHeading1 ( ) != 0 || approach . getLandHeading2 ( ) != 0 ) {
var item = { $ : {
'index' : approachIdx ,
'no' : approach . getNumber ( ) ,
'approach-alt' : approach . getApproachAltAsl ( ) ,
'land-alt' : approach . getLandAltAsl ( ) ,
'approach-direction' : approach . getApproachDirection ( ) == 0 ? 'left' : 'right' ,
'landheading1' : approach . getLandHeading1 ( ) ,
'landheading2' : approach . getLandHeading2 ( ) ,
'sealevel-ref' : approach . getIsSeaLevelRef ( ) ? 'true' : 'false'
} } ;
data . fwapproach . push ( item ) ;
}
approachIdx ++ ;
}
var builder = new xml2js . Builder ( { 'rootName' : 'mission' , 'renderOpts' : { 'pretty' : true , 'indent' : '\t' , 'newline' : '\n' } } ) ;
var xml = builder . buildObject ( data ) ;
xml = xml . replace ( /missionitem mission/g , 'meta mission' ) ;
fs . writeFile ( filename , xml , ( err ) => {
if ( err ) {
GUI . log ( i18n . getMessage ( 'ErrorWritingFile' ) ) ;
return console . error ( err ) ;
}
let sFilename = String ( filename . split ( '\\' ) . pop ( ) . split ( '/' ) . pop ( ) ) ;
GUI . log ( sFilename + i18n . getMessage ( 'savedSuccessfully' ) ) ;
updateFilename ( sFilename ) ;
} ) ;
}
/////////////////////////////////////////////
// Load/Save FC mission Toolbox
// mission = configurator store, WP number indexed from 0, FC.MISSION_PLANNER = FC NVM store, WP number indexed from 1
/////////////////////////////////////////////
function getWaypointsFromFC ( loadEeprom ) {
var loadChainer = new MSPChainerClass ( ) ;
var chain = [ mspHelper . loadFwApproach ] ;
if ( loadEeprom ) {
chain . push ( function ( callback ) {
MSP . send _message ( MSPCodes . MSP _WP _MISSION _LOAD , [ 0 ] , callback ) ;
} ) ;
}
chain . push ( mspHelper . loadWaypoints ) ;
chain . push ( function ( ) {
GUI . log ( i18n . getMessage ( 'endGetPoint' ) ) ;
if ( loadEeprom ) {
GUI . log ( i18n . getMessage ( 'eeprom_load_ok' ) ) ;
$ ( '#loadEepromMissionButton' ) . removeClass ( 'disabled' ) ;
} else {
$ ( '#loadMissionButton' ) . removeClass ( 'disabled' ) ;
}
if ( ! FC . MISSION _PLANNER . getCountBusyPoints ( ) ) {
GUI . alert ( i18n . getMessage ( 'no_waypoints_to_load' ) ) ;
return ;
}
mission . reinit ( ) ;
mission . copy ( FC . MISSION _PLANNER ) ;
mission . update ( false , true ) ;
/* check multimissions */
multimissionCount = 0 ;
mission . get ( ) . forEach ( function ( element ) {
if ( element . getEndMission ( ) == 0xA5 ) {
element . setMultiMissionIdx ( multimissionCount ) ;
multimissionCount ++ ;
}
} ) ;
multimissionCount = multimissionCount > 1 ? multimissionCount : 0 ;
multimission . reinit ( ) ;
if ( multimissionCount > 1 ) {
multimission . copy ( mission ) ;
$ ( '#missionPlannerMultiMission' ) . fadeIn ( 300 ) ;
}
renderMultimissionTable ( ) ;
setView ( 16 ) ;
redrawLayers ( ) ;
updateTotalInfo ( ) ;
} ) ;
loadChainer . setChain ( chain ) ;
loadChainer . execute ( ) ;
}
function sendWaypointsToFC ( saveEeprom ) {
FC . MISSION _PLANNER . reinit ( ) ;
FC . MISSION _PLANNER . copy ( mission ) ;
FC . MISSION _PLANNER . update ( false , true , true ) ;
let saveChainer = new MSPChainerClass ( ) ;
saveChainer . setChain ( [
mspHelper . saveWaypoints ,
mspHelper . saveFwApproach ,
function ( ) {
GUI . log ( i18n . getMessage ( 'endSendPoint' ) ) ;
if ( saveEeprom ) {
$ ( '#saveEepromMissionButton' ) . removeClass ( 'disabled' ) ;
GUI . log ( i18n . getMessage ( 'eeprom_saved_ok' ) ) ;
MSP . send _message ( MSPCodes . MSP _WP _MISSION _SAVE , [ 0 ] , false , setMissionIndex ) ;
} else {
$ ( '#saveMissionButton' ) . removeClass ( 'disabled' ) ;
}
mission . setMaxWaypoints ( FC . MISSION _PLANNER . getMaxWaypoints ( ) ) ;
mission . setValidMission ( FC . MISSION _PLANNER . getValidMission ( ) ) ;
mission . setCountBusyPoints ( FC . MISSION _PLANNER . getCountBusyPoints ( ) ) ;
multimission . setMaxWaypoints ( mission . getMaxWaypoints ( ) ) ;
updateTotalInfo ( ) ;
mission . reinit ( ) ;
mission . copy ( FC . MISSION _PLANNER ) ;
mission . update ( false , true ) ;
refreshLayers ( ) ;
$ ( '#MPeditPoint' ) . fadeOut ( 300 ) ;
}
] ) ;
saveChainer . execute ( ) ;
function setMissionIndex ( ) {
let activeIndex = singleMissionActive ( ) ? 1 : $ ( '#activeNissionIndex' ) . text ( ) ;
mspHelper . setSetting ( "nav_wp_multi_mission_index" , activeIndex , function ( ) {
MSP . send _message ( MSPCodes . MSP _EEPROM _WRITE , false , false , function ( ) {
GUI . log ( i18n . getMessage ( 'multimission_active_index_saved_eeprom' ) ) ;
} ) ;
} ) ;
}
}
function updateTotalInfo ( ) {
if ( CONFIGURATOR . connectionValid ) {
let availableWPs = mission . getMaxWaypoints ( ) - mission . get ( ) . length ;
if ( multimissionCount && singleMissionActive ( ) ) {
availableWPs = availableWPs - multimission . get ( ) . length ;
}
$ ( '#availablePoints' ) . text ( availableWPs + '/' + mission . getMaxWaypoints ( ) ) ;
$ ( '#missionValid' ) . html ( mission . getValidMission ( ) ? i18n . getMessage ( 'armingCheckPass' ) : i18n . getMessage ( 'armingCheckFail' ) ) ;
}
}
function updateFilename ( filename ) {
$ ( '#missionFilename' ) . text ( filename ) ;
$ ( '#infoMissionFilename' ) . show ( ) ;
}
function changeSwitchery ( element , checked ) {
if ( ( element . is ( ':checked' ) && checked == false ) || ( ! element . is ( ':checked' ) && checked == true ) ) {
element . parent ( ) . find ( '.switcherymid' ) . trigger ( 'click' ) ;
}
}
function updateSelectedShAndFwAp ( index ) {
selectedSafehome = FC . SAFEHOMES . get ( ) [ index ] ;
selectedFwApproachSh = FC . FW _APPROACH . get ( ) [ index ] ;
}
/ * r e s e t A l t i t u d e = t r u e : F o r s e l e c t e d W P s o n l y . C h a n g e s W P A l t i t u d e v a l u e b a c k t o p r e v i o u s v a l u e i f s e t t i n g b e l o w g r o u n d l e v e l .
^ resetAltitude = false : changes WP Altitude to value required to give ground clearance = default Altitude setting
^ AbsAltCheck : check value for whether or not to use absolute altitude . This can be the P3 bitset or excplicitly set to true or false * /
function checkAltElevSanity ( resetAltitude , checkAltitude , elevation , AbsAltCheck ) {
let groundClearance = "NO HOME" ;
let altitude = checkAltitude ;
AbsAltCheck = ( typeof AbsAltCheck == "boolean" ) ? AbsAltCheck : TABS . mission _control . isBitSet ( AbsAltCheck , MWNP . P3 . ALT _TYPE ) ;
if ( AbsAltCheck ) {
if ( checkAltitude < 100 * elevation ) {
if ( resetAltitude ) {
GUI . alert ( i18n . getMessage ( 'MissionPlannerAltitudeChangeReset' ) ) ;
altitude = selectedMarker . getAlt ( ) ;
} else {
altitude = settings . alt + 100 * elevation ;
}
}
groundClearance = altitude / 100 - elevation ;
} else if ( homeMarkers . length && HOME . getAlt ( ) != "N/A" ) {
let elevationAtHome = HOME . getAlt ( ) ;
if ( ( checkAltitude / 100 + elevationAtHome ) < elevation ) {
if ( resetAltitude ) {
GUI . alert ( i18n . getMessage ( 'MissionPlannerAltitudeChangeReset' ) ) ;
altitude = selectedMarker . getAlt ( ) ;
} else {
let currentGroundClearance = 100 * Number ( $ ( '#groundClearanceValueAtWP' ) . text ( ) ) ;
if ( isNaN ( currentGroundClearance ) || selectedMarker == null ) {
currentGroundClearance = settings . alt ; // use default altitude if no current ground clearance
}
altitude = currentGroundClearance + 100 * ( elevation - elevationAtHome ) ;
}
}
groundClearance = altitude / 100 + ( elevationAtHome - elevation ) ;
}
$ ( '#pointAlt' ) . val ( altitude ) ;
let altitudeMeters = parseInt ( altitude ) / 100 ;
$ ( '#altitudeInMeters' ) . text ( ` ${ altitudeMeters } m ` ) ;
document . getElementById ( 'groundClearanceAtWP' ) . style . color = groundClearance < ( settings . alt / 100 ) ? "#FF0000" : "#303030" ;
$ ( '#groundClearanceValueAtWP' ) . text ( ` ${ groundClearance } ` ) ;
return altitude ;
}
function plotElevation ( ) {
if ( $ ( '#missionPlannerElevation' ) . is ( ":visible" ) && ! disableMarkerEdit ) {
if ( mission . isEmpty ( ) ) {
var data = [ [ 0 ] , [ 0 ] ] ;
var layout = { showlegend : true ,
legend : {
"orientation" : "h" ,
xanchor : "center" ,
y : 1.3 ,
x : 0.5
} ,
title : 'Mission Elevation Profile' ,
xaxis : {
title : 'Distance (m)'
} ,
yaxis : {
title : 'Elevation (m)' ,
} ,
height : 300 ,
}
Plotly . newPlot ( 'elevationDiv' , data , layout ) ;
}
else {
( async ( ) => {
const [ lengthMission , totalMissionDistance , samples , elevation , altPoint2measure , namePoint2measure , refPoint2measure ] = await mission . getElevation ( globalSettings ) ;
let x _elevation = Array . from ( Array ( samples + 1 ) , ( _ , i ) => i * totalMissionDistance / samples ) ;
var trace _WGS84 = {
x : x _elevation ,
y : elevation ,
type : 'scatter' ,
name : 'WGS84 elevation' ,
hovertemplate : '<b>Elevation</b>: %{y} m' ,
fill : 'tozeroy' ,
line : {
color : '#ff7f0e' ,
} ,
} ;
let y _missionElevation = altPoint2measure . map ( ( x , i ) => x / 100 + HOME . getAlt ( ) * ( 1 - refPoint2measure [ i ] ) ) ;
let y _elevationReference = refPoint2measure . map ( ( x , i ) => ( x == 1 ? "WGS84" : "Take-off Home" ) ) ;
var trace _missionHeight = {
x : lengthMission ,
y : y _missionElevation ,
type : 'scatter' ,
mode : 'lines+markers+text' ,
name : 'Mission altitude' ,
text : namePoint2measure ,
textposition : 'top center' ,
textfont : {
family : 'Raleway, sans-serif'
} ,
customdata : y _elevationReference ,
hovertemplate : '<b>WP</b>: %{text}' +
'<br><b>Elevation</b>: %{y} m<br>' +
'<b>Reference</b>: %{customdata}' ,
line : {
color : '#1497f1' ,
} ,
marker : {
color : '#1f77b4' ,
} ,
} ;
/ * S h o w m u l t i m i s s i o n n u m b e r i n p l o t t i t l e w h e n s i n g l e m i s s i o n d i s p l a y e d
* Not updated when ALL multi missions displayed since plot disabled * /
let missionNumber = '' ;
if ( multimissionCount ) {
missionNumber = ' ' + ( $ ( '#multimissionOptionList' ) . val ( ) ) ;
}
var layout = { showlegend : true ,
legend : {
"orientation" : "h" ,
xanchor : "center" ,
y : 1.3 ,
x : 0.5
} ,
title : 'Mission' + missionNumber + ' Elevation Profile' ,
xaxis : {
title : 'Distance (m)'
} ,
yaxis : {
title : 'Elevation (m)' ,
range : [ - 10 + Math . min ( Math . min ( ... y _missionElevation ) , Math . min ( ... elevation ) ) , 10 + Math . max ( Math . max ( ... y _missionElevation ) , Math . max ( ... elevation ) ) ] ,
} ,
height : 300 ,
}
var data = [ trace _WGS84 , trace _missionHeight ] ;
Plotly . newPlot ( 'elevationDiv' , data , layout ) ;
} ) ( )
}
}
}
function parseBooleans ( str ) {
if ( /^(?:true|false)$/i . test ( str ) ) {
str = str . toLowerCase ( ) === 'true' ;
}
return str ;
} ;
} ;
TABS . mission _control . isBitSet = function ( bits , testBit ) {
let isTrue = ( ( bits & ( 1 << testBit ) ) != 0 ) ;
return isTrue ;
}
TABS . mission _control . setBit = function ( bits , bit , value ) {
return value ? bits |= ( 1 << bit ) : bits &= ~ ( 1 << bit ) ;
}
// window.addEventListener("error", handleError, true);
// function handleError(evt) {
// if (evt.message) { // Chrome sometimes provides this
// GUI.alert("error: "+evt.message +" at linenumber: "+evt.lineno+" of file: "+evt.filename);
// } else {
// GUI.alert("error: "+evt.type+" from element: "+(evt.srcElement || evt.target));
// }
// }
TABS . mission _control . cleanup = function ( callback ) {
if ( callback ) callback ( ) ;
} ;