'use strict' ;
// MultiWii NAV Protocol
var MWNP = MWNP || { } ;
// WayPoint type
MWNP . WPTYPE = {
WAYPOINT : 1 ,
PH _UNLIM : 2 ,
PH _TIME : 3 ,
RTH : 4 ,
SET _POI : 5 ,
JUMP : 6 ,
SET _HEAD : 7 ,
LAND : 8
} ;
// Reverse WayPoint type dictionary
MWNP . WPTYPE . REV = {
1 : 'WAYPOINT' ,
2 : 'PH_UNLIM' ,
3 : 'PH_TIME' ,
4 : 'RTH' ,
5 : 'SET_POI' ,
6 : 'JUMP' ,
7 : 'SET_HEAD' ,
8 : 'LAND'
} ;
// Dictionary of Parameter1,2,3 definition depending on type of action selected (refer to MWNP.WPTYPE)
var dictOfLabelParameterPoint = {
1 : { parameter1 : 'Speed (cm/s)' , parameter2 : '' , parameter3 : '' } ,
2 : { parameter1 : '' , parameter2 : '' , parameter3 : '' } ,
3 : { parameter1 : 'Wait time (s)' , parameter2 : 'Speed (cm/s)' , parameter3 : '' } ,
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 : '' }
} ;
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 rthUpdateInterval = 0 ;
if ( GUI . active _tab != 'mission_control' ) {
GUI . active _tab = 'mission_control' ;
googleAnalytics . sendAppView ( 'Mission Control' ) ;
}
if ( CONFIGURATOR . connectionValid ) {
var loadChainer = new MSPChainerClass ( ) ;
loadChainer . setChain ( [
mspHelper . getMissionInfo
] ) ;
loadChainer . setExitPoint ( loadHtml ) ;
loadChainer . execute ( ) ;
} else {
// FC not connected, load page anyway
loadHtml ( ) ;
}
function loadHtml ( ) {
GUI . load ( "./tabs/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 ;
}
if ( typeof require !== "undefined" ) {
loadSettings ( ) ;
// let the dom load finish, avoiding the resizing of the map
setTimeout ( initMap , 200 ) ;
} else {
$ ( '#missionMap, #missionControls' ) . hide ( ) ;
$ ( '#notLoadMap' ) . show ( ) ;
}
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 = GPS _DATA . lat / 10000000 ;
let lon = GPS _DATA . lon / 10000000 ;
//Update map
if ( 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 ( ( 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: ' + SENSOR _DATA . kinematics [ 2 ] +
'\nAlt: ' + SENSOR _DATA . altitude +
'm\nSpeed: ' + GPS _DATA . speed + 'cm/s\n' +
'Dist: ' + GPS _DATA . distanceToHome + 'm' ) ;
//update RTH every 5th GPS update since it really shouldn't change
if ( rthUpdateInterval >= 5 )
{
MISSION _PLANER . bufferPoint . number = - 1 ; //needed to get point 0 which id RTH
MSP . send _message ( MSPCodes . MSP _WP , mspHelper . crunch ( MSPCodes . MSP _WP ) , false , function rth _update ( ) {
var coord = ol . proj . fromLonLat ( [ MISSION _PLANER . bufferPoint . lon , MISSION _PLANER . bufferPoint . lat ] ) ;
rthGeo . setCoordinates ( coord ) ;
} ) ;
rthUpdateInterval = 0 ;
}
rthUpdateInterval ++ ;
}
}
/ *
* enable data pulling if not offline
* Refreshing data at 5 Hz ... Could slow this down if we have performance issues
* /
if ( ! isOffline )
{
helper . mspBalancedInterval . add ( 'gps_pull' , 200 , 3 , function gps _update ( ) {
// avoid usage of the GPS commands until a GPS sensor is detected for targets that are compiled without GPS support.
if ( ! have _sensor ( CONFIG . activeSensors , 'gps' ) ) {
update _gpsTrack ( ) ;
return ;
}
if ( helper . mspQueue . shouldDrop ( ) ) {
return ;
}
get _raw _gps _data ( ) ;
} ) ;
}
GUI . content _ready ( callback ) ;
}
var markers = [ ] ;
var lines = [ ] ;
var map ;
var selectedMarker = null ;
var nonMarkerPoint = [ ] ;
var nonMarkerPointListRead = [ ] ;
var isOptions = false ;
var oldMarkers = null ;
var pointFromBuffer = { } ;
var pointForSend = 0 ;
var actionPointForSend = 0 ;
var settings = { speed : 0 , alt : 5000 } ;
/////////////////////////////////////////////
// Reinit Form
/////////////////////////////////////////////
// Function to clear/reinit Jquery variable
function clearEditForm ( ) {
$ ( '#pointLat' ) . val ( '' ) ;
$ ( '#pointLon' ) . val ( '' ) ;
$ ( '#pointAlt' ) . val ( '' ) ;
$ ( '#pointP1' ) . val ( '' ) ;
$ ( '#pointP2' ) . val ( '' ) ;
$ ( '#pointP3' ) . val ( '' ) ;
$ ( '[name=Options]' ) . filter ( '[value=None]' ) . prop ( 'checked' , true ) ;
$ ( '#Options_LandRTH' ) . prop ( 'checked' , false ) ;
$ ( '#Options_TargetJUMP' ) . val ( 0 ) ;
$ ( '#Options_NumberJUMP' ) . val ( 0 ) ;
$ ( '#Options_HeadingHead' ) . val ( - 1 ) ;
$ ( '[name=pointNumber]' ) . val ( '' ) ;
$ ( '#MPeditPoint' ) . fadeOut ( 300 ) ;
}
/////////////////////////////////////////////
// Manage Settings
/////////////////////////////////////////////
function loadSettings ( ) {
chrome . storage . local . get ( 'missionPlanerSettings' , function ( result ) {
if ( result . missionPlanerSettings ) {
settings = result . missionPlanerSettings ;
}
refreshSettings ( ) ;
} ) ;
}
function saveSettings ( ) {
chrome . storage . local . set ( { 'missionPlanerSettings' : settings } ) ;
}
function refreshSettings ( ) {
$ ( '#MPdefaultPointAlt' ) . val ( settings . alt ) ;
$ ( '#MPdefaultPointSpeed' ) . val ( settings . speed ) ;
}
function closeSettingsPanel ( ) {
$ ( '#missionPlanerSettings' ) . hide ( ) ;
$ ( '#missionPlanerTotalInfo' ) . fadeIn ( 300 ) ;
if ( selectedMarker !== null ) {
$ ( '#MPeditPoint' ) . fadeIn ( 300 ) ;
}
}
/////////////////////////////////////////////
// Manage Plotting functions
/////////////////////////////////////////////
// Function to repaint lines between markers
function repaint ( ) {
var oldPos ;
var oldAction ;
var poiNumber ;
var poiList ;
var lengthPoiList ;
var activatePoi = false ;
var activateHead = false ;
var oldHeading ;
var xmlItemNumber = 0 ;
for ( var i in lines ) {
map . removeLayer ( lines [ i ] ) ;
}
lines = [ ] ;
poiList = [ ] ;
$ ( '#missionDistance' ) . text ( 0 ) ;
map . getLayers ( ) . forEach ( function ( t ) {
if ( t instanceof ol . layer . Vector && typeof t . alt !== 'undefined' ) {
var geometry = t . getSource ( ) . getFeatures ( ) [ 0 ] . getGeometry ( ) ;
var action = t . action ;
var markerNumber = t . number ;
var options = t . options ;
if ( action == 5 ) {
// If action is Set_POI, increment counter of POI
poiNumber = markerNumber ;
lengthPoiList = poiList . push ( poiNumber ) ;
activatePoi = true ;
}
else {
// If classic WPs, draw standard line in-between
if ( typeof oldPos !== 'undefined' && activatePoi != true && activateHead != true ) {
paintLine ( oldPos , geometry . getCoordinates ( ) ) ;
}
// 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 ( ( lengthPoiList % 2 ) == 0 ) {
paintLine ( oldPos , geometry . getCoordinates ( ) , '#ffb725' , 5 ) ;
}
else {
paintLine ( oldPos , geometry . getCoordinates ( ) , '#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 , geometry . getCoordinates ( ) , '#1497f1' , 0 , lineText = String ( oldHeading ) + "°" ) ;
}
// If classic WPs is defined with a JUMP options, draw pink dashed line in-between
if ( options . key == "JUMP" ) {
paintLine ( geometry . getCoordinates ( ) , markers [ options . targetWP - 1 ] . getSource ( ) . getFeatures ( ) [ 0 ] . getGeometry ( ) . getCoordinates ( ) , '#e935d6' , 5 , "Repeat x" + String ( options . numRepeat ) ) ;
}
// 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 ( options . key == "SET_HEAD" ) {
if ( options . heading == "-1" ) {
activatePoi = false ;
activateHead = false ;
oldHeading = 'undefined'
}
else if ( typeof options . heading != 'undefined' && options . heading != "-1" ) {
activateHead = true ;
oldHeading = options . heading
}
}
oldPos = geometry . getCoordinates ( ) ;
}
}
} ) ;
//reset text position
if ( textGeom ) {
textGeom . setCoordinates ( map . getCoordinateFromPixel ( [ 0 , 0 ] ) ) ;
}
}
// function modified to take into account optional argument such color, linedash and line label
function paintLine ( pos1 , pos2 , color = '#1497f1' , lineDash = 0 , lineText = "" ) {
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 ,
placement : 'line' ,
textBaseline : 'ideographic' ,
stroke : new ol . style . Stroke ( {
color : color
} ) ,
} ) ,
} ) ) ;
var vectorSource = new ol . source . Vector ( {
features : [ feature ]
} ) ;
var vectorLayer = new ol . layer . Vector ( {
source : vectorSource
} ) ;
lines . push ( vectorLayer ) ;
var length = ol . Sphere . getLength ( line ) + parseFloat ( $ ( '#missionDistance' ) . text ( ) ) ;
$ ( '#missionDistance' ) . text ( length . toFixed ( 3 ) ) ;
map . addLayer ( vectorLayer ) ;
}
// Function modified to add action name and marker numbering to help changing icon depending on those items
function getPointIcon ( _action , isEdit , markerNumber = '' ) {
var dictofPoint = {
1 : 'WP' ,
2 : 'PH' ,
3 : 'PH' ,
//4: '',
5 : 'POI' ,
//6: '',
//7: 'head',
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' + ( dictofPoint [ _action ] != '' ? '_' + dictofPoint [ _action ] : '' ) + ( isEdit ? '_edit' : '' ) + '.png'
} ) ) ,
text : new ol . style . Text ( ( {
text : String ( Number ( markerNumber ) + 1 ) ,
font : '12px sans-serif' ,
offsetY : - 15 ,
offsetX : - 2 ,
fill : new ol . style . Fill ( {
color : '#FFFFFF'
} ) ,
stroke : new ol . style . Stroke ( {
color : '#FFFFFF'
} ) ,
} ) )
} ) ;
}
// Function modified by adding parameter 1,2,3 needed in MSP, plus options dictionary to take into account WP behavior changer such as JUMP, SET_HEAD, RTH
function addMarker ( _pos , _alt , _action , _parameter1 = 0 , _parameter2 = 0 , _parameter3 = 0 , _options = { key : "None" } ) {
var iconFeature = new ol . Feature ( {
geometry : new ol . geom . Point ( _pos ) ,
name : 'Null Island' ,
population : 4000 ,
rainfall : 500
} ) ;
iconFeature . setStyle ( getPointIcon ( _action , false , String ( markers . length ) ) ) ;
var vectorSource = new ol . source . Vector ( {
features : [ iconFeature ]
} ) ;
var vectorLayer = new ol . layer . Vector ( {
source : vectorSource
} ) ;
vectorLayer . alt = _alt ;
vectorLayer . number = markers . length ;
vectorLayer . action = _action ;
vectorLayer . parameter1 = _parameter1 ;
vectorLayer . parameter2 = _parameter2 ;
vectorLayer . parameter3 = _parameter3 ;
vectorLayer . options = _options ;
markers . push ( vectorLayer ) ;
return vectorLayer ;
}
/////////////////////////////////////////////
// Manage Map construction
/////////////////////////////////////////////
function initMap ( ) {
var app = { } ;
/ * *
* @ 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 ( ) {
$ ( '#MPeditPoint, #missionPlanerTotalInfo' , '#missionPlanerTemplate' ) . hide ( ) ;
$ ( '#missionPlanerSettings' ) . 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 ) ;
/ * *
* @ param { ol . MapBrowserEvent } evt Map browser event .
* @ return { boolean } ` true ` to start the drag sequence .
* /
app . Drag . prototype . handleDownEvent = function ( evt ) {
var map = evt . map ;
var feature = map . forEachFeatureAtPixel ( evt . pixel ,
function ( feature , layer ) {
return feature ;
} ) ;
if ( feature ) {
this . coordinate _ = evt . coordinate ;
this . feature _ = feature ;
}
return ! ! feature ;
} ;
/ * *
* @ param { ol . MapBrowserEvent } evt Map browser event .
* /
app . Drag . prototype . handleDragEvent = function ( evt ) {
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 ( ) ) ;
geometry . translate ( deltaX , deltaY ) ;
this . coordinate _ [ 0 ] = evt . coordinate [ 0 ] ;
this . coordinate _ [ 1 ] = evt . coordinate [ 1 ] ;
repaint ( ) ;
} ;
/ * *
* @ 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 ) {
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 ) {
this . coordinate _ = null ;
this . feature _ = null ;
return false ;
} ;
var lat = ( GPS _DATA ? ( GPS _DATA . lat / 10000000 ) : 0 ) ;
var lon = ( GPS _DATA ? ( GPS _DATA . lon / 10000000 ) : 0 ) ;
let mapLayer ;
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 ( ) ;
}
map = new ol . Map ( {
controls : ol . control . defaults ( {
attributionOptions : {
collapsible : false
}
} ) . extend ( [
new app . PlannerSettingsControl ( ) ,
//new app.PlannerTemplateControl()
] ) ,
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 ) {
chrome . storage . local . set ( { 'missionPlanerLastValues' : {
center : ol . proj . toLonLat ( map . getView ( ) . getCenter ( ) ) ,
zoom : map . getView ( ) . getZoom ( )
} } ) ;
} ) ;
// load map view settings on startup
chrome . storage . local . get ( 'missionPlanerLastValues' , function ( result ) {
if ( result . missionPlanerLastValues && result . missionPlanerLastValues . center ) {
map . getView ( ) . setCenter ( ol . proj . fromLonLat ( result . missionPlanerLastValues . center ) ) ;
map . getView ( ) . setZoom ( result . missionPlanerLastValues . zoom ) ;
}
} ) ;
map . on ( 'click' , function ( evt ) {
if ( selectedMarker != null ) {
try {
selectedMarker . getSource ( ) . getFeatures ( ) [ 0 ] . setStyle ( getPointIcon ( selectedMarker . action , false , selectedMarker . number ) ) ;
selectedMarker = null ;
clearEditForm ( ) ;
} catch ( e ) {
GUI . log ( e ) ;
}
}
var selectedFeature = map . forEachFeatureAtPixel ( evt . pixel ,
function ( feature , layer ) {
return feature ;
} ) ;
var tempMarker = map . forEachFeatureAtPixel ( evt . pixel ,
function ( feature , layer ) {
return layer ;
} ) ;
if ( selectedFeature ) {
for ( var i in markers ) {
if ( markers [ i ] == tempMarker ) {
selectedMarker = tempMarker ;
var geometry = selectedFeature . getGeometry ( ) ;
var coord = ol . proj . toLonLat ( geometry . getCoordinates ( ) ) ;
selectedFeature . setStyle ( getPointIcon ( selectedMarker . action , true , selectedMarker . number ) ) ;
var altitudeMeters = app . ConvertCentimetersToMeters ( selectedMarker . alt ) ;
$ ( '#altitudeInMeters' ) . text ( ` ${ altitudeMeters } m ` ) ;
$ ( '#pointLon' ) . val ( Math . round ( coord [ 0 ] * 10000000 ) / 10000000 ) ;
$ ( '#pointLat' ) . val ( Math . round ( coord [ 1 ] * 10000000 ) / 10000000 ) ;
$ ( '#pointAlt' ) . val ( selectedMarker . alt ) ;
$ ( '#pointType' ) . val ( selectedMarker . action ) ;
// Change SpeedValue to Parameter1, 2, 3
$ ( '#pointP1' ) . val ( selectedMarker . parameter1 ) ;
$ ( '#pointP2' ) . val ( selectedMarker . parameter2 ) ;
$ ( '#pointP3' ) . val ( selectedMarker . parameter3 ) ;
$ ( '[name=Options]' ) . filter ( '[value=' + selectedMarker . options [ 'key' ] + ']' ) . prop ( 'checked' , true ) ;
// Manage RTH, JUMP, SET_HEAD options for WP
if ( selectedMarker . options . key == "RTH" ) {
$ ( '#Options_LandRTH' ) . prop ( 'checked' , selectedMarker . options . landAfter ) ;
}
else if ( selectedMarker . options . key == "JUMP" ) {
$ ( '#Options_TargetJUMP' ) . val ( selectedMarker . options . targetWP ) ;
$ ( '#Options_NumberJUMP' ) . val ( selectedMarker . options . numRepeat ) ;
}
else if ( selectedMarker . options . key == "SET_HEAD" ) {
$ ( '#Options_HeadingHead' ) . val ( selectedMarker . options . heading ) ;
}
// Selection box update depending on choice of type of waypoint
for ( var j in dictOfLabelParameterPoint [ selectedMarker . action ] ) {
if ( dictOfLabelParameterPoint [ selectedMarker . action ] [ j ] != '' ) {
$ ( '#pointP' + String ( j ) . slice ( - 1 ) + 'class' ) . fadeIn ( 300 ) ;
$ ( 'label[for=pointP' + String ( j ) . slice ( - 1 ) + ']' ) . html ( dictOfLabelParameterPoint [ selectedMarker . action ] [ j ] ) ;
}
else { $ ( '#pointP' + String ( j ) . slice ( - 1 ) + 'class' ) . fadeOut ( 300 ) ; }
}
if ( [ 1 , 2 , 3 , 8 ] . includes ( selectedMarker . action ) || [ '1' , '2' , '3' , '8' ] . includes ( selectedMarker . action ) ) {
$ ( '#pointOptionclass' ) . fadeIn ( 300 ) ;
}
else { $ ( '#pointOptionclass' ) . fadeOut ( 300 ) ; }
$ ( '#MPeditPoint' ) . fadeIn ( 300 ) ;
}
}
}
else {
map . addLayer ( addMarker ( evt . coordinate , settings . alt , MWNP . WPTYPE . WAYPOINT , settings . speed ) ) ;
repaint ( ) ;
}
} ) ;
// change mouse cursor when over marker
$ ( map . getViewport ( ) ) . on ( 'mousemove' , function ( e ) {
var pixel = map . getEventPixel ( e . originalEvent ) ;
var hit = map . forEachFeatureAtPixel ( pixel , function ( feature , layer ) {
return true ;
} ) ;
if ( hit ) {
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 ) ;
$ ( '#pointAlt' ) . keyup ( function ( ) {
let altitudeMeters = app . ConvertCentimetersToMeters ( $ ( this ) . val ( ) ) ;
$ ( '#altitudeInMeters' ) . text ( ` ${ altitudeMeters } m ` ) ;
} ) ;
$ ( '#removeAllPoints' ) . on ( 'click' , function ( ) {
if ( markers . length && confirm ( chrome . i18n . getMessage ( 'confirm_delete_all_points' ) ) ) {
removeAllPoints ( ) ;
}
} ) ;
$ ( '#removePoint' ) . on ( 'click' , function ( ) {
if ( selectedMarker ) {
var tmp = [ ] ;
for ( var i in markers ) {
if ( markers [ i ] !== selectedMarker && typeof markers [ i ] . action !== "undefined" ) {
tmp . push ( markers [ i ] ) ;
}
}
map . removeLayer ( selectedMarker ) ;
markers = tmp ;
selectedMarker = null ;
clearEditForm ( ) ;
repaint ( ) ;
}
} ) ;
// SavePoint function updated to take into account P1 to P3 parameter and JUMP,RTH, SET_HEAD options for WP
$ ( '#savePoint' ) . on ( 'click' , function ( ) {
if ( selectedMarker ) {
map . getLayers ( ) . forEach ( function ( t ) {
if ( t === selectedMarker ) {
var geometry = t . getSource ( ) . getFeatures ( ) [ 0 ] . getGeometry ( ) ;
geometry . setCoordinates ( ol . proj . fromLonLat ( [ parseFloat ( $ ( '#pointLon' ) . val ( ) ) , parseFloat ( $ ( '#pointLat' ) . val ( ) ) ] ) ) ;
t . alt = $ ( '#pointAlt' ) . val ( ) ;
t . action = $ ( '#pointType' ) . val ( ) ;
// if action is Set_POI, PH_UNLIM, LAND, set parameter_i to 0
if ( t . action == '5' || t . action == '2' || t . action == '8' ) {
t . parameter1 = 0 ;
t . parameter2 = 0 ;
t . parameter3 = 0 ;
}
// else for other kind of waypoints, set parameter_i to pointP_i value
else {
console . log ( "$('#pointP1').val() : " , $ ( '#pointP1' ) . val ( ) ) ;
t . parameter1 = $ ( '#pointP1' ) . val ( ) ;
t . parameter2 = $ ( '#pointP2' ) . val ( ) ;
t . parameter3 = $ ( '#pointP3' ) . val ( ) ;
}
// Manage Options
// if RTH options selected, store GUI value in t.options
if ( $ ( 'input[name=Options]:checked' ) . val ( ) == "RTH" ) {
t . options = { key : $ ( 'input[name=Options]:checked' ) . val ( ) ,
landAfter : $ ( '#Options_LandRTH' ) . prop ( 'checked' )
} ;
}
// if JUMP options selected, store GUI value in t.options
else if ( $ ( 'input[name=Options]:checked' ) . val ( ) == "JUMP" ) {
// check if users input values verify the condition i an integer btw [0,99] and within length of Markers
if ( ! Array . from ( { length : markers . length } , ( v , i ) => i + 1 ) . includes ( Number ( $ ( '#Options_TargetJUMP' ) . val ( ) ) ) || ( Number ( $ ( '#Options_NumberJUMP' ) . val ( ) ) < 0 || Number ( $ ( '#Options_NumberJUMP' ) . val ( ) ) > 99 ) ) {
alert ( chrome . i18n . getMessage ( 'MissionPlannerJumpSettingsCheck' ) )
t . options = { key : 'None' }
}
else {
t . options = { key : $ ( 'input[name=Options]:checked' ) . val ( ) ,
targetWP : $ ( '#Options_TargetJUMP' ) . val ( ) ,
numRepeat : $ ( '#Options_NumberJUMP' ) . val ( )
} ;
}
}
// if SET_HEAD options selected, store GUI value in t.options
else if ( $ ( 'input[name=Options]:checked' ) . val ( ) == "SET_HEAD" ) {
// Check if Heading is btw [0, 360°] or = -1
if ( $ ( '#Options_HeadingHead' ) . val ( ) > 360 || ( $ ( '#Options_HeadingHead' ) . val ( ) < 0 && $ ( '#Options_HeadingHead' ) . val ( ) != - 1 ) ) {
alert ( chrome . i18n . getMessage ( 'MissionPlannerHeadSettingsCheck' ) )
t . options = { key : 'None' }
}
else {
t . options = { key : $ ( 'input[name=Options]:checked' ) . val ( ) ,
heading : $ ( '#Options_HeadingHead' ) . val ( )
} ;
}
}
else {
t . options = { key : $ ( 'input[name=Options]:checked' ) . val ( ) }
}
}
} ) ;
selectedMarker . getSource ( ) . getFeatures ( ) [ 0 ] . setStyle ( getPointIcon ( selectedMarker . action , false , selectedMarker . number ) ) ;
selectedMarker = null ;
clearEditForm ( ) ;
repaint ( ) ;
}
} ) ;
$ ( '#loadFileMissionButton' ) . on ( 'click' , function ( ) {
if ( markers . length && ! confirm ( chrome . i18n . getMessage ( 'confirm_delete_all_points' ) ) ) return ;
removeAllPoints ( ) ;
nwdialog . setContext ( document ) ;
nwdialog . openFileDialog ( function ( result ) {
loadMissionFile ( result ) ;
} )
} ) ;
$ ( '#saveFileMissionButton' ) . on ( 'click' , function ( ) {
nwdialog . setContext ( document ) ;
nwdialog . saveFileDialog ( '' , '.mission' , function ( result ) {
saveMissionFile ( result ) ;
} )
} ) ;
$ ( '#loadMissionButton' ) . on ( 'click' , function ( ) {
if ( markers . length && ! confirm ( chrome . i18n . getMessage ( 'confirm_delete_all_points' ) ) ) return ;
removeAllPoints ( ) ;
$ ( this ) . addClass ( 'disabled' ) ;
GUI . log ( 'Start get point' ) ;
// Reinit some internal parameters
pointForSend = 0 ;
actionPointForSend = 0 ;
nonMarkerPoint = [ ] ;
nonMarkerPointListRead = [ ] ;
var isOptions = false ;
var oldMarkers = null ;
getNextPoint ( ) ;
} ) ;
$ ( '#saveMissionButton' ) . on ( 'click' , function ( ) {
$ ( this ) . addClass ( 'disabled' ) ;
GUI . log ( 'Start send point' ) ;
// Reinit some internal parameters
pointForSend = 0 ;
actionPointForSend = 0 ;
nonMarkerPoint = [ ] ;
nonMarkerPointListRead = [ ] ;
var isOptions = false ;
var oldMarkers = null ;
sendNextPoint ( ) ;
} ) ;
$ ( '#loadEepromMissionButton' ) . on ( 'click' , function ( ) {
if ( markers . length && ! confirm ( chrome . i18n . getMessage ( 'confirm_delete_all_points' ) ) ) return ;
removeAllPoints ( ) ;
GUI . log ( chrome . i18n . getMessage ( 'eeprom_load_ok' ) ) ;
MSP . send _message ( MSPCodes . MSP _WP _MISSION _LOAD , [ 0 ] , getPointsFromEprom ) ;
} ) ;
$ ( '#saveEepromMissionButton' ) . on ( 'click' , function ( ) {
GUI . log ( chrome . i18n . getMessage ( 'eeprom_saved_ok' ) ) ;
MSP . send _message ( MSPCodes . MSP _WP _MISSION _SAVE , [ 0 ] , false ) ;
} ) ;
$ ( '#saveSettings' ) . on ( 'click' , function ( ) {
settings = { speed : $ ( '#MPdefaultPointSpeed' ) . val ( ) , alt : $ ( '#MPdefaultPointAlt' ) . val ( ) } ;
saveSettings ( ) ;
closeSettingsPanel ( ) ;
} ) ;
$ ( '#cancelSettings' ) . on ( 'click' , function ( ) {
loadSettings ( ) ;
closeSettingsPanel ( ) ;
} ) ;
// Add function to update parameter i field in the selected Edit WP Box
$ ( '#pointType' ) . on ( 'change' , function ( ) {
selectedMarker . action = $ ( '#pointType' ) . val ( ) ;
for ( var j in dictOfLabelParameterPoint [ selectedMarker . action ] ) {
if ( dictOfLabelParameterPoint [ selectedMarker . action ] [ j ] != '' ) {
$ ( '#pointP' + String ( j ) . slice ( - 1 ) + 'class' ) . fadeIn ( 300 ) ;
$ ( 'label[for=pointP' + String ( j ) . slice ( - 1 ) + ']' ) . html ( dictOfLabelParameterPoint [ selectedMarker . action ] [ j ] ) ;
}
else { $ ( '#pointP' + String ( j ) . slice ( - 1 ) + 'class' ) . fadeOut ( 300 ) ; }
}
if ( [ "1" , "2" , "3" ] . includes ( selectedMarker . action ) ) {
$ ( '#pointOptionclass' ) . fadeIn ( 300 ) ;
}
else { $ ( '#pointOptionclass' ) . fadeOut ( 300 ) ; }
} ) ;
updateTotalInfo ( ) ;
}
/////////////////////////////////////////////
// Manage Buttons toolbox
/////////////////////////////////////////////
function removeAllPoints ( ) {
for ( var i in markers ) {
map . removeLayer ( markers [ i ] ) ;
}
markers = [ ] ;
clearEditForm ( ) ;
updateTotalInfo ( ) ;
repaint ( ) ;
}
function loadMissionFile ( filename ) {
const fs = require ( 'fs' ) ;
if ( ! window . xml2js ) return GUI . log ( '<span style="color: red">Error reading file (xml2js not found)</span>' ) ;
fs . readFile ( filename , ( err , data ) => {
if ( err ) {
GUI . log ( '<span style="color: red">Error reading file</span>' ) ;
return console . error ( err ) ;
}
window . xml2js . Parser ( { 'explicitChildren' : true , 'preserveChildrenOrder' : true } ) . parseString ( data , ( err , result ) => {
if ( err ) {
GUI . log ( '<span style="color: red">Error parsing file</span>' ) ;
return console . error ( err ) ;
}
// parse mission file
var mission = { points : [ ] } ;
var node = null ;
var nodemission = null ;
for ( var noderoot in result ) {
if ( ! nodemission && noderoot . match ( /mission/i ) ) {
nodemission = result [ noderoot ] ;
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 . version = node . $ [ attr ]
}
}
} else if ( node [ '#name' ] . match ( /mwp/i ) && node . $ ) {
mission . center = { } ;
for ( var attr in node . $ ) {
if ( attr . match ( /zoom/i ) ) {
mission . center . zoom = parseInt ( node . $ [ attr ] ) ;
} else if ( attr . match ( /cx/i ) ) {
mission . center . lon = parseFloat ( node . $ [ attr ] ) ;
} else if ( attr . match ( /cy/i ) ) {
mission . center . lat = parseFloat ( node . $ [ attr ] ) ;
}
}
} else if ( node [ '#name' ] . match ( /missionitem/i ) && node . $ ) {
var point = { } ;
for ( var attr in node . $ ) {
if ( attr . match ( /no/i ) ) {
point . index = parseInt ( node . $ [ attr ] ) ;
} else if ( attr . match ( /action/i ) ) {
if ( node . $ [ attr ] . match ( /WAYPOINT/i ) ) {
point . action = MWNP . WPTYPE . WAYPOINT ;
} else if ( node . $ [ attr ] . match ( /PH_UNLIM/i ) || node . $ [ attr ] . match ( /POSHOLD_UNLIM/i ) ) {
point . action = MWNP . WPTYPE . PH _UNLIM ;
} else if ( node . $ [ attr ] . match ( /PH_TIME/i ) || node . $ [ attr ] . match ( /POSHOLD_TIME/i ) ) {
point . action = MWNP . WPTYPE . PH _TIME ;
} else if ( node . $ [ attr ] . match ( /RTH/i ) ) {
point . action = MWNP . WPTYPE . RTH ;
} else if ( node . $ [ attr ] . match ( /SET_POI/i ) ) {
point . action = MWNP . WPTYPE . SET _POI ;
} else if ( node . $ [ attr ] . match ( /JUMP/i ) ) {
point . action = MWNP . WPTYPE . JUMP ;
} else if ( node . $ [ attr ] . match ( /SET_HEAD/i ) ) {
point . action = MWNP . WPTYPE . SET _HEAD ;
} else if ( node . $ [ attr ] . match ( /LAND/i ) ) {
point . action = MWNP . WPTYPE . LAND ;
} else {
point . action = 0 ;
}
} else if ( attr . match ( /lat/i ) ) {
point . lat = parseFloat ( node . $ [ attr ] ) ;
} else if ( attr . match ( /lon/i ) ) {
point . lon = parseFloat ( node . $ [ attr ] ) ;
} else if ( attr . match ( /alt/i ) ) {
point . alt = ( parseInt ( node . $ [ attr ] ) * 100 ) ;
} else if ( attr . match ( /parameter1/i ) ) {
point . p1 = parseInt ( node . $ [ attr ] ) ;
} else if ( attr . match ( /parameter2/i ) ) {
point . p2 = parseInt ( node . $ [ attr ] ) ;
} else if ( attr . match ( /parameter3/i ) ) {
point . p3 = parseInt ( node . $ [ attr ] ) ;
}
}
mission . points . push ( point ) ;
}
}
}
}
}
// draw actual mission
removeAllPoints ( ) ;
// Create nonMarkerPointListRead list to store index of non marker point (i.e RTH, SET_HEAD, JUMP) => useful for JUMP part
var nonMarkerPointListRead = [ ]
for ( var i = 0 ; i < mission . points . length ; i ++ ) {
if ( [ MWNP . WPTYPE . JUMP , MWNP . WPTYPE . SET _HEAD , MWNP . WPTYPE . RTH ] . includes ( mission . points [ i ] . action ) ) { nonMarkerPointListRead . push ( mission . points [ i ] . index ) ; } ;
}
// Updated code to take into account WP options (JUMP, SET_HEAD, RTH)
for ( var i = 0 ; i < mission . points . length ; i ++ ) {
if ( [ MWNP . WPTYPE . WAYPOINT , MWNP . WPTYPE . PH _UNLIM , MWNP . WPTYPE . PH _TIME , MWNP . WPTYPE . LAND , MWNP . WPTYPE . SET _POI ] . includes ( mission . points [ i ] . action ) ) {
if ( i < mission . points . length - 1 ) {
var coord = ol . proj . fromLonLat ( [ mission . points [ i ] . lon , mission . points [ i ] . lat ] ) ;
if ( mission . points [ i + 1 ] . action == MWNP . WPTYPE . SET _HEAD ) {
var options = { key : 'SET_HEAD' ,
heading : mission . points [ i + 1 ] . p1
} ;
}
else if ( mission . points [ i + 1 ] . action == MWNP . WPTYPE . JUMP ) {
var options = { key : 'JUMP' ,
targetWP : getNumberOfNonMarkerForJumpReversed ( nonMarkerPointListRead , mission . points [ i + 1 ] . p1 ) ,
numRepeat : mission . points [ i + 1 ] . p2
} ;
}
else if ( mission . points [ i + 1 ] . action == MWNP . WPTYPE . RTH ) {
var options = { key : 'RTH' ,
landAfter : mission . points [ i + 1 ] . p1
} ;
}
else {
var options = { key : 'None' } ;
}
map . addLayer ( addMarker ( coord , mission . points [ i ] . alt , mission . points [ i ] . action , mission . points [ i ] . p1 , mission . points [ i ] . p2 , mission . points [ i ] . p3 , options ) ) ;
if ( i == 0 ) {
map . getView ( ) . setCenter ( coord ) ;
map . getView ( ) . setZoom ( 16 ) ;
}
}
else {
var coord = ol . proj . fromLonLat ( [ mission . points [ i ] . lon , mission . points [ i ] . lat ] ) ;
map . addLayer ( addMarker ( coord , mission . points [ i ] . alt , mission . points [ i ] . action , mission . points [ i ] . p1 , mission . points [ i ] . p2 , mission . points [ i ] . p3 ) ) ;
if ( i == 0 ) {
map . getView ( ) . setCenter ( coord ) ;
map . getView ( ) . setZoom ( 16 ) ;
}
}
}
}
if ( mission . center ) {
var coord = ol . proj . fromLonLat ( [ mission . center . lon , mission . center . lat ] ) ;
map . getView ( ) . setCenter ( coord ) ;
if ( mission . center . zoom ) map . getView ( ) . setZoom ( mission . center . zoom ) ;
}
repaint ( ) ;
updateTotalInfo ( ) ;
} ) ;
} ) ;
}
function saveMissionFile ( filename ) {
const fs = require ( 'fs' ) ;
if ( ! window . xml2js ) return GUI . log ( '<span style="color: red">Error writing file (xml2js not found)</span>' ) ;
var center = ol . proj . toLonLat ( map . getView ( ) . getCenter ( ) ) ;
var zoom = map . getView ( ) . getZoom ( ) ;
var data = {
'version' : { $ : { 'value' : '2.3-pre8' } } ,
'mwp' : { $ : { 'cx' : ( Math . round ( center [ 0 ] * 10000000 ) / 10000000 ) , 'cy' : ( Math . round ( center [ 1 ] * 10000000 ) / 10000000 ) , 'zoom' : zoom } } ,
'missionitem' : [ ]
} ;
// init secondary counter for real marker numbers taking into account JUMP, SET_HEAD, RTH insertion
var j = 1 ;
var nonMarkerPoint = [ ] ;
for ( var i = 0 ; i < markers . length ; i ++ ) {
var geometry = markers [ i ] . getSource ( ) . getFeatures ( ) [ 0 ] . getGeometry ( ) ;
var coordinate = ol . proj . toLonLat ( geometry . getCoordinates ( ) ) ;
// if marker is Set_POI, PH_UNLIM, LAND
if ( markers [ i ] . action == '5' || markers [ i ] . action == '2' || markers [ i ] . action == '8' ) {
var point = { $ : {
'no' : ( j ) ,
'action' : MWNP . WPTYPE . REV [ markers [ i ] . action ] ,
'lon' : ( Math . round ( coordinate [ 0 ] * 10000000 ) / 10000000 ) ,
'lat' : ( Math . round ( coordinate [ 1 ] * 10000000 ) / 10000000 ) ,
'alt' : ( markers [ i ] . alt / 100 ) ,
'parameter1' : 0 ,
'parameter2' : 0 ,
'parameter3' : 0 ,
} } ;
data . missionitem . push ( point ) ;
j ++ ;
}
// else marker is not Set_POI, PH_UNLIM, LAND
else {
var point = { $ : {
'no' : ( j ) ,
'action' : MWNP . WPTYPE . REV [ markers [ i ] . action ] ,
'lon' : ( Math . round ( coordinate [ 0 ] * 10000000 ) / 10000000 ) ,
'lat' : ( Math . round ( coordinate [ 1 ] * 10000000 ) / 10000000 ) ,
'alt' : ( markers [ i ] . alt / 100 ) ,
'parameter1' : markers [ i ] . parameter1 ,
'parameter2' : markers [ i ] . parameter2 ,
'parameter3' : markers [ i ] . parameter3 ,
} } ;
data . missionitem . push ( point ) ;
j ++ ;
}
// Manage Options for markers
// If marker has options key = JUMP, provide JUMP data (Waypoint target for Jump and number of repeat) to Parameter1 and Parameter2
if ( markers [ i ] . options . key == "JUMP" ) {
nonMarkerPoint . push ( j ) ;
point = { $ : {
'no' : ( j ) ,
'action' : 'JUMP' ,
'lon' : 0 ,
'lat' : 0 ,
'alt' : 0 ,
'parameter1' : String ( getNumberOfNonMarkerForJump2 ( nonMarkerPoint , Number ( markers [ i ] . options . targetWP ) ) ) ,
'parameter2' : markers [ i ] . options . numRepeat ,
'parameter3' : 0
} } ;
data . missionitem . push ( point ) ;
j ++ ;
}
// If marker has options key = SET_HEAD, provide SET_HEAD heading data to Parameter1
else if ( markers [ i ] . options . key == "SET_HEAD" ) {
point = { $ : {
'no' : ( j ) ,
'action' : 'SET_HEAD' ,
'lon' : 0 ,
'lat' : 0 ,
'alt' : 0 ,
'parameter1' : markers [ i ] . options . heading ,
'parameter2' : 0 ,
'parameter3' : 0
} } ;
data . missionitem . push ( point ) ;
nonMarkerPoint . push ( j ) ;
j ++ ;
}
// If marker has options key = RTH, provide RTH data (whether landing is required) to Parameter1
else if ( markers [ i ] . options . key == "RTH" ) {
actionPointForSend ++ ;
point = { $ : {
'no' : ( j ) ,
'action' : 'RTH' ,
'lon' : 0 ,
'lat' : 0 ,
'alt' : ( markers [ i ] . alt / 100 ) ,
'parameter1' : ( markers [ i ] . options . landAfter ) ? 1 : 0 ,
'parameter2' : 0 ,
'parameter3' : 0
} } ;
data . missionitem . push ( point ) ;
nonMarkerPoint . push ( j ) ;
j ++ ;
} ;
}
var builder = new window . xml2js . Builder ( { 'rootName' : 'mission' , 'renderOpts' : { 'pretty' : true , 'indent' : '\t' , 'newline' : '\n' } } ) ;
var xml = builder . buildObject ( data ) ;
fs . writeFile ( filename , xml , ( err ) => {
if ( err ) {
GUI . log ( '<span style="color: red">Error writing file</span>' ) ;
return console . error ( err ) ;
}
GUI . log ( 'File saved' ) ;
} ) ;
}
// New: function to get number of Non Marker points such as JUMP, SET_HEAD and RTH
function getNumberOfNonMarkerForJump2 ( nonMarkerPointList , numTargetMarker ) {
for ( i = 1 ; i < nonMarkerPointList . length ; i ++ ) {
if ( numTargetMarker >= nonMarkerPointList [ i - 1 ] ) {
numTargetMarker ++ ;
}
else {
return numTargetMarker ;
}
}
}
// New: Reversed function to get number of Non Marker points such as JUMP, SET_HEAD and RTH
function getNumberOfNonMarkerForJumpReversed ( nonMarkerPointList , numTargetMarker ) {
var numTargetMarkerOut = 0 ;
for ( i = 1 ; i < nonMarkerPointList . length ; i ++ ) {
if ( numTargetMarker >= nonMarkerPointList [ i - 1 ] ) {
numTargetMarkerOut ++ ;
}
else {
return numTargetMarker - numTargetMarkerOut ;
}
}
}
function getPointsFromEprom ( ) {
pointForSend = 0 ;
actionPointForSend = 0 ;
nonMarkerPoint = [ ] ;
nonMarkerPointListRead = [ ] ;
isOptions = false ;
oldMarkers = null ;
pointFromBuffer = { } ;
MSP . send _message ( MSPCodes . MSP _WP _GETINFO , false , false , getNextPoint ) ;
}
function endGetPoint ( ) {
GUI . log ( 'End get point' ) ;
$ ( '#loadMissionButton' ) . removeClass ( 'disabled' ) ;
repaint ( ) ;
updateTotalInfo ( ) ;
}
function getNextPoint ( ) {
if ( MISSION _PLANER . countBusyPoints == 0 ) {
endGetPoint ( ) ;
return ;
}
// Populate a dictionary pointFromBuffer which stores all the point values from buffer to be post-treated then (Needed for JUMP option at least)
if ( pointForSend > 0 ) {
pointFromBuffer [ MISSION _PLANER . bufferPoint . number ] = {
number : MISSION _PLANER . bufferPoint . number ,
lon : MISSION _PLANER . bufferPoint . lon ,
lat : MISSION _PLANER . bufferPoint . lat ,
action : MISSION _PLANER . bufferPoint . action ,
alt : MISSION _PLANER . bufferPoint . alt ,
p1 : MISSION _PLANER . bufferPoint . p1 ,
p2 : MISSION _PLANER . bufferPoint . p2 ,
p3 : MISSION _PLANER . bufferPoint . p3
} ;
if ( [ MWNP . WPTYPE . JUMP , MWNP . WPTYPE . SET _HEAD , MWNP . WPTYPE . RTH ] . includes ( MISSION _PLANER . bufferPoint . action ) ) { nonMarkerPointListRead . push ( MISSION _PLANER . bufferPoint . number ) ; } ;
}
// Once all points have been scanned and pointFromBuffer populated, then scan pointFromBuffer to generate the Map Layers Markers
if ( pointForSend >= MISSION _PLANER . countBusyPoints ) {
Object . keys ( pointFromBuffer ) . forEach ( function ( key ) {
if ( [ MWNP . WPTYPE . WAYPOINT , MWNP . WPTYPE . PH _UNLIM , MWNP . WPTYPE . PH _TIME , MWNP . WPTYPE . LAND , MWNP . WPTYPE . SET _POI ] . includes ( pointFromBuffer [ key ] . action ) ) {
if ( ( Number ( key ) + 1 ) <= MISSION _PLANER . countBusyPoints ) {
var coord = ol . proj . fromLonLat ( [ pointFromBuffer [ key ] . lon , pointFromBuffer [ key ] . lat ] ) ;
if ( pointFromBuffer [ Number ( key ) + 1 ] . action == MWNP . WPTYPE . SET _HEAD ) {
var options = { key : 'SET_HEAD' ,
heading : pointFromBuffer [ Number ( key ) + 1 ] . p1
} ;
}
else if ( pointFromBuffer [ Number ( key ) + 1 ] . action == MWNP . WPTYPE . JUMP ) {
var options = { key : 'JUMP' ,
targetWP : getNumberOfNonMarkerForJumpReversed ( nonMarkerPointListRead , pointFromBuffer [ Number ( key ) + 1 ] . p1 ) ,
numRepeat : pointFromBuffer [ Number ( key ) + 1 ] . p2
} ;
}
else if ( pointFromBuffer [ Number ( key ) + 1 ] . action == MWNP . WPTYPE . RTH ) {
var options = { key : 'RTH' ,
landAfter : pointFromBuffer [ Number ( key ) + 1 ] . p1
} ;
}
else {
var options = { key : 'None' } ;
}
map . addLayer ( addMarker ( coord , pointFromBuffer [ key ] . alt , pointFromBuffer [ key ] . action , pointFromBuffer [ key ] . p1 , pointFromBuffer [ key ] . p2 , pointFromBuffer [ key ] . p3 , options ) ) ;
if ( key == 1 ) {
map . getView ( ) . setCenter ( coord ) ;
}
}
else {
var coord = ol . proj . fromLonLat ( [ pointFromBuffer [ key ] . lon , pointFromBuffer [ key ] . lat ] ) ;
map . addLayer ( addMarker ( coord , pointFromBuffer [ key ] . alt , pointFromBuffer [ key ] . action , pointFromBuffer [ key ] . p1 , pointFromBuffer [ key ] . p2 , pointFromBuffer [ key ] . p3 ) ) ;
if ( key == 1 ) {
map . getView ( ) . setCenter ( coord ) ;
}
}
}
} ) ;
endGetPoint ( ) ;
return ;
}
MISSION _PLANER . bufferPoint . number = pointForSend ;
pointForSend ++ ;
MSP . send _message ( MSPCodes . MSP _WP , mspHelper . crunch ( MSPCodes . MSP _WP ) , false , getNextPoint ) ;
}
function sendNextPoint ( ) {
if ( pointForSend >= markers . length ) {
endSendPoint ( ) ;
return ;
}
var geometry = markers [ pointForSend ] . getSource ( ) . getFeatures ( ) [ 0 ] . getGeometry ( ) ;
var coordinate = ol . proj . toLonLat ( geometry . getCoordinates ( ) ) ;
// If MISSION_PLANER.bufferPoint do not content any options keys (i.e different from None) => isOptions==false
if ( isOptions == false ) {
if ( markers [ pointForSend ] . action == '5' || markers [ pointForSend ] . action == '2' || markers [ pointForSend ] . action == '8' ) {
MISSION _PLANER . bufferPoint . number = pointForSend + actionPointForSend + 1 ;
MISSION _PLANER . bufferPoint . action = markers [ pointForSend ] . action ;
MISSION _PLANER . bufferPoint . lon = parseInt ( coordinate [ 0 ] * 10000000 ) ;
MISSION _PLANER . bufferPoint . lat = parseInt ( coordinate [ 1 ] * 10000000 ) ;
MISSION _PLANER . bufferPoint . alt = markers [ pointForSend ] . alt ;
MISSION _PLANER . bufferPoint . p1 = 0 ;
MISSION _PLANER . bufferPoint . p2 = 0 ;
MISSION _PLANER . bufferPoint . p3 = 0 ;
}
else {
MISSION _PLANER . bufferPoint . number = pointForSend + actionPointForSend + 1 ;
MISSION _PLANER . bufferPoint . action = markers [ pointForSend ] . action ;
MISSION _PLANER . bufferPoint . lon = parseInt ( coordinate [ 0 ] * 10000000 ) ;
MISSION _PLANER . bufferPoint . lat = parseInt ( coordinate [ 1 ] * 10000000 ) ;
MISSION _PLANER . bufferPoint . alt = markers [ pointForSend ] . alt ;
MISSION _PLANER . bufferPoint . p1 = markers [ pointForSend ] . parameter1 ;
MISSION _PLANER . bufferPoint . p2 = markers [ pointForSend ] . parameter2 ;
MISSION _PLANER . bufferPoint . p3 = markers [ pointForSend ] . parameter3 ;
}
if ( markers [ pointForSend ] . options . key != "None" ) {
isOptions = true
}
else {
isOptions = false
pointForSend ++ ;
}
oldMarkers = markers [ pointForSend ]
if ( pointForSend >= markers . length ) {
MISSION _PLANER . bufferPoint . endMission = 0xA5 ;
}
else {
MISSION _PLANER . bufferPoint . endMission = 0 ;
}
MSP . send _message ( MSPCodes . MSP _SET _WP , mspHelper . crunch ( MSPCodes . MSP _SET _WP ) , false , sendNextPoint ) ;
}
// else if MISSION_PLANER.bufferPoint do content any options keys (i.e different from None) => isOptions==true
else if ( isOptions == true ) {
if ( oldMarkers . options . key == "JUMP" ) {
actionPointForSend ++ ;
nonMarkerPoint . push ( pointForSend + actionPointForSend + 1 ) ;
MISSION _PLANER . bufferPoint . number = pointForSend + actionPointForSend + 1 ;
MISSION _PLANER . bufferPoint . action = String ( MWNP . WPTYPE [ oldMarkers . options . key ] ) ;
MISSION _PLANER . bufferPoint . lon = 0 ;
MISSION _PLANER . bufferPoint . lat = 0 ;
MISSION _PLANER . bufferPoint . alt = 0 ;
MISSION _PLANER . bufferPoint . p1 = getNumberOfNonMarkerForJump2 ( nonMarkerPoint , Number ( oldMarkers . options . targetWP ) ) ;
MISSION _PLANER . bufferPoint . p2 = Number ( oldMarkers . options . numRepeat ) ;
MISSION _PLANER . bufferPoint . p3 = 0 ;
}
else if ( oldMarkers . options . key == "SET_HEAD" ) {
actionPointForSend ++ ;
nonMarkerPoint . push ( pointForSend + actionPointForSend + 1 ) ;
MISSION _PLANER . bufferPoint . number = pointForSend + actionPointForSend + 1 ;
MISSION _PLANER . bufferPoint . action = String ( MWNP . WPTYPE [ oldMarkers . options . key ] ) ;
MISSION _PLANER . bufferPoint . lon = 0 ;
MISSION _PLANER . bufferPoint . lat = 0 ;
MISSION _PLANER . bufferPoint . alt = 0 ;
MISSION _PLANER . bufferPoint . p1 = Number ( oldMarkers . options . heading ) ;
MISSION _PLANER . bufferPoint . p2 = 0 ;
MISSION _PLANER . bufferPoint . p3 = 0 ;
}
else if ( oldMarkers . options . key == "RTH" ) {
actionPointForSend ++ ;
nonMarkerPoint . push ( pointForSend + actionPointForSend + 1 ) ;
MISSION _PLANER . bufferPoint . number = pointForSend + actionPointForSend + 1 ;
MISSION _PLANER . bufferPoint . action = String ( MWNP . WPTYPE [ oldMarkers . options . key ] ) ;
MISSION _PLANER . bufferPoint . lon = 0 ;
MISSION _PLANER . bufferPoint . lat = 0 ;
MISSION _PLANER . bufferPoint . alt = Number ( oldMarkers . alt ) ;
MISSION _PLANER . bufferPoint . p1 = ( Number ( oldMarkers . options . landAfter ) ) ? 1 : 0 ;
MISSION _PLANER . bufferPoint . p2 = 0 ;
MISSION _PLANER . bufferPoint . p3 = 0 ;
}
isOptions = false ;
pointForSend ++ ;
if ( pointForSend >= markers . length ) {
MISSION _PLANER . bufferPoint . endMission = 0xA5 ;
}
else {
MISSION _PLANER . bufferPoint . endMission = 0 ;
}
MSP . send _message ( MSPCodes . MSP _SET _WP , mspHelper . crunch ( MSPCodes . MSP _SET _WP ) , false , sendNextPoint ) ;
}
}
function endSendPoint ( ) {
GUI . log ( 'End send point' ) ;
MSP . send _message ( MSPCodes . MSP _WP _GETINFO , false , false , updateTotalInfo ) ;
$ ( '#saveMissionButton' ) . removeClass ( 'disabled' ) ;
}
function updateTotalInfo ( ) {
if ( CONFIGURATOR . connectionValid ) {
$ ( '#availablePoints' ) . text ( MISSION _PLANER . countBusyPoints + '/' + MISSION _PLANER . maxWaypoints ) ;
$ ( '#missionValid' ) . html ( MISSION _PLANER . isValidMission ? chrome . i18n . getMessage ( 'armingCheckPass' ) : chrome . i18n . getMessage ( 'armingCheckFail' ) ) ;
}
}
} ;
TABS . mission _control . cleanup = function ( callback ) {
if ( callback ) callback ( ) ;
} ;