ThinkGeo.com    |     Documentation    |     Premium Support

Dissolving Polygon Features

Hi Thinkgeo Team,



I am using PostgreSqlFeatureLayer to query and dissolve features as shown in the code snipet below


public void DissolveDistrict(Persistence.Web.Map.PostgreSqlFeatureLayer layer) {
            layer.Open();
            DataTable data = layer.FeatureSource.ExecuteQuery(“select distinct dist_name from iringa_region”);
            DbfColumn NameColumn = new DbfColumn(“dist_name”, DbfColumnType.String,250,0);
            PostgreSqlFeatureSource sources = new PostgreSqlFeatureSource(layer.ConnectionString, layer.TableName, “gid”);            
            ThinkGeo.MapSuite.Core.InMemoryFeatureLayer districts = new ThinkGeo.MapSuite.Core.InMemoryFeatureLayer();            
            districts.Open();
            foreach (DataRow dataRow in data.Rows)
            {
                Collection<AreaBaseShape> polygonShapes = new Collection<AreaBaseShape>();
                Collection<Feature> features = layer.FeatureSource.GetFeaturesByColumnValue(“dist_name”, System.Convert.ToString(dataRow[0]));
                
                foreach (Feature feature in features)
                {
                    AreaBaseShape polygonShape = (AreaBaseShape)feature.GetShape();
                    polygonShapes.Add(polygonShape);
                }
 
                int count = polygonShapes.Count;
 
                
                MultipolygonShape multiPolygonShape = PolygonShape.Union(polygonShapes);               
                Dictionary<stringstring> Columns = new Dictionary<stringstring>();
                Columns.Add(“dist_name”, System.Convert.ToString(dataRow[0]));
                Feature newFeature = new Feature(multiPolygonShape, Columns);
                districts.InternalFeatures.Add(dataRow[0].ToString(),newFeature);
            }
            
            DefaultMap.DynamicOverlay.Layers.Clear();
            districts.ZoomLevelSet.ZoomLevel02.DefaultTextStyle = TextStyles.Capital3(“dist_name”);
            districts.ZoomLevelSet.ZoomLevel02.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
            districts.ZoomLevelSet.ZoomLevel02.DefaultAreaStyle = AreaStyles.CreateSimpleAreaStyle(GeoColor.StandardColors.Transparent, GeoColor.SimpleColors.PaleGreen);
            districts.DrawingQuality = DrawingQuality.HighQuality;           
            DefaultMap.DynamicOverlay.Layers.Add(“districts”,districts);
            DefaultMap.CurrentExtent = districts.GetBoundingBox();
            districts.Close();
        }

The result is as shown in the image below



The problem with the resulting layer as seen in the image above is that, it has alot of unwanted dots and lines. I expected to have only 5 polygons with clear area. 



Secondly in my codes above there is a line as shown below for lebeling each resulting polygon but the labels are not appearing


districts.ZoomLevelSet.ZoomLevel02.DefaultTextStyle = TextStyles.Capital3(“dist_name”);

Can you please help me where I am going wrong?



Best Regards,

Vincent

Hi Vincent,



I the unclear area render effect is caused by the dissolve way. I found you add the polygons into a multi polygon, in this case, each inner polygon will draw separately. I think what we need is union the polygon into one polygon and render then separately. So the solution for this issue could be use the following code to get an union polygon and add into the InMemoryFeatureLayer.




MultipolygonShape newMultiPolygonShape = MultipolygonShape.Union(multiPolygonShape.Polygons);
districts.InternalFeatures.Add(dataRow[0].ToString(), newMultiPolygonShape);





If this doesn’t satisfy your requirement, please try to convert your InMemoryFeatureLayer to a ShapeFileFeatureLayer with the attached code; then send to us. We will try to figure out what happens inside.



The text is not shown is caused by the column is not set on the InMemoryFeatureLayer. I think it will be fine when we add the column into the InMemoryFeatureLayer right after the districts layer is Opened, like this:



districts.Columns.Add(new FeatureSourceColumn("dist_name", "Character", 30));



Hope it works for you. Please feel free to let us know if you have more queries.



Thanks,
Howard



private static void ExportToShapeFile(InMemoryFeatureLayer sourceLayer, string targetPathFileName)
{
if (!sourceLayer.IsOpen) sourceLayer.Open();
Collection<featuresourcecolumn> sourceColumns = sourceLayer.GetColumns();
string folderName = Path.GetDirectoryName(targetPathFileName);
if (!Directory.Exists(folderName)) Directory.CreateDirectory(folderName);
IEnumerable<dbfcolumn> targetColumns = sourceColumns.Select(c => new DbfColumn(c.ColumnName, DbfColumnType.Character, c.MaxLength, 0));
ShapeFileFeatureLayer.CreateShapeFile(ShapeFileType.Polygon, targetPathFileName, targetColumns);
ShapeFileFeatureLayer targetLayer = new ShapeFileFeatureLayer(targetPathFileName, ShapeFileReadWriteMode.ReadWrite);
targetLayer.Open();
targetLayer.EditTools.BeginTransaction();
foreach (var feature in sourceLayer.QueryTools.GetAllFeatures(ReturningColumnsType.AllColumns))
{
targetLayer.EditTools.Add(feature);
}
targetLayer.EditTools.CommitTransaction();
}


Hi Howard,



I have implemented it the way you have suggested but the unclear area still appears. I can send you the source shape file but it has propriatory data and therefore can not upload it here on the forum. Can you give me an alternative way of sending the shape file to you?





Best Regards,

Vincent

Hi Vincent, 
  
 Thanks for your further information, you can send the file to forumsupport@thinkgeo.com
  
 Regards, 
  
 Gary

Hi Gary,



