mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2026-08-11 03:43:38 +00:00
Merge branch 'develop' into FF/Fox2
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
--- **Wrapper** -- AIRBASE is a wrapper class to handle the DCS Airbase objects.
|
||||
--
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
--
|
||||
-- ### Author: **FlightControl**
|
||||
--
|
||||
--
|
||||
-- ### Contributions: **funkyfranky**
|
||||
--
|
||||
--
|
||||
-- ===
|
||||
--
|
||||
--
|
||||
-- @module Wrapper.Airbase
|
||||
-- @image Wrapper_Airbase.JPG
|
||||
|
||||
@@ -19,40 +19,40 @@
|
||||
-- @extends Wrapper.Positionable#POSITIONABLE
|
||||
|
||||
--- Wrapper class to handle the DCS Airbase objects:
|
||||
--
|
||||
--
|
||||
-- * Support all DCS Airbase APIs.
|
||||
-- * Enhance with Airbase specific APIs not in the DCS Airbase API set.
|
||||
--
|
||||
--
|
||||
-- ## AIRBASE reference methods
|
||||
--
|
||||
--
|
||||
-- For each DCS Airbase object alive within a running mission, a AIRBASE wrapper object (instance) will be created within the _@{DATABASE} object.
|
||||
-- This is done at the beginning of the mission (when the mission starts).
|
||||
--
|
||||
--
|
||||
-- The AIRBASE class **does not contain a :New()** method, rather it provides **:Find()** methods to retrieve the object reference
|
||||
-- using the DCS Airbase or the DCS AirbaseName.
|
||||
--
|
||||
-- Another thing to know is that AIRBASE objects do not "contain" the DCS Airbase object.
|
||||
--
|
||||
-- Another thing to know is that AIRBASE objects do not "contain" the DCS Airbase object.
|
||||
-- The AIRBASE methods will reference the DCS Airbase object by name when it is needed during API execution.
|
||||
-- If the DCS Airbase object does not exist or is nil, the AIRBASE methods will return nil and log an exception in the DCS.log file.
|
||||
--
|
||||
--
|
||||
-- The AIRBASE class provides the following functions to retrieve quickly the relevant AIRBASE instance:
|
||||
--
|
||||
--
|
||||
-- * @{#AIRBASE.Find}(): Find a AIRBASE instance from the _DATABASE object using a DCS Airbase object.
|
||||
-- * @{#AIRBASE.FindByName}(): Find a AIRBASE instance from the _DATABASE object using a DCS Airbase name.
|
||||
--
|
||||
--
|
||||
-- IMPORTANT: ONE SHOULD NEVER SANATIZE these AIRBASE OBJECT REFERENCES! (make the AIRBASE object references nil).
|
||||
--
|
||||
--
|
||||
-- ## DCS Airbase APIs
|
||||
--
|
||||
--
|
||||
-- The DCS Airbase APIs are used extensively within MOOSE. The AIRBASE class has for each DCS Airbase API a corresponding method.
|
||||
-- To be able to distinguish easily in your code the difference between a AIRBASE API call and a DCS Airbase API call,
|
||||
-- the first letter of the method is also capitalized. So, by example, the DCS Airbase method @{DCSWrapper.Airbase#Airbase.getName}()
|
||||
-- is implemented in the AIRBASE class as @{#AIRBASE.GetName}().
|
||||
--
|
||||
--
|
||||
-- @field #AIRBASE AIRBASE
|
||||
AIRBASE = {
|
||||
ClassName="AIRBASE",
|
||||
CategoryName = {
|
||||
CategoryName = {
|
||||
[Airbase.Category.AIRDROME] = "Airdrome",
|
||||
[Airbase.Category.HELIPAD] = "Helipad",
|
||||
[Airbase.Category.SHIP] = "Ship",
|
||||
@@ -61,9 +61,9 @@ AIRBASE = {
|
||||
}
|
||||
|
||||
--- Enumeration to identify the airbases in the Caucasus region.
|
||||
--
|
||||
--
|
||||
-- These are all airbases of Caucasus:
|
||||
--
|
||||
--
|
||||
-- * AIRBASE.Caucasus.Gelendzhik
|
||||
-- * AIRBASE.Caucasus.Krasnodar_Pashkovsky
|
||||
-- * AIRBASE.Caucasus.Sukhumi_Babushara
|
||||
@@ -85,7 +85,7 @@ AIRBASE = {
|
||||
-- * AIRBASE.Caucasus.Nalchik
|
||||
-- * AIRBASE.Caucasus.Mozdok
|
||||
-- * AIRBASE.Caucasus.Beslan
|
||||
--
|
||||
--
|
||||
-- @field Caucasus
|
||||
AIRBASE.Caucasus = {
|
||||
["Gelendzhik"] = "Gelendzhik",
|
||||
@@ -112,7 +112,7 @@ AIRBASE.Caucasus = {
|
||||
}
|
||||
|
||||
--- These are all airbases of Nevada:
|
||||
--
|
||||
--
|
||||
-- * AIRBASE.Nevada.Creech_AFB
|
||||
-- * AIRBASE.Nevada.Groom_Lake_AFB
|
||||
-- * AIRBASE.Nevada.McCarran_International_Airport
|
||||
@@ -131,7 +131,7 @@ AIRBASE.Caucasus = {
|
||||
-- * AIRBASE.Nevada.Pahute_Mesa_Airstrip
|
||||
-- * AIRBASE.Nevada.Tonopah_Airport
|
||||
-- * AIRBASE.Nevada.Tonopah_Test_Range_Airfield
|
||||
-- @field Nevada
|
||||
-- @field Nevada
|
||||
AIRBASE.Nevada = {
|
||||
["Creech_AFB"] = "Creech AFB",
|
||||
["Groom_Lake_AFB"] = "Groom Lake AFB",
|
||||
@@ -154,7 +154,7 @@ AIRBASE.Nevada = {
|
||||
}
|
||||
|
||||
--- These are all airbases of Normandy:
|
||||
--
|
||||
--
|
||||
-- * AIRBASE.Normandy.Saint_Pierre_du_Mont
|
||||
-- * AIRBASE.Normandy.Lignerolles
|
||||
-- * AIRBASE.Normandy.Cretteville
|
||||
@@ -264,7 +264,7 @@ AIRBASE.PersianGulf = {
|
||||
["Bandar_Abbas_Intl"] = "Bandar Abbas Intl",
|
||||
["Bandar_Lengeh"] = "Bandar Lengeh",
|
||||
["Bandar_e_Jask_airfield"] = "Bandar-e-Jask airfield",
|
||||
["Dubai_Intl"] = "Dubai Intl",
|
||||
["Dubai_Intl"] = "Dubai Intl",
|
||||
["Fujairah_Intl"] = "Fujairah Intl",
|
||||
["Havadarya"] = "Havadarya",
|
||||
["Jiroft_Airport"] = "Jiroft Airport",
|
||||
@@ -284,7 +284,7 @@ AIRBASE.PersianGulf = {
|
||||
["Tunb_Island_AFB"] = "Tunb Island AFB",
|
||||
["Tunb_Kochak"] = "Tunb Kochak",
|
||||
}
|
||||
|
||||
|
||||
--- AIRBASE.ParkingSpot ".Coordinate, ".TerminalID", ".TerminalType", ".TOAC", ".Free", ".TerminalID0", ".DistToRwy".
|
||||
-- @type AIRBASE.ParkingSpot
|
||||
-- @field Core.Point#COORDINATE Coordinate Coordinate of the parking spot.
|
||||
@@ -294,11 +294,11 @@ AIRBASE.PersianGulf = {
|
||||
-- @field #boolean Free This spot is currently free, i.e. there is no alive aircraft on it at the present moment.
|
||||
-- @field #number TerminalID0 Unknown what this means. If you know, please tell us!
|
||||
-- @field #number DistToRwy Distance to runway in meters. Currently bugged and giving the same number as the TerminalID.
|
||||
|
||||
|
||||
--- Terminal Types of parking spots. See also https://wiki.hoggitworld.com/view/DCS_func_getParking
|
||||
--
|
||||
--
|
||||
-- Supported types are:
|
||||
--
|
||||
--
|
||||
-- * AIRBASE.TerminalType.Runway = 16: Valid spawn points on runway.
|
||||
-- * AIRBASE.TerminalType.HelicopterOnly = 40: Special spots for Helicopers.
|
||||
-- * AIRBASE.TerminalType.Shelter = 68: Hardened Air Shelter. Currently only on Caucaus map.
|
||||
@@ -307,7 +307,7 @@ AIRBASE.PersianGulf = {
|
||||
-- * AIRBASE.TerminalType.OpenMedOrBig = 176: Combines OpenMed and OpenBig spots.
|
||||
-- * AIRBASE.TerminalType.HelicopterUnsable = 216: Combines HelicopterOnly, OpenMed and OpenBig.
|
||||
-- * AIRBASE.TerminalType.FighterAircraft = 244: Combines Shelter. OpenMed and OpenBig spots. So effectively all spots usable by fixed wing aircraft.
|
||||
--
|
||||
--
|
||||
-- @type AIRBASE.TerminalType
|
||||
-- @field #number Runway 16: Valid spawn points on runway.
|
||||
-- @field #number HelicopterOnly 40: Special spots for Helicopers.
|
||||
@@ -331,13 +331,13 @@ AIRBASE.TerminalType = {
|
||||
--- Runway data.
|
||||
-- @type AIRBASE.Runway
|
||||
-- @field #number heading Heading of the runway in degrees.
|
||||
-- @field #string idx Runway ID: heading 070° ==> idx="07".
|
||||
-- @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.
|
||||
-- @param #AIRBASE self
|
||||
-- @param #string AirbaseName The name of the airbase.
|
||||
@@ -368,7 +368,7 @@ end
|
||||
-- @param #string AirbaseName The Airbase Name.
|
||||
-- @return #AIRBASE self
|
||||
function AIRBASE:FindByName( AirbaseName )
|
||||
|
||||
|
||||
local AirbaseFound = _DATABASE:FindAirbase( AirbaseName )
|
||||
return AirbaseFound
|
||||
end
|
||||
@@ -378,18 +378,18 @@ end
|
||||
-- @param #number id Airbase ID.
|
||||
-- @return #AIRBASE self
|
||||
function AIRBASE:FindByID(id)
|
||||
|
||||
|
||||
for name,_airbase in pairs(_DATABASE.AIRBASES) do
|
||||
local airbase=_airbase --#AIRBASE
|
||||
|
||||
|
||||
local aid=tonumber(airbase:GetID())
|
||||
|
||||
|
||||
if aid==id then
|
||||
return airbase
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
@@ -398,11 +398,11 @@ end
|
||||
-- @return DCS#Airbase DCS airbase object.
|
||||
function AIRBASE:GetDCSObject()
|
||||
local DCSAirbase = Airbase.getByName( self.AirbaseName )
|
||||
|
||||
|
||||
if DCSAirbase then
|
||||
return DCSAirbase
|
||||
end
|
||||
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
@@ -418,7 +418,7 @@ end
|
||||
-- @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, category)
|
||||
|
||||
|
||||
local airbases={}
|
||||
for _,_airbase in pairs(_DATABASE.AIRBASES) do
|
||||
local airbase=_airbase --#AIRBASE
|
||||
@@ -428,28 +428,28 @@ function AIRBASE.GetAllAirbases(coalition, category)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return airbases
|
||||
end
|
||||
|
||||
|
||||
--- Returns a table of parking data for a given airbase. If the optional parameter *available* is true only available parking will be returned, otherwise all parking at the base is returned. Term types have the following enumerated values:
|
||||
--
|
||||
--
|
||||
-- * 16 : Valid spawn points on runway
|
||||
-- * 40 : Helicopter only spawn
|
||||
-- * 40 : Helicopter only spawn
|
||||
-- * 68 : Hardened Air Shelter
|
||||
-- * 72 : Open/Shelter air airplane only
|
||||
-- * 104: Open air spawn
|
||||
--
|
||||
--
|
||||
-- Note that only Caucuses will return 68 as it is the only map currently with hardened air shelters.
|
||||
-- 104 are also generally larger, but does not guarantee a large aircraft like the B-52 or a C-130 are capable of spawning there.
|
||||
--
|
||||
--
|
||||
-- Table entries:
|
||||
--
|
||||
--
|
||||
-- * Term_index is the id for the parking
|
||||
-- * vTerminal pos is its vec3 position in the world
|
||||
-- * fDistToRW is the distance to the take-off position for the active runway from the parking.
|
||||
--
|
||||
--
|
||||
-- @param #AIRBASE self
|
||||
-- @param #boolean available If true, only available parking spots will be returned.
|
||||
-- @return #table Table with parking data. See https://wiki.hoggitworld.com/view/DCS_func_getParking
|
||||
@@ -458,13 +458,13 @@ function AIRBASE:GetParkingData(available)
|
||||
|
||||
-- Get DCS airbase object.
|
||||
local DCSAirbase=self:GetDCSObject()
|
||||
|
||||
|
||||
-- Get parking data.
|
||||
local parkingdata=nil
|
||||
if DCSAirbase then
|
||||
parkingdata=DCSAirbase:getParking(available)
|
||||
end
|
||||
|
||||
|
||||
self:T2({parkingdata=parkingdata})
|
||||
return parkingdata
|
||||
end
|
||||
@@ -477,27 +477,27 @@ function AIRBASE:GetParkingSpotsNumber(termtype)
|
||||
|
||||
-- Get free parking spots data.
|
||||
local parkingdata=self:GetParkingData(false)
|
||||
|
||||
|
||||
local nspots=0
|
||||
for _,parkingspot in pairs(parkingdata) do
|
||||
if AIRBASE._CheckTerminalType(parkingspot.Term_Type, termtype) then
|
||||
nspots=nspots+1
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return nspots
|
||||
end
|
||||
|
||||
--- Get number of free parking spots at an airbase.
|
||||
-- @param #AIRBASE self
|
||||
-- @param #AIRBASE.TerminalType termtype Terminal type.
|
||||
-- @param #boolean allowTOAC If true, spots are considered free even though TO_AC is true. Default is off which is saver to avoid spawning aircraft on top of each other. Option might be enabled for FARPS and ships.
|
||||
-- @param #boolean allowTOAC If true, spots are considered free even though TO_AC is true. Default is off which is saver to avoid spawning aircraft on top of each other. Option might be enabled for FARPS and ships.
|
||||
-- @return #number Number of free parking spots at this airbase.
|
||||
function AIRBASE:GetFreeParkingSpotsNumber(termtype, allowTOAC)
|
||||
|
||||
-- Get free parking spots data.
|
||||
local parkingdata=self:GetParkingData(true)
|
||||
|
||||
|
||||
local nfree=0
|
||||
for _,parkingspot in pairs(parkingdata) do
|
||||
-- Spots on runway are not counted unless explicitly requested.
|
||||
@@ -507,7 +507,7 @@ function AIRBASE:GetFreeParkingSpotsNumber(termtype, allowTOAC)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return nfree
|
||||
end
|
||||
|
||||
@@ -520,7 +520,7 @@ function AIRBASE:GetFreeParkingSpotsCoordinates(termtype, allowTOAC)
|
||||
|
||||
-- Get free parking spots data.
|
||||
local parkingdata=self:GetParkingData(true)
|
||||
|
||||
|
||||
-- Put coordinates of free spots into table.
|
||||
local spots={}
|
||||
for _,parkingspot in pairs(parkingdata) do
|
||||
@@ -531,7 +531,7 @@ function AIRBASE:GetFreeParkingSpotsCoordinates(termtype, allowTOAC)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return spots
|
||||
end
|
||||
|
||||
@@ -543,23 +543,23 @@ function AIRBASE:GetParkingSpotsCoordinates(termtype)
|
||||
|
||||
-- Get all parking spots data.
|
||||
local parkingdata=self:GetParkingData(false)
|
||||
|
||||
|
||||
-- Put coordinates of free spots into table.
|
||||
local spots={}
|
||||
for _,parkingspot in ipairs(parkingdata) do
|
||||
|
||||
|
||||
-- Coordinates on runway are not returned unless explicitly requested.
|
||||
if AIRBASE._CheckTerminalType(parkingspot.Term_Type, termtype) then
|
||||
|
||||
|
||||
-- Get coordinate from Vec3 terminal position.
|
||||
local _coord=COORDINATE:NewFromVec3(parkingspot.vTerminalPos)
|
||||
|
||||
|
||||
-- Add to table.
|
||||
table.insert(spots, _coord)
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
return spots
|
||||
end
|
||||
|
||||
@@ -570,11 +570,11 @@ end
|
||||
-- @return #table Table free parking spots. Table has the elements ".Coordinate, ".TerminalID", ".TerminalType", ".TOAC", ".Free", ".TerminalID0", ".DistToRwy".
|
||||
function AIRBASE:GetParkingSpotsTable(termtype)
|
||||
|
||||
-- Get parking data of all spots (free or occupied)
|
||||
-- Get parking data of all spots (free or occupied)
|
||||
local parkingdata=self:GetParkingData(false)
|
||||
-- Get parking data of all free spots.
|
||||
local parkingfree=self:GetParkingData(true)
|
||||
|
||||
|
||||
-- Function to ckeck if any parking spot is free.
|
||||
local function _isfree(_tocheck)
|
||||
for _,_spot in pairs(parkingfree) do
|
||||
@@ -584,7 +584,7 @@ function AIRBASE:GetParkingSpotsTable(termtype)
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
-- Put coordinates of parking spots into table.
|
||||
local spots={}
|
||||
for _,_spot in pairs(parkingdata) do
|
||||
@@ -595,22 +595,22 @@ function AIRBASE:GetParkingSpotsTable(termtype)
|
||||
table.insert(spots, {Coordinate=_coord, TerminalID=_spot.Term_Index, TerminalType=_spot.Term_Type, TOAC=_spot.TO_AC, Free=_free, TerminalID0=_spot.Term_Index_0, DistToRwy=_spot.fDistToRW})
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
self:T2({ spots = spots } )
|
||||
|
||||
|
||||
return spots
|
||||
end
|
||||
|
||||
--- Get a table containing the coordinates, terminal index and terminal type of free parking spots at an airbase.
|
||||
-- @param #AIRBASE self
|
||||
-- @param #AIRBASE.TerminalType termtype Terminal type.
|
||||
-- @param #boolean allowTOAC If true, spots are considered free even though TO_AC is true. Default is off which is saver to avoid spawning aircraft on top of each other. Option might be enabled for FARPS and ships.
|
||||
-- @param #boolean allowTOAC If true, spots are considered free even though TO_AC is true. Default is off which is saver to avoid spawning aircraft on top of each other. Option might be enabled for FARPS and ships.
|
||||
-- @return #table Table free parking spots. Table has the elements ".Coordinate, ".TerminalID", ".TerminalType", ".TOAC", ".Free", ".TerminalID0", ".DistToRwy".
|
||||
function AIRBASE:GetFreeParkingSpotsTable(termtype, allowTOAC)
|
||||
|
||||
-- Get parking data of all free spots.
|
||||
local parkingfree=self:GetParkingData(true)
|
||||
|
||||
|
||||
-- Put coordinates of free spots into table.
|
||||
local freespots={}
|
||||
for _,_spot in pairs(parkingfree) do
|
||||
@@ -621,7 +621,7 @@ function AIRBASE:GetFreeParkingSpotsTable(termtype, allowTOAC)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
return freespots
|
||||
end
|
||||
|
||||
@@ -634,10 +634,10 @@ function AIRBASE:GetParkingSpotData(TerminalID)
|
||||
|
||||
-- Get parking data.
|
||||
local parkingdata=self:GetParkingSpotsTable()
|
||||
|
||||
|
||||
-- Debug output.
|
||||
self:T2({parkingdata=parkingdata})
|
||||
|
||||
|
||||
for _,_spot in pairs(parkingdata) do
|
||||
local spot=_spot --#AIRBASE.ParkingSpot
|
||||
self:T({TerminalID=spot.TerminalID,TerminalType=spot.TerminalType})
|
||||
@@ -645,7 +645,7 @@ function AIRBASE:GetParkingSpotData(TerminalID)
|
||||
return spot
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
self:E("ERROR: Could not find spot with Terminal ID="..tostring(TerminalID))
|
||||
return nil
|
||||
end
|
||||
@@ -667,18 +667,18 @@ function AIRBASE:MarkParkingSpots(termtype, mark)
|
||||
-- Get airbase name.
|
||||
local airbasename=self:GetName()
|
||||
self:E(string.format("Parking spots at %s for termial type %s:", airbasename, tostring(termtype)))
|
||||
|
||||
|
||||
for _,_spot in pairs(parkingdata) do
|
||||
|
||||
|
||||
-- Mark text.
|
||||
local _text=string.format("Term Index=%d, Term Type=%d, Free=%s, TOAC=%s, Term ID0=%d, Dist2Rwy=%.1f m",
|
||||
_spot.TerminalID, _spot.TerminalType,tostring(_spot.Free),tostring(_spot.TOAC),_spot.TerminalID0,_spot.DistToRwy)
|
||||
|
||||
|
||||
-- Create mark on the F10 map.
|
||||
if mark then
|
||||
_spot.Coordinate:MarkToAll(_text)
|
||||
end
|
||||
|
||||
|
||||
-- Info to DCS.log file.
|
||||
local _text=string.format("%s, Term Index=%3d, Term Type=%03d, Free=%5s, TOAC=%5s, Term ID0=%3d, Dist2Rwy=%.1f m",
|
||||
airbasename, _spot.TerminalID, _spot.TerminalType,tostring(_spot.Free),tostring(_spot.TOAC),_spot.TerminalID0,_spot.DistToRwy)
|
||||
@@ -696,7 +696,7 @@ end
|
||||
-- @param #boolean scanstatics (Optional) Scan for statics as obstacles. Default true.
|
||||
-- @param #boolean scanscenery (Optional) Scan for scenery as obstacles. Default false. Can cause problems with e.g. shelters.
|
||||
-- @param #boolean verysafe (Optional) If true, wait until an aircraft has taken off until the parking spot is considered to be free. Defaul false.
|
||||
-- @param #number nspots (Optional) Number of freeparking spots requested. Default is the number of aircraft in the group.
|
||||
-- @param #number nspots (Optional) Number of freeparking spots requested. Default is the number of aircraft in the group.
|
||||
-- @param #table parkingdata (Optional) Parking spots data table. If not given it is automatically derived from the GetParkingSpotsTable() function.
|
||||
-- @return #table Table of coordinates and terminal IDs of free parking spots. Each table entry has the elements .Coordinate and .TerminalID.
|
||||
function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius, scanunits, scanstatics, scanscenery, verysafe, nspots, parkingdata)
|
||||
@@ -714,8 +714,8 @@ function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius,
|
||||
end
|
||||
if verysafe==nil then
|
||||
verysafe=false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Function calculating the overlap of two (square) objects.
|
||||
local function _overlap(object1, object2, dist)
|
||||
local pos1=object1 --Wrapper.Positionable#POSITIONABLE
|
||||
@@ -723,107 +723,107 @@ function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius,
|
||||
local r1=pos1:GetBoundingRadius()
|
||||
local r2=pos2:GetBoundingRadius()
|
||||
if r1 and r2 then
|
||||
local safedist=(r1+r2)*1.1
|
||||
local safedist=(r1+r2)*1.1
|
||||
local safe = (dist > safedist)
|
||||
self:T2(string.format("r1=%.1f r2=%.1f s=%.1f d=%.1f ==> safe=%s", r1, r2, safedist, dist, tostring(safe)))
|
||||
return safe
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Get airport name.
|
||||
local airport=self:GetName()
|
||||
|
||||
|
||||
-- Get parking spot data table. This contains free and "non-free" spots.
|
||||
-- Note that there are three major issues with the DCS getParking() function:
|
||||
-- 1. A spot is considered as NOT free until an aircraft that is present has finally taken off. This might be a bit long especiall at smaller airports.
|
||||
-- 2. A "free" spot does not take the aircraft size into accound. So if two big aircraft are spawned on spots next to each other, they might overlap and get destroyed.
|
||||
-- 3. The routine return a free spot, if there a static objects placed on the spot.
|
||||
parkingdata=parkingdata or self:GetParkingSpotsTable(terminaltype)
|
||||
|
||||
|
||||
-- Get the aircraft size, i.e. it's longest side of x,z.
|
||||
local aircraft=group:GetUnit(1)
|
||||
local _aircraftsize, ax,ay,az=aircraft:GetObjectSize()
|
||||
|
||||
|
||||
-- Number of spots we are looking for. Note that, e.g. grouping can require a number different from the group size!
|
||||
local _nspots=nspots or group:GetSize()
|
||||
|
||||
|
||||
-- Debug info.
|
||||
self:E(string.format("%s: Looking for %d parking spot(s) for aircraft of size %.1f m (x=%.1f,y=%.1f,z=%.1f) at termial type %s.", airport, _nspots, _aircraftsize, ax, ay, az, tostring(terminaltype)))
|
||||
|
||||
|
||||
-- Table of valid spots.
|
||||
local validspots={}
|
||||
local nvalid=0
|
||||
|
||||
|
||||
-- Test other stuff if no parking spot is available.
|
||||
local _test=false
|
||||
if _test then
|
||||
return validspots
|
||||
end
|
||||
|
||||
|
||||
-- Mark all found obstacles on F10 map for debugging.
|
||||
local markobstacles=false
|
||||
|
||||
|
||||
-- Loop over all known parking spots
|
||||
for _,parkingspot in pairs(parkingdata) do
|
||||
|
||||
|
||||
-- Coordinate of the parking spot.
|
||||
local _spot=parkingspot.Coordinate -- Core.Point#COORDINATE
|
||||
local _termid=parkingspot.TerminalID
|
||||
|
||||
|
||||
self:T2({_termid=_termid})
|
||||
|
||||
|
||||
if AIRBASE._CheckTerminalType(parkingspot.TerminalType, terminaltype) then
|
||||
|
||||
|
||||
-- Very safe uses the DCS getParking() info to check if a spot is free. Unfortunately, the function returns free=false until the aircraft has actually taken-off.
|
||||
if verysafe and (parkingspot.Free==false or parkingspot.TOAC==true) then
|
||||
|
||||
|
||||
-- DCS getParking() routine returned that spot is not free.
|
||||
self:T(string.format("%s: Parking spot id %d NOT free (or aircraft has not taken off yet). Free=%s, TOAC=%s.", airport, parkingspot.TerminalID, tostring(parkingspot.Free), tostring(parkingspot.TOAC)))
|
||||
|
||||
|
||||
else
|
||||
|
||||
|
||||
-- Scan a radius of 50 meters around the spot.
|
||||
local _,_,_,_units,_statics,_sceneries=_spot:ScanObjects(scanradius, scanunits, scanstatics, scanscenery)
|
||||
|
||||
|
||||
-- Loop over objects within scan radius.
|
||||
local occupied=false
|
||||
|
||||
-- Check all units.
|
||||
|
||||
-- Check all units.
|
||||
for _,unit in pairs(_units) do
|
||||
local _coord=unit:GetCoordinate()
|
||||
local _dist=_coord:Get2DDistance(_spot)
|
||||
local _dist=_coord:Get2DDistance(_spot)
|
||||
local _safe=_overlap(aircraft, unit, _dist)
|
||||
|
||||
|
||||
if markobstacles then
|
||||
local l,x,y,z=unit:GetObjectSize()
|
||||
_coord:MarkToAll(string.format("Unit %s\nx=%.1f y=%.1f z=%.1f\nl=%.1f d=%.1f\nspot %d safe=%s", unit:GetName(),x,y,z,l,_dist, _termid, tostring(_safe)))
|
||||
end
|
||||
|
||||
|
||||
if scanunits and not _safe then
|
||||
occupied=true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Check all statics.
|
||||
for _,static in pairs(_statics) do
|
||||
local _static=STATIC:Find(static)
|
||||
local _vec3=static:getPoint()
|
||||
local _coord=COORDINATE:NewFromVec3(_vec3)
|
||||
local _dist=_coord:Get2DDistance(_spot)
|
||||
local _dist=_coord:Get2DDistance(_spot)
|
||||
local _safe=_overlap(aircraft,_static,_dist)
|
||||
|
||||
|
||||
if markobstacles then
|
||||
local l,x,y,z=_static:GetObjectSize()
|
||||
_coord:MarkToAll(string.format("Static %s\nx=%.1f y=%.1f z=%.1f\nl=%.1f d=%.1f\nspot %d safe=%s", static:getName(),x,y,z,l,_dist, _termid, tostring(_safe)))
|
||||
end
|
||||
|
||||
|
||||
if scanstatics and not _safe then
|
||||
occupied=true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Check all scenery.
|
||||
for _,scenery in pairs(_sceneries) do
|
||||
local _scenery=SCENERY:Register(scenery:getTypeName(), scenery)
|
||||
@@ -831,17 +831,17 @@ function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius,
|
||||
local _coord=COORDINATE:NewFromVec3(_vec3)
|
||||
local _dist=_coord:Get2DDistance(_spot)
|
||||
local _safe=_overlap(aircraft,_scenery,_dist)
|
||||
|
||||
|
||||
if markobstacles then
|
||||
local l,x,y,z=scenery:GetObjectSize(scenery)
|
||||
_coord:MarkToAll(string.format("Scenery %s\nx=%.1f y=%.1f z=%.1f\nl=%.1f d=%.1f\nspot %d safe=%s", scenery:getTypeName(),x,y,z,l,_dist, _termid, tostring(_safe)))
|
||||
end
|
||||
|
||||
|
||||
if scanscenery and not _safe then
|
||||
occupied=true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Now check the already given spots so that we do not put a large aircraft next to one we already assigned a nearby spot.
|
||||
for _,_takenspot in pairs(validspots) do
|
||||
local _dist=_takenspot.Coordinate:Get2DDistance(_spot)
|
||||
@@ -850,7 +850,7 @@ function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius,
|
||||
occupied=true
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--_spot:MarkToAll(string.format("Parking spot %d free=%s", parkingspot.TerminalID, tostring(not occupied)))
|
||||
if occupied then
|
||||
self:I(string.format("%s: Parking spot id %d occupied.", airport, _termid))
|
||||
@@ -862,16 +862,16 @@ function AIRBASE:FindFreeParkingSpotForAircraft(group, terminaltype, scanradius,
|
||||
nvalid=nvalid+1
|
||||
self:I(string.format("%s: Parking spot id %d free. Nfree=%d/%d.", airport, _termid, nvalid,_nspots))
|
||||
end
|
||||
|
||||
|
||||
end -- loop over units
|
||||
|
||||
|
||||
-- We found enough spots.
|
||||
if nvalid>=_nspots then
|
||||
return validspots
|
||||
end
|
||||
end -- check terminal type
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Retrun spots we found, even if there were not enough.
|
||||
return validspots
|
||||
end
|
||||
@@ -880,54 +880,54 @@ end
|
||||
-- @param #AIRBASE self
|
||||
-- @param Wrapper.Group#GROUP group Group to be checked.
|
||||
-- @param #number radius Radius around the spawn point to be checked. Default is 50 m.
|
||||
-- @param #boolean despawn If true, the group is destroyed.
|
||||
-- @param #boolean despawn If true, the group is destroyed.
|
||||
-- @return #boolean True if group is within radius around spawn points on runway.
|
||||
function AIRBASE:CheckOnRunWay(group, radius, despawn)
|
||||
|
||||
-- Default radius.
|
||||
radius=radius or 50
|
||||
|
||||
|
||||
-- We only check at real airbases (not FARPS or ships).
|
||||
if self:GetDesc().category~=Airbase.Category.AIRDROME then
|
||||
return false
|
||||
end
|
||||
|
||||
if group and group:IsAlive() then
|
||||
|
||||
|
||||
-- Debug.
|
||||
self:T(string.format("%s, checking if group %s is on runway?",self:GetName(), group:GetName()))
|
||||
|
||||
|
||||
-- Get coordinates on runway.
|
||||
local runwaypoints=self:GetParkingSpotsCoordinates(AIRBASE.TerminalType.Runway)
|
||||
|
||||
|
||||
-- Mark runway spawn points.
|
||||
--[[
|
||||
for _i,_coord in pairs(runwaypoints) do
|
||||
_coord:MarkToAll(string.format("runway %d",_i))
|
||||
end
|
||||
]]
|
||||
|
||||
|
||||
-- Get units of group.
|
||||
local units=group:GetUnits()
|
||||
|
||||
|
||||
-- Loop over units.
|
||||
for _,_unit in pairs(units) do
|
||||
|
||||
|
||||
local unit=_unit --Wrapper.Unit#UNIT
|
||||
|
||||
|
||||
-- Check if unit is alive and not in air.
|
||||
if unit and unit:IsAlive() and not unit:InAir() then
|
||||
self:T(string.format("%s, checking if unit %s is on runway?",self:GetName(), unit:GetName()))
|
||||
|
||||
|
||||
-- Loop over runway spawn points.
|
||||
for _i,_coord in pairs(runwaypoints) do
|
||||
|
||||
-- Distance between unit and spawn pos.
|
||||
local dist=unit:GetCoordinate():Get2DDistance(_coord)
|
||||
|
||||
|
||||
-- Mark unit spawn points for debugging.
|
||||
--unit:GetCoordinate():MarkToAll(string.format("unit %s distance to rwy %d = %d",unit:GetName(),_i, dist))
|
||||
|
||||
|
||||
-- Check if unit is withing radius.
|
||||
if dist<radius then
|
||||
self:E(string.format("%s, unit %s of group %s was spawned on runway #%d. Distance %.1f < radius %.1f m. Despawn = %s.", self:GetName(), unit:GetName(), group:GetName(),_i, dist, radius, tostring(despawn)))
|
||||
@@ -940,16 +940,16 @@ function AIRBASE:CheckOnRunWay(group, radius, despawn)
|
||||
self:T(string.format("%s, unit %s of group %s was NOT spawned on runway #%d. Distance %.1f > radius %.1f m. Despawn = %s.", self:GetName(), unit:GetName(), group:GetName(),_i, dist, radius, tostring(despawn)))
|
||||
--unit:FlareGreen()
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
else
|
||||
self:T(string.format("%s, checking if unit %s of group %s is on runway. Unit is NOT alive.",self:GetName(), unit:GetName(), group:GetName()))
|
||||
end
|
||||
self:T(string.format("%s, checking if unit %s of group %s is on runway. Unit is NOT alive.",self:GetName(), unit:GetName(), group:GetName()))
|
||||
end
|
||||
end
|
||||
else
|
||||
self:T(string.format("%s, checking if group %s is on runway. Group is NOT alive.",self:GetName(), group:GetName()))
|
||||
end
|
||||
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
@@ -980,15 +980,15 @@ function AIRBASE._CheckTerminalType(Term_Type, termtype)
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- Init no match.
|
||||
local match=false
|
||||
|
||||
-- Standar case.
|
||||
|
||||
-- Standar case.
|
||||
if Term_Type==termtype then
|
||||
match=true
|
||||
end
|
||||
|
||||
|
||||
-- Artificial cases. Combination of terminal types.
|
||||
if termtype==AIRBASE.TerminalType.OpenMedOrBig then
|
||||
if Term_Type==AIRBASE.TerminalType.OpenMed or Term_Type==AIRBASE.TerminalType.OpenBig then
|
||||
@@ -1003,114 +1003,119 @@ function AIRBASE._CheckTerminalType(Term_Type, termtype)
|
||||
match=true
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
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)
|
||||
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
|
||||
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"
|
||||
|
||||
-- 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.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
|
||||
runway.position:MarkToAll(string.format("Runway %s Heading=%03d", runway.idx, runway.heading))
|
||||
|
||||
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
|
||||
|
||||
local runway={} --#AIRBASE.Runway
|
||||
runway.heading=r.heading-180
|
||||
if runway.heading<0 then
|
||||
runway.heading=runway.heading+360
|
||||
end
|
||||
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
|
||||
runway.position:MarkToAll(string.format("Runway %s Heading=%03d", runway.idx, runway.heading))
|
||||
|
||||
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)
|
||||
table.insert(inverse, runway)
|
||||
end
|
||||
|
||||
|
||||
-- Add inverse runway.
|
||||
for _,runway in pairs(inverse) do
|
||||
-- Add runway.
|
||||
table.insert(runways, runway)
|
||||
table.insert(runways, runway)
|
||||
end
|
||||
|
||||
|
||||
return runways
|
||||
end
|
||||
|
||||
@@ -1138,48 +1143,45 @@ function AIRBASE:GetActiveRunway(magvar)
|
||||
-- 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))
|
||||
|
||||
--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
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user