ThinkGeo.com    |     Documentation    |     Premium Support

Optimizing Shape Files for Performance

Hello,


I would like get your opinions and suggestions on how to optimize the structure of shape files to achieve maximum possible performance in rendering the map.


My case is as follows :


I have the map data for the whole country. But, it is not a big file including everything, instead roads (as polylines) for each city has its own shape file. Also, the shapefile data has something like the following structure.


City01_Roads.shp, City02_Roads.shp, City03_Roads.shp etc.


ID (int), Feature Name (string), Road Type (string), etc...


123, Backway Street, Street

125, Trueway Street, Street

190, Marvin Avenue, Avenue

213, Sunset Boulevard, Boulevard

233, E-66 Highway, Highway

356, Friday 13th Highway, Highway


So I have a ValueStyle to render these according to the road type. Also, zoomlevels are adjusted as to show only relevant types of roads according to zoomlevel.


Something like the following code is used  (First time trying to use the source code feature, hope it will show up well) :


 


ShapeFileFeatureLayer roadLayer = new ShapeFileFeatureLayer(MapPath("~/App_Data/City34_road.shp"));
roadLayer.RequireIndex = true;
roadLayer.DrawingMarginPercentage = 50;

// Zoom level 01-12
ValueStyle valueStyle = new ValueStyle();
valueStyle.ColumnName = "TIPI"; // Road type
valueStyle.ValueItems.Add(new ValueItem("Devlet Yolu", LineStyles.Highway1));
valueStyle.ValueItems.Add(new ValueItem("Otoyol", LineStyles.Highway1));
valueStyle.ValueItems.Add(new ValueItem("Otoyol Bağlantısı", LineStyles.Highway1));

valueStyle.ValueItems[0].DefaultLineStyle.InnerPen.Color = GeoColor.StandardColors.LightPink;

roadLayer.ZoomLevelSet.ZoomLevel01.CustomStyles.Add(valueStyle);
roadLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level12;

// Zoom level 13-16
ValueStyle valueStyle2 = new ValueStyle();
valueStyle2.ColumnName = "TIPI";
valueStyle2.ValueItems.Add(new ValueItem("Cadde", LineStyles.LocalRoad2));
valueStyle2.ValueItems.Add(new ValueItem("Bulvar", LineStyles.Highway2));
valueStyle2.ValueItems.Add(new ValueItem("Devlet Yolu", LineStyles.Highway1));
valueStyle2.ValueItems.Add(new ValueItem("Otoyol", LineStyles.Highway1));
valueStyle2.ValueItems.Add(new ValueItem("Otoyol Bağlantısı", LineStyles.Highway1));

valueStyle2.ValueItems[3].DefaultLineStyle.InnerPen.Color = GeoColor.StandardColors.LightPink;
valueStyle2.ValueItems.Add(new ValueItem("İl Yolu", LineStyles.Interstate1));

roadLayer.ZoomLevelSet.ZoomLevel13.CustomStyles.Add(valueStyle2);
roadLayer.ZoomLevelSet.ZoomLevel13.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level16;

// Zoom level 17-20
ValueStyle valueStyle3 = new ValueStyle();
valueStyle3.ColumnName = "TIPI";
valueStyle3.ValueItems.Add(new ValueItem("Yol", LineStyles.LocalRoad3));
valueStyle3.ValueItems.Add(new ValueItem("Sokak", LineStyles.LocalRoad2));
valueStyle3.ValueItems.Add(new ValueItem("Cadde", LineStyles.LocalRoad2));
valueStyle3.ValueItems.Add(new ValueItem("Bulvar", LineStyles.Highway2));
valueStyle3.ValueItems.Add(new ValueItem("Devlet Yolu", LineStyles.Highway1));
valueStyle3.ValueItems.Add(new ValueItem("Otoyol", LineStyles.Highway1));
valueStyle3.ValueItems.Add(new ValueItem("Otoyol Bağlantısı", LineStyles.Highway1));

valueStyle3.ValueItems[4].DefaultLineStyle.InnerPen.Color = GeoColor.StandardColors.LightPink;
valueStyle3.ValueItems.Add(new ValueItem("İl Yolu", LineStyles.Interstate1));
valueStyle3.ValueItems.Add(new ValueItem("İç Yol", LineStyles.LocalRoad4));

roadLayer.ZoomLevelSet.ZoomLevel17.CustomStyles.Add(valueStyle3);
roadLayer.ZoomLevelSet.ZoomLevel17.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;

mcTest.StaticOverlay.Layers.Add(roadLayer);


But these are quite big files and the biggest one has the following sizes


shp file : 25 MB

dbf file : 25 MB

shx file : 2 MB

prj file : 1 KB (this is constant anyway)


