Improved clusters
This commit is contained in:
Frank 2020-07-19 18:31:09 +02:00
parent 5cb1036618
commit 5fa75bf6b9
3 changed files with 226 additions and 56 deletions

View File

@ -1810,7 +1810,7 @@ function AUFTRAG:onafterStatus(From, Event, To)
local commander=self.wingcommander and tostring(self.wingcommander.coalition) or "N/A" local commander=self.wingcommander and tostring(self.wingcommander.coalition) or "N/A"
-- Info message. -- Info message.
self:I(self.lid..string.format("Status %s: Target=%s, T=%s-%s, assets=%d, groups=%d, targets=%d, wing=%s, commander=%s", self.status, targetname, Cstart, Cstop, #self.assets, Ngroups, Ntargets, airwing, commander)) self:T(self.lid..string.format("Status %s: Target=%s, T=%s-%s, assets=%d, groups=%d, targets=%d, wing=%s, commander=%s", self.status, targetname, Cstart, Cstop, #self.assets, Ngroups, Ntargets, airwing, commander))
-- Check for error. -- Check for error.
if fsmstate~=self.status then if fsmstate~=self.status then
@ -1822,7 +1822,7 @@ function AUFTRAG:onafterStatus(From, Event, To)
local groupdata=_groupdata --#AUFTRAG.GroupData local groupdata=_groupdata --#AUFTRAG.GroupData
text=text..string.format("\n- %s: status mission=%s opsgroup=%s", groupname, groupdata.status, groupdata.opsgroup and groupdata.opsgroup:GetState() or "N/A") text=text..string.format("\n- %s: status mission=%s opsgroup=%s", groupname, groupdata.status, groupdata.opsgroup and groupdata.opsgroup:GetState() or "N/A")
end end
self:I(self.lid..text) self:T(self.lid..text)
local ready2evaluate=self.Tover and Tnow-self.Tover>=self.dTevaluate or false local ready2evaluate=self.Tover and Tnow-self.Tover>=self.dTevaluate or false
@ -2886,7 +2886,6 @@ function AUFTRAG:UpdateMarker()
self.marker=MARKER:New(targetcoord, text):ReadOnly():ToAll() self.marker=MARKER:New(targetcoord, text):ReadOnly():ToAll()
end end
else else
if self.marker:GetText()~=text then if self.marker:GetText()~=text then

View File

@ -488,17 +488,20 @@ end
-- FSM Events -- FSM Events
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- On after "MissionAssign" event. Mission is added to the AIRWING mission queue. --- On after "AssignMissionAssignAirforce" event.
-- @param #CHIEF self -- @param #CHIEF self
-- @param #string From From state. -- @param #string From From state.
-- @param #string Event Event. -- @param #string Event Event.
-- @param #string To To state. -- @param #string To To state.
-- @param Ops.AirWing#AIRWING Airwing The AIRWING.
-- @param Ops.Auftrag#AUFTRAG Mission The mission. -- @param Ops.Auftrag#AUFTRAG Mission The mission.
function CHIEF:onafterMissionAssign(From, Event, To, Airwing, Mission) function CHIEF:onafterAssignMissionAirforce(From, Event, To, Mission)
self:I(self.lid..string.format("Assigning mission %s (%s) to airwing %s", Mission.name, Mission.type, Airwing.alias)) if self.wingcommander then
Airwing:AddMission(Mission) self:I(self.lid..string.format("Assigning mission %s (%s) to WINGCOMMANDER", Mission.name, Mission.type))
self.wingcommander:AddMission(Mission)
else
self:E(self.lid..string.format("Mission cannot be assigned as no WINGCOMMANDER is defined."))
end
end end

View File

@ -281,7 +281,6 @@ end
--- On after Start event. Starts the FLIGHTGROUP FSM and event handlers. --- On after Start event. Starts the FLIGHTGROUP FSM and event handlers.
-- @param #INTEL self -- @param #INTEL self
-- @param Wrapper.Group#GROUP Group Flight group.
-- @param #string From From state. -- @param #string From From state.
-- @param #string Event Event. -- @param #string Event Event.
-- @param #string To To state. -- @param #string To To state.
@ -297,7 +296,6 @@ end
--- On after "Status" event. --- On after "Status" event.
-- @param #INTEL self -- @param #INTEL self
-- @param Wrapper.Group#GROUP Group Flight group.
-- @param #string From From state. -- @param #string From From state.
-- @param #string Event Event. -- @param #string Event Event.
-- @param #string To To state. -- @param #string To To state.
@ -619,16 +617,56 @@ end
-- Cluster Functions -- Cluster Functions
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Create detected items. --- Paint picture of the battle field.
-- @param #INTEL self -- @param #INTEL self
function INTEL:PaintPicture() function INTEL:PaintPicture()
-- First remove all lost contacts from clusters.
for _,_contact in pairs(self.ContactsLost) do
local contact=_contact --#INTEL.Contact
local cluster=self:GetClustersOfContact(contact)
if cluster then
self:RemoveContactFromCluster(contact, cluster)
end
end
for _,_contact in pairs(self.Contacts) do
local contact=_contact --#INTEL.Contact
if not self:CheckContactInClusters(contact) then
local cluster=self:IsContactPartOfAnyClusters(contact)
if cluster then
self:AddContactToCluster(contact, cluster)
else
local newcluster=self:CreateCluster(contact.position)
self:AddContactToCluster(contact, newcluster)
end
end
end
if false then
local contacts={} local contacts={}
for _,_contact in pairs(self.Contacts) do for _,_contact in pairs(self.Contacts) do
local contact=_contact --#INTEL.Contact local contact=_contact --#INTEL.Contact
if not self:CheckContactInClusters(contact) then if not self:CheckContactInClusters(contact) then
-- Check if contact is part of known clusters.
local cluster=self:IsContactPartOfAnyCluster(contact)
if cluster then
self:AddContactToCluster(contact, cluster)
else
table.insert(contacts, contact.groupname) table.insert(contacts, contact.groupname)
end end
end
end end
local contacts={} local contacts={}
@ -675,16 +713,8 @@ function INTEL:PaintPicture()
end end
end end
--[[ --- Check if a contact is in the list.
env.info("FF before removing neighbours")
for _,contact in pairs(contacts) do
env.info(string.format("Group %s has %d neighbours", contact.name, contact.n))
end
]]
local function checkcontact(contact) local function checkcontact(contact)
for _,c in pairs(contacts) do for _,c in pairs(contacts) do
if c.name==contact.name then if c.name==contact.name then
return true return true
@ -697,52 +727,125 @@ function INTEL:PaintPicture()
if checkcontact(contact) then if checkcontact(contact) then
local cluster={} --#INTEL.Cluster
cluster.index=self.clustercounter
cluster.groups={}
table.insert(cluster.groups, contact.name)
cluster.Contacts={}
table.insert(cluster.groups, self:GetContactByName(contact.name))
local Contact=self:GetContactByName(contact.name) local Contact=self:GetContactByName(contact.name)
cluster.coordinate=Contact.position
cluster.size=1 local cluster=self:CreateCluster(Contact.position)
self:AddContactToCluster(Contact, cluster)
for _,neighbour in pairs(contact.neighbours) do for _,neighbour in pairs(contact.neighbours) do
-- Remove contact from table as this is now part of a cluster.
removecontact(neighbour.name) removecontact(neighbour.name)
table.insert(cluster.groups, neighbour.name) local Neighbour=self:GetContactByName(neighbour.name)
cluster.size=cluster.size+1
self:AddContactToCluster(Neighbour, cluster)
table.insert(cluster.groups, self:GetContactByName(neighbour.name))
end end
local text=string.format("Cluster #%d. Size %d", cluster.index, cluster.size)
cluster.maker=MARKER:New(cluster.coordinate, text):ToAll() end
end
end -- if false then
-- Update F10 marker text if cluster has changed.
for _,cluster in pairs(self.Clusters) do
-- Update F10 marker.
self:UpdateClusterMarker(cluster)
end
end
--- Create a new cluster.
-- @param #INTEL self
-- @param Core.Point#COORDINATE coordinate The coordinate of the cluster.
-- @return #INTEL.Cluster cluster The cluster.
function INTEL:CreateCluster(coordinate)
-- Create new cluster
local cluster={} --#INTEL.Cluster
cluster.index=self.clustercounter
cluster.coordinate=coordinate
cluster.threatlevelSum=0
cluster.threatlevelMax=0
cluster.size=0
cluster.Contacts={}
-- Add cluster. -- Add cluster.
table.insert(self.Clusters, cluster) table.insert(self.Clusters, cluster)
-- Increase couter. -- Increase counter.
self.clustercounter=self.clustercounter+1 self.clustercounter=self.clustercounter+1
end return cluster
end end
--[[ --- Add a contact to the cluster.
table.sort(contacts, sort) -- @param #INTEL self
-- @param #INTEL.Contact contact The contact.
-- @param #INTEL.Cluster cluster The cluster.
function INTEL:AddContactToCluster(contact, cluster)
env.info("FF after removing neighbours") if contact and cluster then
for i,cluster in pairs(clusters) do
env.info(string.format("Cluster %d has %d groups", i, cluster.n)) -- Add neighbour to cluster contacts.
table.insert(cluster.Contacts, contact)
cluster.threatlevelSum=cluster.threatlevelSum+contact.threatlevel
cluster.size=cluster.size+1
end end
]]
end end
--- Remove a contact from a cluster.
-- @param #INTEL self
-- @param #INTEL.Contact contact The contact.
-- @param #INTEL.Cluster cluster The cluster.
function INTEL:RemoveContactFromCluster(contact, cluster)
if contact and cluster then
for i,_contact in pairs(cluster.Contacts) do
local Contact=_contact --#INTEL.Contact
if Contact.groupname==contact.groupname then
cluster.threatlevelSum=cluster.threatlevelSum-contact.threatlevel
cluster.size=cluster.size-1
table.remove(cluster.Contacts, i)
return
end
end
end
end
--- Calculate cluster threatlevel sum.
-- @param #INTEL self
-- @param #INTEL.Cluster cluster The cluster of contacts.
-- @return #number Sum of all threat levels of all groups in the cluster.
function INTEL:CalcClusterThreatlevelSum(cluster)
local threatlevel=0
for _,_contact in pairs(cluster.Contacts) do
local contact=_contact --#INTEL.Contact
threatlevel=threatlevel+contact.threatlevel
end
return threatlevel
end
--- Check if contact is in any known cluster. --- Check if contact is in any known cluster.
-- @param #INTEL self -- @param #INTEL self
-- @param #INTEL.Contact contact The contact. -- @param #INTEL.Contact contact The contact.
@ -764,6 +867,71 @@ function INTEL:CheckContactInClusters(contact)
return false return false
end end
--- Check if contact is close to any contact of known clusters.
-- @param #INTEL self
-- @param #INTEL.Contact contact The contact.
-- @return #INTEL.Cluster The cluster this contact is part of or nil otherwise.
function INTEL:IsContactPartOfAnyClusters(contact)
for _,_cluster in pairs(self.Clusters) do
local cluster=_cluster --#INTEL.Cluster
for _,_contact in pairs(cluster.Contacts) do
local Contact=_contact --#INTEL.Contact
local dist=Contact.position:Get2DDistance(contact.position)
if dist<10*1000 then
return cluster
end
end
end
return nil
end
--- Check if contact is in any known cluster.
-- @param #INTEL self
-- @param #INTEL.Contact contact The contact.
-- @return #INTEL.Cluster The cluster this contact belongs to or nil.
function INTEL:GetClustersOfContact(contact)
for _,_cluster in pairs(self.Clusters) do
local cluster=_cluster --#INTEL.Cluster
for _,_contact in pairs(cluster.Contacts) do
local Contact=_contact --#INTEL.Contact
if Contact.groupname==contact.groupname then
return cluster
end
end
end
return nil
end
--- Update cluster F10 marker.
-- @param #INTEL self
-- @param #INTEL.Cluster cluster The cluster.
function INTEL:UpdateClusterMarker(cluster)
-- Create a marker.
local text=string.format("Cluster #%d. Size %d, TLsum=%d", cluster.index, cluster.size, cluster.threatlevelSum)
if not cluster.marker then
cluster.marker=MARKER:New(cluster.coordinate, text):ToAll()
else
if cluster.marker.text~=text then
cluster.marker:UpdateText(text)
end
end
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------