This commit is contained in:
2025-09-12 15:20:28 +08:00
commit 3257a14c32
449 changed files with 388780 additions and 0 deletions

View File

@@ -0,0 +1,808 @@
# ****************************************************************************
# CUI
#
# The Advanced Framework for Simulation, Integration, and Modeling (AFSIM)
#
# The use, dissemination or disclosure of data in this file is subject to
# limitation or restriction. See accompanying README and LICENSE for details.
# ****************************************************************************
#acts as a job-pass-through if a commander exists
#otherwise:
#creates and updates "zone" and "flank" jobs
#does not perform any jobs
include_once processors/ripr_agents/common/common_platform_script.txt
processor AIGCI-thinker WSF_AIGCI_PROCESSOR
#debug
#script_debug_writes on
script_debug_writes off
update_interval 5.0 sec
script_variables
# the GCI uses these threat priority pairs to dispatch it's subordinates
# the string is a platforms category (can have more than one category)
# the number is its priority
Map<string, double> ThreatTypePriority = Map<string, double>();
ThreatTypePriority["unknown"] = 0.0;
ThreatTypePriority["uav"] = 2.0;
ThreatTypePriority["sam"] = 4.0;
ThreatTypePriority["ship"] = 4.0;
ThreatTypePriority["awacs"] = 4.0;
ThreatTypePriority["bomber"] = 2.0;
ThreatTypePriority["jammer"] = 0.0;
ThreatTypePriority["fighter"] = 5.0;
ThreatTypePriority["missile"] = 9.0;
ThreatTypePriority["missile_fast"] = 9.0;
ThreatTypePriority["FIRE_CONTROL"] = 6.0;
ThreatTypePriority["strike_target"] = 20.0;
ThreatTypePriority["primary_target"] = 20.0;
ThreatTypePriority["secondary_target"] = 10.0;
#ThreatTypePriority["2D_RADAR"] = 0.0;
#ThreatTypePriority["3D_RADAR"] = 0.0;
#ThreatTypePriority["ACQUISITION"] = 0.0;
#ThreatTypePriority["HF_RADAR"] = 0.0;
bool mCreateFlankJobs = true;
bool mDrawClusters = false;
Array<Vec3> mBowTieZonePoints = Array<Vec3>();
bool mUseClustersInZones = false;
Array<string> mZoneNames = Array<string>();
Array<WsfTrack> trackArray = Array<WsfTrack>();
Map<string, WsfRIPRJob> mZoneJobMap = Map<string, WsfRIPRJob>();
Map<string, WsfCluster> mZoneCluster = Map<string, WsfCluster>();
Map<int, int> mJobToWinnerMap = Map<int, int>();
Map<int, int> mFlankToClusterMap = Map<int, int>();
Map<int, int> mClusterToFlankMap = Map<int, int>();
Array<string> mCompletedFlanks = Array<string>();
Map<string, double> mFlankNameToTimeCompleteMap = Map<string, double>();
int mMaxTotalFlankJobsEverToCreate = 1;
int mMaxJobWinnersForFlank = 2;
###double mFlankJobPriorityScale = 0.75; // make > 1 for more important than clusters
double mFlankJobPriorityScale = 1.5; // make > 1 for more important than clusters
double cFLANK_DISTANCE = 60.0; // flank towards a point approximately this many nm to the side of target
int mFlankJobsCreated = 0; // utility variable, not a constant to set
int mFlankJobsCompleted = 0; // utility variable, not a constant to set
//after a completed flank on a cluster, don't do another on that same cluster until this time passes
double mFlankRepeatDelay = 300.0; //in units of seconds
int mMaxJobWinnersForGciZone = 1;
int mLastNumClusters = 0;
WsfClusterManager cManager;
WsfDraw draw = WsfDraw();
end_script_variables
#
# utility method used to draw lines between tracks in a cluster
# lines are drawn in a star-burst pattern from the center out
#
script void aigci_draw_cluster_star(WsfCluster cluster)
int trackCount = cluster.Count();
WsfGeoPoint center = cluster.MeanLocation();
//draw.SetId("cluster-lines");
draw.SetLineStyle("solid");
draw.BeginLines();
draw.SetColor(1.0,1.0,0.0);
for (int j = 0; j < trackCount; j = j + 1 )
{
WsfTrack t = cluster.Entry(j);
draw.Vertex(center);
draw.Vertex(t.CurrentLocation());
}
draw.End();
end_script
#
# utility method used to draw lines around tracks in a cluster
# lines are drawn according to the convex hull of the cluster members
#
script void draw_cluster_hull(WsfCluster cluster)
Array<WsfGeoPoint> pts = cluster.ConvexHull();
//writeln_d(" ~~~ aigci cluster convex hull pts: ", pts.Size());
if (pts.Size() <= 0)
{
return;
}
WsfGeoPoint first = pts.Get(0);
draw.SetColor(1.0,0.5,0.0); //orange?
draw.SetLineStyle("solid");
draw.SetLineSize(2);
draw.BeginPolyline();
for (int j = 0; j < pts.Size(); j = j + 1 )
{
WsfGeoPoint pt = pts.Get(j);
draw.Vertex(pt);
//writeln_d(" ~~~ aigci cluster convex hull pt ", j+1, ": ", pt.Latitude(), ", ", pt.Longitude());
}
draw.Vertex(first);
draw.End();
end_script
#
# utility method used to draw points where the raw tracks in a tracklist are
#
script void aigci_draw_raw_tracks(WsfLocalTrackList aList)
draw.SetColor(1.0,1.0,0.0); //yellow
draw.SetPointSize(5);
draw.BeginPoints();
foreach (WsfLocalTrack t in aList)
{
for (int j = 0; j < t.RawTrackCount(); j = j + 1 )
{
WsfTrack raw = t.RawTrack(j);
draw.Vertex(raw.ReportedLocation());
}
}
draw.End();
end_script
script void aigci_draw_track_to_truth()
WsfLocalTrackList aList = PLATFORM.MasterTrackList();
draw.SetColor(0.0,0.5,1.0); //blue-green
draw.SetLineSize(3);
draw.BeginLines();
foreach (WsfLocalTrack t in aList)
{
WsfPlatform plat = WsfSimulation.FindPlatform( t.TargetIndex() );
if (plat.IsValid())
{
draw.Vertex(plat.Location());
//draw.Vertex(t.ReportedLocation());
draw.Vertex(t.CurrentLocation());
bool broke = false;
if (t.Altitude()<0 || t.Altitude()>31000)
{
writeln("TRACK BROKE!!!");
broke = true;
}
writeln("local track: ", t.TrackId().ToString(), " target: ", t.TargetName());
for (int i=0; i<t.RawTrackCount(); i=i+1)
{
WsfTrack raw = t.RawTrack(i);
writeln(" raw: ", raw.TrackId().ToString());
#if (broke)
#{
WsfPlatform owner = WsfSimulation.FindPlatform(raw.TrackId().Name());
if (owner.IsValid()) {
WsfLocalTrack t2 = owner.MasterTrackList().Find(raw.TrackId());
if (t2.IsValid())
{
for (int j=0; j<t2.RawTrackCount(); j=j+1)
{
writeln(" more raw: ", t2.RawTrack(j).TrackId().ToString());
}
}
}
#}
}
}
}
draw.End();
end_script
#
# if the gci agent wasn't given zones to monitor, then it
# dynamically clusters all threats in its tracklist and
# creates zone/cluster jobs off of those
#
script void aigci_update_with_clusters_array(Array<WsfTrack> aTrackArray)
//writeln_d(" ~~~ aigci tracklist count: ", localTracks.Count());
cManager.UpdateClusters(TIME_NOW,aTrackArray);
int NumClusters = cManager.Count();
for (int i = 0; i < NumClusters; i = i + 1 )
{
WsfCluster cluster = cManager.Entry(i);
string ClusterName = PLATFORM.Name() + "_" + (string)i;
//no need to have a zone on the platform: deprecated!
//cluster.UpdatePlatformZone(PLATFORM,ClusterName,(5.0/60.0)); //5 minutes (1/12th of a degree)
if (mDrawClusters == true)
{
draw_cluster_hull(cluster);
}
WsfGeoPoint clusterPoint = cluster.MeanLocation();
double clusterBearing = cluster.Bearing();
bool clusterBearingValid = cluster.BearingValid();
#writeln("~~~ aiGCI - cluster ", ClusterName, " bearing valid: ", clusterBearingValid, ", CLUSTER BEARING ", clusterBearing);
#for (int i = 0; i < cluster.Count(); i = i + 1 )
#{
# WsfTrack t = cluster.Entry(i);
# writeln("~~~ aiGCI - cluster entry ", t.TargetName(), ", bearing = ", t.Bearing());
#}
int occupants = cluster.Count();
double ClusterPriority = (double)occupants;
if( occupants > 0 )
{
if( mZoneJobMap.Exists( ClusterName ) )
{
//writeln_d("~~~ aiGCI, updating job for cluster: ", ClusterName);
//job exists for zone with threats, update job priority
WsfRIPRJob temp = mZoneJobMap.Get( ClusterName );
//job priority could have changed, set it
temp.Priority( ClusterPriority );
temp.SetData( "ZonePoint", WsfGeoPoint(clusterPoint) );
temp.SetData( "ZoneBearing", clusterBearing );
temp.SetData( "ZoneBearingValid", clusterBearingValid );
//number of threats inside zone could have changed, set it
temp.SetData( "ZoneNumThreats", occupants );
Array<string> arr = Array<string>();
for (int i = 0; i < occupants; i = i + 1 )
{
arr.PushBack(cluster.Entry(i).TargetName());
}
temp.SetData( "ZoneThreatNameArray", arr );
}
else
{
//zone just became hot, job not created yet, create one
WsfRIPRJob temp = WsfRIPRJob.Create( PROCESSOR,
"zone",
"zone-" + ClusterName,
ClusterPriority,
mMaxJobWinnersForGciZone );
temp.SetData( "ZoneName", ClusterName );
temp.SetData( "ZonePoint", WsfGeoPoint(clusterPoint) );
temp.SetData( "ZoneBearing", clusterBearing );
temp.SetData( "ZoneBearingValid", clusterBearingValid );
temp.SetData( "ZoneNumThreats", occupants );
temp.SetData( "for_air", 1 );
Array<string> arr = Array<string>();
for (int i = 0; i < occupants; i = i + 1 )
{
arr.PushBack(cluster.Entry(i).TargetName());
writeln_d("job target: ", cluster.Entry(i).TargetName());
}
temp.SetData( "ZoneThreatNameArray", arr );
AddJob(temp);
mZoneJobMap.Set( ClusterName, temp );
writeln_d("+++ ", PLATFORM.Name(), " job change, ADD: ", temp.Name() );
}
}
else
{
//no threats in cluster, make sure job for cluster doesn't exist or is deleted
if( mZoneJobMap.Exists( ClusterName ) )
{
writeln_d("--- ", PLATFORM.Name(), " job change, REMOVE: ", mZoneJobMap.Get(ClusterName).Name() );
RemoveJob( mZoneJobMap.Get(ClusterName) );
//mZoneJobMap.Erase( ClusterName );
mZoneJobMap.Remove( ClusterName );
}
}
}
//remove any additional clusters
for( int j = NumClusters; j < mLastNumClusters; j = j+1 )
{
string ClusterName = PLATFORM.Name() + "_" + (string)j;
if( mZoneJobMap.Exists( ClusterName ) )
{
writeln_d("--- ", PLATFORM.Name(), " job change, REMOVE: ", mZoneJobMap.Get(ClusterName).Name() );
RemoveJob( mZoneJobMap.Get(ClusterName) );
//mZoneJobMap.Erase( ClusterName );
mZoneJobMap.Remove( ClusterName );
}
}
mLastNumClusters = NumClusters;
end_script
script void aigci_update_with_clusters(WsfLocalTrackList localTracks)
trackArray.Clear();
foreach (WsfTrack track in localTracks)
{
track.SetBearing( track.Heading() ); #useful for the cluster processing
trackArray.PushBack(track);
}
aigci_update_with_clusters_array(trackArray);
end_script
script void aigci_update_with_clusters_in_zones()
#extern bool TestTrackCategory(WsfTrack,string);
WsfLocalTrackList localTracks = PLATFORM.MasterTrackList();
writeln_d("~~~ localTracks.Count() = ", localTracks.Count());
trackArray.Clear();
foreach (WsfTrack track in localTracks)
{
// if the track is not a foe, we'll ignore it
if (!(track.IsValid()) || !track.IFF_Foe() || TestTrackCategory(track,"unknown"))
{
continue;
}
foreach( string zName in mZoneNames )
{
if( track.WithinZoneOf( PLATFORM, zName ) )
{
track.SetBearing( track.Heading() ); #useful for the cluster processing
trackArray.PushBack(track);
}
}
}
aigci_update_with_clusters_array(trackArray);
end_script
#
# if the gci agent was given WSF zones to monitor, then it only
# creates zone/cluster jobs based on threats in those zones
#
script void aigci_update_with_zones()
#extern string DetermineTrackCategory(WsfTrack);
#extern bool TestTrackCategory(WsfTrack,string);
WsfLocalTrackList localTracks = PLATFORM.MasterTrackList();
writeln_d("~~~ localTracks.Count() = ", localTracks.Count());
mZoneCluster.Clear();
//build clusters from threats that occupy zones of interest
//clusters can share members simply because zones can overlap
foreach (WsfTrack track in localTracks)
{
// if the track is not a foe, we'll ignore it
if (!(track.IsValid()) || !track.IFF_Foe() || TestTrackCategory(track,"unknown"))
{
continue;
}
#if( track.LocationValid() ) { writeln_d("~~~ Considering: ", track.TrackId().Name(), ".", track.TrackId().Number(), " -> ", track.TargetName()); }
if (track.LocationValid())
{
//zones can overlap, so check all zones for each track
foreach( string zName in mZoneNames )
{
if( track.WithinZoneOf( PLATFORM, zName ) )
{
track.SetBearing( track.Heading() ); #useful for the cluster processing
if (!mZoneCluster.Exists(zName))
{
mZoneCluster.Set(zName, WsfCluster.Create(track));
}
else
{
mZoneCluster.Get(zName).Add(track);
}
}
}
}
}
//ensure a job exists for each occupied zone (cluster of threats)
foreach ( string name : WsfCluster cluster in mZoneCluster)
{
double ZoneJobPriority = 0.0;
Array<string> targetNames = Array<string>();
for (int i = 0; i < cluster.Count(); i = i + 1)
{
WsfTrack aTrack = cluster.Entry(i);
string trgtType = DetermineTrackCategory(aTrack);
ZoneJobPriority = ZoneJobPriority + ThreatTypePriority.Get(trgtType);
targetNames.PushBack(aTrack.TargetName());
}
if( mZoneJobMap.Exists( name ) )
{
//writeln("LBM - update zone job count: ", cluster.Count());
//job exists for zone with threats, update job priority
WsfRIPRJob temp = mZoneJobMap.Get( name );
//job priority could have changed, set it
temp.Priority( ZoneJobPriority );
temp.SetData( "ZonePoint", WsfGeoPoint(cluster.MeanLocation()) );
temp.SetData( "ZoneBearing", cluster.Bearing() );
temp.SetData( "ZoneBearingValid", cluster.BearingValid() );
temp.SetData( "ZoneNumThreats", cluster.Count() );
temp.SetData( "ZoneThreatNameArray", targetNames );
}
else
{
//writeln("LBM - create zone job. count: ", cluster.Count());
//zone just became hot, job not created yet, create one
WsfRIPRJob temp = WsfRIPRJob.Create( PROCESSOR, "zone", "zone-" + name, ZoneJobPriority, mMaxJobWinnersForGciZone );
temp.SetData( "ZoneName", name );
temp.SetData( "ZonePoint", WsfGeoPoint(cluster.MeanLocation()) );
temp.SetData( "ZoneBearing", cluster.Bearing() );
temp.SetData( "ZoneBearingValid", cluster.BearingValid() );
temp.SetData( "ZoneNumThreats", cluster.Count() );
temp.SetData( "ZoneThreatNameArray", targetNames );
temp.SetData( "for_air", 1 );
AddJob(temp);
mZoneJobMap.Set(name, temp);
writeln_d("+++ ", PLATFORM.Name(), " job change, ADD: ", temp.Name() );
}
}
//remove existing jobs for which their is no occupied zone (no cluster of threats)
Array<WsfRIPRJob> jobs = GetJobs();
foreach (WsfRIPRJob x in jobs)
{
string zName = (string)x.GetData("ZoneName");
if (!mZoneCluster.Exists(zName))
{
writeln_d("--- ", PLATFORM.Name(), " job change, REMOVE: ", x.GetDescription());
RemoveJob(x);
mZoneJobMap.Erase(zName);
}
}
end_script
#
# script callback method for when a flank job is completed
# the job board calls this when a flank job that it owns has been marked as complete
#
script void aigci_flank_complete(int jobID)
//save job in completed array
//remove job from created array
WsfRIPRJob aJob = GetJobById( jobID );
writeln_d("~~~ Flank Job Completed: ", aJob.GetDescription());
mCompletedFlanks.PushBack( aJob.Name() );
mFlankNameToTimeCompleteMap.Set( aJob.Name(), TIME_NOW );
int clusterId = mFlankToClusterMap.Get( jobID );
mFlankToClusterMap.Erase( jobID );
mClusterToFlankMap.Erase( clusterId );
mFlankJobsCompleted = mFlankJobsCompleted + 1;
end_script
#
# method for administering flank jobs, if they are enabled
#
script void aigci_update_flanks()
//check if this gci is done creating & updating the flank jobs
if( mFlankJobsCompleted >= mMaxTotalFlankJobsEverToCreate )
{
writeln_d( "~~~ aiGCI - Max Flank Jobs Completed, return now!" );
return;
}
//check for clusters that went away & thus we can't flank them anymore
//otherwise, update the flank job
foreach( int flankJobId : int clusterJobId in mFlankToClusterMap )
{
WsfRIPRJob flankJob = GetJobById( flankJobId );
WsfRIPRJob clusterJob = GetJobById( clusterJobId );
if( clusterJob.IsValid() )
{
if( flankJob.IsValid() )
{
if (flankJob.GetBestProgress() >= 1.0 )
{
writeln("GCI removing completed flank job!!!");
mCompletedFlanks.PushBack( flankJob.Name() );
mFlankNameToTimeCompleteMap.Set( flankJob.Name(), TIME_NOW );
int flankId = flankJob.GetId();
int clusterId = mFlankToClusterMap.Get( flankId );
mFlankToClusterMap.Erase( flankId );
mClusterToFlankMap.Erase( clusterId );
mFlankJobsCompleted = mFlankJobsCompleted + 1;
mFlankToClusterMap.Remove( flankId );
mClusterToFlankMap.Remove( clusterId );
RemoveJob( flankJob );
}
else
{
writeln_d( "~~~ aiGCI - updating flank job ", flankJob.Name(), " with cluster ", clusterJob.Name(), "!!!" );
writeln_d("best flank progress: ", flankJob.GetBestProgress());
WsfGeoPoint point = (WsfGeoPoint)clusterJob.GetData().Get("ZonePoint");
double bearing = (double)clusterJob.GetData().Get("ZoneBearing");
bool bearingValid = (bool)clusterJob.GetData().Get("ZoneBearingValid");
//writeln_d( "~~~ aiGCI - flank job BEARING: ", bearing );
string flankZoneName = "flank" + clusterJob.Name();
//writeln(PLATFORM.Name(), " UpdateFlankZone( ", TIME_NOW, ", ", flankZoneName, ", ", point.ToString(), ", ", bearing, ", ", cFLANK_DISTANCE);
//now the wsfzone can be treated as a relative zone, and doesn't need updating
//UpdateFlankZone( TIME_NOW, flankZoneName, point, bearing, cFLANK_DISTANCE );
//update the flank job with relevant cluster information
flankJob.Priority( (mFlankJobPriorityScale * clusterJob.GetPriority()) );
flankJob.SetData( "FlankZoneName", flankZoneName );
flankJob.SetData( "ZonePoint", WsfGeoPoint(point) );
flankJob.SetData( "ZoneBearing", bearing );
flankJob.SetData( "ZoneBearingValid", bearingValid );
flankJob.SetData( "ZoneNumThreats", (int)clusterJob.GetData().Get("ZoneNumThreats") );
}
}
else
{
writeln_d( "~~~ aiGCI - cluster valid, but flank not valid!" );
}
}
else
{
//remove flank job, cluster went away
WsfRIPRJob tJob = GetJobById( flankJobId );
writeln_d("--- ", PLATFORM.Name(), " job change, REMOVE: ", tJob.Name() );
mFlankToClusterMap.Remove( flankJobId );
mClusterToFlankMap.Remove( clusterJobId );
RemoveJob( tJob );
if( mFlankJobsCreated > 0 )
{
mFlankJobsCreated = mFlankJobsCreated - 1;
}
}
}
//check if only the updates were needed, or if we can create more flank jobs
if( mFlankJobsCreated >= mMaxTotalFlankJobsEverToCreate )
{
writeln_d( "~~~ aiGCI - max flank jobs created, no need for more!" );
return;
}
//create a new flank job if a cluster exists that never had one
double DistClosestCluster = MATH.DOUBLE_MAX();
WsfRIPRJob JobWithClusterToFlank;
Array<WsfRIPRJob> jobs = GetJobs();
foreach (WsfRIPRJob aJob in jobs)
{
//if job is a cluster job (not a flank job) & is not being flanked already
//then consider it as a candidate for flanking, else continue
if( mFlankToClusterMap.Exists( aJob.GetId() ) || mClusterToFlankMap.Exists( aJob.GetId() ) )
{
//writeln_d( "~~~ aiGCI - job ", aJob.Name(), " is either a flank job or a zone thats already being flanked!" );
continue;
}
//if enough time hasn't elapsed since the last flank performed on this cluster, then continue
string newFlankName = "flank" + aJob.Name();
if( mFlankNameToTimeCompleteMap.Exists( newFlankName ) )
{
double lastFlankTime = mFlankNameToTimeCompleteMap.Get( newFlankName );
if( TIME_NOW < (lastFlankTime + mFlankRepeatDelay) )
{
continue;
}
}
WsfGeoPoint cPoint = (WsfGeoPoint)aJob.GetData().Get("ZonePoint");
double dist = PLATFORM.GroundRangeTo(cPoint);
if( dist < DistClosestCluster )
{
JobWithClusterToFlank = aJob;
}
}
//if no flank job exists yet, and there is a cluster to flank, create job
if( JobWithClusterToFlank.IsValid() )
{
WsfGeoPoint clusterPoint = (WsfGeoPoint)JobWithClusterToFlank.GetData().Get("ZonePoint");
double clusterBearing = (double)JobWithClusterToFlank.GetData().Get("ZoneBearing");
bool clusterBearingValid = (bool)JobWithClusterToFlank.GetData().Get("ZoneBearingValid");
int clusterOccupants = (int)JobWithClusterToFlank.GetData().Get("ZoneNumThreats");
string clusterZoneName = (string)JobWithClusterToFlank.GetData().Get("ZoneName");
string flankZoneName = "flank" + JobWithClusterToFlank.Name();
WsfRIPRJob NewFlankJob = WsfRIPRJob.Create( PROCESSOR,
"flank",
flankZoneName,
(mFlankJobPriorityScale * JobWithClusterToFlank.GetPriority()),
mMaxJobWinnersForFlank );
NewFlankJob.SetData( "ZoneName", clusterZoneName );
NewFlankJob.SetData( "FlankZoneName", flankZoneName );
NewFlankJob.SetData( "ZonePoint", WsfGeoPoint(clusterPoint) );
NewFlankJob.SetData( "ZoneBearing", clusterBearing );
NewFlankJob.SetData( "ZoneBearingValid", clusterBearingValid );
NewFlankJob.SetData( "ZoneNumThreats", clusterOccupants );
double FlankDistanceMeters = cFLANK_DISTANCE * MATH.M_PER_NM();
NewFlankJob.SetData( "FlankDistance", (1.8 * FlankDistanceMeters) ); //pursue a point 10% inside the flank zone, the flank width is 2*FlankDist
NewFlankJob.SetData( "OnJobComplete", "aigci_flank_complete" );
NewFlankJob.SetData( "for_air", 1 );
WsfZone flankZone = WsfZone.CreatePolygonal(PLATFORM, mBowTieZonePoints); //creates a relative zone
NewFlankJob.SetData( "FlankZone", flankZone );
AddJob(NewFlankJob);
writeln_d("+++ ", PLATFORM.Name(), " job change, ADD: ", NewFlankJob.Name() );
mFlankJobsCreated = mFlankJobsCreated + 1;
//save link between the flank & the cluster thats being flanked
mFlankToClusterMap.Set( NewFlankJob.GetId(), JobWithClusterToFlank.GetId() );
mClusterToFlankMap.Set( JobWithClusterToFlank.GetId(), NewFlankJob.GetId() );
//now we can use a WsfZone and not have to update a platform zone
//writeln(PLATFORM.Name(), " UpdateFlankZone( ", TIME_NOW, ", ", flankZoneName, ", ", clusterPoint.ToString(), ", ", clusterBearing, ", ", cFLANK_DISTANCE);
//UpdateFlankZone( TIME_NOW, flankZoneName, clusterPoint, clusterBearing, cFLANK_DISTANCE );
}
end_script
#
# main update loop of the gci agent
# this agent determines his role (commander or not?) and then
# administers zone (cluster) & flank jobs for his subordinates
#
on_update
writeln_d("--- aigci_update Platform: ", PLATFORM.Name(), ", Time: ", TIME_NOW);
//aigci_draw_track_to_truth();
double duration = 0.0;
double lStartTime = GetWallClockTime();
if( GetRIPRCommanderProcessor().IsValid() )
{
//if the gci has a commander, then let its subordinates win jobs from the commander
//the commander should create the same kinds of jobs that the gci would have created
//these kinds include zone (cluster) jobs, or maybe even flank jobs
SetJobPassThrough(true);
writeln_d( "~~~ aigci is a job pass through now. time: ", TIME_NOW);
}
else
{
SetJobPassThrough(false);
if( mZoneNames.Size() > 0 )
{
if ( mUseClustersInZones )
{
writeln_d( "~~~ aigci update w clusters in zones: ", PLATFORM.Name(), "- time: ", TIME_NOW);
aigci_update_with_clusters_in_zones();
}
else
{
writeln_d( "~~~ aigci update w zones: ", PLATFORM.Name(), "- time: ", TIME_NOW);
aigci_update_with_zones();
}
}
else
{
writeln_d( "~~~ aigci update w clusters: ", PLATFORM.Name(), "- time: ", TIME_NOW);
WsfLocalTrackList localTracks;
localTracks = PLATFORM.MasterTrackList();
aigci_update_with_clusters(localTracks);
}
if (mCreateFlankJobs == true)
{
aigci_update_flanks();
}
Array<WsfRIPRJob> jobs = GetJobs();
foreach( WsfRIPRJob aJob in jobs )
{
if( ! mJobToWinnerMap.Exists( aJob.GetId() ) )
{
mJobToWinnerMap.Set( aJob.GetId(), 0 );
}
else
{
int currWinners = aJob.GetNumWinners();
int lastWinners = mJobToWinnerMap.Get( aJob.GetId() );
if( currWinners != lastWinners )
{
string NewComment = "AIGCI - Sub took a job: " + aJob.Name() + " - " + aJob.GetDescription();
PLATFORM.Comment(NewComment);
mJobToWinnerMap.Set( aJob.GetId(), currWinners );
}
}
}
}
duration = GetWallClockTime() - lStartTime;
writeln_d("~~~ on_update GCI Platform: ", PLATFORM.Name(), "- Process Time: ", duration);
end_on_update
on_initialize2
draw.SetDuration(PROCESSOR.UpdateInterval()); //try it here, after the processor is setup
end_on_initialize2
on_initialize
cManager = WsfClusterManager.Create(); // creates a cluster manager owned by this script
cManager.SetClusterMethod("H_TREE_MAX"); // default is: "K_MEANS"
cManager.SetDistanceFunction("POSITION_VELOCITY"); // default is: "POSITION_ONLY"
//cManager.SetDistanceLimit(46300); // ~25 nautical miles
cManager.SetDistanceLimit(92600); // ~50 nautical miles
//cManager.SetDistanceLimit(185200); // ~100 nautical miles
mJobToWinnerMap = Map<int, int>();
mFlankToClusterMap = Map<int, int>();
mClusterToFlankMap = Map<int, int>();
mCompletedFlanks = Array<string>();
mZoneJobMap = Map<string, WsfRIPRJob>();
mFlankNameToTimeCompleteMap = Map<string, double>();
Array<WsfZone> zoneList = PLATFORM.Zones();
foreach( WsfZone z in zoneList)
{
mZoneNames.PushBack(z.Name());
}
foreach( string x in mZoneNames )
{
writeln_d("~~~ GCI now monitoring retrived zone: ", x );
}
if( mZoneNames.Size() == 0 )
{
writeln_d( "~~~ No GCI zones defined, using Dynamic Clustering!" );
}
double FlankDistanceMeters = cFLANK_DISTANCE * MATH.M_PER_NM();
//create simple bowtie shape, based on specified size parameters
double w1 = 2.0 * FlankDistanceMeters; //Bow Tie Width (meters)
double h2 = 0.75 * FlankDistanceMeters; //Bow Tie Outter Thickness (meters)
double h1 = 0.5 * h2; //Bow Tie Inner Thickness (meters)
mBowTieZonePoints.PushBack(Vec3.Construct( h1, 0, 0));
mBowTieZonePoints.PushBack(Vec3.Construct( h2, w1, 0));
mBowTieZonePoints.PushBack(Vec3.Construct( -h2, w1, 0));
mBowTieZonePoints.PushBack(Vec3.Construct( -h1, 0, 0));
mBowTieZonePoints.PushBack(Vec3.Construct( -h2, -w1, 0));
mBowTieZonePoints.PushBack(Vec3.Construct( h2, -w1, 0));
end_on_initialize
end_processor