Thank you for the prompt response. I have already sent it to the above email. Its projection is EPSG 21037



Best Regards,

Vincent

Hi Vincent, 
  
 Sorry for the inconvenience that the forum support is in weekend. I will ask for that and try to track this problem. 
  
 Thanks for your patient. 
 Howard

Hi Vincent,



I got your shapefile, and I found the unclear area are inner rings. With your shapefile, I did following two steps.



1, Union all the features inside of the shapefile.
2, Optionally remove the inner ring inside of the union multipolygon. I listed two options in the loop, please feel free to choose one.


ShapeFileFeatureLayer layer = new ShapeFileFeatureLayer(“iringa_region.shp”);
layer.Open();
Collection<Feature> features = layer.QueryTools.GetAllFeatures(ReturningColumnsType.NoColumns);
 
MultipolygonShape multipolygon = MultipolygonShape.Union(features);
foreach (var polygon in multipolygon.Polygons)
{
    // option 1, we can clear all the inner rings inside of the polygon.
    polygon.InnerRings.Clear();
 
    // option 2, we can optionally remove the rings inside of the polygon.
    for (int i = polygon.InnerRings.Count - 1; i >= 0; i–)
    {
        double area = polygon.InnerRings<i>.GetArea(GeographyUnit.DecimalDegree, AreaUnit.SquareMeters);
        if (area < 20) polygon.InnerRings.RemoveAt(i);
    }
}
 
Bitmap bitmap = new Bitmap(512, 512);
GdiPlusGeoCanvas canvas = new GdiPlusGeoCanvas();
canvas.BeginDrawing(bitmap, layer.GetBoundingBox(), GeographyUnit.DecimalDegree);
canvas.DrawArea(multipolygon, new GeoPen(new GeoSolidBrush(GeoColor.StandardColors.Black)), new GeoSolidBrush(GeoColor.StandardColors.Gray), DrawingLevel.LevelOne);
canvas.EndDrawing();
 
bitmap.Save(“d:\1.png”);


Then I draw the final multi polygon and the effect is this.



Thanks and feel free to let me know if you have more queries,
Howard

Hi Howard,



Thank you for the solution. Now everything goes fine except sometimes I get an error “Directed Edge visited twice during ring-building at (14387.1198046585, 63398.5613653939, NaN)” when dissolving using dist_name column.





Best Regards,

Vincent






Hi Howard,



Apart from the ‘directed edge visited twice’ problem stated above, also by dissolving using dist_name column, some resulting features are labeled and some are not although the corresponding labeling source column has content for each feature. Can you look at these problems please?





Best Regardss,

Vincent

Hi Vincent, 
  
 Does this exception thrown by this line: MultipolygonShape multipolygon = MultipolygonShape.Union(features) ? 
  
 If not, could you please make sure which line thrown it, and stack track information should be helpful. 
  
 Regards, 
  
 Don

Hi Don,



Thank you for the reply. Yes it is thrown by the line  MultipolygonShape multipolygon = MultipolygonShape.Union(features). Please do not forget the labeling problem.





Best Regards,

Vincent

Hi Vincent,



This exception might be thrown by NTS. We can simply fix it by the following code. If this doesn’t work, please write the features’ wkt into a txt file and send to us, we will verify this issue. 


MultipolygonShape multipolygon1 = MultipolygonShape.Union(features.Select(f => SqlTypesGeometryHelper.MakeValid(f)));





I don’t quite understand the labeling issue. Could you provide us a screenshot or a code block, so that we can well understand it?



Thanks,
Howard

Hi Howard, 

To elaborate my problem on labeling of the resulting features after dissolving I have sent an email to support@thinkgeo.com titled ‘Dissolving Sample Shape File’ which has an attachment with a shape file. Can you please dissolve the features of the shape file using the column “ward_name”? (i.e. dissolve everything with each distinct ward_name and label the resulting feature with ward_name content) If you do, you will see my labeling problem. If it goes successifully please give me the codes so that I can establish where I am making mistake.





Best Regards,

Vincent

Hi Howard,

Did you get any idea?



Best Regards,

Vincent

Hi Vincent,



I got your email this morning and I have some ideas for you. With my attached project, it works fine for the dissolving and the label issue. Please take a look at that.



1. In the project, I didn’t get any exception during the union process. But I wrote another option for you, if you still have that exception, please feel free to use my uncomment code.
2. The label issue is a strategy. It suppresses some of the labels that are too close or the area has not enough space to entirely draw the label. So we can simply set the following code to draw all the labels.
targetLayer.ZoomLevelSet.ZoomLevel01.DefaultTextStyle.DuplicateRule = LabelDuplicateRule.UnlimitedDuplicateLabels;
3. The final result is like this:
 





Hope it helps and feel free to let us know if you have more queries.



Thanks,
Howard

Post11781.zip (978 KB)

Hi Howard,



Thank you very much indeed for your help. Everything is now working fine meeting our expectations.





Best Regards,

Vincent

Hi Vincent, 
  
 Good to hear it helps. 
 Any questions, please feel free to let us know. 
  
 Regards, 
 Troy

Hi Team,



In you above dessolving result there are some protruding lines long the boundaries as shown in the image below taken from your result above. 







Is there a way to remove these lines similarly like you do with inner rings?



Best Regards,

Vincent

Hi Vincent, 
  
 We can buffer those shapes to solve it. In the codes provided from Howard, please add the below codes: 
  
  
multipolygon = multipolygon.Buffer(1, GeographyUnit.DecimalDegree, DistanceUnit.Meter);

                // we can decide how to retain the unioned column values.
                Feature newFeature = new Feature(multipolygon, item.First().ColumnValues);
                unionFeatures.Add(newFeature);
 
 Regards, 
 Troy