ET GeoWizards Scripting
Smooth Polygons - How to do it?
Since the release of EditTools for ArcView 3.x, and even more often after the release of ET GeoWizards this is one of the most frequently asked questions. In general this should not be a procedure much more difficult than smoothing a polyline, but there are several considerations that need to be taken into account. Read the ET GeoWizards Frequently Asked Questions for an explanation.
So if we want to smooth polygons and preserve the topological relationships between them we need a several step procedure:
Step1: Convert your polygons to polylines
Step2: Clean the resulting polyline layer
Step3: Smooth the polylines
Step4: Build a new polygon feature class from the smoothed polylines
This is achievable with the functions available in ET GeoWizards 8.7, but each of the steps needs to be performed via the interface.
The main purpose of this topic is to show how the Scripting introduced in ET GeoWizards 9.0 can help you to perform complex geoprocessing with just few lines of code.
How to smooth polygons and keep the polygon dataset topologically correct?
The four step procedure above is a bit generalized. We need at least two more steps if you want to preserve the polygon attributes. The scheme below gives a graphic description of the entire process
The process above might look a bit complex, but can be achieved using ET GeoWizards Scripting with just few lines of code (Have in mind that to achieve this with the standard ArcObjects you'll need thousands lines of code)
A. Basic code - If we remove the comments it is about 20 lines of code. If we take out the declarations and the basic stuff, the entire procedure is accomplished in 8 lines of code!
Sub SmoothPolygons1() 'Some declarations needed Dim pMxDoc As IMxDocument 'Current document Dim pMap As IMap ' The map Dim ET As New ETGW_Core ' ET GeoWizards library Dim pFeatureLayer As IFeatureLayer 'A feature layer Dim pInFeatureClass As IFeatureClass ' The input feature class Dim pOutFeatureClass As IFeatureClass ' The resulting feature class Dim pLabelFeatureClass As IFeatureClass ' A feature class that we going to use to transfer the attributes ' Now set some of the variables Set pMxDoc = ThisDocument 'Get the document Set pMap = pMxDoc.FocusMap ' Get the Map ' Here we are going to use the currently selected layer in the TOC to Set pFeatureLayer = pMxDoc.SelectedLayer ' Get the polygon layer to be smoothed Set pInFeatureClass = pFeatureLayer.FeatureClass 'Get the feature class of the input layer 'Here the actual process begins '1. Get the label points of the original polygons Set pLabelFeatureClass = ET.PolygonToPoint(pInFeatureClass, "c:\00\labels.shp", "Label", False) '2. Convert the polygons to polylines Set pOutFeatureClass = ET.PolygonToPolyline(pInFeatureClass, "c:\00\polylines.shp") '3. Clean the polylines ( the duplicate lines on the common boundary need to be removed) Set pOutFeatureClass = ET.CleanPolyline(pOutFeatureClass, "c:\00\polylines_clean.shp", 0.0001) '4. An optional step that might be needed if we want better approximation of the original polygons Set pOutFeatureClass = ET.DensifyPolylines(pOutFeatureClass, "c:\00\polylines_densified.shp", 0.02, 0.02) '5. This is the actual smoothing Set pOutFeatureClass = ET.SmoothPolylines(pOutFeatureClass, "c:\00\polylines_smooth.shp", "bSpline", 5, 3) '6. Another optional step - getting rid of the excess vertices Set pOutFeatureClass = ET.GeneralizePolylines(pOutFeatureClass, "c:\00\polylines_generalized.shp", 0.0002) '7. Now we can rebuild the polygons using the smoothed polylines Set pOutFeatureClass = ET.BuildPolygons(pOutFeatureClass, "c:\00\polygons.shp", False, 0.0001) '8. Use the Spatial Join to get the attributes back to the smoothed polygons Set pOutFeatureClass = ET.Spatial_Join(pOutFeatureClass, pLabelFeatureClass, _ "c:\00\polygons_final.shp", "Nearest", True, 0) 'The rest is standard Set pFeatureLayer = New FeatureLayer 'create a new feature layer Set pFeatureLayer.FeatureClass = pOutFeatureClass 'set the feature class to the layer pFeatureLayer.Name = pOutFeatureClass.AliasName ' set the name of the layer pMap.AddLayer pFeatureLayer ' add the layer to the map End Sub |
B. Some error checking, resources and file cleaning is always a good practice. The code becomes a bit longer, but is more manageable
Sub SmoothPolygons2() Dim pMxDoc As IMxDocument Dim pMap As IMap Dim ET As New ETGW_Core Dim pFeatureLayer As IFeatureLayer Dim pInFeatureClass As IFeatureClass Dim pOutFeatureClass As IFeatureClass Dim pLabelFeatureClass As IFeatureClass Dim bDone As Boolean On Error GoTo EH Set pMxDoc = ThisDocument Set pMap = pMxDoc.FocusMap Set pFeatureLayer = pMxDoc.SelectedLayer 'Check if the user has selected a layer in the TOC If pFeatureLayer Is Nothing Then MsgBox "No selected layer" Exit Sub End If Set pInFeatureClass = pFeatureLayer.FeatureClass Set pLabelFeatureClass = ET.PolygonToPoint(pInFeatureClass, "c:\00\labels.shp", "Label", False) 'Check if the process completed successfully. This step is repeated for every sub process below If pLabelFeatureClass Is Nothing Then MsgBox "Error in step 0" Exit Sub End If Set pOutFeatureClass = ET.PolygonToPolyline(pInFeatureClass, "c:\00\polylines.shp") If pOutFeatureClass Is Nothing Then MsgBox "Error in step 1" Exit Sub End If Set pOutFeatureClass = ET.CleanPolyline(pOutFeatureClass, "c:\00\polylines_clean.shp", 0.0001) If pOutFeatureClass Is Nothing Then MsgBox "Error in step 2" Exit Sub End If Set pOutFeatureClass = ET.DensifyPolylines(pOutFeatureClass, "c:\00\polylines_densified.shp", 0.02, 0.02) If pOutFeatureClass Is Nothing Then MsgBox "Error in step 3" Exit Sub End If Set pOutFeatureClass = ET.SmoothPolylines(pOutFeatureClass, "c:\00\polylines_smooth.shp", "bSpline", 5, 3) If pOutFeatureClass Is Nothing Then MsgBox "Error in step 4" Exit Sub End If Set pOutFeatureClass = ET.GeneralizePolylines(pOutFeatureClass, "c:\00\polylines_generalized.shp", 0.0002) If pOutFeatureClass Is Nothing Then MsgBox "Error in step 5" Exit Sub End If Set pOutFeatureClass = ET.BuildPolygons(pOutFeatureClass, "c:\00\polygons.shp", False, 0.0001) If pOutFeatureClass Is Nothing Then MsgBox "Error in step 6" Exit Sub End If Set pOutFeatureClass = ET.Spatial_Join(pOutFeatureClass, pLabelFeatureClass, _ "c:\00\polygons_final.shp", "Nearest", True, 0) If pOutFeatureClass Is Nothing Then MsgBox "Error in step 7" Exit Sub End If 'Delete the unneeded intermediate feature classes bDone = ET.Deletefeature class("c:\00\labels.shp") bDone = ET.Deletefeature class("c:\00\polylines.shp") bDone = ET.Deletefeature class("c:\00\polylines_clean.shp") bDone = ET.Deletefeature class("c:\00\polylines_densified.shp") bDone = ET.Deletefeature class("c:\00\polylines_smooth.shp") bDone = ET.Deletefeature class("c:\00\polylines_generalized.shp") bDone = ET.Deletefeature class("c:\00\polygons.shp") Set pFeatureLayer = New FeatureLayer Set pFeatureLayer.FeatureClass = pOutFeatureClass pFeatureLayer.Name = pOutFeatureClass.AliasName pMap.AddLayer pFeatureLayer 'Release the object variables Set pMxDoc = Nothing Set pMap = Nothing Set pFeatureLayer = Nothing Set pInFeatureClass = Nothing Set pOutFeatureClass = Nothing Set pLabelFeatureClass = Nothing Exit Sub EH: MsgBox Err.Description End Sub |