This post is also a continuation of a previous one. I have the code (in VBA and ARcObjects) shown below to measure each angle of a selected polygon in degrees. I have the following problems: 1. Some angles are negative and I do not wish this since I measure the interior angles of a polygon. 2. Some angles are measured wrong i.e. I get the reflex angle instead of the normal angle. e.g. 270 instead of 90 degrees.
Could somebody see the code and help me for the neccessary modifications please? There is a procedure that calls a function shown also below. Thanks.
'This procedure gives the angles between the vertices of a polygon
' ----------------------------------------
Dim pMxDoc As IMxDocument
Dim pGeoFtrLyr As IFeatureLayer
Dim pFtrCls As IFeatureClass
Dim pFtrCsr As IFeatureCursor
Dim pFtr As IFeature
Dim pGeomColl As IGeometryCollection
Dim pSegColl As ISegmentCollection
Dim pCurve As ICurve
Dim pLine1 As ILine
Dim pLine2 As ILine
Dim dVtxAng As Double
Dim i As Long, j As Long
Dim PI As Double
' ' Calc PI
PI = Atn(1) * 4
' Get a cursor on the features in the first layer
Set pMxDoc = ThisDocument
Set pGeoFtrLyr = pMxDoc.FocusMap.Layer(12)
Set pFtrCsr = pGeoFtrLyr.Search(Nothing, False)
'Select a polygon
Dim pEnumFeature As IEnumFeature
Set pEnumFeature = pMxDoc.FocusMap.FeatureSelection
pEnumFeature.Reset
Set pFtr = pEnumFeature.Next
If pFtr Is Nothing Then
MsgBox "Please select a valid feature", vbInformation
Exit Sub
End If
If Not TypeOf pFtr.ShapeCopy Is IPointCollection Then
MsgBox "Not a valid feature", vbInformation
Exit Sub
End If
' Get all disjoint paths
Set pGeomColl = pFtr.ShapeCopy
' Loop thru the paths
For i = 0 To pGeomColl.GeometryCount - 1
' Get all segments that make up this path
Set pSegColl = pGeomColl.Geometry(i)
Set pCurve = pSegColl
' Loop thru the segments
For j = 0 To pSegColl.SegmentCount - 2
' Get the next two lines
Set pLine1 = pSegColl.Segment(j)
Set pLine2 = pSegColl.Segment(j + 1)
' Calculate the left side angle (in degrees)
dVtxAng = CalcAngleBetweenLines(pLine1, pLine2, True)
MsgBox Abs(dVtxAng * 57.2957795)
Next j
' Check for a closed polylin
If pCurve.IsClosed Then
Debug.Print pFtr.OID; " is closed!"
Set pLine1 = pSegColl.Segment(j)
Set pLine2 = pSegColl.Segment(0)
dVtxAng = CalcAngleBetweenLines(pLine1, pLine2, True)
'get each angle of the polygon in degrees
MsgBox dVtxAng * 57.2957795
End If
Next i
End Sub
Private Function CalcAngleBetweenLines(pLine1 As ILine, pLine2 As ILine, AsDegrees as Boolean) As Double
Dim dAng1 As Double, dAng2 As Double, dVtxAng As Double, PI As Double
dVtxAng = pLine1.Angle - pLine2.Angle
' Get the reversed angle of the first line
pLine1.ReverseOrientation
dAng1 = pLine1.Angle
If dAng1 < 0 Then dAng1 = 2 * PI + dAng1
pLine1.ReverseOrientation
' Get the angle fo the second line
dAng2 = pLine2.Angle
If dAng2 < 0 Then dAng2 = 2 * PI + dAng2
' subtract 2 from 1 - that's the smallest angle between the two lines
dVtxAng = dAng1 - dAng2
' Ensure we have the angle to the left of the lines
If dVtxAng >= 2 * PI Then
dVtxAng = dVtxAng - 2 * PI
ElseIf dVtxAng < 0 Then
dVtxAng = dVtxAng + 2 * PI
End If
CalcAngleBetweenLines = dVtxAng
End Function
Answer
The angle by which the direction deviates as you move from one segment (AB) to the next (BC) across their common vertex (B) is the difference in angles, dAng = pLine2.Angle - pLine1.Angle.
The angle to the left of the polyline ...ABC... is the supplement of this deviation, Pi - dAng. The angle to the right of the polyline is Pi + dAng. Which of those sides (right or left) is the interior depends on your convention for orienting polygon boundaries. To make sure the one you use is in the range [0, 2*Pi), reduce your answer modulo 2*Pi. In languages where the modulo function only works correctly with positive values--or just to be sure--add another 2*PI before applying it.
In pseudocode the left hand angle therefore is
dAng = Mod(3*PI - (pLine1.Angle - pLine2.Angle), 2*PI)
Because VBA does not have a floating point modulus function (AFAIK), implement one yourself:
Private Function fmod(x As Double, b As Double) As Double
fmod = x - Int(x / b) * b
End Function
Private Function CalcAngleBetweenLines(pLine1 As ILine, pLine2 As ILine) As Double
Const pi = 3.14159265358979
CalcAngleBetweenLines = fmod(3*pi - (pLine1.Angle - pLine2.Angle), 2*pi)
End Function
That's all you need.
No comments:
Post a Comment