From 73525feb68b3d719ca38e3b5477a4b9ca71939c4 Mon Sep 17 00:00:00 2001 From: Frank Date: Sat, 12 Apr 2025 11:14:01 +0200 Subject: [PATCH 1/8] Update Beacons.lua - Added user functions - Fixed bug with incorrect position --- .../Moose/Navigation/Beacons.lua | 218 +++++++++++++++--- 1 file changed, 190 insertions(+), 28 deletions(-) diff --git a/Moose Development/Moose/Navigation/Beacons.lua b/Moose Development/Moose/Navigation/Beacons.lua index ec7b4d060..e3b1f2472 100644 --- a/Moose Development/Moose/Navigation/Beacons.lua +++ b/Moose Development/Moose/Navigation/Beacons.lua @@ -18,7 +18,6 @@ -- @module Navigation.Beacons -- @image NAVIGATION_Beacons.png - ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- @@ -32,23 +31,31 @@ -- -- @extends Core.Base#BASE ---- *A fleet of British ships at war are the best negotiators.* -- Horatio Nelson +--- *Hope is the beacon that guides lost ships back to the shore.* -- -- === -- -- # The BEACONS Concept -- --- The NAVFIX class has a great 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. -- --- Bla, bla... +-- **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.New}() function. +-- 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 +-- +-- ## Get Closest Beacon -- --- local beacons=BEACONS:New("G:\Games\DCS World Testing\Mods\terrains\GermanyColdWar\beacons.lua") --- --- This is how it works. -- -- @field #BEACONS BEACONS = { @@ -57,20 +64,61 @@ BEACONS = { 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 #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. + --- BEACONS class version. -- @field #string version -BEACONS.version="0.0.0" +BEACONS.version="0.0.1" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- ToDo list ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO: A lot... +-- TODO: TACAN channel from frequency +-- TODO: 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 + + beacon.vec3={x=beacon.position[1], y=beacon.position[2], z=beacon.position[3]} + + table.insert(self.beacons, beacon) + end + + self:I(string.format("Added %d beacons", #self.beacons)) + + + 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. @@ -79,7 +127,20 @@ 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 @@ -87,18 +148,110 @@ end -- User Functions ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---- Add marker all beacons on the F10 map. +--- 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`. +-- @return #BEACONS.Beacon The closest beacon. +function BEACONS:GetClosestBeacon(Coordinate, TypeID) + + local beacon=nil --#BEACONS.Beacon + local distmin=math.huge + + for _,_beacon in pairs(self.beacons) do + local bc=_beacon --#BEACONS.Beacon + + if TypeID==nil or TypeID==bc.type then + + local dist=Coordinate:Get2DDistance(bc.vec3) + + if dist Date: Sat, 12 Apr 2025 21:18:19 +0200 Subject: [PATCH 2/8] Update Beacons.lua - Added channel - Added scenery --- .../Moose/Navigation/Beacons.lua | 95 +++++++++++++++++-- 1 file changed, 86 insertions(+), 9 deletions(-) diff --git a/Moose Development/Moose/Navigation/Beacons.lua b/Moose Development/Moose/Navigation/Beacons.lua index e3b1f2472..cce4ff9f8 100644 --- a/Moose Development/Moose/Navigation/Beacons.lua +++ b/Moose Development/Moose/Navigation/Beacons.lua @@ -2,7 +2,9 @@ -- -- **Main Features:** -- --- * Beacons of the map +-- * Access beacons of the map +-- * Find closest beacon +-- * Get frequencies and channels -- -- === -- @@ -54,6 +56,10 @@ -- -- # User Functions -- +-- ## F10 Map Markers +-- +-- ## Position +-- -- ## Get Closest Beacon -- -- @@ -71,6 +77,7 @@ BEACONS = { -- @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. @@ -78,18 +85,20 @@ BEACONS = { -- @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.1" +BEACONS.version="0.0.2" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- ToDo list ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- TODO: A lot... --- TODO: TACAN channel from frequency --- TODO: Scenery object +-- DONE: TACAN channel from frequency (was already in beacon.lua as channel) +-- DONE: Scenery object ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Constructor(s) @@ -107,14 +116,36 @@ function BEACONS:NewFromTable(BeaconTable) 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)) - return self end @@ -214,7 +245,28 @@ function BEACONS:GetBeacons(TypeID) return beacons end +--- Count beacons, optionally of a given type. +-- @param #BEACONS self +-- @param #number TypeID (Optional) Only count specific beacon types, *e.g.* `BEACON.Type.TACAN`. +-- @return #number Number of beacons. +function BEACONS:CountBeacons(TypeID) + local n=#self.beacons + + if TypeID then + for _,_beacon in pairs(self.beacons) do + local bc=_beacon --#BEACONS.Beacon + + if TypeID==bc.type then + n=n+1 + end + end + else + n=#self.beacons + end + + return n +end --- Add markers for all beacons on the F10 map. -- @param #BEACONS self @@ -266,18 +318,44 @@ end -- @return #string Marker text. function BEACONS:_GetMarkerText(beacon) - local frequency=beacon.frequency~=nil and beacon.frequency/1000 or -1 + local frequency, funit=self:_GetFrequency(beacon.frequency) local direction=beacon.direction~=nil and beacon.direction or -1 local text=string.format("Beacon %s", tostring(beacon.beaconId)) text=text..string.format("\nCallsign: %s", tostring(beacon.callsign)) - text=text..string.format("\nType: %s", tostring(self:_GetTypeName(beacon.type))) - text=text..string.format("\nFrequency: %.3f kHz", frequency) + text=text..string.format("\nType: %s", tostring(beacon.typeName)) + --if beacon.type==BEACON.Type.TACAN or beacon.type==BEACON.Type.RSBN or beacon.type==BEACON.Type.PRMG_GLIDESLOPE or beacon.type==BEACON.Type.PRMG_LOCALIZER then + if UTILS.IsInTable({BEACON.Type.TACAN, BEACON.Type.RSBN, BEACON.Type.PRMG_GLIDESLOPE, BEACON.Type.PRMG_LOCALIZER}, beacon.type) then + text=text..string.format("\nChannel: %s", tostring(beacon.channel)) + end + text=text..string.format("\nFrequency: %.3f %s", frequency, funit) text=text..string.format("\nDirection: %.1f°", direction) return text end + +--- Get converted frequency. +-- @param #BEACONS self +-- @param #number freq Frequency in Hz. +-- @return #number Frequency in better unit. +-- @return #string Unit ("Hz", "kHz", "MHz"). +function BEACONS:_GetFrequency(freq) + + freq=freq or 0 + local unit="Hz" + + if freq>=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. @@ -295,7 +373,6 @@ function BEACONS:_GetTypeName(typeID) return "Unknown" end - ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- From 0a9717a8c2a6d884a6c9730e5d5083310e6b3184 Mon Sep 17 00:00:00 2001 From: Frank Date: Sun, 13 Apr 2025 23:14:19 +0200 Subject: [PATCH 3/8] RADIOS - Added new class RADIOS --- Moose Development/Moose/Modules.lua | 1 + Moose Development/Moose/Modules_local.lua | 1 + Moose Development/Moose/Navigation/Radios.lua | 324 ++++++++++++++++++ Moose Development/Moose/Utilities/Enums.lua | 25 ++ 4 files changed, 351 insertions(+) create mode 100644 Moose Development/Moose/Navigation/Radios.lua diff --git a/Moose Development/Moose/Modules.lua b/Moose Development/Moose/Modules.lua index fecf7f271..24c23898a 100644 --- a/Moose Development/Moose/Modules.lua +++ b/Moose Development/Moose/Modules.lua @@ -189,5 +189,6 @@ __Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Tasking/Task_Capture_Dispatch __Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Navigation/Point.lua' ) __Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Navigation/Beacons.lua' ) +__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Navigation/Radios.lua' ) __Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Globals.lua' ) diff --git a/Moose Development/Moose/Modules_local.lua b/Moose Development/Moose/Modules_local.lua index 15e1b3b05..0fea70e2e 100644 --- a/Moose Development/Moose/Modules_local.lua +++ b/Moose Development/Moose/Modules_local.lua @@ -181,5 +181,6 @@ __Moose.Include( 'Tasking\\Task_Capture_Dispatcher.lua' ) __Moose.Include( 'Navigation\\Point.lua' ) __Moose.Include( 'Navigation\\Beacons.lua' ) +__Moose.Include( 'Navigation\\Radios.lua' ) __Moose.Include( 'Globals.lua' ) diff --git a/Moose Development/Moose/Navigation/Radios.lua b/Moose Development/Moose/Navigation/Radios.lua new file mode 100644 index 000000000..5b1d5e013 --- /dev/null +++ b/Moose Development/Moose/Navigation/Radios.lua @@ -0,0 +1,324 @@ +--- **NAVIGATION** - Airbase radios. +-- +-- **Main Features:** +-- +-- * Get radio frequencies of airbases +-- +-- === +-- +-- ## Example Missions: +-- +-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/Navigation%20-%20Radios). +-- +-- === +-- +-- ### Author: **funkyfranky** +-- +-- === +-- @module Navigation.Radios +-- @image NAVIGATION_Radios.png + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- RADIOS class. +-- @type RADIOS +-- +-- @field #string ClassName Name of the class. +-- @field #number verbose Verbosity of output. +-- @field #table radios Radios. +-- +-- @extends Core.Base#BASE + +--- *It's not true I had nothing on, I had the radio on.* -- *Marilyn Monroe* +-- +-- === +-- +-- # The RADIOS Concept +-- +-- This class is desinged to make information about radios of a map/theatre easier accessible. The information contains mostly the frequencies of airbases 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 `radio.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 `RADIOS` object can be created with the @{#RADIOS.NewFromFile}(*radio_lua_file*) function. +-- +-- local radios=RADIOS:NewFromFile("\Mods\terrains\\radios.lua") +-- radios:MarkerShow() +-- +-- This will load the radios 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 radios are present. +-- +-- # User Functions +-- +-- ## F10 Map Markers +-- +-- ## Position +-- +-- ## Closest Radio +-- +-- +-- @field #RADIOS +RADIOS = { + ClassName = "RADIOS", + verbose = 0, + radios = {}, +} + +--- Radio item data structure. +-- @type RADIOS.Radio +-- @field #string radioId Radio ID. +-- @field #table role Roles of the radio (usually {"ground", "tower", "approach"}). +-- @field #table callsign Callsigns of the radio (usually the airbase name). +-- @field #table frequency Frequencies of the radios. +-- @field #table position Position table. +-- @field #table sceneObjects Scenery objects. +-- @field #string name Name of the airbase. +-- @field Wrapper.Airbase#AIRBASE airbase Airbase. + +--- Radio item data structure. +-- @type RADIOS.Frequency +-- @field #number modu Modulation type. +-- @field #number freq Frequency in Hz. + + +--- RADIOS class version. +-- @field #string version +RADIOS.version="0.0.0" + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- ToDo list +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +-- TODO: A lot... + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Constructor(s) +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Create a new RADIOS class instance from a given table. +-- @param #RADIOS self +-- @param #table RadioTable Table with radios info. +-- @return #RADIOS self +function RADIOS:NewFromTable(RadioTable) + + -- Inherit everything from BASE class. + self=BASE:Inherit(self, BASE:New()) -- #RADIOS + + local airbasenames=AIRBASE.GetAllAirbaseNames() + + for _,_radio in pairs(RadioTable) do + local radio=_radio --#RADIOS.Radio + + --UTILS.PrintTableToLog(radio) + --UTILS.PrintTableToLog(radio.callsign) + + -- The table structure of callsign is a bit awkward. We need to get the airbase name. + local cs=radio.callsign[1] + if cs and cs.common then + radio.name=cs.common[1] + elseif cs and cs.nato then + radio.name=cs.nato[1] + else + radio.name="Unknown" + end + + --UTILS.PrintTableToLog(radio.callsign) + + radio.name=self:_GetAirbaseName(airbasenames, radio.name) + + radio.airbase=AIRBASE:FindByName(radio.name) + + if radio.airbase then + radio.coordinate=radio.airbase:GetCoordinate() + end + + -- Add to table + table.insert(self.radios, radio) + end + + -- Debug output + self:I(string.format("Added %d radios", #self.radios)) + + return self +end + + +--- Create a new RADIOS class instance from a given file. +-- @param #RADIOS self +-- @param #string FileName Full path to the file containing the map radios. +-- @return #RADIOS self +function RADIOS:NewFromFile(FileName) + + -- Inherit everything from BASE class. + self=BASE:Inherit(self, BASE:New()) -- #RADIOS + + local exists=UTILS.FileExists(FileName) + + if exists==false then + self:E(string.format("ERROR: file with radios info does not exist! File=%s", tostring(FileName))) + return nil + end + + -- This will create a global table `radio` + dofile(FileName) + + -- Get radios from table. + self=self:NewFromTable(radio) + + return self +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- User Functions +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Get 3D position vector of a specific radio. +-- @param #RADIOS self +-- @param #RADIOS.Radio radio The radio data structure. +-- @return DCS#Vec3 Position vector. +function RADIOS:GetVec3(radio) + return radio.vec3 +end + +--- Get COORDINATE of a specific radio. +-- @param #RADIOS self +-- @param #RADIOS.Radio radio The radio data structure. +-- @return Core.Point#COORDINATE The coordinate. +function RADIOS:GetCoordinate(radio) + return radio.coordinate +end + +--- Add markers for all radios on the F10 map. +-- @param #RADIOS self +-- @param #RADIOS.Radio Radio (Optional) Only this specifc radio. +-- @return #RADIOS self +function RADIOS:MarkerShow(Radio) + + for _,_radio in pairs(self.radios) do + local radio=_radio --#RADIOS.Radio + if Radio==nil or Radio.radioId==radio.radioId then + local coord=self:GetCoordinate(radio) + if coord then + local text=self:_GetMarkerText(radio) + if radio.markerID then + UTILS.RemoveMark(radio.markerID) + end + radio.markerID=coord:MarkToAll(text) + end + end + end + + return self +end + +--- Remove markers of all radios from the F10 map. +-- @param #RADIOS self +-- @param #RADIOS.Radio Radio (Optional) Only this specifc radio. +-- @return #RADIOS self +function RADIOS:MarkerRemove(Radio) + + for _,_radio in pairs(self.radios) do + local radio=_radio --#RADIOS.Radio + if Radio==nil or Radio.radioId==radio.radioId then + if radio.markerID then + UTILS.RemoveMark(radio.markerID) + radio.markerID=nil + end + end + end + + return self +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Private Functions +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Get text displayed in the F10 marker. +-- @param #RADIOS self +-- @param #RADIOS.Radio radio The radio data structure. +-- @return #string Marker text. +function RADIOS:_GetMarkerText(radio) + + local text=string.format("Radio %s", tostring(radio.name)) + for b,f in pairs(radio.frequency) do + local frequency=f --#RADIOS.Frequency + local mod=frequency[1] + local fre=frequency[2] + local freq, funit=self:_GetFrequency(fre) + --UTILS.PrintTableToLog(frequency) + local band=self:_GetBandName(b) + text=text..string.format("\n%s: %.3f %s", band, freq, funit) + end + + return text +end + + +--- Get converted frequency. +-- @param #RADIOS self +-- @param #number freq Frequency in Hz. +-- @return #number Frequency in better unit. +-- @return #string Unit ("Hz", "kHz", "MHz"). +function RADIOS:_GetFrequency(freq) + + freq=freq or 0 + local unit="Hz" + + if freq>=1e6 then + freq=freq/1e6 + unit="MHz" + elseif freq>=1e3 then + freq=freq/1e3 + unit="kHz" + end + + return freq, unit +end + +--- Get name of frequency band. +-- @param #RADIOS self +-- @param #number BandNumber Band as number. +-- @return #string Band name. +function RADIOS:_GetBandName(BandNumber) + + if BandNumber~=nil then + for bandName,bandNumber in pairs(ENUMS.FrequencyBand) do + if bandNumber==BandNumber then + return bandName + end + end + end + + return "Unknown" +end + +--- Get name of frequency band. +-- @param #RADIOS self +-- @param #table airbasenames Names of all airbases. +-- @param #string name Name of airbase. +-- @return #string Name of airbase +function RADIOS:_GetAirbaseName(airbasenames, name) + + local airbase=AIRBASE:FindByName(name) + + if airbase then + return name + else + for _,airbasename in pairs(airbasenames) do + if string.find(airbasename, name) then + return airbasename + end + end + end + + return "Unknown" +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- diff --git a/Moose Development/Moose/Utilities/Enums.lua b/Moose Development/Moose/Utilities/Enums.lua index a269fb972..4e6ef999f 100644 --- a/Moose Development/Moose/Utilities/Enums.lua +++ b/Moose Development/Moose/Utilities/Enums.lua @@ -1359,3 +1359,28 @@ ENUMS.FARPObjectTypeNamesAndShape ={ [ENUMS.FARPType.PADSINGLE] = { TypeName="FARP_SINGLE_01", ShapeName="FARP_SINGLE_01"}, } +--- Radio frequency bands (HF, VHF, UHF) +-- @type ENUMS.FrequencyBand +-- @field #number HF High frequency +-- @field #number VHF_LOW Very high frequency +-- @field #number VHF_HI Very high frequency +-- @field #number UHF Ultra high frequency +ENUMS.FrequencyBand = { + HF = 0, + VHF_LOW = 1, + VHF_HI = 2, + UHF = 3, +} + +--- Radio modulation types (AM, FM) +-- @type ENUMS.ModulationType +-- @field #number AM Amplitude modulation +-- @field #number FM Frequency modulation +-- @field #number AMFM Amplitude and frequency modulation +-- @field #number DISCARD Discard modulation +ENUMS.ModulationType = { + AM = 0, + FM = 1, + AMFM = 2, + DISCARD = -1, +} From 17f672dad43f5d06175bd3a1e559fe4f4112fdb8 Mon Sep 17 00:00:00 2001 From: Frank Date: Mon, 14 Apr 2025 15:49:39 +0200 Subject: [PATCH 4/8] Towns - Added new Class for towns --- Moose Development/Moose/Modules.lua | 1 + Moose Development/Moose/Modules_local.lua | 1 + Moose Development/Moose/Navigation/Towns.lua | 261 +++++++++++++++++++ 3 files changed, 263 insertions(+) create mode 100644 Moose Development/Moose/Navigation/Towns.lua diff --git a/Moose Development/Moose/Modules.lua b/Moose Development/Moose/Modules.lua index 24c23898a..13f30e38f 100644 --- a/Moose Development/Moose/Modules.lua +++ b/Moose Development/Moose/Modules.lua @@ -190,5 +190,6 @@ __Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Tasking/Task_Capture_Dispatch __Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Navigation/Point.lua' ) __Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Navigation/Beacons.lua' ) __Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Navigation/Radios.lua' ) +__Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Navigation/Towns.lua' ) __Moose.Include( MOOSE_DEVELOPMENT_FOLDER..'/Moose/Globals.lua' ) diff --git a/Moose Development/Moose/Modules_local.lua b/Moose Development/Moose/Modules_local.lua index 0fea70e2e..f43c2a378 100644 --- a/Moose Development/Moose/Modules_local.lua +++ b/Moose Development/Moose/Modules_local.lua @@ -182,5 +182,6 @@ __Moose.Include( 'Tasking\\Task_Capture_Dispatcher.lua' ) __Moose.Include( 'Navigation\\Point.lua' ) __Moose.Include( 'Navigation\\Beacons.lua' ) __Moose.Include( 'Navigation\\Radios.lua' ) +__Moose.Include( 'Navigation\\Towns.lua' ) __Moose.Include( 'Globals.lua' ) diff --git a/Moose Development/Moose/Navigation/Towns.lua b/Moose Development/Moose/Navigation/Towns.lua new file mode 100644 index 000000000..fc31e65d5 --- /dev/null +++ b/Moose Development/Moose/Navigation/Towns.lua @@ -0,0 +1,261 @@ +--- **NAVIGATION** - Beacons of the map/theatre. +-- +-- **Main Features:** +-- +-- * Find towns of map +-- * Road and rail connections +-- +-- === +-- +-- ## Example Missions: +-- +-- Demo missions can be found on [github](https://github.com/FlightControl-Master/MOOSE_MISSIONS/tree/develop/Navigation%20-%20Towns). +-- +-- === +-- +-- ### Author: **funkyfranky** +-- +-- === +-- @module Navigation.Towns +-- @image NAVIGATION_Towns.png + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- TOWNS class. +-- @type TOWNS +-- +-- @field #string ClassName Name of the class. +-- @field #number verbose Verbosity of output. +-- @field #table towns Towns. +-- +-- @extends Core.Base#BASE + +--- *Hope is the beacon that guides lost ships back to the shore.* +-- +-- === +-- +-- # The TOWNS Concept +-- +-- This class is desinged to make information about towns of a map/theatre easier accessible. The information contains location and road/rail connections of the towns. +-- +-- **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 `towns.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 `TOWNS` object can be created with the @{#TOWNS.NewFromFile}(*towns_lua_file*) function. +-- +-- local towns=TOWNS:NewFromFile("\Mods\terrains\\towns.lua") +-- towns:MarkerShow() +-- +-- This will load the towns 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 towns are present. +-- +-- # User Functions +-- +-- ## F10 Map Markers +-- +-- ## Position +-- +-- ## Get Closest Town +-- +-- +-- @field #TOWNS +TOWNS = { + ClassName = "TOWNS", + verbose = 0, + towns = {}, +} + +--- Town data. +-- @type TOWNS.Town +-- @field #string display_name Displayed name. +-- @field #string name Name of the town. +-- @field #number latitude Latitude. +-- @field #number longitude Longitude +-- @field DCS#Vec3 vec3 Position vector 3D. +-- @field Core.Point#COORDINATE coordinate The coordinate. +-- @field Core.Point#COORDINATE coordRoad The coordinate of the closest road. +-- @field Core.Point#COORDINATE coordRail The coordinate of the closest railway. +-- @field #number markerID ID for the F10 marker. + +--- TOWNS class version. +-- @field #string version +TOWNS.version="0.0.0" + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- ToDo list +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +-- TODO: A lot... +-- TODO: Road connection +-- TODO: Rail connection + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- Constructor(s) +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Create a new TOWNS class instance from a given table. +-- @param #TOWNS self +-- @param #table TownTable Table with all towns data. +-- @return #TOWNS self +function TOWNS:NewFromTable(TownTable) + + -- Inherit everything from BASE class. + self=BASE:Inherit(self, BASE:New()) -- #TOWNS + + for TownName,_town in pairs(TownTable) do + local town=_town --#TOWNS.Town + + town.name=TownName + + -- Get coordinate + town.coordinate=COORDINATE:NewFromLLDD(town.latitude, town.longitude) + + -- Add to table + table.insert(self.towns, town) + end + + -- Debug output + self:I(string.format("Added %d towns", #self.towns)) + + return self +end + + +--- Create a new TOWNS class instance from a given file. +-- @param #TOWNS self +-- @param #string FileName Full path to the file containing the towns data. +-- @return #TOWNS self +function TOWNS:NewFromFile(FileName) + + -- Inherit everything from BASE class. + self=BASE:Inherit(self, BASE:New()) -- #TOWNS + + local exists=UTILS.FileExists(FileName) + + if exists==false then + self:E(string.format("ERROR: file with towns info does not exist!")) + return nil + end + + -- This will create a global table `towns` + dofile(FileName) + + -- Get towns from table. + self=self:NewFromTable(towns) + + return self +end + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +-- User Functions +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +--- Get 3D position vector of a specific town. +-- @param #TOWNS self +-- @param #TOWNS.Town town The town data structure. +-- @return DCS#Vec3 Position vector. +function TOWNS:GetVec3(town) + return town.vec3 +end + +--- Get COORDINATE of a specific town. +-- @param #TOWNS self +-- @param #TOWNS.Town town The town data structure. +-- @return Core.Point#COORDINATE The coordinate. +function TOWNS:GetCoordinate(town) + return town.coordinate +end + +--- Find closest town to a given coordinate. +-- @param #TOWNS self +-- @param Core.Point#COORDINATE Coordinate The reference coordinate. +-- @return #TOWNS.Town The closest town. +function TOWNS:GetClosestTown(Coordinate) + + local Town=nil --#TOWNS.Town + local distmin=math.huge + + for _,_town in pairs(self.towns) do + local town=_town --#TOWNS.Town + + local dist=Coordinate:Get2DDistance(bc.coordinate) + + if dist Date: Mon, 14 Apr 2025 22:42:29 +0200 Subject: [PATCH 5/8] Update Towns.lua --- Moose Development/Moose/Navigation/Towns.lua | 43 ++++++++++++++++++-- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/Moose Development/Moose/Navigation/Towns.lua b/Moose Development/Moose/Navigation/Towns.lua index fc31e65d5..dda193874 100644 --- a/Moose Development/Moose/Navigation/Towns.lua +++ b/Moose Development/Moose/Navigation/Towns.lua @@ -83,7 +83,7 @@ TOWNS = { --- TOWNS class version. -- @field #string version -TOWNS.version="0.0.0" +TOWNS.version="0.0.1" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- ToDo list @@ -92,6 +92,7 @@ TOWNS.version="0.0.0" -- TODO: A lot... -- TODO: Road connection -- TODO: Rail connection +-- TODO: Connection between towns ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Constructor(s) @@ -114,6 +115,12 @@ function TOWNS:NewFromTable(TownTable) -- Get coordinate town.coordinate=COORDINATE:NewFromLLDD(town.latitude, town.longitude) + -- Get coordinate of closest road + town.coordRoad=town.coordinate:GetClosestPointToRoad() + + -- Get coordinate of closest rail + town.coordRail=town.coordinate:GetClosestPointToRoad(true) + -- Add to table table.insert(self.towns, town) end @@ -170,6 +177,34 @@ function TOWNS:GetCoordinate(town) return town.coordinate end +--- Get closest road coordinate of a town. +-- @param #TOWNS self +-- @param #TOWNS.Town town The town data structure. +-- @return Core.Point#COORDINATE The closest road coordinate. +function TOWNS:GetCoordRoad(town) + return town.coordRoad +end + +--- Get closest rail coordinate of a town. +-- @param #TOWNS self +-- @param #TOWNS.Town town The town data structure. +-- @return Core.Point#COORDINATE The closest rail coordinate. +function TOWNS:GetCoordRail(town) + return town.coordRail +end + +--- Get road connection between two towns. +-- @param #TOWNS self +-- @param #TOWNS.Town townA The town data structure. +-- @param #TOWNS.Town townB The town data structure. +-- @return #table Table containing path coordinates. +function TOWNS:GetConnectionRoad(townA, townB) + + local path=townA.coordRoad:GetPathOnRoad(townB.coordRoad) + + return path +end + --- Find closest town to a given coordinate. -- @param #TOWNS self -- @param Core.Point#COORDINATE Coordinate The reference coordinate. @@ -182,7 +217,7 @@ function TOWNS:GetClosestTown(Coordinate) for _,_town in pairs(self.towns) do local town=_town --#TOWNS.Town - local dist=Coordinate:Get2DDistance(bc.coordinate) + local dist=Coordinate:Get2DDistance(town.coordinate) if dist Date: Tue, 15 Apr 2025 22:06:53 +0200 Subject: [PATCH 6/8] Update Beacons.lua - Fixed bug in counting beacons - Added option to mark certain beacon types - Improved maker text --- .../Moose/Navigation/Beacons.lua | 49 ++++++++++++------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/Moose Development/Moose/Navigation/Beacons.lua b/Moose Development/Moose/Navigation/Beacons.lua index cce4ff9f8..03ed7dc7c 100644 --- a/Moose Development/Moose/Navigation/Beacons.lua +++ b/Moose Development/Moose/Navigation/Beacons.lua @@ -66,7 +66,7 @@ -- @field #BEACONS BEACONS = { ClassName = "BEACONS", - verbose = 0, + verbose = 1, beacons = {}, } @@ -90,7 +90,7 @@ BEACONS = { --- BEACONS class version. -- @field #string version -BEACONS.version="0.0.2" +BEACONS.version="0.0.3" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- ToDo list @@ -146,6 +146,15 @@ function BEACONS:NewFromTable(BeaconTable) -- 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 @@ -251,7 +260,7 @@ end -- @return #number Number of beacons. function BEACONS:CountBeacons(TypeID) - local n=#self.beacons + local n=0 if TypeID then for _,_beacon in pairs(self.beacons) do @@ -268,39 +277,45 @@ function BEACONS:CountBeacons(TypeID) return n end ---- Add markers for all beacons on the F10 map. +--- Add markers for all beacons on the F10 map. Optionally, only a specific beacon or a certain beacon type can be marked. -- @param #BEACONS self -- @param #BEACONS.Beacon Beacon (Optional) Only this specifc beacon. +-- @param #number TypeID (Optional) Only show specific beacon types, *e.g.* `BEACON.Type.TACAN`. -- @return #BEACONS self -function BEACONS:MarkerShow(Beacon) +function BEACONS:MarkerShow(Beacon, TypeID) for _,_beacon in pairs(self.beacons) do local beacon=_beacon --#BEACONS.Beacon if Beacon==nil or Beacon.beaconId==beacon.beaconId then - local text=self:_GetMarkerText(beacon) - local coord=COORDINATE:NewFromVec3(beacon.vec3) - if beacon.markerID then - UTILS.RemoveMark(beacon.markerID) + if TypeID==nil or beacon.type==TypeID then + local text=self:_GetMarkerText(beacon) + local coord=COORDINATE:NewFromVec3(beacon.vec3) + if beacon.markerID then + UTILS.RemoveMark(beacon.markerID) + end + beacon.markerID=coord:MarkToAll(text) end - beacon.markerID=coord:MarkToAll(text) end end return self end ---- Remove markers of all beacons from the F10 map. +--- Remove markers of all beacons from the F10 map. Optionally, remove only marker of a specific beacon or a certain beacon type. -- @param #BEACONS self -- @param #BEACONS.Beacon Beacon (Optional) Only this specifc beacon. +-- @param #number TypeID (Optional) Only show specific beacon types, *e.g.* `BEACON.Type.TACAN`. -- @return #BEACONS self -function BEACONS:MarkerRemove(Beacon) +function BEACONS:MarkerRemove(Beacon, TypeID) for _,_beacon in pairs(self.beacons) do local beacon=_beacon --#BEACONS.Beacon if Beacon==nil or Beacon.beaconId==beacon.beaconId then - if beacon.markerID then - UTILS.RemoveMark(beacon.markerID) - beacon.markerID=nil + if TypeID==nil or beacon.type==TypeID then + if beacon.markerID then + UTILS.RemoveMark(beacon.markerID) + beacon.markerID=nil + end end end end @@ -321,10 +336,8 @@ function BEACONS:_GetMarkerText(beacon) local frequency, funit=self:_GetFrequency(beacon.frequency) local direction=beacon.direction~=nil and beacon.direction or -1 - local text=string.format("Beacon %s", tostring(beacon.beaconId)) + local text=string.format("Beacon %s [ID=%s]", tostring(beacon.typeName), tostring(beacon.beaconId)) text=text..string.format("\nCallsign: %s", tostring(beacon.callsign)) - text=text..string.format("\nType: %s", tostring(beacon.typeName)) - --if beacon.type==BEACON.Type.TACAN or beacon.type==BEACON.Type.RSBN or beacon.type==BEACON.Type.PRMG_GLIDESLOPE or beacon.type==BEACON.Type.PRMG_LOCALIZER then if UTILS.IsInTable({BEACON.Type.TACAN, BEACON.Type.RSBN, BEACON.Type.PRMG_GLIDESLOPE, BEACON.Type.PRMG_LOCALIZER}, beacon.type) then text=text..string.format("\nChannel: %s", tostring(beacon.channel)) end From ce61f454bf73975e7d1ac927d79e4832831739bc Mon Sep 17 00:00:00 2001 From: Frank Date: Thu, 17 Apr 2025 20:34:46 +0200 Subject: [PATCH 7/8] Update Beacons.lua - Added excludelist to GetClosestBeacon function --- Moose Development/Moose/Navigation/Beacons.lua | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Moose Development/Moose/Navigation/Beacons.lua b/Moose Development/Moose/Navigation/Beacons.lua index 03ed7dc7c..f22fecaf5 100644 --- a/Moose Development/Moose/Navigation/Beacons.lua +++ b/Moose Development/Moose/Navigation/Beacons.lua @@ -90,7 +90,7 @@ BEACONS = { --- BEACONS class version. -- @field #string version -BEACONS.version="0.0.3" +BEACONS.version="0.0.4" ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -- ToDo list @@ -209,20 +209,24 @@ end -- @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) +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 then + if (TypeID==nil or TypeID==bc.type) and (not UTILS.IsInTable(ExcludeList, bc, "beaconId")) then local dist=Coordinate:Get2DDistance(bc.vec3) - if dist Date: Sun, 26 Oct 2025 15:19:34 +0100 Subject: [PATCH 8/8] Update Radios.lua --- Moose Development/Moose/Navigation/Radios.lua | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Moose Development/Moose/Navigation/Radios.lua b/Moose Development/Moose/Navigation/Radios.lua index 5b1d5e013..7e13e57e3 100644 --- a/Moose Development/Moose/Navigation/Radios.lua +++ b/Moose Development/Moose/Navigation/Radios.lua @@ -162,6 +162,9 @@ function RADIOS:NewFromFile(FileName) self:E(string.format("ERROR: file with radios info does not exist! File=%s", tostring(FileName))) return nil end + + -- Backup DCS radio table + local radiobak=UTILS.DeepCopy(radio) -- This will create a global table `radio` dofile(FileName) @@ -169,6 +172,9 @@ function RADIOS:NewFromFile(FileName) -- Get radios from table. self=self:NewFromTable(radio) + -- Restore DCS radio table + radio=UTILS.DeepCopy(radiobak) + return self end