Updated detection algorithm

Now the detected sets are kept consistent to previous sets. New
algorithm developed. This is important to keep assigned tasks consistent
with the detected sets.
This commit is contained in:
FlightControl
2016-07-10 09:11:05 +02:00
parent 40a9c1f7d1
commit 17abcb7b7f
19 changed files with 812 additions and 51696 deletions

View File

@@ -73,23 +73,26 @@
-- @type DETECTION_BASE
-- @field Group#GROUP DetectionGroups The GROUP in the Forward Air Controller role.
-- @field DCSTypes#Distance DetectionRange The range till which targets are accepted to be detected.
-- @field #DETECTION_BASE.DetectedSets DetectedSets A list of @{Set#SET_BASE}s containing the objects in each set that were detected. The base class will not build the detected sets, but will leave that to the derived classes.
-- @field #DETECTION_BASE.DetectedObjects DetectedObjects The list of detected objects.
-- @field #number DetectionRun
-- @extends Base#BASE
DETECTION_BASE = {
ClassName = "DETECTION_BASE",
DetectedSets = {},
DetectedObjects = {},
DetectionGroups = nil,
DetectionRange = nil,
DetectedObjects = {},
DetectionRun = 0,
}
--- @type DETECTION_BASE.DetectedSets
-- @list <Set#SET_BASE>
--- @type DETECTION_BASE.DetectedZones
-- @list <Zone#ZONE_BASE>
--- @type DETECTION_BASE.DetectedObjects
-- @list <#DETECTION_BASE.DetectedObject>
--- @type DETECTION_BASE.DetectedObject
-- @field #string Name
-- @field #boolean Visible
-- @field #string Type
-- @field #number Distance
-- @field #boolean Identified
--- DETECTION constructor.
-- @param #DETECTION_BASE self
@@ -173,13 +176,19 @@ function DETECTION_BASE:InitDetectDLINK( DetectDLINK )
self.DetectDLINK = DetectDLINK
end
--- Gets the Detection group.
--- Gets a detected object with a given name.
-- @param #DETECTION_BASE self
-- @return Group#GROUP self
function DETECTION_BASE:GetDetectionGroups()
self:F2()
return self.DetectionGroups
-- @param #string ObjectName
-- @return #DETECTION_BASE.DetectedObject
function DETECTION_BASE:GetDetectedObject( ObjectName )
self:F( ObjectName )
if ObjectName then
local DetectedObject = self.DetectedObjects[ObjectName]
return DetectedObject
end
return nil
end
--- Get the detected @{Set#SET_BASE}s.
@@ -214,13 +223,13 @@ function DETECTION_BASE:GetDetectedSet( Index )
return nil
end
--- Get the detected @{Zone}s.
--- Get the detection Groups.
-- @param #DETECTION_BASE self
-- @return #DETECTION_BASE.DetectedZones DetectedZones
function DETECTION_BASE:GetDetectedZones()
-- @return Group#GROUP
function DETECTION_BASE:GetDetectionGroups()
local DetectionZones = self.DetectedZones
return DetectionZones
local DetectionGroups = self.DetectionGroups
return DetectionGroups
end
--- Make a DetectionSet table. This function will be overridden in the derived clsses.
@@ -255,8 +264,7 @@ function DETECTION_BASE:_DetectionScheduler( SchedulerName )
self:F2( { SchedulerName } )
self.DetectedObjects = {}
self.DetectedSets = {}
self.DetectedZones = {}
self.DetectionRun = self.DetectionRun + 1
if self.DetectionGroups:IsAlive() then
local DetectionGroupsName = self.DetectionGroups:GetName()
@@ -286,7 +294,7 @@ function DETECTION_BASE:_DetectionScheduler( SchedulerName )
( DetectionDetectedObjectPositionVec3.z - DetectionGroupsPositionVec3.z )^2
) ^ 0.5 / 1000
self:T( { DetectionGroupsName, DetectionDetectedObjectName, Distance } )
self:T2( { DetectionGroupsName, DetectionDetectedObjectName, Distance } )
if Distance <= self.DetectionRange then
@@ -297,6 +305,7 @@ function DETECTION_BASE:_DetectionScheduler( SchedulerName )
self.DetectedObjects[DetectionDetectedObjectName].Visible = DetectionDetectedTarget.visible
self.DetectedObjects[DetectionDetectedObjectName].Type = DetectionDetectedTarget.type
self.DetectedObjects[DetectionDetectedObjectName].Distance = DetectionDetectedTarget.distance
self.DetectedObjects[DetectionDetectedObjectName].Identified = false -- This flag is used to control identification.
else
-- if beyond the DetectionRange then nullify...
if self.DetectedObjects[DetectionDetectedObjectName] then
@@ -324,27 +333,26 @@ function DETECTION_BASE:_DetectionScheduler( SchedulerName )
end
end
--- @type DETECTION_UNITGROUPS.DetectedSets
-- @list <Set#SET_UNIT>
--
--- @type DETECTION_UNITGROUPS.DetectedZones
-- @list <Zone#ZONE_UNIT>
--
--- DETECTION_UNITGROUPS class
-- @type DETECTION_UNITGROUPS
-- @param DCSTypes#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target.
-- @field #DETECTION_UNITGROUPS.DetectedSets DetectedSets A list of @{Set#SET_UNIT}s containing the units in each set that were detected within a DetectionZoneRange.
-- @field #DETECTION_UNITGROUPS.DetectedZones DetectedZones A list of @{Zone#ZONE_UNIT}s containing the zones of the reference detected units.
-- @field DCSTypes#Distance DetectionZoneRange The range till which targets are grouped upon the first detected target.
-- @field #DETECTION_UNITGROUPS.DetectedAreas DetectedAreas A list of areas containing the set of @{Unit}s, @{Zone}s, the center @{Unit} within the zone, and ID of each area that was detected within a DetectionZoneRange.
-- @extends Detection#DETECTION_BASE
DETECTION_UNITGROUPS = {
ClassName = "DETECTION_UNITGROUPS",
DetectedZones = {},
DetectedAreas = { n = 0 },
DetectionZoneRange = nil,
}
--- @type DETECTION_UNITGROUPS.DetectedAreas
-- @list <#DETECTION_UNITGROUPS.DetectedArea>
--- @type DETECTION_UNITGROUPS.DetectedArea
-- @field Set#SET_UNIT Set -- The Set of Units in the detected area.
-- @field Zone#ZONE_UNIT Zone -- The Zone of the detected area.
-- @field #number AreaID -- The identifier of the detected area.
--- DETECTION_UNITGROUPS constructor.
@@ -357,6 +365,7 @@ function DETECTION_UNITGROUPS:New( DetectionGroups, DetectionRange, DetectionZon
-- Inherits from DETECTION_BASE
local self = BASE:Inherit( self, DETECTION_BASE:New( DetectionGroups, DetectionRange ) )
self.DetectionZoneRange = DetectionZoneRange
self:Schedule( 10, 30 )
@@ -364,31 +373,73 @@ function DETECTION_UNITGROUPS:New( DetectionGroups, DetectionRange, DetectionZon
return self
end
--- Get the detected @{Zone#ZONE_UNIT}s.
-- @param #DETECTION_UNITGROUPS self
-- @return #DETECTION_UNITGROUPS.DetectedZones DetectedZones
function DETECTION_UNITGROUPS:GetDetectedZones()
local DetectedZones = self.DetectedZones
return DetectedZones
--- Add a detected @{#DETECTION_UNITGROUPS.DetectedArea}.
-- @param Set#SET_UNIT Set -- The Set of Units in the detected area.
-- @param Zone#ZONE_UNIT Zone -- The Zone of the detected area.
-- @return #DETECTION_UNITGROUPS.DetectedArea DetectedArea
function DETECTION_UNITGROUPS:AddDetectedArea( Set, Zone )
local DetectedAreas = self:GetDetectedAreas()
DetectedAreas.n = self:GetDetectedAreaCount() + 1
DetectedAreas[DetectedAreas.n] = {}
local DetectedArea = DetectedAreas[DetectedAreas.n]
DetectedArea.Set = Set
DetectedArea.Zone = Zone
DetectedArea.AreaID = #DetectedAreas
return DetectedArea
end
--- Get the amount of @{Zone#ZONE_UNIT}s with detected units.
--- Remove a detected @{#DETECTION_UNITGROUPS.DetectedArea} with a given Index.
-- @param #DETECTION_UNITGROUPS self
-- @return #number Count
function DETECTION_UNITGROUPS:GetDetectedZoneCount()
local DetectedZoneCount = #self.DetectedZones
return DetectedZoneCount
-- @param #number Index The Index of the detection are to be removed.
-- @return #nil
function DETECTION_UNITGROUPS:RemoveDetectedArea( Index )
local DetectedAreas = self:GetDetectedAreas()
local DetectedAreaCount = self:GetDetectedAreaCount()
DetectedAreas[Index] = nil
DetectedAreas.n = DetectedAreas.n - 1
return nil
end
--- Get a SET of detected objects using a given numeric index.
--- Get the detected @{#DETECTION_UNITGROUPS.DetectedAreas}.
-- @param #DETECTION_UNITGROUPS self
-- @return #DETECTION_UNITGROUPS.DetectedAreas DetectedAreas
function DETECTION_UNITGROUPS:GetDetectedAreas()
local DetectedAreas = self.DetectedAreas
return DetectedAreas
end
--- Get the amount of @{#DETECTION_UNITGROUPS.DetectedAreas}.
-- @param #DETECTION_UNITGROUPS self
-- @return #number DetectedAreaCount
function DETECTION_UNITGROUPS:GetDetectedAreaCount()
local DetectedAreaCount = self.DetectedAreas.n
return DetectedAreaCount
end
--- Get the @{Set#SET_UNIT} of a detecttion area using a given numeric index.
-- @param #DETECTION_UNITGROUPS self
-- @param #number Index
-- @return Zone#ZONE_UNIT
-- @return Set#SET_UNIT DetectedSet
function DETECTION_UNITGROUPS:GetDetectedSet( Index )
local DetectedSetUnit = self.DetectedAreas[Index].Set
if DetectedSetUnit then
return DetectedSetUnit
end
return nil
end
--- Get the @{Zone#ZONE_UNIT} of a detection area using a given numeric index.
-- @param #DETECTION_UNITGROUPS self
-- @param #number Index
-- @return Zone#ZONE_UNIT DetectedZone
function DETECTION_UNITGROUPS:GetDetectedZone( Index )
local DetectedZone = self.DetectedZones[Index]
local DetectedZone = self.DetectedAreas[Index].Zone
if DetectedZone then
return DetectedZone
end
@@ -396,6 +447,7 @@ function DETECTION_UNITGROUPS:GetDetectedZone( Index )
return nil
end
--- Smoke the detected units
-- @param #DETECTION_UNITGROUPS self
-- @return #DETECTION_UNITGROUPS self
@@ -443,34 +495,126 @@ end
function DETECTION_UNITGROUPS:CreateDetectionSets()
self:F2()
for DetectedUnitName, DetectedUnitData in pairs( self.DetectedObjects ) do
self:T( DetectedUnitData.Name )
local DetectedUnit = UNIT:FindByName( DetectedUnitData.Name ) -- Unit#UNIT
if DetectedUnit and DetectedUnit:IsAlive() then
self:T( DetectedUnit:GetName() )
if #self.DetectedSets == 0 then
self:T( { "Adding Unit Set #", 1 } )
self.DetectedZones[1] = ZONE_UNIT:New( DetectedUnitName, DetectedUnit, self.DetectionZoneRange )
self.DetectedSets[1] = SET_UNIT:New()
self.DetectedSets[1]:AddUnit( DetectedUnit )
-- First go through all detected sets, and check if there are new detected units, match all existing detected units and identify undetected units.
-- Regroup when needed, split groups when needed.
for DetectedAreaID, DetectedAreaData in ipairs( self.DetectedAreas ) do
local DetectedArea = DetectedAreaData -- #DETECTION_UNITGROUPS.DetectedArea
if DetectedArea then
local DetectedSet = DetectedArea.Set
local DetectedZone = DetectedArea.Zone
-- first test if the center unit is detected in the detection area.
local AreaExists = false -- This flag will determine of the detected area is still existing.
local DetectedObject = self:GetDetectedObject( DetectedArea.Zone.ZoneUNIT.UnitName )
self:T( DetectedObject )
if DetectedObject then
DetectedObject.Identified = true
AreaExists = true
self:T( { DetectedArea = DetectedArea.AreaID, "Detected Center Unit " .. DetectedArea.Zone.ZoneUNIT.UnitName } )
else
local AddedToSet = false
for DetectedZoneIndex = 1, #self.DetectedZones do
self:T( "Detected Unit Set #" .. DetectedZoneIndex )
local DetectedUnitSet = self.DetectedSets[DetectedZoneIndex] -- Set#SET_BASE
local DetectedZone = self.DetectedZones[DetectedZoneIndex] -- Zone#ZONE_UNIT
if DetectedUnit:IsInZone( DetectedZone ) then
self:T( "Adding to Unit Set #" .. DetectedZoneIndex )
DetectedUnitSet:AddUnit( DetectedUnit )
AddedToSet = true
-- The center object of the detected area has not been detected. Find an other unit of the set to become the center of the area.
-- First remove the center unit from the set.
DetectedSet:RemoveUnitsByName( DetectedArea.Zone.ZoneUNIT.UnitName )
self:T( { DetectedArea = DetectedArea.AreaID, "Removed Center Unit " .. DetectedArea.Zone.ZoneUNIT.UnitName } )
for DetectedUnitName, DetectedUnitData in pairs( DetectedSet:GetSet() ) do
local DetectedUnit = DetectedUnitData -- Unit#UNIT
local DetectedObject = self:GetDetectedObject( DetectedUnit.UnitName )
if DetectedObject then
if DetectedObject.Identified == false and DetectedUnit:IsAlive() then
DetectedObject.Identified = true
AreaExists = true
-- Assign the Unit as the new center unit of the detected area.
DetectedArea.Zone = ZONE_UNIT:New( DetectedUnit:GetName(), DetectedUnit, self.DetectionZoneRange )
self:T( { DetectedArea = DetectedArea.AreaID, "New Center Unit " .. DetectedArea.Zone.ZoneUNIT.UnitName } )
break
end
end
end
if AddedToSet == false then
local DetectedZoneIndex = #self.DetectedZones + 1
self:T( "Adding new zone #" .. DetectedZoneIndex )
self.DetectedZones[DetectedZoneIndex] = ZONE_UNIT:New( DetectedUnitName, DetectedUnit, self.DetectionZoneRange )
self.DetectedSets[DetectedZoneIndex] = SET_UNIT:New()
self.DetectedSets[DetectedZoneIndex]:AddUnit( DetectedUnit )
end
-- Now we've determined the center unit of the area, now we can iterate the units in the detected area.
-- Note that the position of the area may have moved due to the center unit repositioning.
-- If no center unit was identified, then the detected area does not exist anymore and should be deleted, as there are no valid units that can be the center unit.
if AreaExists then
-- ok, we found the center unit of the area, now iterate through the detected area set and see which units are still within the center unit zone ...
-- Those units within the zone are flagged as Identified.
-- If a unit was not found in the set, remove it from the set. This may be added later to other existing or new sets.
for DetectedUnitName, DetectedUnitData in pairs( DetectedSet:GetSet() ) do
local DetectedUnit = DetectedUnitData -- Unit#UNIT
local DetectedObject = self:GetDetectedObject( DetectedUnit:GetName() )
if DetectedObject then
if DetectedObject.Identified == false then
if DetectedUnit:IsInZone( DetectedZone ) then
DetectedObject.Identified = true
self:T( { DetectedArea = DetectedArea.AreaID, "Unit in zone " .. DetectedUnit.UnitName } )
else
-- Not anymore in the zone. Remove from the set.
DetectedSet:Remove( DetectedUnitName )
self:T( { DetectedArea = DetectedArea.AreaID, "Unit not in zone " .. DetectedUnit.UnitName } )
end
end
else
-- The detected object has not been found, delete from the Set!
DetectedSet:Remove( DetectedUnitName )
self:T( { DetectedArea = DetectedArea.AreaID, "Unit not found " .. DetectedUnit.UnitName } )
end
end
else
self:T( { DetectedArea = DetectedArea.AreaID, "Removed detected area " } )
self:RemoveDetectedArea( DetectedAreaID )
end
end
end
-- We iterated through the existing detection areas and:
-- - We checked which units are still detected in each detection area. Those units were flagged as Identified.
-- - We recentered the detection area to new center units where it was needed.
--
-- Now we need to loop through the unidentified detected units and see where they belong:
-- - They can be added to a new detection area and become the new center unit.
-- - They can be added to a new detection area.
for DetectedUnitName, DetectedObjectData in pairs( self.DetectedObjects ) do
local DetectedObject = DetectedObjectData -- #DETECTION_BASE.DetectedObject
if DetectedObject.Identified == false then
-- We found an unidentified unit outside of any existing detection area.
local DetectedUnit = UNIT:FindByName( DetectedObjectData.Name ) -- Unit#UNIT
if DetectedUnit and DetectedUnit:IsAlive() then
self:T( { "Search for " .. DetectedObjectData.Name, DetectedObjectData.Identified } )
local AddedToDetectionArea = false
for DetectedAreaID, DetectedAreaData in ipairs( self.DetectedAreas ) do
local DetectedArea = DetectedAreaData -- #DETECTION_UNITGROUPS.DetectedArea
if DetectedArea then
self:T( "Detection Area #" .. DetectedArea.AreaID )
local DetectedSet = DetectedArea.Set
local DetectedZone = DetectedArea.Zone -- Zone#ZONE_UNIT
if DetectedUnit:IsInZone( DetectedZone ) then
DetectedSet:AddUnit( DetectedUnit )
AddedToDetectionArea = true
DetectedObject.Identified = true
self:T( "Detection Area #" .. DetectedArea.AreaID .. " added unit " .. DetectedUnit.UnitName )
end
end
end
if AddedToDetectionArea == false then
-- New detection area
local DetectedArea = self:AddDetectedArea(
SET_UNIT:New(),
ZONE_UNIT:New( DetectedUnitName, DetectedUnit, self.DetectionZoneRange )
)
self:T( { "Added Detection Area #", DetectedArea.AreaID } )
DetectedArea.Set:AddUnit( DetectedUnit )
self:T( "Detection Area #" .. DetectedArea.AreaID .. " added unit " .. DetectedUnit.UnitName )
DetectedObject.Identified = true
end
end
end
@@ -478,14 +622,17 @@ function DETECTION_UNITGROUPS:CreateDetectionSets()
-- Now all the tests should have been build, now make some smoke and flares...
for DetectedZoneIndex = 1, #self.DetectedZones do
local DetectedUnitSet = self.DetectedSets[DetectedZoneIndex] -- Set#SET_BASE
local DetectedZone = self.DetectedZones[DetectedZoneIndex] -- Zone#ZONE_UNIT
self:T( "Detected Set #" .. DetectedZoneIndex )
DetectedUnitSet:ForEachUnit(
for DetectedAreaID, DetectedAreaData in ipairs( self.DetectedAreas ) do
local DetectedArea = DetectedAreaData -- #DETECTION_UNITGROUPS.DetectedArea
local DetectedSet = DetectedArea.Set
local DetectedZone = DetectedArea.Zone
DetectedZone.ZoneUNIT:SmokeRed()
DetectedSet:ForEachUnit(
--- @param Unit#UNIT DetectedUnit
function( DetectedUnit )
self:T( DetectedUnit:GetName() )
self:T( "Detected Set #" .. DetectedArea.AreaID .. ":" .. DetectedUnit:GetName() )
if self._FlareDetectedUnits then
DetectedUnit:FlareRed()
end