ids file : 4 MB

idx file : 25 MB


approximate number of features (polylines) : 250000


Total data set (excluding Map Suite index files) is about 550 MB.


I'm thinking of the following ways to use the data, but I have no idea which one would be better. I would have to spend less time on trial and error, if I could have some pointers here.


1) Use the shape files as they are. We have 81 cities, thus I would have 81 static feature layers. There would also be a few more layers for POIs or geographic features etc.


2) Concatenate all the cities into one big Country.shp file.


3) Concatenate all the cities into one big Country.shp file. Then, from this data, create a layer for each type of road. Such as Country_streets.shp, Country_highways.shp etc. and load them as feature layers.


4) Something else ???


 


Best regards,


Hakan Çelik



Hakan, 
  
   I think your reasoning is sound on the options.   
  
   It is important that we get rid of the ValueStyle as that will slow things down because it needs extra data and there is more logic.  We also need to reduce the number of shape files if possible.  Having one large shape file would be the best.  This minimizes the number of open, close, and index queries.  To get rid of the value style and minimize the number of shape files you have a few options.  The first it to combine all the roads and then split them into shape files by road type.  In this way you will have just a few road shape files and you can render them directly with a style without having to use any decision based styles that need extra DBF columns.  Another way would be to create one large shape file for the roads and then use a custom spatial index.  When you build and index you can specify a group of features.  This will make a sparse index of just a certain road type.  When you create your layer you specify for highways that you want the ‘allroads.shp’ and the 'highways.idx”.  In this way you can have one large shape file but when we query the index we only find highways.  This means that you will have one large shape file with multiple smaller index files.  Please let me know if this makes sense. 
  
   I also suggest that you look at the Layer.DrawingTime or some similar property.  It will record how long it took to draw this layer last time.  You can look to see which layers are taking the most time and possibly what to improve.  What I find is that right behind lines the biggest issue are area shapes of things like countries or local regions especially for the web.  The reason is that if we draw a small tile and it has a background of a country we need to fetch the country record with all of its vertexes even if non of them display on the screen or you are in the middle of it.  We have to read, convert, and draw this large area every time.  This can really slow things down.  This is hard issue to solve but what we have done in the past is at lower levels we have a version of the area file where the areas are split into small grid sized areas so that at low extents they draw quickly.  We also then create a line based shape file to display the borders.  This works very well when your country or boundary files are complex. 
  
 Let me know if any of this applies to you.  Let me know what you think and I would be happy to think of more items to help with you specific dataset.  Unfortunately they are few silver bullets for these problems.  The best thing to do is measure the drawing times and consider what should be better. 
  
 David

Hi, 
  
 I am trying to archieve the same thing.  I need to draw my roads differently according to the road type.  I’m interested in using multiple index files for one single shape layer.  How to generate index files according to the road type? 
  
 Can the multiple index files be used with the MultipleShapeFileFeatureLayer?  My streets shape files are called streets_van.shp, streets_ric.shp, streets_bur.shp, etc.  I provide streets_van.shp for my client who wants to see only Vancouver roads.  However, they want the flexibility see my more cities when they request it.  So, we use the MultipleShapeFileFeatureLayer with wildcard ‘streets???.shp’ to provide the flexibility to add more regions without changing our code or configurating our application differently.  It will be a perfect solution if the mulitple index files works with the MultipleShapeFileFeatureLayer for us. 
  
 Thanks, 
 Tracy

Hi, Tracy 
  
 If your road data is not so big and also you own your better cache system; there is no need to generate index files according to the road type. 
 Your idea is right; first off build all midx and mids for the whole street data and then you just need to dump files your clients need into data folder. 
  
 Thanks, 
 Khalil 


Hi Khalil, 
  
 What I want to do is to draw my roads differently.  For road type for example ferry routes, I’d like to draw it in different color than my regular roads in the streets??? multi layer. 
  
 Thanks, 
 Tracy

Hi, Tracy 
  
 You could implement it using ValueStyle. We have a DrawFeaturesBasedOnValues sample in our installed samples which you can find its source code at "Samples\Styles\DrawFeaturesBasedOnValues.aspx". 
  
 Thanks, 
 Khalil

Hi,


We're using the scalingImageStyle from gis.thinkgeo.com/Support/DiscussionForums/tabid/143/aff/16/aft/5014/afv/topic/Default.aspx


How can we use it with ValueStyle? Try to use it but it complaint about not having collection argument:



ValueStyle valueStyle = new ValueStyle();
valueStyle.ColumnName = "FERRY_TYPE";
valueStyle.ValueItems.Add(new ValueItem("H", imageStyle));

Thanks,


Tracy



Hi, Tracy 



