mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-10-29 16:58:06 +00:00
commit
dea7a5674c
@ -562,7 +562,7 @@ do -- COORDINATE
|
||||
|
||||
--- Return the height of the land at the coordinate.
|
||||
-- @param #COORDINATE self
|
||||
-- @return #number
|
||||
-- @return #number Land height (ASL) in meters.
|
||||
function COORDINATE:GetLandHeight()
|
||||
local Vec2 = { x = self.x, y = self.z }
|
||||
return land.getHeight( Vec2 )
|
||||
@ -1100,10 +1100,8 @@ do -- COORDINATE
|
||||
elseif AirbaseCategory == Airbase.Category.AIRDROME then
|
||||
RoutePoint.airdromeId = AirbaseID
|
||||
else
|
||||
self:T("ERROR: Unknown airbase category in COORDINATE:WaypointAir()!")
|
||||
self:E("ERROR: Unknown airbase category in COORDINATE:WaypointAir()!")
|
||||
end
|
||||
|
||||
--self:MarkToAll(string.format("Landing waypoint at airbase %s, ID=%d, Category=%d", airbase:GetName(), AirbaseID, AirbaseCategory ))
|
||||
end
|
||||
|
||||
-- Time in minutes to stay at the airbase before resuming route.
|
||||
@ -1270,17 +1268,23 @@ do -- COORDINATE
|
||||
-- Loop over all airbases.
|
||||
for _,_airbase in pairs(airbases) do
|
||||
local airbase=_airbase --Wrapper.Airbase#AIRBASE
|
||||
local category=airbase:GetDesc().category
|
||||
if Category and Category==category or Category==nil then
|
||||
local dist=self:Get2DDistance(airbase:GetCoordinate())
|
||||
if closest==nil then
|
||||
distmin=dist
|
||||
closest=airbase
|
||||
else
|
||||
if dist<distmin then
|
||||
if airbase then
|
||||
local category=airbase:GetCategory()
|
||||
if Category and Category==category or Category==nil then
|
||||
|
||||
-- Distance to airbase.
|
||||
local dist=self:Get2DDistance(airbase:GetCoordinate())
|
||||
|
||||
if closest==nil then
|
||||
distmin=dist
|
||||
closest=airbase
|
||||
end
|
||||
else
|
||||
if dist<distmin then
|
||||
distmin=dist
|
||||
closest=airbase
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1296,6 +1300,7 @@ do -- COORDINATE
|
||||
-- @return Core.Point#COORDINATE Coordinate of the nearest parking spot.
|
||||
-- @return #number Terminal ID.
|
||||
-- @return #number Distance to closest parking spot in meters.
|
||||
-- @return Wrapper.Airbase#AIRBASE#ParkingSpot Parking spot table.
|
||||
function COORDINATE:GetClosestParkingSpot(airbase, terminaltype, free)
|
||||
|
||||
-- Get airbase table.
|
||||
@ -1310,6 +1315,7 @@ do -- COORDINATE
|
||||
local _closest=nil --Core.Point#COORDINATE
|
||||
local _termID=nil
|
||||
local _distmin=nil
|
||||
local spot=nil --Wrapper.Airbase#AIRBASE.ParkingSpot
|
||||
|
||||
-- Loop over all airbases.
|
||||
for _,_airbase in pairs(airbases) do
|
||||
@ -1329,11 +1335,13 @@ do -- COORDINATE
|
||||
_closest=_coord
|
||||
_distmin=_dist
|
||||
_termID=_spot.TerminalID
|
||||
spot=_spot
|
||||
else
|
||||
if _dist<_distmin then
|
||||
_distmin=_dist
|
||||
_closest=_coord
|
||||
_termID=_spot.TerminalID
|
||||
spot=_spot
|
||||
end
|
||||
end
|
||||
|
||||
@ -1341,7 +1349,7 @@ do -- COORDINATE
|
||||
end
|
||||
end
|
||||
|
||||
return _closest, _termID, _distmin
|
||||
return _closest, _termID, _distmin, spot
|
||||
end
|
||||
|
||||
--- Gets the nearest free parking spot.
|
||||
@ -1943,7 +1951,7 @@ do -- COORDINATE
|
||||
|
||||
local LL_Accuracy = Settings and Settings.LL_Accuracy or _SETTINGS.LL_Accuracy
|
||||
local lat, lon = coord.LOtoLL( self:GetVec3() )
|
||||
return "LL DMS, " .. UTILS.tostringLL( lat, lon, LL_Accuracy, true )
|
||||
return "LL DMS " .. UTILS.tostringLL( lat, lon, LL_Accuracy, true )
|
||||
end
|
||||
|
||||
--- Provides a Lat Lon string in Degree Decimal Minute format.
|
||||
@ -1954,7 +1962,7 @@ do -- COORDINATE
|
||||
|
||||
local LL_Accuracy = Settings and Settings.LL_Accuracy or _SETTINGS.LL_Accuracy
|
||||
local lat, lon = coord.LOtoLL( self:GetVec3() )
|
||||
return "LL DDM, " .. UTILS.tostringLL( lat, lon, LL_Accuracy, false )
|
||||
return "LL DDM " .. UTILS.tostringLL( lat, lon, LL_Accuracy, false )
|
||||
end
|
||||
|
||||
--- Provides a MGRS string
|
||||
@ -1966,7 +1974,7 @@ do -- COORDINATE
|
||||
local MGRS_Accuracy = Settings and Settings.MGRS_Accuracy or _SETTINGS.MGRS_Accuracy
|
||||
local lat, lon = coord.LOtoLL( self:GetVec3() )
|
||||
local MGRS = coord.LLtoMGRS( lat, lon )
|
||||
return "MGRS, " .. UTILS.tostringMGRS( MGRS, MGRS_Accuracy )
|
||||
return "MGRS " .. UTILS.tostringMGRS( MGRS, MGRS_Accuracy )
|
||||
end
|
||||
|
||||
--- Provides a coordinate string of the point, based on a coordinate format system:
|
||||
|
||||
@ -420,6 +420,7 @@ end
|
||||
BEACON = {
|
||||
ClassName = "BEACON",
|
||||
Positionable = nil,
|
||||
name=nil,
|
||||
}
|
||||
|
||||
--- Beacon types supported by DCS.
|
||||
@ -496,6 +497,8 @@ function BEACON:New(Positionable)
|
||||
-- Set positionable.
|
||||
if Positionable:GetPointVec2() then -- It's stupid, but the only way I found to make sure positionable is valid
|
||||
self.Positionable = Positionable
|
||||
self.name=Positionable:GetName()
|
||||
self:I(string.format("New BEACON %s", tostring(self.name)))
|
||||
return self
|
||||
end
|
||||
|
||||
@ -550,7 +553,7 @@ function BEACON:ActivateTACAN(Channel, Mode, Message, Bearing, Duration)
|
||||
local UnitID=self.Positionable:GetID()
|
||||
|
||||
-- Debug.
|
||||
self:T({"TACAN BEACON started!"})
|
||||
self:I({string.format("BEACON Activating TACAN %s: Channel=%d%s, Morse=%s, Bearing=%s, Duration=%s!", tostring(self.name), Channel, Mode, Message, tostring(Bearing), tostring(Duration))})
|
||||
|
||||
-- Start beacon.
|
||||
self.Positionable:CommandActivateBeacon(Type, System, Frequency, UnitID, Channel, Mode, AA, Message, Bearing)
|
||||
|
||||
@ -51,9 +51,12 @@ RADIOQUEUE = {
|
||||
-- @field #string filename Name of the file to be transmitted.
|
||||
-- @field #string path Path in miz file where the file is located.
|
||||
-- @field #number duration Duration in seconds.
|
||||
-- @field #string subtitle Subtitle of the transmission.
|
||||
-- @field #number subduration Duration of the subtitle being displayed.
|
||||
-- @field #number Tstarted Mission time (abs) in seconds when the transmission started.
|
||||
-- @field #boolean isplaying If true, transmission is currently playing.
|
||||
-- @field #number Tplay Mission time (abs) in seconds when the transmission should be played.
|
||||
-- @field #number interval Interval in seconds before next transmission.
|
||||
|
||||
|
||||
--- Create a new RADIOQUEUE object for a given radio frequency/modulation.
|
||||
@ -97,7 +100,7 @@ function RADIOQUEUE:Start(delay, dt)
|
||||
|
||||
dt=dt or 0.01
|
||||
|
||||
self:I(self.lid..string.format("Starting RADIOQUEUE in %.1f seconds with interval dt=%.3f seconds.", delay, dt))
|
||||
self:I(self.lid..string.format("Starting RADIOQUEUE on Frequency %.2f MHz [modulation=%d] in %.1f seconds (dt=%.3f sec)", self.frequency/1000000, self.modulation, delay, dt))
|
||||
|
||||
self.RQid=self.scheduler:Schedule(self, self._CheckRadioQueue, {}, delay, dt)
|
||||
|
||||
@ -138,13 +141,17 @@ end
|
||||
-- @param #string filename The name of the sound file.
|
||||
-- @param #number duration The duration of the sound file in seconds.
|
||||
-- @param #string path The directory within the miz file where the sound is located. Default "l10n/DEFAULT/".
|
||||
-- @param #string subtitle Subtitle of the transmission.
|
||||
-- @param #number subduration Duration [sec] of the subtitle being displayed. Default 5 sec.
|
||||
-- @return #RADIOQUEUE self The RADIOQUEUE object.
|
||||
function RADIOQUEUE:SetDigit(digit, filename, duration, path)
|
||||
function RADIOQUEUE:SetDigit(digit, filename, duration, path, subtitle, subduration)
|
||||
|
||||
local transmission={} --#RADIOQUEUE.Transmission
|
||||
transmission.filename=filename
|
||||
transmission.duration=duration
|
||||
transmission.path=path or "l10n/DEFAULT/"
|
||||
transmission.subtitle=nil
|
||||
transmission.subduration=nil
|
||||
|
||||
-- Convert digit to string in case it is given as a number.
|
||||
if type(digit)=="number" then
|
||||
@ -170,6 +177,8 @@ function RADIOQUEUE:AddTransmission(transmission)
|
||||
|
||||
-- Add to queue.
|
||||
table.insert(self.queue, transmission)
|
||||
|
||||
--TODO: Start scheduler.
|
||||
|
||||
return self
|
||||
end
|
||||
@ -181,8 +190,10 @@ end
|
||||
-- @param #number path Directory path inside the miz file where the sound file is located. Default "l10n/DEFAULT/".
|
||||
-- @param #number tstart Start time (abs) seconds. Default now.
|
||||
-- @param #number interval Interval in seconds after the last transmission finished.
|
||||
-- @param #string subtitle Subtitle of the transmission.
|
||||
-- @param #number subduration Duration [sec] of the subtitle being displayed. Default 5 sec.
|
||||
-- @return #RADIOQUEUE self The RADIOQUEUE object.
|
||||
function RADIOQUEUE:NewTransmission(filename, duration, path, tstart, interval)
|
||||
function RADIOQUEUE:NewTransmission(filename, duration, path, tstart, interval, subtitle, subduration)
|
||||
|
||||
-- Sanity checks.
|
||||
if not filename then
|
||||
@ -209,6 +220,13 @@ function RADIOQUEUE:NewTransmission(filename, duration, path, tstart, interval)
|
||||
transmission.duration=duration
|
||||
transmission.path=path or "l10n/DEFAULT/"
|
||||
transmission.Tplay=tstart or timer.getAbsTime()
|
||||
transmission.subtitle=subtitle
|
||||
transmission.interval=interval or 0
|
||||
if transmission.subtitle then
|
||||
transmission.subduration=subduration or 5
|
||||
else
|
||||
transmission.subduration=nil
|
||||
end
|
||||
|
||||
-- Add transmission to queue.
|
||||
self:AddTransmission(transmission)
|
||||
@ -275,9 +293,6 @@ function RADIOQUEUE:Broadcast(transmission)
|
||||
-- Construct file name.
|
||||
local filename=string.format("%s%s", transmission.path, transmission.filename)
|
||||
|
||||
-- Create subtitle for transmission.
|
||||
--local subtitle=self:_RadioSubtitle(radio, call, loud)
|
||||
|
||||
if sender then
|
||||
|
||||
-- Broadcasting from aircraft. Only players tuned in to the right frequency will see the message.
|
||||
@ -296,7 +311,7 @@ function RADIOQUEUE:Broadcast(transmission)
|
||||
id = "TransmitMessage",
|
||||
params = {
|
||||
file=filename,
|
||||
duration=transmission.subduration or 5,
|
||||
duration=transmission.subduration,
|
||||
subtitle=transmission.subtitle or "",
|
||||
loop=false,
|
||||
}}
|
||||
@ -310,7 +325,7 @@ function RADIOQUEUE:Broadcast(transmission)
|
||||
else
|
||||
|
||||
-- Broadcasting from carrier. No subtitle possible. Need to send messages to players.
|
||||
self:T(self.lid..string.format("Broadcasting from carrier via trigger.action.radioTransmission()."))
|
||||
self:T(self.lid..string.format("Broadcasting via trigger.action.radioTransmission()."))
|
||||
|
||||
-- Position from where to transmit.
|
||||
local vec3=nil
|
||||
@ -330,8 +345,8 @@ function RADIOQUEUE:Broadcast(transmission)
|
||||
|
||||
-- Transmit via trigger.
|
||||
if vec3 then
|
||||
self:E("Sending")
|
||||
self:E( { filename = filename, vec3 = vec3, modulation = self.modulation, frequency = self.frequency, power = self.power } )
|
||||
self:T("Sending")
|
||||
self:T( { filename = filename, vec3 = vec3, modulation = self.modulation, frequency = self.frequency, power = self.power } )
|
||||
trigger.action.radioTransmission(filename, vec3, self.modulation, false, self.frequency, self.power)
|
||||
end
|
||||
|
||||
@ -344,6 +359,7 @@ function RADIOQUEUE:_CheckRadioQueue()
|
||||
|
||||
-- Check if queue is empty.
|
||||
if #self.queue==0 then
|
||||
--TODO: stop scheduler.
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
@ -68,6 +68,7 @@ __Moose.Include( 'Scripts/Moose/Functional/Fox.lua' )
|
||||
__Moose.Include( 'Scripts/Moose/Ops/Airboss.lua' )
|
||||
__Moose.Include( 'Scripts/Moose/Ops/RecoveryTanker.lua' )
|
||||
__Moose.Include( 'Scripts/Moose/Ops/RescueHelo.lua' )
|
||||
__Moose.Include( 'Scripts/Moose/Ops/ATIS.lua' )
|
||||
|
||||
__Moose.Include( 'Scripts/Moose/AI/AI_Balancer.lua' )
|
||||
__Moose.Include( 'Scripts/Moose/AI/AI_Air.lua' )
|
||||
|
||||
1079
Moose Development/Moose/Ops/ATIS.lua
Normal file
1079
Moose Development/Moose/Ops/ATIS.lua
Normal file
File diff suppressed because it is too large
Load Diff
@ -432,12 +432,13 @@ UTILS.tostringLL = function( lat, lon, acc, DMS)
|
||||
if acc <= 0 then -- no decimal place.
|
||||
secFrmtStr = '%02d'
|
||||
else
|
||||
local width = 3 + acc -- 01.310 - that's a width of 6, for example.
|
||||
local width = 3 + acc -- 01.310 - that's a width of 6, for example. Acc is limited to 2 for DMS!
|
||||
secFrmtStr = '%0' .. width .. '.' .. acc .. 'f'
|
||||
end
|
||||
|
||||
return string.format('%03d', latDeg) .. ' ' .. string.format('%02d', latMin) .. '\' ' .. string.format(secFrmtStr, latSec) .. '"' .. latHemi .. ' '
|
||||
.. string.format('%03d', lonDeg) .. ' ' .. string.format('%02d', lonMin) .. '\' ' .. string.format(secFrmtStr, lonSec) .. '"' .. lonHemi
|
||||
-- 024° 23' 12"N or 024° 23' 12.03"N
|
||||
return string.format('%03d°', latDeg) .. ' ' .. string.format('%02d', latMin) .. '\' ' .. string.format(secFrmtStr, latSec) .. '"' .. latHemi .. ' '
|
||||
.. string.format('%03d°', lonDeg) .. ' ' .. string.format('%02d', lonMin) .. '\' ' .. string.format(secFrmtStr, lonSec) .. '"' .. lonHemi
|
||||
|
||||
else -- degrees, decimal minutes.
|
||||
latMin = UTILS.Round(latMin, acc)
|
||||
@ -461,8 +462,9 @@ UTILS.tostringLL = function( lat, lon, acc, DMS)
|
||||
minFrmtStr = '%0' .. width .. '.' .. acc .. 'f'
|
||||
end
|
||||
|
||||
return string.format('%03d', latDeg) .. ' ' .. string.format(minFrmtStr, latMin) .. '\'' .. latHemi .. ' '
|
||||
.. string.format('%03d', lonDeg) .. ' ' .. string.format(minFrmtStr, lonMin) .. '\'' .. lonHemi
|
||||
-- 024 23'N or 024 23.123'N
|
||||
return string.format('%03d°', latDeg) .. ' ' .. string.format(minFrmtStr, latMin) .. '\'' .. latHemi .. ' '
|
||||
.. string.format('%03d°', lonDeg) .. ' ' .. string.format(minFrmtStr, lonMin) .. '\'' .. lonHemi
|
||||
|
||||
end
|
||||
end
|
||||
@ -657,8 +659,9 @@ end
|
||||
|
||||
--- Convert time in seconds to hours, minutes and seconds.
|
||||
-- @param #number seconds Time in seconds, e.g. from timer.getAbsTime() function.
|
||||
-- @param #boolean short (Optional) If true, use short output, i.e. (HH:)MM:SS without day.
|
||||
-- @return #string Time in format Hours:Minutes:Seconds+Days (HH:MM:SS+D).
|
||||
function UTILS.SecondsToClock(seconds)
|
||||
function UTILS.SecondsToClock(seconds, short)
|
||||
|
||||
-- Nil check.
|
||||
if seconds==nil then
|
||||
@ -678,7 +681,15 @@ function UTILS.SecondsToClock(seconds)
|
||||
local mins = string.format("%02.f", math.floor(_seconds/60 - (hours*60)))
|
||||
local secs = string.format("%02.f", math.floor(_seconds - hours*3600 - mins *60))
|
||||
local days = string.format("%d", seconds/(60*60*24))
|
||||
return hours..":"..mins..":"..secs.."+"..days
|
||||
local clock=hours..":"..mins..":"..secs.."+"..days
|
||||
if short then
|
||||
if hours=="00" then
|
||||
clock=mins..":"..secs
|
||||
else
|
||||
clock=hours..":"..mins..":"..secs
|
||||
end
|
||||
end
|
||||
return clock
|
||||
end
|
||||
end
|
||||
|
||||
@ -983,3 +994,16 @@ function UTILS.FileExists(file)
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
--- Checks the current memory usage collectgarbage("count"). Info is printed to the DCS log file. Time stamp is the current mission runtime.
|
||||
-- @param #boolean output If true, print to DCS log file.
|
||||
-- @return #number Memory usage in kByte.
|
||||
function UTILS.CheckMemory(output)
|
||||
local time=timer.getTime()
|
||||
local clock=UTILS.SecondsToClock(time)
|
||||
local mem=collectgarbage("count")
|
||||
if output then
|
||||
env.info(string.format("T=%s Memory usage %d kByte = %.2f MByte", clock, mem, mem/1024))
|
||||
end
|
||||
return mem
|
||||
end
|
||||
|
||||
@ -13,6 +13,9 @@
|
||||
|
||||
|
||||
--- @type AIRBASE
|
||||
-- @field #string ClassName Name of the class, i.e. "AIRBASE".
|
||||
-- @field #table CategoryName Names of airbase categories.
|
||||
-- @field #number activerwyno Active runway number (forced).
|
||||
-- @extends Wrapper.Positionable#POSITIONABLE
|
||||
|
||||
--- Wrapper class to handle the DCS Airbase objects:
|
||||
@ -54,6 +57,7 @@ AIRBASE = {
|
||||
[Airbase.Category.HELIPAD] = "Helipad",
|
||||
[Airbase.Category.SHIP] = "Ship",
|
||||
},
|
||||
activerwyno=nil,
|
||||
}
|
||||
|
||||
--- Enumeration to identify the airbases in the Caucasus region.
|
||||
@ -324,6 +328,14 @@ AIRBASE.TerminalType = {
|
||||
FighterAircraft=244,
|
||||
}
|
||||
|
||||
--- Runway data.
|
||||
-- @type AIRBASE.Runway
|
||||
-- @field #number heading Heading of the runway in degrees.
|
||||
-- @field #string idx Runway ID: heading 070° ==> idx="07".
|
||||
-- @field #number length Length of runway in meters.
|
||||
-- @field Core.Point#COORDINATE position Position of runway start.
|
||||
-- @field Core.Point#COORDINATE endpoint End point of runway.
|
||||
|
||||
-- Registration.
|
||||
|
||||
--- Create a new AIRBASE from DCSAirbase.
|
||||
@ -403,13 +415,17 @@ end
|
||||
|
||||
--- Get all airbases of the current map. This includes ships and FARPS.
|
||||
-- @param DCS#Coalition coalition (Optional) Return only airbases belonging to the specified coalition. By default, all airbases of the map are returned.
|
||||
-- @param #number category (Optional) Return only airbases of a certain category, e.g. Airbase.Category.FARP
|
||||
-- @return #table Table containing all airbase objects of the current map.
|
||||
function AIRBASE.GetAllAirbases(coalition)
|
||||
function AIRBASE.GetAllAirbases(coalition, category)
|
||||
|
||||
local airbases={}
|
||||
for _,airbase in pairs(_DATABASE.AIRBASES) do
|
||||
for _,_airbase in pairs(_DATABASE.AIRBASES) do
|
||||
local airbase=_airbase --#AIRBASE
|
||||
if (coalition~=nil and airbase:GetCoalition()==coalition) or coalition==nil then
|
||||
table.insert(airbases, airbase)
|
||||
if category==nil or category==airbase:GetAirbaseCategory() then
|
||||
table.insert(airbases, airbase)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -530,7 +546,7 @@ function AIRBASE:GetParkingSpotsCoordinates(termtype)
|
||||
|
||||
-- Put coordinates of free spots into table.
|
||||
local spots={}
|
||||
for _,parkingspot in pairs(parkingdata) do
|
||||
for _,parkingspot in ipairs(parkingdata) do
|
||||
|
||||
-- Coordinates on runway are not returned unless explicitly requested.
|
||||
if AIRBASE._CheckTerminalType(parkingspot.Term_Type, termtype) then
|
||||
@ -990,3 +1006,185 @@ function AIRBASE._CheckTerminalType(Term_Type, termtype)
|
||||
|
||||
return match
|
||||
end
|
||||
|
||||
--- Get runways data. Only for airdromes!
|
||||
-- @param #AIRBASE self
|
||||
-- @param #number magvar (Optional) Magnetic variation in degrees.
|
||||
-- @param #boolean mark (Optional) Place markers with runway data on F10 map.
|
||||
-- @return #table Runway data.
|
||||
function AIRBASE:GetRunwayData(magvar, mark)
|
||||
|
||||
-- Runway table.
|
||||
local runways={}
|
||||
|
||||
if self:GetAirbaseCategory()~=Airbase.Category.AIRDROME then
|
||||
return {}
|
||||
end
|
||||
|
||||
-- Get spawn points on runway.
|
||||
local runwaycoords=self:GetParkingSpotsCoordinates(AIRBASE.TerminalType.Runway)
|
||||
|
||||
-- Magnetic declination.
|
||||
magvar=magvar or UTILS.GetMagneticDeclination()
|
||||
|
||||
local N=#runwaycoords
|
||||
local dN=2
|
||||
local ex=false
|
||||
|
||||
local name=self:GetName()
|
||||
if name==AIRBASE.Nevada.Jean_Airport or
|
||||
name==AIRBASE.Nevada.Creech_AFB or
|
||||
name==AIRBASE.PersianGulf.Abu_Dhabi_International_Airport or
|
||||
name==AIRBASE.PersianGulf.Dubai_Intl or
|
||||
name==AIRBASE.PersianGulf.Shiraz_International_Airport or
|
||||
name==AIRBASE.PersianGulf.Kish_International_Airport then
|
||||
|
||||
N=#runwaycoords/2
|
||||
dN=1
|
||||
ex=true
|
||||
end
|
||||
|
||||
|
||||
for i=1,N,dN do
|
||||
|
||||
local j=i+1
|
||||
if ex then
|
||||
--j=N+i
|
||||
j=#runwaycoords-i+1
|
||||
end
|
||||
|
||||
-- Coordinates of the two runway points.
|
||||
local c1=runwaycoords[i] --Core.Point#COORDINATES
|
||||
local c2=runwaycoords[j] --Core.Point#COORDINATES
|
||||
|
||||
-- Heading of runway.
|
||||
local hdg=c1:HeadingTo(c2)
|
||||
|
||||
-- Runway ID: heading=070° ==> idx="07"
|
||||
local idx=string.format("%02d", UTILS.Round((hdg-magvar)/10, 0))
|
||||
|
||||
-- Runway table.
|
||||
local runway={} --#AIRBASE.Runway
|
||||
runway.heading=hdg
|
||||
runway.idx=idx
|
||||
runway.length=c1:Get2DDistance(c2)
|
||||
runway.position=c1
|
||||
runway.endpoint=c2
|
||||
|
||||
-- Debug info.
|
||||
self:T(string.format("Airbase %s: Adding runway id=%s, heading=%03d, length=%d m", self:GetName(), runway.idx, runway.heading, runway.length))
|
||||
|
||||
-- Debug mark
|
||||
if mark then
|
||||
runway.position:MarkToAll(string.format("Runway %s: true heading=%03d, length=%d m", runway.idx, runway.heading, runway.length))
|
||||
end
|
||||
|
||||
-- Add runway.
|
||||
table.insert(runways, runway)
|
||||
|
||||
end
|
||||
|
||||
-- Get inverse runways
|
||||
local inverse={}
|
||||
for _,_runway in pairs(runways) do
|
||||
local r=_runway --#AIRBASE.Runway
|
||||
|
||||
local runway={} --#AIRBASE.Runway
|
||||
runway.heading=r.heading-180
|
||||
if runway.heading<0 then
|
||||
runway.heading=runway.heading+360
|
||||
end
|
||||
runway.idx=string.format("%02d", math.max(0, UTILS.Round((runway.heading-magvar)/10, 0)))
|
||||
runway.length=r.length
|
||||
runway.position=r.endpoint
|
||||
runway.endpoint=r.position
|
||||
|
||||
-- Debug info.
|
||||
self:T(string.format("Airbase %s: Adding runway id=%s, heading=%03d, length=%d m", self:GetName(), runway.idx, runway.heading, runway.length))
|
||||
|
||||
-- Debug mark
|
||||
if mark then
|
||||
runway.position:MarkToAll(string.format("Runway %s: true heading=%03d, length=%d m", runway.idx, runway.heading, runway.length))
|
||||
end
|
||||
|
||||
-- Add runway.
|
||||
table.insert(inverse, runway)
|
||||
end
|
||||
|
||||
-- Add inverse runway.
|
||||
for _,runway in pairs(inverse) do
|
||||
table.insert(runways, runway)
|
||||
end
|
||||
|
||||
return runways
|
||||
end
|
||||
|
||||
--- Set the active runway in case it cannot be determined by the wind direction.
|
||||
-- @param #AIRBASE self
|
||||
-- @param #number iactive Number of the active runway in the runway data table.
|
||||
function AIRBASE:SetActiveRunway(iactive)
|
||||
self.activerwyno=iactive
|
||||
end
|
||||
|
||||
--- Get the active runway based on current wind direction.
|
||||
-- @param #AIRBASE self
|
||||
-- @param #number magvar (Optional) Magnetic variation in degrees.
|
||||
-- @return #AIRBASE.Runway Active runway data table.
|
||||
function AIRBASE:GetActiveRunway(magvar)
|
||||
|
||||
-- Get runways data (initialize if necessary).
|
||||
local runways=self:GetRunwayData(magvar)
|
||||
|
||||
-- Return user forced active runway if it was set.
|
||||
if self.activerwyno then
|
||||
return runways[self.activerwyno]
|
||||
end
|
||||
|
||||
-- Get wind vector.
|
||||
local Vwind=self:GetCoordinate():GetWindWithTurbulenceVec3()
|
||||
local norm=UTILS.VecNorm(Vwind)
|
||||
|
||||
-- Active runway number.
|
||||
local iact=1
|
||||
|
||||
-- Check if wind is blowing (norm>0).
|
||||
if norm>0 then
|
||||
|
||||
-- Normalize wind (not necessary).
|
||||
Vwind.x=Vwind.x/norm
|
||||
Vwind.y=0
|
||||
Vwind.z=Vwind.z/norm
|
||||
|
||||
-- Loop over runways.
|
||||
local dotmin=nil
|
||||
for i,_runway in pairs(runways) do
|
||||
local runway=_runway --#AIRBASE.Runway
|
||||
|
||||
-- Angle in rad.
|
||||
local alpha=math.rad(runway.heading)
|
||||
|
||||
-- Runway vector.
|
||||
local Vrunway={x=math.cos(alpha), y=0, z=math.sin(alpha)}
|
||||
|
||||
-- Dot product: parallel component of the two vectors.
|
||||
local dot=UTILS.VecDot(Vwind, Vrunway)
|
||||
|
||||
-- Debug.
|
||||
--env.info(string.format("runway=%03d° dot=%.3f", runway.heading, dot))
|
||||
|
||||
-- New min?
|
||||
if dotmin==nil or dot<dotmin then
|
||||
dotmin=dot
|
||||
iact=i
|
||||
end
|
||||
|
||||
end
|
||||
else
|
||||
self:E("WARNING: Norm of wind is zero! Cannot determine active runway based on wind direction.")
|
||||
end
|
||||
|
||||
return runways[iact]
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -63,6 +63,7 @@ Functional/Fox.lua
|
||||
Ops/Airboss.lua
|
||||
Ops/RecoveryTanker.lua
|
||||
Ops/RescueHelo.lua
|
||||
Ops/ATIS.lua
|
||||
|
||||
AI/AI_Balancer.lua
|
||||
AI/AI_Air.lua
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user