ThinkGeo.com    |     Blog    |     Wiki    |     Support

rTreeSpatialIndex does not contain Feature for the Points-of-Interest shapefiles

We use the World Map Kit 5.0 with the 2009 Street Data Update ro render the shapefiles for our Desktop Edition application.  The code we use to render the shapefiles is modeled after the sample application delivered in the WorldMapKitSDK.  With the code as delivered in the SDK, I never see any of the points from the Points-of-interest layers for any of the church, golf, hospital, and all the LPT layers for the 56 states.



I have narrowed down the issue to the DrawCore method in the WorldMapKitRenderLayer which use this line of code



if (rtreeSpatialIndex != null)

{

    candidateLayerNames = rtreeSpatialIndex.GetFetureIdsIntersectingBoundingBox(extent);

}



I never see any of the layers for the Points-of-Interest shapefiles in the candidateLayerNames retruned from this call.  In fact, if I remove the usage of the candidateLayerNames in the following foreach and process all of the static layers and dyanmic layers the Points-of-Interest are displayed on the map as expected with appropriate labels.  



The rtreeSpatialIndex is created in the Constructor for WorldMapKitRenderLayer with the code



if (File.Exist(Path.Combine(datafolder, "LayersBoundingBoxes.idx)) && rtreeSpatialIndex == null)

{

   rtreeSpatialIndex = new RTreeSpatialIndex(Path.Combine(datafolder, "LayerBoundingBoxes.idx"), RtreeSpatialIndexReadWriteMode.ReadOnly);

}



 I do not know how to verfiy it but I believe that the "LayerBoundingBoxes.idx"  is missing the bounding boxes for all of the Point-of-Interest shapefiles.    I do not know how to create a good "LayerBoundingBoxes.idx"  but I did attempt to add bounding boxes for the Points-of-Interest layers in the code to the rtreeSpatialIndex object.  Even though the layers have the "HasBoundingBox = true" the layer.GetBoundingBox() is always throwing an exception for the WorldMapKitShapeFileFeatureLayer containing the shapefiles for the church, golf, hospital layers.  Is there anyway to get the bounding box for these Point-of-Interest layers?



Why does the code always fail to include the church,golf, hospital and LPT shapefiles in the candidateLayersName collection?  Has anyone else solved the issue of not seeing the Point-of-interest layers when using the WorldMapKit shapefiles?



Thanks for any help that you can provide.



Richard 










Hi Richard, 
  
 It looks your idx file is broken? 
  
 Please try to rebuild index file for it like this: 
  
 ShapeFileFeatureSource.BuildIndexFile(“YourPOIShapeFilePath”, BuildIndexMode.Rebuild); 
  
 It’s a static function, so you can remove it after run it once. 
  
 Please let me know whether the new idx file solve your issue. 
  
 Regards, 
  
 Don

Don, 
  
 Thank you so much for the quick response. 
 I tried your suggestion and used  
  
 ShapeFileFeatureSource.BuildIndexFile("gchurch.shp", BuildIndexMode.Rebuild);  
 ShapeFileFeatureSource.BuildIndexFile("ggolf.shp", BuildIndexMode.Rebuild);  
 ShapeFileFeatureSource.BuildIndexFile("ghospitl.shp", BuildIndexMode.Rebuild);  
  
 on the WorldMapKit shapefiles.  This did indeed rebuild the index files for these shapefiles.  However this had no impact at all on getting the churches, golf, or hospitals to display on the map. I could not figure out how to use this to rebuild the LayersBoundingBoxes.idx that is provided in the WorldMapKit SDK  
  
 Instead I tried to figure out the forum topic "WorldMap Kit BoundingBox Errors" from 1-28-2010.  I seemed to be getting the same exceptions on the GetBoundingBox call for the "Points-of-Interest" layers as they were discussing in this forum topic.  As a workaround for the exception on GetBoundingBox, I hardcoded a bounding box roughly containing North America.  I then modified the WorlMapKitRenderLayer code to add a boundingbox for each of the "LPT", "church", "golf", and "hospital" shapefiles to rtreeSpatialIndex object.  I guess since the rtreeSpatialIndex is initialized from the "LayersBoundingBoxes.idx that adding these boundingboxes automatically overwrites the "LayersBoundingBoxes.idx. I then removed the calls to CreatePointSpatialIndex (the local function in the WorldMapRederLayer.cs).  Now the layers for Point-of-interest are included in the candidateLayerNames in DrawCore and therfore the symbols are displayed on the map as expected.  Below is the code that I modified:  
  
         ///  
         /// Method to render the symbols for Hospital layer for for the WorldMapKit render layer. 
         ///  
         /// WorldMapKit ShapeFile Feature layer. 
         /// <returns></returns> 
         private void RenderSymbolHospital(ref WorldMapKitShapeFileFeatureLayer layer) 
         { 
             layer.Name = "Hospitals"; 
  
             layer.DrawingQuality = DrawingQuality.HighQuality; 
             layer.ZoomLevelSet.ZoomLevel15.DefaultPointStyle = new PointStyle(new GeoImage(dataFolder + @"\Images\hospital_detailed.png")); 
             layer.ZoomLevelSet.ZoomLevel15.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20; 
             //TODO Force the rtreeSpatialIndex to have an boundingbox for each of the LPT layers 
             CreatePointSpatialIndex(layer); 
  
             staticLayers.Add(layer); 
         } 
         ///  
         /// Add layer boundingbox to the rtreeSpatialIndex. 
         ///  
         ///  
         private void CreatePointSpatialIndex(WorldMapKitShapeFileFeatureLayer layer) 
         { 
             try 
             { 
                 rtreeSpatialIndex.Open(); 
                 layer.Open(); 
                 //TODO layer.GetBoundingBox() always throws an exception for Points-of-Interest layers 
                 //TODO Not a very good estimation for bounding box but this will 
                 //TODO at least restrict  bounding box to roughly North America 
                 RectangleShape boundingbox = new RectangleShape(-160, 70, -60, 20);//layer.GetBoundingBox(); 
                 boundingbox.Id = Path.GetFileName(layer.ShapePathFileName); 
                 rtreeSpatialIndex.Add(boundingbox); 
                 layer.Close(); 
             } 
             catch (Exception ex) 
             { 
                 logger.ErrorFormat( 
                     "Exception while CreatePointSpatialIndex {1}. Exception: {0}", 
                     ex, layer.ShapePathFileName); 
             } 
         } 
  
         ///  
         /// Override the Drawcore for the WorldMapKit Render layer. 
         ///  
         /// canvas for drawing. 
         /// labels for all layers. 
         /// <returns></returns> 
         protected override void DrawCore(GeoCanvas canvas, Collection<SimpleCandidate> labelsInAllLayers) 
         { 
             DateTime startTime = DateTime.Now; 
             RectangleShape extent = canvas.CurrentWorldExtent; 
             object image = canvas.NativeImage; 
             GeographyUnit unit = canvas.MapUnit; 
             bool isInDrawing = canvas.IsDrawing; 
             if (isInDrawing) 
             { 
                 canvas.EndDrawing(); 
             } 
  
             Collection<string> candidateLayerNames = new Collection<string>(); 
  
             if (rtreeSpatialIndex != null) 
             { 
                 candidateLayerNames = rtreeSpatialIndex.GetFeatureIdsIntersectingBoundingBox(extent); 
             } 
             string shapePathFileName = string.Empty; 
             try 
             { 
                 foreach (WorldMapKitShapeFileFeatureLayer layer in staticLayers) 
                 { 
                     if (candidateLayerNames.Count == 0 || 
                         candidateLayerNames.Contains(Path.GetFileName(layer.ShapePathFileName))) 
                     { 
                         shapePathFileName = layer.ShapePathFileName; 
                         canvas.BeginDrawing(image, extent, unit); 
                         layer.Open(); 
                         layer.Draw(canvas, labelsInAllLayers); 
                         //layer.Close(); 
                         //canvas.EndDrawing(); 
                     } 
                 } 
  
                 foreach (WorldMapKitShapeFileFeatureLayer layer in dynamicLayers) 
                 { 
                     if (candidateLayerNames.Count == 0 || 
                         candidateLayerNames.Contains(Path.GetFileName(layer.ShapePathFileName))) 
                     { 
                         shapePathFileName = layer.ShapePathFileName; 
                         canvas.BeginDrawing(image, extent, unit); 
                         layer.Open(); 
                         layer.Draw(canvas, labelsInAllLayers); 
                         //layer.Close(); 
                         //canvas.EndDrawing(); 
                     } 
                 } 
                 canvas.EndDrawing(); 
  
  
                 if (isInDrawing) 
                 { 
                     canvas.BeginDrawing(image, extent, unit); 
                 } 
             } 
             catch (Exception ex) 
             { 
                 logger.ErrorFormat( 
                     "Exception while getting Features for Drawing the static and dynamic layers of World Map Kit map for file {1}. Exception: {0}", 
                     ex, shapePathFileName); 
                 canvas.EndDrawing(); 
             } 
  
             DateTime stopTime = DateTime.Now; 
             TimeSpan duration = stopTime - startTime; 
             logger.InfoFormat("Elapsed time of rendering on WorldMapKitData layer from: {0} is: {1} ", dataFolder, duration); 
         } 
  
 Although, this has provided a solution, using the hardcoded boundingbox for North America does not seem very efficient- at least not for all the shapefiles for each of the 56 states as there are 382 of these shapefiles. There is probably some way to automatically GetBoundingBox for the layers but I have not figured this out.  It probably has sometihing to to with the RTreeSpatialIndex methods CreateRectangleSpatialIndex and CreatePointSpatialIndex that were discussed in the old forum topic above but I could not get these to work to build the idx file for these shapefiles. If anyone could provide me with a sample of the use of these that would build the idx for all the features in the shapefiles, I would greatly appreciate it. 
  
 Thanks for the help. 
  
 Richard 
  
   


Hi Richard, 
  
 I found this topic you mentioned here: thinkgeo.com/forums/MapSuite/tabid/143/aft/6972/Default.aspx 
  
 It looks we can dynamic extend current extent in rtreeSpatialIndex and your code did that. 
  
 Sorry I am not very clearly what the LayerBoundingBoxes.idx is works for, but it looks like just a basic setting for everyone and if you want to include your layers you need keep adding new extent to it. 
  
 So maybe you don’t need to specified a starter extent to rtreeSpatialIndex, but just loop all layers and add their extent to it after it is initialized. 
  
 Regards, 
  
 Don

Don, 
  
 Thanks again for you input. 
  
 The LayersBoundingBoxes.idx is an index delivered in the WorldMapKitSDK 5.0.  I would guess that it should have included an index entry for all the Shapefiles contained in the WorldMapKitSDK 5.0. There are around 900 shapefiles delivered in the 5.0 version using the Street Data 2009.  The only shapefiles that appear to have issues (that I have discovered so far) are the shapefiles in the USA folder in the LPT and POI subfolders. 
  
 The WorldMapKitSDK also has sample application showing how the MapKit data can be used with the DesKtop, Services, Silverlight, Web and WPF products.  The main class to build layers from the WorldMapKitData is the WorldMapKitRenderLayer.cs. This class has a property showPOI which is initialized as false and must be set by the caller in order for the POI shapefiles to be generated into layers in the WorldMapKitRenderLayer.  This showPOI include the church,golf,and hospitals from the POI subfolder but also include all the LPT shapefiles for the 56 states which contain 382 shapefiles.   
  
 If I had to  make a guess on this, I would imagine that whatever process was used to generate the LayersBoundingBoxes.idx included in the WorldMapKitSDK installation also used code with the same “showPOI” property and that it was probably false bypassing all the POI and LPT shapefiles.  My workaround above creates the index entry in the LayersBoundingBoxes.idx for these missing shapefiles. 
  
 It would be nice to know that the index is missing the POI and LPT due to such an oversight as opposed to intentionally skipping them for other reasons that have greater impact such as speed or efficiency.  Also it would be nice to know if creating a bounding box of the size of North America is going to adversly affect performance when using the map in an area the size of Delaware for the 6 shapefiles making up Delaware LPT’s. 
  
 My real question then is how should the bounding boxes be generated for the shapefiles for the individual states so that they do not represent an area the size of North America when they can’t possible have data outside the boundary of the state.  I have thought about trying to somehow capture the bounding boxes used for the CTYCU, TKLA, and WAT shapefiles for each specific state but I am not comfortable enough with the LayersBoundingBoxes.idx to know how to read and write to it to make such a update. The CTYCU, TKLA, and WAT shapefiles for all 56 states are definately included in LayersBoundingBoxes.idx which I have confirmed using the debugger showing the the correct shapefiles in the candidateLayerNames in DrawCore. 
  
 Thanks again for the help. 
  
 Richard

Hi Richard, 
  
 Thanks for your detail description. 
  
 I am asking our developer and wait their response about LayersBoundingBoxes.idx. 
  
 But I think you can build your own LayersBoundingBoxes.idx follow this way: 
  
 1. Build a standalone project for it, load all target layers. 
 2. Create a new layer named LayersBoundingBoxes.shp. 
 3. Loop the layers and get bounding box, convert the bounding box to feature and add them to the LayersBoundingBoxes.shp. 
 4. Build index file for this layer. 
  
 Do you think that will works for you? 
  
 Regards, 
  
 Don

Don, 
  
 I think this is a good outline except for one thing.  As it was stated in the other forum post from 2010 mentioned above, when the shapefiles for the LPT, and POI layers are loaded, the GetBoundingBox for the layer always returns an exception. So in the step 3 of your suggestion “get the bounding box” is not a straight forward step.  Essentially,  I have already tried to do what you have suggested.  In my code sample above, there is a method I created called CreatePointSpatialIndex (sorry this is poorly named as it duplicates a method in the MapSuite class).  The method was doing a GetBoundingBox for each LPT and POI layer and adding the bounding box to the rtreeSpatialIndex which is also written to LayersBoudningBoxes.idx.  The issue is the exception on GetBoundingBox.  Therefore, I had commented out the GetBoundingBox replacing it with the hardcoded RectangleShape for North America.   
  
 I am guessing that the only way to avoid the exception is to calculate the bounding box is other way.  Maybe my coping all the feature out of the original FeatureSource and adding them into some new layer.  The forum entry from 2010 implied that something like this was done but the details weren’t clear enough on how they did it. 
  
 Thanks for following up on this.  I do greatly appreciate your help and comments. 
  
 Richard

Hi Richard, 



My last reply just focus your question “how should the bounding boxes be generated for the shapefiles for the individual states”. 



I read the 2010 topic again, it looks Jiong choose don’t use WorldMapKitShapeFileFeatureLayer, he said “GetBoundingBox() for WorldMapKitShapeFileFeatureLayer still got exception, while for ShapeFileFeatureLayer is OK, So finally I use ShapeFileFeatureLayer”. So he should haven’t solve this problem. 



You mentioned you still have exception, but I haven’t succeed reproduced that in my machine, so I cannot trace that quickly. Could you please paste more detail information about the exception for example the complete stack-trace.



Regards, 



Don