So it surely wasn't easy. In fact I never did get everything to work, but I did learn some things and perhaps others will be able to build upon this:My original reason for doing this original was that I didn't know what graphic I wanted to remove from being clustered until I saw what graphics were left over after clustering (by left-over I mean not clustered).I was able to cluster the graphics, but I wasn't able to do it properly. Clusters were far too close together and just sitting on top of eachother, or else they were just all gobbled together. But it also seemed that some graphics were just not getting grouped together. public override void ClusterGraphicsAsync(IEnumerable<Graphic> graphics, double resolution)
{
int incomingTotal = graphics.Count();
int total = 0;
//TODO run on seperate cancellable thread
//BackgroundWorkers or Tasks executed on the thread pool are possible options.
//if (bw.IsBusy != true)
//{
// bw.RunWorkerAsync();
//}
//else
//{
//}
GraphicCollection returnGraphics = new GraphicCollection();
//Group graphics into collections that will be turned into clusters
IEnumerable<GraphicCollection> graphicGroups = groupGraphics(graphics, resolution);
GraphicCollection gCollection;
for (int i = 0; i < graphicGroups.Count(); i++ )
{
gCollection = graphicGroups.ElementAt(i);
if (gCollection.Count > 2)
{
Utility.removeTextSymbols(ref gCollection); //need to remove TextSymbols or else they will be counted
MapPoint mp = getCenter(gCollection);
Graphic cluster = OnCreateGraphic2(gCollection, mp, gCollection.Count);
returnGraphics.Add(cluster);
total += gCollection.Count;
}
else //should just add one TextSymbol and one GraphicSymbol
{
foreach (Graphic g in gCollection)
{
returnGraphics.Add(g);
}
total += 1;
}
}
//raise ClusteringCompleted by invoking OnClusteringCompleted
OnClusteringCompleted(returnGraphics);
}
private IEnumerable<GraphicCollection> groupGraphics(IEnumerable<Graphic> graphics, double resolution)
{
Queue<Graphic> q = new Queue<Graphic>(graphics);
Collection<GraphicCollection> clusters = new Collection<GraphicCollection>();
int totalCount = 0;
double range = resolution * 50;
while (q.Count > 0)
{
Graphic g = q.Dequeue();
GraphicCollection gCollection = new GraphicCollection();
Envelope searchEnvelope = g.Geometry.Extent;
//expand the evelope to include the search resolution
searchEnvelope.XMax += (60*resolution);
searchEnvelope.YMax += (60*resolution);
searchEnvelope.XMin -= (60*resolution);
searchEnvelope.YMin -= (60*resolution);
gCollection.Add(g);
//iterate through q, finding all graphics within extent
if (q.Count > 0)
{
Graphic searchG = null;
Graphic firstSearchG = null;
Graphic prevSearchG = null;
//remove graphics from queue that are within searchEvelope
while (q.Count > 0 && (searchG == null || searchG != firstSearchG || prevSearchG == null))
{
prevSearchG = searchG;
searchG = q.Dequeue(); //new search graphic
if (firstSearchG == null)
{
firstSearchG = searchG;
}
//if (searchEnvelope.Intersects(searchG.Geometry.Extent) == true)
//if (envelopesIntersect(searchEnvelope, searchG.Geometry.Extent) == true)
if (withinRange(g, searchG, range) == true)
{
if (searchG.Symbol.GetType() == typeof(ESRI.ArcGIS.Client.FeatureService.Symbols.PictureMarkerSymbol))
{
gCollection.Insert(0,searchG);
}
else
{
gCollection.Add(searchG); //send textsymbol to end of colelction, so drawn last
}
totalCount++;
if (searchG == firstSearchG)
{
firstSearchG = null;
}
}
else
{
q.Enqueue(searchG);
}
}
}
clusters.Add(gCollection);
}
return clusters;
}
private bool withinRange(Graphic g1, Graphic g2, double range)
{
double a = g2.Geometry.Extent.YMax - g1.Geometry.Extent.YMax;
double b = g2.Geometry.Extent.XMax - g1.Geometry.Extent.XMax;
double c = Math.Sqrt(Math.Pow(a, 2) + Math.Pow(b, 2));
if (c <= range)
{
return true;
}
return false;
}