Maybe there is some misunderstanding about ValueStyle. We have a  "DrawFeaturesBasedOnValues" sample in our installed samples, and you could paste the code below to it and test it. 


                Map1.MapBackground.BackgroundBrush = new GeoSolidBrush(GeoColor.FromHtml("#E5E3DF"));
                Map1.CurrentExtent = new RectangleShape(-125, 72, 50, -46);
                Map1.MapUnit = GeographyUnit.DecimalDegree;

                WorldMapKitWmsWebOverlay worldMapKitOverlay = new WorldMapKitWmsWebOverlay();
                Map1.CustomOverlays.Add(worldMapKitOverlay);

                ShapeFileFeatureLayer citiesLayer = new ShapeFileFeatureLayer(Server.MapPath("~/SampleData/World/capital.shp"));
                citiesLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;

                ScalingImageStyle imageStyle = new ScalingImageStyle();
                imageStyle.Image = new GeoImage(Server.MapPath("../../theme/default/samplepic/city.png"));
                Collection<Style> customStyles = new Collection<Style>();
                customStyles.Add(imageStyle);
                // Draw features based on values
                ValueStyle valueStyle = new ValueStyle();
                valueStyle.ColumnName = "POP_RANK";
                valueStyle.ValueItems.Add(new ValueItem("1", PointStyles.Capital1));
                valueStyle.ValueItems.Add(new ValueItem("2", PointStyles.Capital3));
                valueStyle.ValueItems.Add(new ValueItem("3", customStyles));
                citiesLayer.ZoomLevelSet.ZoomLevel01.CustomStyles.Add(valueStyle);
                citiesLayer.DrawingMarginPercentage = 50;

                LayerOverlay staticOverlay = new LayerOverlay();
                staticOverlay.Layers.Add("CitiesLayer", citiesLayer);
                staticOverlay.IsBaseOverlay = false;
                Map1.CustomOverlays.Add(staticOverlay);


Thanks,


Khalil



Hi,


Thanks for the sample code. 


We now have a question about the labeling.


Using ValueStyle shows more labels than using regular style; and we notice performance slow down when more labels are displayed.  How can we use ValueStyle but keep as few labels as possible like using regular style?


Here is our code:



ValueStyle valueStyle = new ValueStyle();
valueStyle.ColumnName = "FERRY_TYPE";
Collection<Style> customStyles = new Collection<Style>();
customStyles.Add(map_def.hwytextStyle);
valueStyle.ValueItems.Add(new ValueItem("H", customStyles));
multiLayer.ZoomLevelSet.ZoomLevel12.CustomStyles.Add(valueStyle);
multiLayer.ZoomLevelSet.ZoomLevel12.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level16;

Attached are two files that one uses Value style and the other use just regular style.


Thanks,


Tracy



1881-ValueStyleMap.JPG (84.1 KB)

Hey, Tracy 
  
 Sorry for delay response. RegexStyle and ValueStyle almost have the same logic for DrawCore method. The problem maybe is caused by that you get different features using these two styles. ValueStye uses exact match but RegexStyle uses fuzzy matching; so the features you get using ValueStyle maybe is more than the features that RegexStyle get. 
  
 Thanks, 
 Khalil

Hi Khalil, 
  
 thanks for the reply. but I don’t think it’s the source data. 
 in the picture you will see more label for one street when using ValueStyle as compare to one that doesn’t use RegexStyle or ValueStyle. 
 e.g. let say for a street that is called Main St. you will see more labels on the map repeated more then when not using the RegexStyle or ValueStyle.

Hi, Tracy 
  
 I can’t see the picture or attached files you have mentioned in the previous posts. Generally it won’t draw many more labels on one street unless some street have divided into many parts and the labels are the same in DBF file.  
 If you can’t post image or files please send them to support@thinkgoe.com and ask him forward to me. So I will handler it quickly. 
  
 Thanks, 
 Khalil

Hi Khalil,


I hope this time I did it right to attach.


Thanks,


Tracy



1882-RegularStyleMap.JPG (67.3 KB)
1881-ValueStyleMap.JPG (84.1 KB)

Hi, Tracy 
  
 Yes, I get these images. It does draw more labels if you use ValueStyle instead of RegularStyle. Please try to set the properties below: 
                 streetsLayer.ZoomLevelSet.ZoomLevel10.DefaultTextStyle.OverlappingRule = LabelOverlappingRule.NoOverlapping; 
                 streetsLayer.ZoomLevelSet.ZoomLevel10.DefaultTextStyle.DuplicateRule = LabelDuplicateRule.NoDuplicateLabels; 
 If it still couldn’t solve your problem, please send us the app and data, so we could recreate it and fix it quickly. 
 Sorry for the inconvenience for you. 
  
 Thanks, 
 Khalil