' Copyright 2008 ESRI
'
' All rights reserved under the copyright laws of the United States
' and applicable international laws, treaties, and conventions.
'
' You may freely redistribute and use this sample code, with or
' without modification, provided you include the original copyright
' notice and use restrictions.
'
' See use restrictions at <your ArcGIS install location>/developerkit/userestrictions.txt.
'
'
'Title: Automatic symbol rotation
'Date: November 28, 2000
'Purpose: This sample code is designed to automatically rotate point symbols based on the
' line feature they are snapped to. The point features being added must have symbol
' rotation turned on for the extension to work correctly.
'
'To use:
'1.) Run Categories.exe and register the dll under ESRI Editor Extensions.
'2.) Start ArcMap and line and point data.
'3.) Make sure the symbology of at least one point layer is set for symbol rotation
'4.) Snap the point feature with rotation symbology to other line features.
'
Option Explicit
Implements IExtension
Dim WithEvents m_pEd As Editor
Dim WithEvents m_pMap As Map
Dim m_pEditor As IEditor
Dim m_bTracking As Boolean
Dim m_pRenderer As IRotationRenderer
Dim m_dClosestDist As Double
Private Sub Class_Initialize()
m_bTracking = False
End Sub
Private Property Get IExtension_Name() As String
IExtension_Name = "Switch Attribute Mover"
End Property
Private Sub IExtension_Shutdown()
Set m_pEditor = Nothing
Set m_pEd = Nothing
Set m_pRenderer = Nothing
End Sub
Private Sub IExtension_Startup(initializationData As Variant)
Set m_pEditor = initializationData
Set m_pEd = m_pEditor
End Sub
Private Sub m_pEd_OnCreateFeature(ByVal obj As esriGeoDatabase.IObject)
On Error GoTo ErrHand:
If m_bTracking Then
Rotate obj, True
End If
Exit Sub
ErrHand:
MsgBox "RotateSymbolOnCreate - " & Err.Description
End Sub
Private Sub Rotate(obj As IObject, bSetToZero As Boolean)
On Error GoTo ErrHand:
Dim pAddFeature As IFeature
Dim iLoop As Integer, pField As Long
Dim pSnapEnv As ISnapEnvironment
Dim pSnapAgent As IFeatureSnapAgent
Dim pTempSegment As ISegment, pClosestSegment As ISegment
Dim pFields As IFields, dAngle As Double
Set pAddFeature = obj
'Figure out what segment we snapped to.
Set pTempSegment = Nothing
Set pClosestSegment = Nothing
Set pSnapEnv = m_pEditor
m_dClosestDist = 999999999
For iLoop = 0 To pSnapEnv.SnapAgentCount - 1
If TypeOf pSnapEnv.SnapAgent(iLoop) Is IFeatureSnapAgent Then
Set pSnapAgent = pSnapEnv.SnapAgent(iLoop)
If pSnapAgent.HitType = esriGeometryPartBoundary And _
(pSnapAgent.FeatureClass.ShapeType = esriGeometryPolyline Or _
pSnapAgent.FeatureClass.ShapeType = esriGeometryPolygon) Then
Set pTempSegment = FindClosestSegment(pAddFeature, _
pSnapEnv.SnapTolerance, pSnapAgent.FeatureCache)
If Not pTempSegment Is Nothing Then
Set pClosestSegment = pTempSegment
Else
End If
End If
End If
Next iLoop
'Get the angle from the segment we snapped to.
If Not pClosestSegment Is Nothing Then
Dim pLine As ILine
If TypeOf pClosestSegment Is ILine Then
Set pLine = New esriGeometry.Line
pLine.PutCoords pClosestSegment.FromPoint, pClosestSegment.ToPoint
ElseIf TypeOf pClosestSegment Is ICurve Then
Dim pCurve As ICurve
Dim pOutPoint As IPoint
Set pOutPoint = New esriGeometry.Point
Set pLine = New esriGeometry.Line
Dim dAlongDist As Double, dFromDist As Double, dLength As Double, bSide As Boolean
Set pCurve = pClosestSegment
pCurve.QueryPointAndDistance esriExtendTangents, pAddFeature.Shape, False, pOutPoint, dAlongDist, _
dFromDist, bSide
dLength = 1
pCurve.QueryTangent esriExtendTangents, dAlongDist, False, dLength, pLine
End If
'Rotate the symbol to the correct angle
dAngle = pLine.Angle * (180 / 3.14159265358979)
If m_pRenderer.RotationType = esriRotateSymbolGeographic Then
dAngle = Abs(dAngle - 360) + 90
End If
If dAngle > 360 Then
dAngle = dAngle - 360
ElseIf dAngle < 0 Then
dAngle = dAngle + 360
End If
Else
If bSetToZero Then
dAngle = 0
End If
End If
'Apply the angle we found
Set pFields = pAddFeature.Fields
pField = pFields.FindField(m_pRenderer.RotationField)
pAddFeature.Value(pField) = Round(dAngle, 0)
Exit Sub
ErrHand:
MsgBox "Rotate - " & Err.Description
Exit Sub
End Sub
Private Sub m_pEd_OnCurrentLayerChanged()
TrackingCheck
End Sub
Private Function FindClosestSegment(pPtFeature As IFeature, _
pSnapTolerance As Double, pFeatureCache As IFeatureCache) As ISegment
Dim pLoop As Integer, pSnapDist As Double, lPart As Long, lSegment As Long
Dim pGeom As IHitTest, pTempSegment As ISegment
Dim bSnapFlag As Boolean, pTempPolyline As ISegmentCollection
Dim pHitPoint As IPoint, bSide As Boolean
Dim pGeomColl As IGeometryCollection, pTempPolyline2 As ISegmentCollection
Set pHitPoint = New esriGeometry.Point
Set pTempSegment = Nothing
For pLoop = 0 To pFeatureCache.Count - 1
Set pGeom = pFeatureCache.Feature(pLoop).Shape
bSnapFlag = pGeom.HitTest(pPtFeature.Shape, pSnapTolerance, esriGeometryPartBoundary, _
pHitPoint, pSnapDist, lPart, lSegment, bSide)
If bSnapFlag And (pSnapDist < m_dClosestDist) Then
Set pTempPolyline = pFeatureCache.Feature(pLoop).Shape
Dim pClone As IClone
If lPart > 0 Then
Set pGeomColl = pTempPolyline
Set pTempPolyline2 = pGeomColl.Geometry(lPart)
Set pClone = pTempPolyline2.Segment(lSegment)
Else
Set pClone = pTempPolyline.Segment(lSegment)
End If
Set pTempSegment = pClone.Clone
m_dClosestDist = pSnapDist
End If
Next pLoop
Set FindClosestSegment = pTempSegment
End Function
Private Sub m_pEd_OnStartEditing()
'Set map global at this point, because the Map property of the editor is empty at extension startup
Set m_pMap = m_pEditor.Map
End Sub
Private Sub m_pMap_ContentsChanged()
TrackingCheck
End Sub
Private Sub TrackingCheck()
On Error GoTo ErrHand:
Dim pEdLayer As IEditLayers, pCurLayer As IFeatureLayer
If m_pEditor Is Nothing Then Exit Sub
If m_pEditor.EditState <> esriStateEditing Then Exit Sub
Set pEdLayer = m_pEditor
If pEdLayer.CurrentLayer Is Nothing Then
m_bTracking = False
Exit Sub
End If
Set pCurLayer = pEdLayer.CurrentLayer
If Not TypeOf pCurLayer Is IGeoFeatureLayer Then
m_bTracking = False
Exit Sub
End If
Dim pRenderer As IRotationRenderer
Dim pGeoLayer As IGeoFeatureLayer
Set pGeoLayer = pCurLayer
Set pRenderer = pGeoLayer.Renderer
If pRenderer.RotationField = "" Then
m_bTracking = False
Set m_pRenderer = Nothing
Else
Set m_pRenderer = pRenderer
m_bTracking = True
End If
Exit Sub
ErrHand:
MsgBox "RotateSym-TrackingCheck - " & Err.Description
End Sub