--- **NAVIGATION** - Beacons of the map/theatre. -- -- **Main Features:** -- -- * Access beacons of the map -- * Find closest beacon -- * Get frequencies and channels -- -- === -- -- ## Example Missions: -- -- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/Navigation%20-%20Beacons). -- -- === -- -- ### Author: **funkyfranky** -- -- === -- @module Navigation.Beacons -- @image NAVIGATION_Beacons.png ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- BEACONS class. -- @type BEACONS -- -- @field #string ClassName Name of the class. -- @field #number verbose Verbosity of output. -- @field #table beacons Beacons. -- -- @extends Core.Base#BASE --- *Hope is the beacon that guides lost ships back to the shore.* -- -- === -- -- # The BEACONS Concept -- -- This class is desinged to make information about beacons of a map/theatre easier accessible. The information contains location, type and frequencies of all or specific beacons of the map. -- -- **Note** that try to avoid hard coding stuff in Moose since DCS is updated frequently and things change. Therefore, the main source of information is either a file `beacons.lua` that can be -- found in the installation directory of DCS for each map or a table that the user needs to provide. -- -- # Basic Setup -- -- A new `BEACONS` object can be created with the @{#BEACONS.NewFromFile}(*beacons_lua_file*) function. -- -- local beacons=BEACONS:NewFromFile("\Mods\terrains\\beacons.lua") -- beacons:MarkerShow() -- -- This will load the beacons from the `` for the specific map and place markers on the F10 map. This is the first step you should do to ensure that the file -- you provided is correct and all relevant beacons are present. -- -- # User Functions -- -- ## F10 Map Markers -- -- ## Position -- -- ## Get Closest Beacon -- -- -- @field #BEACONS BEACONS = { ClassName = "BEACONS", verbose = 1, beacons = {}, } --- Mission capability. -- @type BEACONS.Beacon -- @field #function display_name Function that returns the localized name. -- @field #number type Beacon type. -- @field #string beaconId Beacon ID. -- @field #string callsign Call sign. -- @field #number frequency Frequency in Hz. -- @field #number channel TACAN, RSBN or PRMG channel depending on type. -- @field #table position Position table. -- @field #number direction Direction in degrees. -- @field #table positionGeo Table with latitude and longitude. -- @field #table sceneObjects Table with scenery objects, e.g. `{t:393396742}`. -- @field #number chartOffsetX No idea what this offset is?! -- @field DCS#Vec3 vec3 Position vector 3D. -- @field #number markerID ID for the F10 marker. -- @field #string typeName Name of becon type. -- @field Wrapper.Scenery#SCENERY scenery The scenery object. --- BEACONS class version. -- @field #string version BEACONS.version="0.0.4" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- ToDo list ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO: A lot... -- DONE: TACAN channel from frequency (was already in beacon.lua as channel) -- DONE: Scenery object ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Constructor(s) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- Create a new BECAONS class instance from a given table. -- @param #BEACONS self -- @param #table BeaconTable Table with beacon info. -- @return #BEACONS self function BEACONS:NewFromTable(BeaconTable) -- Inherit everything from BASE class. self=BASE:Inherit(self, BASE:New()) -- #BEACONS for _,_beacon in pairs(BeaconTable) do local beacon=_beacon --#BEACONS.Beacon -- Get 3D vector beacon.vec3={x=beacon.position[1], y=beacon.position[2], z=beacon.position[3]} -- Get coordinate beacon.coordinate=COORDINATE:NewFromVec3(beacon.vec3) -- Get type name beacon.typeName=self:_GetTypeName(beacon.type) -- Find closest scenery object from scan beacon.scenery=beacon.coordinate:FindClosestScenery(20) -- Debug stuff for scenery object if false then if beacon.scenery then env.info(string.format("FF Beacon %s %s %s got scenery object %s, %s", beacon.callsign, beacon.beaconId, beacon.typeName, beacon.scenery:GetName(), beacon.scenery:GetTypeName() )) UTILS.PrintTableToLog(beacon.scenery.SceneryObject) UTILS.PrintTableToLog(beacon.sceneObjects) else env.info(string.format("FF NO scenery object %s %s %s ", beacon.callsign, beacon.beaconId, beacon.typeName)) end end -- Add to table table.insert(self.beacons, beacon) end -- Debug output self:I(string.format("Added %d beacons", #self.beacons)) if self.verbose > 0 then local text="Beacon types:" for typeName,typeID in pairs(BEACON.Type) do local n=self:CountBeacons(typeID) text=text..string.format("\n%s = %d", typeName, n) end self:I(text) end return self end --- Create a new BECAONS class instance from a given file. -- @param #BEACONS self -- @param #string FileName Full path to the file containing the map beacons. -- @return #BEACONS self function BEACONS:NewFromFile(FileName) -- Inherit everything from BASE class. self=BASE:Inherit(self, BASE:New()) -- #BEACONS local exists=UTILS.FileExists(FileName) if exists==false then self:E(string.format("ERROR: file with beacon info does not exist!")) return nil end -- This will create a global table `beacons` dofile(FileName) -- Get beacons from table. self=self:NewFromTable(beacons) return self end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- User Functions ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --- Get 3D position vector of a specific beacon. -- @param #BEACONS self -- @param #BEACONS.Beacon beacon The beacon data structure. -- @return DCS#Vec3 Position vector. function BEACONS:GetVec3(beacon) return beacon.vec3 end --- Get COORDINATE of a specific beacon. -- @param #BEACONS self -- @param #BEACONS.Beacon beacon The beacon data structure. -- @return Core.Point#COORDINATE The coordinate. function BEACONS:GetCoordinate(beacon) local coordinate=COORDINATE:NewFromVec3(beacon.vec3) return coordinate end --- Find closest beacon to a given coordinate. -- @param #BEACONS self -- @param Core.Point#COORDINATE Coordinate The reference coordinate. -- @param #number TypeID (Optional) Only search for specific beacon types, *e.g.* `BEACON.Type.TACAN`. -- @param #number DistMax (Optional) Max search distance in meters. -- @param #table ExcludeList (Optional) List of beacons to exclude. -- @return #BEACONS.Beacon The closest beacon. function BEACONS:GetClosestBeacon(Coordinate, TypeID, DistMax, ExcludeList) local beacon=nil --#BEACONS.Beacon local distmin=math.huge ExcludeList=ExcludeList or {} for _,_beacon in pairs(self.beacons) do local bc=_beacon --#BEACONS.Beacon if (TypeID==nil or TypeID==bc.type) and (not UTILS.IsInTable(ExcludeList, bc, "beaconId")) then local dist=Coordinate:Get2DDistance(bc.vec3) if dist=1e6 then freq=freq/1e6 unit="MHz" elseif freq>=1e3 then freq=freq/1e3 unit="kHz" end return freq, unit end --- Get name of beacon type. -- @param #BEACONS self -- @param #number typeID Beacon type number. -- @return #string Type name. function BEACONS:_GetTypeName(typeID) if typeID~=nil then for typeName,_typeID in pairs(BEACON.Type) do if _typeID==typeID then return typeName end end end return "Unknown" end ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------