---- #########################################################################
---- # #
---- # GPS Widget for FrSky Horus #
-----# #
---- # License GPLv3: http://www.gnu.org/licenses/gpl-3.0.html #
---- # #
---- # This program is free software; you can redistribute it and/or modify #
---- # it under the terms of the GNU General Public License version 3 as #
---- # published by the Free Software Foundation. #
---- # #
---- # Rev 0.1 #
---- # Tonnie Oostbeek #
---- # #
---- #########################################################################
TempLat = 0
TempLong = 0
head = 0
local options = {
{ "TextColor", COLOR, Black },
{ "Imperial", BOOL, 0 },
{ "Map", VALUE, 1,1,10 },
}
-- in the create function you add all shared variables to the array containing the widget data ('thisWidget')
local function create(zone, options)
local thisWidget = { zone=zone, options=options}
--create array containing all sensor ID's used for quicker retrieval
local ID = {}
ID.GPS = getFieldInfo("GPS") and getFieldInfo("GPS").id or 0
ID.Hdg = getFieldInfo("Hdg") and getFieldInfo("Hdg").id or 0
ID.GSpd = getFieldInfo("GSpd") and getFieldInfo("GSpd").id or 0
ID.GDis = getFieldInfo("GDis") and getFieldInfo("GDis").id or 0
ID.GAlt = getFieldInfo("GAlt") and getFieldInfo("GAlt").id or 0
--add ID to thisWidget
thisWidget.ID = ID
--create array containing all map info per map size
local map = {North={},South={},West={},East={},wx={},wy={},zx={},zy={}}
-- Avenhorn ---
-- coordinates for the small map.
map.North.small = 52.633785
map.South.small = 52.614104
map.West.small = 4.930978
map.East.small = 4.988488
-- No Fly Zone screen coordinates for small map--
map.wx.small = 0
map.wy.small = 0
map.zx.small = 0
map.zy.small = 0
-- coordinates for the medium map.
map.North.medium = 52.641134
map.South.medium = 52.611316
map.West.medium = 4.916037
map.East.medium = 5.002736
-- No Fly Zone screen coordinates for medium map--
map.wx.medium = 0
map.wy.medium = 0
map.zx.medium = 0
map.zy.medium = 0
--coordinates for the largest map.
map.North.large = 52.651519
map.South.large = 52.606515
map.West.large = 4.893172
map.East.large = 5.023711
-- No Fly Zone screen coordinates for large map--
map.wx.large = 0
map.wy.large = 0
map.zx.large = 0
map.zy.large = 0
--add one bitmap per map size and set current map size
map.bmp={}
map.bmp.small = Bitmap.open("/Widgets/Mapnew/map2a.png")
map.bmp.medium = Bitmap.open("/Widgets/Mapnew/map2b.png")
map.bmp.large = Bitmap.open("/Widgets/Mapnew/map2c.png")
--[[
-- MVC Pegasus ---
-- coordinates for the small map.
map.North.small = 52.734818
map.South.small = 52.731422
map.West.small = 5.273051
map.East.small = 5.283480
-- No Fly Zone screen coordinates for small map--
map.wx.small = 0
map.wy.small = 183
map.zx.small = 261
map.zy.small = 271
-- coordinates for the medium map.
map.North.medium = 52.736097
map.South.medium = 52.730953
map.West.medium = 5.270331
map.East.medium = 5.286034
-- No Fly Zone screen coordinates for medium map--
map.wx.medium = 0
map.wy.medium = 153
map.zx.medium = 323
map.zy.medium = 271
--coordinates for the largest map.
map.North.large = 52.737878
map.South.large = 52.730145
map.West.large = 5.266206
map.East.large = 5.289811
-- No Fly Zone screen coordinates for large map--
map.wx.large = 0
map.wy.large = 121
map.zx.large = 354
map.zy.large = 271
--add one bitmap per map size and set current map size
map.bmp={}
map.bmp.small = Bitmap.open("/Widgets/Mapnew/map1a.png")
map.bmp.medium = Bitmap.open("/Widgets/Mapnew/map1b.png")
map.bmp.large = Bitmap.open("/Widgets/Mapnew/map1c.png")
--]]
--set current size
map.current = "large"
--add the map array to thisWidget
thisWidget.map = map
--return the thisWidget array to the opentx API, containing all data to be shared across functions
return thisWidget
end
local function background(thisWidget)
ImperialSet = thisWidget.options.Imperial
thisWidget.gpsLatLong = getValue(thisWidget.ID.GPS)
if (type(thisWidget.gpsLatLong) ~= "table") then
thisWidget.ID.GPS = getFieldInfo("GPS") and getFieldInfo("GPS").id or 0
thisWidget.ID.Hdg = getFieldInfo("Hdg") and getFieldInfo("Hdg").id or 0
thisWidget.ID.GSpd = getFieldInfo("GSpd") and getFieldInfo("GSpd").id or 0
thisWidget.ID.GDis = getFieldInfo("GDis") and getFieldInfo("GDis").id or 0
thisWidget.ID.GAlt = getFieldInfo("GAlt") and getFieldInfo("GAlt").id or 0
model.setGlobalVariable(8,0,0)
return
end
thisWidget.Distance= getValue(thisWidget.ID.GDis)
thisWidget.headingDeg= getValue(thisWidget.ID.Hdg)
thisWidget.Speed= getValue(thisWidget.ID.GSpd)
thisWidget.Altitude = getValue(thisWidget.ID.GAlt)
thisWidget.gpsLat = thisWidget.gpsLatLong.lat
thisWidget.gpsLong = thisWidget.gpsLatLong.lon
-- Part for loading the correct zoomlevel of the map
-- coordinates for the smallest map. These can be found by placing the image back into Google Earth and looking at the overlay
-- parameters
local North = thisWidget.map.North
local South = thisWidget.map.South
local East = thisWidget.map.East
local West = thisWidget.map.West
if thisWidget.gpsLat < North.small and thisWidget.gpsLat > South.small and thisWidget.gpsLong < East.small and thisWidget.gpsLong > West.small then
thisWidget.map.current = "small"
elseif thisWidget.gpsLat < North.medium and thisWidget.gpsLat > South.medium and thisWidget.gpsLong < East.medium and thisWidget.gpsLong > West.medium then
thisWidget.map.current = "medium"
else
thisWidget.map.current = "large"
end
-- Part for setting the correct zoomlevel ends here.
-- Calculate Position in relation to map.
North = North[thisWidget.map.current]
South = South[thisWidget.map.current]
East = East[thisWidget.map.current]
West = West[thisWidget.map.current]
local wx = thisWidget.map.wx[thisWidget.map.current]
local wy = thisWidget.map.wy[thisWidget.map.current]
local zx = thisWidget.map.zx[thisWidget.map.current]
local zy = thisWidget.map.zy[thisWidget.map.current]
thisWidget.x = math.floor(480*((thisWidget.gpsLong - West)/(East - West)))
thisWidget.y = math.floor(272*((North - thisWidget.gpsLat)/(North - South)))
thisWidget.x=math.max(10,thisWidget.x)
thisWidget.x=math.min(thisWidget.x,470)
thisWidget.y=math.max(10,thisWidget.y)
thisWidget.y=math.min(thisWidget.y,262)
if ((thisWidget.x - wx)*(zy-wy))-((thisWidget.y - wy)*(zx-wx)) < 0 then
model.setGlobalVariable(8,0,0)
else
model.setGlobalVariable(8,0,1)
end
end
function calc_bearing()
end
local function update(thisWidget, options)
thisWidget.options = options
end
local function refresh(thisWidget)
local x = 0
local y = 0
background(thisWidget)
if (thisWidget.gpsLat == NIL) or (thisWidget.gpsLong == NIL) then
else
if (thisWidget.gpsLat ~= TempLat) or (thisWidget.gpsLong ~= TempLong) then
--Head = math.acos(math.cos(math.rad(90-thisWidget.gpsLat)) * math.cos(math.rad(90-TempLat)) + math.sin(math.rad(90-thisWidget.gpsLat)) * math.sin(math.rad(90-TempLat)) * math.cos(math.rad(thisWidget.gpsLong-TempLon))) * 6371
y = math.sin(thisWidget.gpsLat-TempLat) * math.cos(thisWidget.gpsLong)
x = math.cos(TempLong) * math.sin(thisWidget.gpsLong) - math.sin(TempLong) * math.cos(thisWidget.gpsLong) * math.cos(thisWidget.gpsLat - TempLat)
head = math.deg(math.atan2(y,x))
if head < 0 then
head = 360 + head
end
TempLat = thisWidget.gpsLat
TempLong = thisWidget.gpsLong
end
end
if (type(thisWidget.gpsLatLong) ~= "table") then
lcd.drawBitmap(thisWidget.map.bmp.large, thisWidget.zone.x -10, thisWidget.zone.y -10)
lcd.setColor(CUSTOM_COLOR, lcd.RGB(255,0,0))
lcd.drawText( 120, 130, "No GPS SIGNAL", DBLSIZE, CUSTOM_COLOR)
return
end
local xvalues = { }
local yvalues = { }
--local headingDeg = thisWidget.headingDeg
local headingDeg = head
local x = thisWidget.x
local y = thisWidget.y
-- A
-- |
-- |
-- C _________________|___________________ D
-- |
-- |
-- |
-- |
-- |
-- |
-- |
-- E ---|--- F
-- B
xvalues.ax = x + (4 * math.sin(math.rad(headingDeg))) -- front of fuselage x position
yvalues.ay = y - (4 * math.cos(math.rad(headingDeg))) -- front of fuselage y position
xvalues.bx = x - (7 * math.sin(math.rad(headingDeg))) -- rear of fuselage x position
yvalues.by = y + (7 * math.cos(math.rad(headingDeg))) -- rear of fuselage y position
xvalues.cx = x + (10 * math.cos(math.rad(headingDeg))) -- left wingtip x position
yvalues.cy = y + (10 * math.sin(math.rad(headingDeg))) -- left wingtip y position
xvalues.dx = x - (10 * math.cos(math.rad(headingDeg))) -- right wingtip x position
yvalues.dy = y - (10 * math.sin(math.rad(headingDeg))) -- right wingtip y position
xvalues.ex = x - ((7 * math.sin(math.rad(headingDeg))) + (3 * math.cos(math.rad(headingDeg)))) -- left tailwing tip x position
yvalues.ey = y + ((7 * math.cos(math.rad(headingDeg))) - (3 * math.sin(math.rad(headingDeg)))) -- left tailwing tip y position
xvalues.fx = x - ((7 * math.sin(math.rad(headingDeg))) - (3 * math.cos(math.rad(headingDeg)))) -- right tailwing tip x position
yvalues.fy = y + ((7 * math.cos(math.rad(headingDeg))) + (3 * math.sin(math.rad(headingDeg)))) -- right tailwing tip y position
--draw background
lcd.drawBitmap(thisWidget.map.bmp[thisWidget.map.current], thisWidget.zone.x -10, thisWidget.zone.y -10)
--draw info
if thisWidget.gpsLat > 0 then
NS = "N"
else
NS = "S"
end
if thisWidget.gpsLong > 0 then
EW = "E"
else
EW = "W"
end
if ImperialSet == 1 then
FM = "ft"
FMx = "miles"
SPD = "mph"
else
FM = "m"
FMx = "Kilometers"
SPD = "km/h"
end
lcd.setColor(CUSTOM_COLOR, WHITE)
lcd.drawText(10, 5, "Speed: "..math.floor(thisWidget.Speed)..SPD , CUSTOM_COLOR + SHADOWED)
lcd.drawText(10, 25, "Altitude: "..math.floor(thisWidget.Altitude)..FM , CUSTOM_COLOR + SHADOWED)
lcd.drawText(180, 5, "Distance: "..math.floor(thisWidget.Distance)..FM , CUSTOM_COLOR + SHADOWED)
--lcd.drawText(460, 5, "Heading: "..math.floor(thisWidget.headingDeg).."deg" , CUSTOM_COLOR + RIGHT + SHADOWED)
lcd.drawText(460, 5, "Heading: "..head.."deg" , CUSTOM_COLOR + RIGHT + SHADOWED)
lcd.drawText(10, 247, "Lat: "..NS..math.abs(thisWidget.gpsLat).." / Lon: "..EW..math.abs(thisWidget.gpsLong), CUSTOM_COLOR + SMLSIZE +SHADOWED)
lcd.drawText(460, 247, "X:"..thisWidget.x.." / Y:"..thisWidget.y , CUSTOM_COLOR + RIGHT + SMLSIZE + SHADOWED)
--draw plane
lcd.setColor(CUSTOM_COLOR, lcd.RGB(255,255,255))
lcd.drawLine(xvalues.ax, yvalues.ay, xvalues.bx, yvalues.by, SOLID, CUSTOM_COLOR)
lcd.drawLine(xvalues.cx, yvalues.cy, xvalues.dx, yvalues.dy, SOLID, CUSTOM_COLOR)
lcd.drawLine(xvalues.ex, yvalues.ey, xvalues.fx, yvalues.fy, SOLID, CUSTOM_COLOR)
--draw noflightzone
lcd.setColor(CUSTOM_COLOR, lcd.RGB(255,0,0))
lcd.drawLine(thisWidget.map.wx[thisWidget.map.current], thisWidget.map.wy[thisWidget.map.current], thisWidget.map.zx[thisWidget.map.current], thisWidget.map.zy[thisWidget.map.current], SOLID, CUSTOM_COLOR)
end
return { name="Map", options=options, create=create, update=update, background=background, refresh=refresh }