Complex Symbology Suggestions needed

Developer
Dec 5, 2010 at 1:01 AM

I need some suggestions regarding a function to generate distinct symbology for a map.

The idea is that I have, for example, counties and regions such that regions are always contiguous within the bounds of a country. So, I need to color them as follows.  
Colors would be cycled through so that no color is repeated within a single country but that colors are reused in other countries.  It should be automatic so when a user digitizes a new region the new region is colored with the next available color for that region.  That is, I don;t want to put a POLYGON_STYLE field in the regions table and color by that.
   
C1/R1 (Country 1/Region 1) = S1 (Sybology 1 )
C1/R2 = S2
C1/R3 = S3
C1/R4 = S4
C1/R5 = S5
C2/R1 = S1
C2/R2 = S2
C2/R3 = S3
C2/R4 = S4
C3/R1 = S1
C3/R2 = S2
C3/R3 = S3
C3/R4 = S4
C3/R5 = S5
C3/R6 = S6
My data structure is just two shape files.  There is not even a foreign key relationship between regions and countries (though I could add it if I need to) So the membership of a region within the countries is determined only by spatial query.
Using Dot Spatial how would approach this problem?
Thanks
Garth Tissington

Developer
Dec 5, 2010 at 1:26 AM

You can always cheat.  You can split up the single featureset into separate countries where each region within that featureset is symbolized by FID.  If you don't want to do that, then what I would recommend is setting up as many categories as the maximum number of regions in a country.  Lets presume its something like 50.  Each is set up with a distinct color or pattern or whatever you want in the Symbolizer.  Then (if you are in indexMode) you can cycle through the FeatureLayer.DrawnStates, manually assigning the category that goes with each integer shape index, according to an intersection test with the countries layer.  If you are in edit mode (relying on features) you will have to create an instance of a DrawingFilter.  This is the same kind of dictionary, except that instead of using a FastDrawnState array using the integer key, it uses IFeature as the key in the index.  So in that case you would cycle through the Features list.  Either way you do it, that's going to be your way to update the scheme programmatically.  It will be nullified if the user changes the scheme using the dialogs in the legend though.

Ted 

Developer
Dec 5, 2010 at 2:32 AM

Ted,

I didn't understant the first suggestion.

>You can split up the single featureset into separate countries where each region within that featureset is symbolized by FID.

Could you explain a little further?

 

Garth

Developer
Dec 5, 2010 at 3:01 AM

You'd just create one output FeatureSet for each country.  It's cheating because you don't actually do anything sophisticated with symbology, but you would have multiple FeatureSets and MapPolygonLayers to work with instead.  You could basically write a loop through the original featureset, test each feature against your countries featureset to see which country shape intersects with the current feature.  Then, add the feature to the output featureset for that country.  Then, when you add them to the map, you could add them all in a group, so that the group could collapse or be expanded.  Setting up the FID criteria is simple in that case because you can just set the scheme to build on unique values based on [FID].  I think you will want to check the Symbology property which should be a PolygonScheme.  That should have "EditorSettings" which you can use in order to configure a scheme that will automatically create unique categories and all that stuff for you when you call ApplyScheme() on the FeatureLayer.

Ted

 

Developer
Dec 5, 2010 at 7:28 PM

Is there nsome sort of way to hook into the drawing processes

 

Like some sort of per feature event?

OnGetSymbology( in Feature, out symbology );

 

 

Developer
Dec 6, 2010 at 7:27 PM

Well, I found a pretty straight forward way to do this.  Maybe this is what you meant in one of your suggestestons..

 

 foreach (var countryFeature in countries50 Layer.DataSet.Features)
 {
 	int iCategoryIndex = 0;
        foreach (var stateFeature in statesLayer.DataSet.Features)
        {
        	if (countryFeature.Overlaps(stateFeature) || countryFeature.Contains(stateFeature))
                {
                        IPolygonCategory category = _stateCategories[iCategoryIndex++];
                        stateLayer.SetCategory(stateFeature, category);
                }
	}
}

 

this does the styling of states exactly as I needed (of course I set up the collections of _stateCategories elsewhere)

However it has two shortcomings

 

a) The categories do not show up in the legend

b) Now, DeleteSelectedFeatures does not work... I guess because each feature has multiple assigned states?

 

Any advice Ted?  Anyone?

 

 

 

Developer
Dec 6, 2010 at 7:40 PM

To make the categories show up in the legend, you need to add them to your scheme by doing myLayer.Symbology.Categories.Add(category1) for example.  Even if you are manually applying the scheme etc.

Not sure about DeleteSelectedFeatures.  I'm not even sure where that is.  But basically selection is handled on the FastDrawnState (or DrawingFilter) independently from the Category assignment.  That is, you should not be causing any problems for selection by using your predefined categories as far as I am aware.  However, you are using the objects in a way that is slightly unconventional.  This means you may be trailblazing a bit through unexpected "features" that crop up.  If  that is the case, we may need to debug it a bit and see what's going wrong.  If you need to delete the features and "DeleteSelectedFeatures" doesn't work even after you add the categories to the Symbology, then you may need to simply cycle through the myFeatureLayer.DrawnStates until you find members where currentFastDrawnState.Selected == true.  In that case, if you keep track of the index, you can delete based on the index.

I'm not sure how effective changing the categories in the legend will work.  changing a category individually should be fine.  But if you open the symbolizer for the whole layer, it might change the categories on you.  There should be an event like "SymbologyChanged" or something that you can catch.  Anyway, I'm sure you will have fun sorting out the details.

Ted