Tom,
I have something for you to try. I remembered that we have a quad tree that is exposed. This is just about as fast as the R-Tree and much easier for me to expose to you. There are a few things to note.
1.This only supports adds. I think this will be fine with you.
2.There is no more GetBoudningBox support. Not sure of you need it. I could be made to work but I didn't have time for it.
3.You need to add a reference to your project for the following two dlls. NetTopologySuite and GeoAPI. You can find them in the bin directory as they are dependencies for us anyway.
4.In the code there is a part where I create an envolope. For that API they ask for x1, x2, y1, and y2. I assume this is the MaxX, MinX, MaxY and MinY but I do not get intelliense to verify this. You may have to juggle the values around. I didn't test it because I didn't have time to setup a project and data.
5.I am not sure how this will work with the way I remove the GetBoundingBox. Only one way to find out!
6.I am pretty sure I am using the API right but not 100% sure.
7.You need to make sure to add the imports that I included.
8.You need to overwrite both classes and I changes some things in the Layer part as well.
I wanted to give you something to hopefully work for a pleasant weekend with no worried on speed. I fear the R-Tree might be hard to expose. Please let me know how it goes.
David
using System.Collections.ObjectModel;
using System.Collections.Generic;
using GisSharpBlog.NetTopologySuite.Index.Quadtree;
using GisSharpBlog.NetTopologySuite.Geometries;
using System.Collections;
using ThinkGeo.MapSuite.Core;
public class IndexedInMemoryFeatureLayer : FeatureLayer
{
public IndexedInMemoryFeatureLayer(IEnumerable<FeatureSourceColumn> featureSourceColumns)
{
// Create our new improved feature source and set it.
this.FeatureSource = new IndexedInMemoryFeatureSource(featureSourceColumns);
}
// Don't mind this code, just some plumbing.
public Collection<FeatureSourceColumn> Columns
{
get
{
if (!FeatureSource.IsOpen)
{
FeatureSource.Open();
}
Collection<FeatureSourceColumn> columns = ((InMemoryFeatureSource)FeatureSource).GetColumns();
return columns;
}
}
// Don't mind this code, just some plumbing.
protected override void OpenCore()
{
base.OpenCore();
if (FeatureSource.Projection != null && !FeatureSource.Projection.IsOpen)
{
FeatureSource.Projection.Open();
}
}
// just say this layer supports getting a bounding box.
// No longer supported
public override bool HasBoundingBox
{
get
{
return false;
}
}
}
public class IndexedInMemoryFeatureSource : InMemoryFeatureSource
{
Dictionary<string, RectangleShape> boundingBoxes = new Dictionary<string, RectangleShape>();
Quadtree quadTree = new Quadtree();
public IndexedInMemoryFeatureSource(IEnumerable<FeatureSourceColumn> featureSourceColumns)
: base(featureSourceColumns)
{
}
protected override TransactionResult CommitTransactionCore(TransactionBuffer transactions)
{
// Here we are going to cache our own bounding boxes and then
// call the default logic to process the transactions
// We only handle adds at this point
// Handle the new features
foreach (KeyValuePair<string, Feature> addTransaction in transactions.AddBuffer)
{
RectangleShape rectangle = ((Feature)addTransaction.Value).GetBoundingBox();
Envelope envelope = new Envelope(rectangle.UpperLeftPoint.X, rectangle.LowerRightPoint.Y, rectangle.UpperLeftPoint.Y, rectangle.LowerRightPoint.Y);
quadTree.Insert(envelope, addTransaction.Key);
}
return base.CommitTransactionCore(transactions);
}
protected override Collection<Feature> GetFeaturesForDrawingCore(RectangleShape boundingBox, double screenWidth, double screenHeight, IEnumerable<string> returningColumnNames)
{
return GetFeaturesBasedOnCachedBoundingBoxes(boundingBox);
}
protected override Collection<Feature> GetFeaturesInsideBoundingBoxCore(RectangleShape boundingBox, IEnumerable<string> returningColumnNames)
{
return GetFeaturesBasedOnCachedBoundingBoxes(boundingBox);
}
private Collection<Feature> GetFeaturesBasedOnCachedBoundingBoxes(RectangleShape extent)
{
Envelope envelope = new Envelope(extent.UpperLeftPoint.X, extent.LowerRightPoint.Y, extent.UpperLeftPoint.Y, extent.LowerRightPoint.Y);
List<string> RecordIds = (List<string>)quadTree.Query(envelope);
Collection<Feature> features = new Collection<Feature>();
foreach (string key in RecordIds)
{
features.Add((Feature)InternalFeatures[key]);
}
return features;
}
//No longer supported
//protected override RectangleShape GetBoundingBoxCore()
//{
// // Here we just optimize the get bounding box since this will
// // be faster than re-calculating them.
// Collection<BaseShape> canidates = new Collection<BaseShape>();
// foreach (string key in boundingBoxes.Keys)
// {
// canidates.Add((RectangleShape)boundingBoxes[key]);
// }
// return ExtentHelper.GetBoundingBoxOfItems(canidates);
//}
}