ThinkGeo.com    |     Documentation    |     Premium Support

Splitting up a Large Shapefile

I have some street based shapefile data that I would like to use in a ShapefileFeatureLayer.  However, the road and street data are in one large shapefile for all levels of roads.  As you can imagine, this creates quite the performance hit (i.e. 20+ seconds to refresh the map on load), since you really do not want to see the most local roads when you are looking at the city, county, or country zoom level.


Is there a way to either:



        
  1. Set style based upon a feature column value (i.e. a number from 1-5 indicating how local it is)?

  2.     
  3. Split one shapefile and associated data into multiple shapefiles (i.e. 5 files to cover each level, say country, county, city, local, rural)


Which of the above approaches would you use?  Can you provide a code sample to do it?


Thanks a ton!



 


Hi Brian,
 
I have made two simple samples using that both two ways you mentioned above. The first way we can use ValueStyle, and the second way I show a simple sample just generate a part shapefile from the original shapefile to show you how to split one large shapefile to some small ones. Following is the code snippet:
 
1. Set ValueStyle based upon a feature column value.
winformsMap1.MapUnit = GeographyUnit.DecimalDegree;
winformsMap1.BackgroundOverlay.BackgroundBrush = new GeoSolidBrush(GeoColor.GeographicColors.ShallowOcean);

ShapeFileFeatureLayer landlockedCountryLayer = new ShapeFileFeatureLayer(@"..\SampleData\Data\Countries02.shp");
landlockedCountryLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
// Draw features based on values   
ValueStyle valueStyle = new ValueStyle();
valueStyle.ColumnName = "LANDLOCKED";
valueStyle.ValueItems.Add(new ValueItem("Y", AreaStyles.Country1));
landlockedCountryLayer.ZoomLevelSet.ZoomLevel01.CustomStyles.Add(valueStyle);

LayerOverlay worldOverlay = new LayerOverlay();
worldOverlay.Layers.Add("LandlockedCountryLayer", landlockedCountryLayer);
winformsMap1.Overlays.Add(worldOverlay);

winformsMap1.CurrentExtent = new RectangleShape(-255.234375, 180.678985595703, 255.234375, -187.055389404297);
winformsMap1.Refresh();  

 
2. Split one shapefile and associated data into multiple shapefiles.
private void GenerateAPartShapeFile(string originalShapefilePath, string newShapefilePath)
{
    ShapeFileFeatureLayer originalLayer = new ShapeFileFeatureLayer(originalShapefilePath);
    ShapeFileFeatureLayer.BuildIndexFile(originalShapefilePath, BuildIndexMode.DoNotRebuild);
    ShapeFileFeatureLayer.CloneShapeFileStructure(originalShapefilePath, newShapefilePath);
    ShapeFileFeatureLayer landlockedCountryLayer = new ShapeFileFeatureLayer(newShapefilePath, ShapeFileReadWriteMode.ReadWrite);
    UpdateNewShapeFile(originalLayer, landlockedCountryLayer);
    ShapeFileFeatureLayer.BuildRecordIdColumn(newShapefilePath, "RECID", BuildRecordIdMode.Rebuild);
}

private void UpdateNewShapeFile(ShapeFileFeatureLayer originalLayer, ShapeFileFeatureLayer newLayer)
{
    newLayer.Open();
    newLayer.EditTools.BeginTransaction();
    originalLayer.Open();
    Collection<Feature> features = originalLayer.FeatureSource.GetFeaturesByColumnValue("LANDLOCKED", "Y", ReturningColumnsType.AllColumns);
    foreach (Feature feature in features)
    {
        newLayer.EditTools.Add(feature);
    }
    newLayer.EditTools.CommitTransaction();
    originalLayer.Close();
    newLayer.Close();
}

 
Because we don't have your data to test, so I can not test the performance to tell you which way is better, maybe you can test with your data to chose the appropriate one.:)
 
Thanks,
 
Any questions please let me know.
 
James

Brian, 
  
   I would highly suggest you split the shape files into multiple ones.  The reasons is that if you go the Value style route we still need to query all of the shapes and then go to the DBF to see if they have the right type.  This is just about as slow as just rendering everything. 
  
 Another approach if you don’t want to split the shape file into multiple ones and want to keep your source data intact you can build custom indexes.  The way this works is that you build a R-Tree index but the index just has the roads of a certain type in them.  When you load the ShapeFileFeatureLayer you can specify a custom index file.  What this does is when we do spatial queries it goes to the index and just finds the records you added to the index.  The other record are kind of hidden to it.  To do this you can use the static method ShapeFileFeatureLayer.BuildIndexFile I would use the 8th overload that allows you to build it off of a regex expression on a column.  If you need a sample on this let me know and we can build something for you on the code community. 
  
   Let me know if this makes sense or need any other suggestions.  I really think a custom index is that way to go if you don’t want to break up your shape files. 
  
 David

 


Brian,
 
As David said, if you don’t want to split the shape file into multiple ones you can build custom shape file indexes. We have made a sample on the code community, you can get it from following link:
code.thinkgeo.com/projects/s...efileindex
 
Thanks
James