# **************************************************************************** # 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 ThreatTypePriority = Map(); 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 mBowTieZonePoints = Array(); bool mUseClustersInZones = false; Array mZoneNames = Array(); Array trackArray = Array(); Map mZoneJobMap = Map(); Map mZoneCluster = Map(); Map mJobToWinnerMap = Map(); Map mFlankToClusterMap = Map(); Map mClusterToFlankMap = Map(); Array mCompletedFlanks = Array(); Map mFlankNameToTimeCompleteMap = Map(); 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 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 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 arr = Array(); 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 arr = Array(); 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 targetNames = Array(); 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 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 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 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(); mFlankToClusterMap = Map(); mClusterToFlankMap = Map(); mCompletedFlanks = Array(); mZoneJobMap = Map(); mFlankNameToTimeCompleteMap = Map(); Array 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