Upload
si-lumba-bf
View
214
Download
0
Embed Size (px)
Citation preview
8/3/2019 Polylines to a Polygon Feature Class
1/5
The code below takes the closed Polylines from an existing FeatureClass, and creates a new
FeatureClass of Polygons from them. The FeatureClass must be in a GeoDatabase
FeatureDataset - the new FeatureClass is created in this FeatureDataset.
How to use:
1. Open ArcMap, open the VBA editor and paste the code below into the code window.2. Add a FeatureDataset containing a Polyline FeatureClass. Some of the Polyline
features should form closed loops.
3. Run the ClosedLinesNewFC macro.Public Sub ClosedLinesNewFC()
'
' Get the current map.
'
Dim pMxDoc As IMxDocument, pMap As IMap
Set pMxDoc = ThisDocument
Set pMap = pMxDoc.FocusMap'
' Here, we select the top layer in the Map to work with.
'
Dim pFeatureLyr As IFeatureLayer, pFeatureClass As IFeatureClass
If TypeOf pMap.Layer(0) Is IFeatureLayer Then
Set pFeatureLyr = pMap.Layer(0)
Set pFeatureClass = pFeatureLyr.FeatureClass
'
' Check the layer belongs to a (Local or Remote) GeoDatabase
FeatureDataset - we will
' add the new FeatureClass of Polygons to this same FeatureDataset.
'
If Not pFeatureClass.FeatureDataset Is Nothing ThenDim pFeatureDataset As IFeatureDataset
Set pFeatureDataset = pFeatureClass.FeatureDataset
If Not pFeatureDataset.Workspace.Type = esriFileSystemWorkspace Then
'
' Check we have some closed lines before going ahead and creating a
FeatureClass.
'
If fnHasClosedLines(pFeatureClass) Then
'
' If we have found some closed lines, then create a FeatureClass.
The first step
' is to establish a fields collection, by copying the existing
Fields collection,' and altering the GeometryDef to contain Polygons instead of
Polylines.
'
Dim pNewFields As IFields
Set pNewFields = fnMakePolygonFields(pFeatureClass.Fields,
pFeatureClass.ShapeFieldName)
If pNewFields Is Nothing Then Exit Sub
If Not pNewFields.FieldCount = pFeatureClass.Fields.FieldCount
Then Exit Sub
'
' Create the new FeatureClass in the FeatureDataset, using the
cloned and edited
' Fields collection, and the name NewPolygons.'
Dim pNewFeatureClass As IFeatureClass
8/3/2019 Polylines to a Polygon Feature Class
2/5
Set pNewFeatureClass =
pFeatureDataset.CreateFeatureClass("NewPolygons", pNewFields, Nothing,
Nothing, esriFTSimple, pFeatureClass.ShapeFieldName, "")
'
' Start editing the FeatureClass we have created.
'
Dim pNewDataset As IDataset, pNewWorkspaceEdit As IWorkspaceEditSet pNewDataset = pNewFeatureClass
Set pNewWorkspaceEdit = pNewDataset.Workspace
pNewWorkspaceEdit.StartEditing False
pNewWorkspaceEdit.StartEditOperation
'
' Now we create a FeatureCursor from all of the features in the
original feature
' class. We use this cursor to iterate the features to find
closed Polylines.
'
Dim pFeatureCursor As IFeatureCursor, pFeature As IFeature
Set pFeatureCursor = pFeatureClass.Search(Nothing, False)
Set pFeature = pFeatureCursor.NextFeature
Dim pCurve As ICurve
Do While Not pFeature Is Nothing
Set pCurve = pFeature.Shape
If fnCurveClosed(pCurve) Then
'
' Add the closed line to the new FeatureClass as a Polygon,
copying the attributes.
'
Dim pPolygon As IPolygon
Set pPolygon = fnPolylineToPolygon(pCurve)
Dim pNewFeature As IFeature
Set pNewFeature = pNewFeatureClass.CreateFeature
'
' Iterate all the Fields to copy the attribute values.
'
Dim i As Integer
For i = 0 To pNewFields.FieldCount - 1
If (Not pNewFields.Field(i).Type = esriFieldTypeGeometry)
And (Not pNewFields.Field(i).Type = esriFieldTypeOID) Then
If pNewFields.Field(i).Editable Then
pNewFeature.Value(i) = pFeature.Value(i)
End If
End If
Next i
Set pNewFeature.Shape = pPolygon
pNewFeature.Store
End If
'
' Get the next Feature in the original Polyline FeatureClass.
'
Set pFeature = pFeatureCursor.NextFeature
Loop
'
' After iterating all of the features, stop the editing operation
and
' save the edits made.
'
pNewWorkspaceEdit.StopEditOperation
pNewWorkspaceEdit.StopEditing True
8/3/2019 Polylines to a Polygon Feature Class
3/5
'
' Add the new FeatureClass to the Map as a layer.
'
Dim pNewFeatureLayer As IFeatureLayer
Set pNewFeatureLayer = New FeatureLayer
Set pNewFeatureLayer.FeatureClass = pNewFeatureClass
pNewFeatureLayer.Name = pNewFeatureClass.AliasNamepMap.AddLayer pNewFeatureLayer
End If
End If
Else
MsgBox "To use this sample, your data should be part of a GeoDatabase
FeatureDataset." _
& vbNewLine & "You can create a FeatureDataset within ArcCatalog",
vbInformation
End If
End If
End Sub
Private Function fnMakePolygonFields(ByVal pOldFields As IFields,strShapeFieldName As String) As IFields
'
' This function creates a new Fields collection from an existing object,
' but changes the Geometry type held to Polylines. We pass in the
existing
' Fields collection by value to avoid changing the existing Fields.
'
If Not pOldFields Is Nothing Then
Set fnMakePolygonFields = pOldFields
Dim pFieldsEdit As esriCore.IFieldsEdit
Dim pFieldEdit As IFieldEdit, pField As IField
Dim pGeomDef As IGeometryDef, pGeomDefEdit As IGeometryDefEdit, lGeom
As Long
'
' Find the Field containing the shapes.
'
lGeom = fnMakePolygonFields.FindField(strShapeFieldName)
Set pField = fnMakePolygonFields.Field(lGeom)
Set pFieldEdit = pField
'
' Copy the current GeometryDefinition, get the GeometryDef editing
interface,
' and change it to store Polygons.
'
Set pGeomDef = pField.GeometryDef
Set pGeomDefEdit = pGeomDef
pGeomDefEdit.GeometryType = esriGeometryPolygon
'
' Set the new GeometryDef back to the Shape field.
'
With pFieldEdit
.Name = strShapeFieldName
.Type = esriFieldTypeGeometry
Set .GeometryDef = pGeomDef
End With
Set pFieldsEdit = fnMakePolygonFields
Set pFieldsEdit.Field(lGeom) = pFieldEdit
End If
End Function
8/3/2019 Polylines to a Polygon Feature Class
4/5
Private Function fnHasClosedLines(pFeatClass As IFeatureClass) As Boolean
fnHasClosedLines = False
If Not pFeatClass.ShapeType = esriGeometryPolyline Then Exit Function
'
' Check each feature in the FeatureClass to see if any features can be
classed as
' closed. We could use the ICurve.IsClosed property, but this way we canallow
' for a small tolerance in the distance between the FromPoint and
ToPoint.
'
Dim pFeatureCursor As IFeatureCursor, pFeature As IFeature
Set pFeatureCursor = pFeatClass.Search(Nothing, False)
Set pFeature = pFeatureCursor.NextFeature
'
' Iterate all Features.
'
Do While Not pFeature Is Nothing
If fnCurveClosed(pFeature.Shape) Then
fnHasClosedLines = TrueExit Function
End If
Set pFeature = pFeatureCursor.NextFeature
Loop
End Function
Private Function fnCurveClosed(pCurve As ICurve) As Boolean
fnCurveClosed = False
'
' We use the IProximityOperator interface to work out the distance
between
' the FromPoint and ToPoint of the curve passed in.
'
Dim pProxOp As IProximityOperator, dblDist As Double
Set pProxOp = pCurve.FromPoint
dblDist = pProxOp.ReturnDistance(pCurve.ToPoint)
'
' This is our tolerance for a 'closed' curve. We could relate this to a
snapping
' tolerance, or to the spatial reference, or to the size of the shape,
instead
' of hardcoding the distance.
'
If (dblDist < 0.0001) Then fnCurveClosed = True
End Function
Private Function fnPolylineToPolygon(ByVal pPolyline As IPolyline) As
IPolygon
'
' This function converts a Polyline to a Polygon, by creating a new
Polygon
' object and copying the Segments from the Polyline to the new Polygon,
and
' then ensuring the Polygon is Simple.
'
Set fnPolylineToPolygon = New Polygon
'
' Passing the Polyline by value means that we do not need to clone the
Polyline.
'
8/3/2019 Polylines to a Polygon Feature Class
5/5
Dim pPolygonSegs As ISegmentCollection, pPolylineSegs As
ISegmentCollection
Set pPolygonSegs = fnPolylineToPolygon
Set pPolylineSegs = pPolyline
'
' Here we copy the Segment objects by using the QuerySegments and
AddSegments' methods on the ISegmentCollection interface, which is implemented by
both
' a Polygon and Polyline coclass.
'
Dim pSegs() As ISegment
ReDim pSegs(pPolylineSegs.SegmentCount - 1) As ISegment
pPolylineSegs.QuerySegments 0, pPolylineSegs.SegmentCount, pSegs(0)
If UBound(pSegs) > 0 Then
pPolygonSegs.AddSegments UBound(pSegs) + 1, pSegs(0)
End If
'
' The Polygon may have it's rings oriented incorrectly, or have
overlapping Rings.' We call simplify here to ensure the new Polygon is Simple, which is a
requirement
' for adding to a FeatureClass.
'
fnPolylineToPolygon.SimplifyPreserveFromTo
End Function