I3DCurve apparently does not account for Z units

557
2
11-02-2011 10:19 PM
RichardFairhurst
MVP Honored Contributor
I ran some code with a feature class that had X, Y, Z and M units to get lengths from the I3DCurve interface.  I ran a test on a feature using a Projected Coordinate System where my initial X, Y and Z units were all in Feet_US and got the expected 3D length value.  Then I modified the feature class to change the Z Units to meters, but I left the X/Y coordinate units in Feet_US.  When I reran the code the 3D length reported by the I3DCurve interface did not change from the previous run when I had the Z units in feet.  I made sure that the polyline I supplied to the interface had been assigned the feature class' Spatial Reference and made sure the Z values I tested were much greater than the change in X/Y so the difference in Z units would have an obvious impact, but that had no effect on the length that the I3DCurve reported.

Here is my main loop code (variables are correctly Dimensioned to the correct types outside the loop) that produced no change in the reported length after I changed my Spatial Reference Z Units from Feet_US to meters.  Am I missing something about how my code should be written to get the I3DCurve interface to recognize the change I made to the Spatial Reference of the Z units?  If I am not than it seems that this interface either has a bug or an undocumented (and unexpected) behavior for its method of calculating the 3D length of the curve when a feature class has mixed X/Y and Z units.

' Assume a Polyline Feature that is Z and M Aware is assigned to pFeat, which is an IFeature
                Dim pSpatialRef As ISpatialReference = pFeat.Shape.SpatialReference
                If Not TypeOf pSpatialRef Is IProjectedCoordinateSystem5 Then
                   ' Currently not able to process Geographic Coordinate System or Unknown
                   MsgBox("Spatial Reference Is Not A Projected Coordinate System")
                   Return
                End If
                pPolyline = New Polyline
                pPolyline.SpatialReference = pSpatialRef ' Make sure Polyline has Spatial Reference
                pPolyline = pFeat.Shape ' Assign geometry to Polyline
                pCurve3D = pPolyline
                pPointColl = pFeat.ShapeCopy ' Assign to pointCollection
                pEnumVert = pPointColl.EnumVertices
                pInPoint = New Point ' Reinitialize Input Point
                pInPoint.SpatialReference = pSpatialRef
                pEnumVert.Reset()
                pEnumVert.QueryNext(pInPoint, lPart, lVert)
                LastPoint = New Point ' Reinitialize Input Point
                i = 1
                Do While Not pInPoint Is Nothing
                    ' For lPtCnt = 0 To pPointColl.PointCount - 1 ' For loop to access all curve points
                    If lPart = 0 And lVert = 0 Then
                        LastPoint = pInPoint
                        GapAdd = 0
                    End If
                    ' pInPoint = pPointColl.Point(lPtCnt) ' Assign Input successive input Points
                    pCurve3D.QueryPointAndDistance3D(ESRI.ArcGIS.Geometry.esriSegmentExtension.esriNoExtension, pInPoint, False, pOutPoint, distAlong, distFrom)
                    If lVert = 0 And Not Ignore_Gaps Then
                        GapAdd = (Math.Sqrt((pInPoint.X - LastPoint.X) ^ 2 + (pInPoint.Y - LastPoint.Y) ^ 2 + ((pInPoint.Z - LastPoint.Z) * ZUnitFactor) ^ 2)) * Measure_Factor + GapAdd
                    End If
                    pEnumVert.put_M(distAlong + GapAdd) ' Modify M to be 3D distance along curve
                    ' pPointColl.ReplacePoints(lPtCnt, 1, 1, pInPoint) ' Replace the point with its new M version'
                    If pEnumVert.IsLastInPart And pPointColl.PointCount <> i Then
                        LastPoint = pInPoint
                        pEnumVert.QueryNext(pInPoint, lPart, lVert)
                    ElseIf Not pEnumVert.IsLastInPart Then
                        pEnumVert.QueryNext(pInPoint, lPart, lVert)
                    Else
                        pInPoint = Nothing
                    End If
                    ' pInPoint = Nothing
                    ' Next lPtCnt
                    i += 1
                Loop
                pFeat.Shape = pPointColl
                pFCursor.UpdateFeature(pFeat) ' Update the cursor
0 Kudos
2 Replies
RichardFairhurst
MVP Honored Contributor
Esri has confirmed the behavior I observed and has logged a bug report under NIM075261 - ICurve3D.Length3D property returns incorrect value  if Z units differ from XY units.  This affects the Geometry calculator for 3D Lengths and any ArcObjects code using this interface when Z units are not the same as XY units.
0 Kudos
WeifengHe
Esri Contributor
This one has been fixed in 10.1, and would probably goes to 10.0SP4 too.
0 Kudos