ThinkGeo.com    |     Documentation    |     Premium Support

Efficient Querying of "Layer" objects

 


I'm using ThinkGeo Mapsuite as a tool for viewing and inputting spatial data into a spatially based numerical model (for grazing simulations). One of my requirements is to query layers to see which polyon (Feature) lies under a point on a predefined grid. We will be doing this for hundreds of thousands of points, so efficient algorithms are important. At the moment, I'm iterating through a predefined grid (say 2000x2000) and calling the following for each grid cell (i.e. 4,000,000 times):



 Collection<feature> features = featureLayer.QueryTools.GetFeaturesContaining(gridpoint, ReturningColumnsType.NoColumns);</feature>

 Unfortunately, this is very slow.... a more efficient way of dealing with this would be to iterate through each feature (in the ShapeFileFeatureLayer), extract the polygon(s) and then test only those grid cells which lie in the Feature's bounding box. This would require a function like, for example:


 if(feature.ContainsPoint(gridpoint))

... but unfortunately, nothing like this exists. Is this something that you could add to the Feature class?? ...or can you suggest a more efficient way of doing this?


I did see a thread on here which mentioned adding the feature layer to the EditInteractiveOverlay class, and then calling CalculateAllControlPoints. This doesn't seem to be a valid option any more - I can't see how we can get a collection of points from this.


Any help would be appreciated.


cheers


David McClymont


DHM Environmental Software Engineering


 



 David,


 
  I can help you out with this.  The reason that the QueryTools is a bit slow is because it uses a file based R-Tree index and then reads the real shape and does the containing calculation.  You do not see the containing on the feature because the feature is just a simple transport for the WKB mainly through the drawing system.  When you want to do calculations on it you want to convert it to some kind of shape.  The Feature has a GetShape method that returns the type of shape it is.  The return type is BaseShape so you need to cast it to the real shape and then you will see all the APIs to get containing etc.  
 
  Having said all of this things are changing and in the future we will probably drop shapes and enhance the feature for the exact reasons you wrote this e-mail.  Having two classes of citizens was not the best design even though it was created to make drawing more fast and efficient which for most of our customers is the 99% of cases.  In your situation it seems like things are mostly calculations so that was not the priority case.  This is changing for us and we are in the process now of upgrading our geometry library and making geometry things lightning fast.  Upgrading the feature and shape system is something in the works right now.  If you get the latest daily build you will see some new API on feature such as union, buffer, and possibly containing.  
 
  I believe that there is still a faster way then looping through each feature and this would be to create an in memory R-Tree index of the polygons and then call the index to find if the point intersects with any of the R-Tree bounding boxes.  In this way you get the advantages of the R-Tree which should prevent the searching of each bounding box as it create a hierarchy tree.  Some sample code is below.
 


        ShapeFileFeatureLayer shapeFileLayer = new ShapeFileFeatureLayer(@"../../Data/Countries02.shp");
        shapeFileLayer.Open();
    
        STRtree rTree = null;

        rTree = new STRtree();
        
        for (int i = 1; i < shapeFileLayer.FeatureSource.GetCount(); i++)
        {
            RectangleShape boundingBox = shapeFileLayer.QueryTools.GetBoundingBoxById(i.ToString()).GetBoundingBox();
            Envelope envelope = new Envelope(boundingBox.UpperLeftPoint.X, boundingBox.LowerRightPoint.X, boundingBox.UpperLeftPoint.Y, boundingBox.LowerRightPoint.Y);

            rTree.Insert(envelope, i);            
        }

        rTree.Build();

        Envelope searchEnvelope = new Envelope(30, 30, 30, 30);

        ArrayList itemsFound = (ArrayList)rTree.Query(searchEnvelope);



Hi Dave… that sound’s awesome… I look forward to trying it out. 
  
 cheers 
 David

Hello David, 
  
 Feel free to let us know if you meet problem on this. 
  
 Regards, 
  
 Gary