Showing results for 
Search instead for 
Did you mean: 

Measure tube length

Honored Contributor
Honored Contributor

Looking to measure the lengths of exhaust header tubes, from data imported from a vendor.


I had a couple journals I found, and the user has tried the "Isoparametric Curve" method that John Baker has posted on here, but none have worked very well.  Isoparametric Curve is getting him data to build the centerline from, but it seem this would be a fairly common procedure.


Any other methods?

NX 11 | Teamcenter 11 | Windows 10

Re: Measure tube length

Gears Esteemed Contributor Gears Esteemed Contributor
Gears Esteemed Contributor

It seems like these statements are a bit at odds with each other:

"but none have worked very well"
"Isoparametric Curve is getting him data to build the centerline from"

Can you elaborate on the issue(s) that you are having?

Re: Measure tube length

Gears Esteemed Contributor Gears Esteemed Contributor
Gears Esteemed Contributor

One journal that I've seen makes some assumptions about the U and V direction of the tube surface. I ran across at least one imported part where the UV directions of the surface were opposite what was assumed. Using the "extract face" command to extract a copy of the tube surface and running the journal on the surface copy fixed that particular case.

Re: Measure tube length

Honored Contributor
Honored Contributor

So far nothing has given a centerline of the tube.  One journal would do straight sections, but not the bends, and kinks in the tubes.


As the user described it to me, the isoparametric curve method gave him geomertry that he can construct an approximate centerline, but not the actual centerline.  I may need to make some time to try it myself


EDIT:  user showed me, that the isoparametric curve method creates a number of circular sections, along the bent portion of tube, and then he constructs an arc thru those center points, to represent the tube centerline.


He/we were hoping for the actual tube centerline.

NX 11 | Teamcenter 11 | Windows 10

Re: Measure tube length

Honored Contributor
Honored Contributor
FYI, just grabbed Frank's code from your nxjournaling site to give a try.
NX 11 | Teamcenter 11 | Windows 10

Re: Measure tube length

Gears Esteemed Contributor Gears Esteemed Contributor
Gears Esteemed Contributor

Another approach is to extract 4 UV curves (pick the U or V direction that gives you curves along the length of the tube); this will give you curves running along the "quadrant points" of the tube. Now make 2 through curve features using the opposing UV curves; this will produce 2 surfaces that intersect at the centerline of the tube. Use "intersection curve" on the two surfaces to extract the centerline.

Re: Measure tube length


Here is another journal that made some improvements as noted.


'Author: Frank Swinkels
'for use only with NX 8.5 or above
'Create approximate centerline of B-surface "tube"
'user will be prompted to select B-surface, a 'through points' studio spline will be created along the centerline

'  modified June 19, 2014 to include creating the bsurface and allow for faces with other then 0 to 1 parameters 
' (typically cylinders or extended cylinders)
' modified June 24 to change for selecting apply or OK
'    Report length of selected tube.

Option Strict Off
Imports System
Imports NXOpen
Imports NXOpen.UF
Imports NXOpenUI
Imports NXOpen.Features
Imports System.IO

Module CableCentreline

    Dim s As Session = Session.GetSession()
    Dim ufs As UFSession = UFSession.GetUFSession()
    Dim workPart As Part = s.Parts.Work
    Dim lw As ListingWindow = s.ListingWindow
    Sub Main()
        Dim no_pts As Integer = Nothing
        Dim pos1 As Integer = Nothing
        Dim junk3(2) As Double
        Dim junk2(1) As Double
        Dim periodic1 As Boolean = False
        Dim theFace As Face = Nothing
        Dim totalLength As Double = 0
        Dim response1 As Selection.Response = Selection.Response.Cancel
        Dim type1 As Integer = Nothing
        Dim subtype1 As Integer = Nothing
        Dim bsurface1 As UFModl.Bsurface = Nothing
        Dim extractedfeat1 As Feature = Nothing
        Dim extractedbodyfeat1 As BodyFeature = Nothing
        Dim extractedbody1() As Body = Nothing
        Dim faces() As Face
        Dim testface As Face
        While select_a_face("Select a tube extracted face or dumb solid face", theFace) = Selection.Response.Ok

            'response1 = select_a_face("Select a tube extracted face or dumb solid face", theFace)
            'If response1 = Selection.Response.Cancel Or response1 = Selection.Response.Back Then GoTo end1
            ' check that it is a bsurface
                ufs.Modl.AskBsurf(theFace.Tag, bsurface1)
                testface = theFace
            Catch ex As Exception
                createExtractedBSurface(theFace, extractedfeat1)
                extractedbodyfeat1 = DirectCast(extractedfeat1, BodyFeature)
                extractedbody1 = extractedbodyfeat1.GetBodies
                faces = extractedbody1(0).GetFaces
                ufs.Modl.AskBsurf(faces(0).Tag, bsurface1)
                testface = faces(0)
            End Try

            Dim noPolesV As Integer = bsurface1.num_poles_v
            Dim noPolesU As Integer = bsurface1.num_poles_u
            Dim poles1(,) As Double = bsurface1.poles
            Dim knotsU() As Double = bsurface1.knots_u
            Dim knotsV() As Double = bsurface1.knots_v
            Dim orderU As Integer = bsurface1.order_u
            Dim orderV As Integer = bsurface1.order_v
            Dim ptno As Integer = Nothing
            Dim params(1) As Double
            Dim pnt0(2) As Double
            Dim pnt1(2) As Double
            Dim pnt2(2) As Double
            Dim pnt3(2) As Double
            Dim vec0(2) As Double
            Dim vec1(2) As Double
            Dim vec2(2) As Double
            Dim vec3(2) As Double
            Dim rads(1) As Double
            Dim tolerance1 As Double = 0.001
            Dim magnitude1 As Double = Nothing
            Dim degree3 As Integer = orderV - 1
            Dim pointtag As Tag = Tag.Null
            Dim ArrayOfPoints(-1) As Point
            Dim uparm() As Double = {0.0, 0.25, 0.5, 0.75}
            Dim delta1 As Double
            Dim sum1 As Double = Nothing
            Dim distance1 As Double = Nothing
            Dim cnt1 As Integer = 0
            Dim tempcpt(2) As Double
            Dim coordinates1 As Point3d
            Dim temptag As Tag = Tag.Null
            ' tube bsurf u around tube, v along the tube
            Dim vparm(noPolesV - 1) As Double
            vparm(0) = 0.0
            vparm(noPolesV - 1) = 1.0
            Dim lengths(noPolesV - 2) As Double
            sum1 = 0.0
            cnt1 = 0
            For i As Integer = noPolesU To noPolesU * noPolesV - 1 Step noPolesU
                pnt1(0) = poles1(i, 0)
                pnt1(1) = poles1(i, 1)
                pnt1(2) = poles1(i, 2)
                pnt2(0) = poles1(i - noPolesU, 0)
                pnt2(1) = poles1(i - noPolesU, 1)
                pnt2(2) = poles1(i - noPolesU, 2)
                ufs.Vec3.Distance(pnt1, pnt2, distance1)
                lengths(cnt1) = distance1
                cnt1 += 1
                sum1 += distance1
            delta1 = 0.0
            For i As Integer = 0 To noPolesV - 2
                delta1 += lengths(i)
                vparm(i + 1) = delta1 / sum1
            Dim uvminmax(3) As Double
            ufs.Modl.AskFaceUvMinmax(testface.Tag, uvminmax)
            Dim total2 As Double = uvminmax(3) - uvminmax(2)
            Dim delta2 As Double = total2 / (noPolesV - 1)
            Dim zero1 As Double = uvminmax(2)
            For i As Integer = 0 To noPolesV - 1
                If i = 0 Then
                    vparm(i) = zero1
                    vparm(i) = vparm(i - 1) + delta2
                End If

            For i As Integer = 0 To noPolesV - 1
                params(0) = uparm(0)
                params(1) = vparm(i)
                ufs.Modl.AskFaceProps(testface.Tag, params, pnt0, junk3, vec0, junk3, junk3, junk3, rads)
                ufs.Vec3.Unitize(vec0, tolerance1, magnitude1, vec0)
                params(0) = uparm(1)
                ufs.Modl.AskFaceProps(testface.Tag, params, pnt1, junk3, vec1, junk3, junk3, junk3, rads)
                params(0) = uparm(2)
                ufs.Modl.AskFaceProps(testface.Tag, params, pnt2, junk3, vec2, junk3, junk3, junk3, rads)
                params(0) = uparm(3)
                ufs.Modl.AskFaceProps(testface.Tag, params, pnt3, junk3, vec3, junk3, junk3, junk3, rads)
                ufs.Vec3.Add(pnt0, pnt1, tempcpt)
                ufs.Vec3.Add(pnt2, tempcpt, tempcpt)
                ufs.Vec3.Add(pnt3, tempcpt, tempcpt)
                tempcpt(0) /= 4.0
                tempcpt(1) /= 4.0
                tempcpt(2) /= 4.0
                coordinates1 = New Point3d(tempcpt(0), tempcpt(1), tempcpt(2))

                ReDim Preserve ArrayOfPoints(i)
                ArrayOfPoints(i) = workPart.Points.CreatePoint(coordinates1)

            periodic1 = False
            Dim myStudioSpline As Features.StudioSpline
            myStudioSpline = CreateStudioSplineThruPoints(ArrayOfPoints, degree3)
            Dim tubeLength As Double = 0
            For Each tempCurve As Curve In myStudioSpline.GetEntities
                tubeLength += tempCurve.GetLength
            totalLength += tubeLength
            lw.WriteLine("section length: " & tubeLength.ToString)
            lw.WriteLine("total length: " & totalLength.ToString)
        End While
    End Sub
    Public Sub createExtractedBSurface(ByVal face1 As Face, ByRef extractedfeat1 As Feature)
        Dim nullFeatures_Feature As Features.Feature = Nothing
        Dim extractFaceBuilder1 As Features.ExtractFaceBuilder
        extractFaceBuilder1 = workPart.Features.CreateExtractFaceBuilder(nullFeatures_Feature)
        extractFaceBuilder1.ParentPart = Features.ExtractFaceBuilder.ParentPartType.WorkPart
        extractFaceBuilder1.Associative = True
        extractFaceBuilder1.FixAtCurrentTimestamp = True
        extractFaceBuilder1.HideOriginal = False
        extractFaceBuilder1.Type = Features.ExtractFaceBuilder.ExtractType.Face
        extractFaceBuilder1.InheritDisplayProperties = False
        extractFaceBuilder1.SurfaceType = Features.ExtractFaceBuilder.FaceSurfaceType.PolynomialCubic
        Dim added1 As Boolean
        added1 = extractFaceBuilder1.ObjectToExtract.Add(face1)
        extractedfeat1 = extractFaceBuilder1.Commit
    End Sub
    Function select_a_face(ByRef prompt As String, ByRef face1 As Face) As Selection.Response
        Dim mask(0) As Selection.MaskTriple
        With mask(0)
            .Type = UFConstants.UF_solid_type
            .Subtype = 0
            .SolidBodySubtype = UFConstants.UF_UI_SEL_FEATURE_ANY_FACE
        End With
        Dim cursor As Point3d = Nothing
        Dim response1 As Selection.Response = Selection.Response.Cancel
        select_a_face = Nothing
        response1 = UI.GetUI.SelectionManager.SelectTaggedObject(prompt, "Select the Face", _
            Selection.SelectionScope.AnyInAssembly, _
            Selection.SelectionAction.ClearAndEnableSpecific, False, _
            False, mask, face1, cursor)
        If response1 = Selection.Response.ObjectSelected Or _
            response1 = Selection.Response.ObjectSelectedByName Then
            Return Selection.Response.Ok
        ElseIf response1 = Selection.Response.Back Then
            Return Selection.Response.Back
            Return Selection.Response.Cancel
        End If
    End Function

    Public Function CreateStudioSplineThruPoints(ByRef points() As Point, ByVal degree3 As Integer) As Features.StudioSpline
        Dim markId9 As Session.UndoMarkId
        markId9 = s.SetUndoMark(Session.MarkVisibility.Visible, "Studio Spline Thru Points")
        Dim Pcount As Integer = points.Length - 1
        Dim nullFeatures_StudioSpline As Features.StudioSpline = Nothing
        Dim studioSplineBuilderex1 As Features.StudioSplineBuilderEx
        studioSplineBuilderex1 = workPart.Features.CreateStudioSplineBuilderEx(nullFeatures_StudioSpline)
        studioSplineBuilderex1.OrientExpress.ReferenceOption = GeometricUtilities.OrientXpressBuilder.Reference.ProgramDefined
        studioSplineBuilderex1.Degree = degree3
        studioSplineBuilderex1.OrientExpress.AxisOption = GeometricUtilities.OrientXpressBuilder.Axis.Passive
        studioSplineBuilderex1.OrientExpress.PlaneOption = GeometricUtilities.OrientXpressBuilder.Plane.Passive
        studioSplineBuilderex1.MatchKnotsType = Features.StudioSplineBuilderEx.MatchKnotsTypes.None
        Dim knots1(-1) As Double
        Dim parameters1(-1) As Double
        Dim nullDirection As Direction = Nothing
        Dim nullScalar As Scalar = Nothing
        Dim nullOffset As Offset = Nothing
        Dim geometricConstraintData(Pcount) As Features.GeometricConstraintData
        For ii As Integer = 0 To Pcount
            geometricConstraintData(ii) = studioSplineBuilderex1.ConstraintManager.CreateGeometricConstraintData()
            geometricConstraintData(ii).Point = points(ii)
            geometricConstraintData(ii).AutomaticConstraintDirection = Features.GeometricConstraintData.ParameterDirection.Iso
            geometricConstraintData(ii).AutomaticConstraintType = Features.GeometricConstraintData.AutoConstraintType.Tangent
            geometricConstraintData(ii).TangentDirection = nullDirection
            geometricConstraintData(ii).TangentMagnitude = nullScalar
            geometricConstraintData(ii).Curvature = nullOffset
            geometricConstraintData(ii).CurvatureDerivative = nullOffset
            geometricConstraintData(ii).HasSymmetricModelingConstraint = False
        Next ii
        Dim feature1 As Features.StudioSpline
        feature1 = studioSplineBuilderex1.CommitFeature()

        Return feature1

    End Function

    Public Function GetUnloadOption(ByVal dummy As String) As Integer
        'Unloads the image when the NX session terminates
        GetUnloadOption = NXOpen.Session.LibraryUnloadOption.Immediately
    End Function

End Module




Frank Swinkels

Re: Measure tube length

Siemens Phenom Siemens Phenom
Siemens Phenom

Intersection is not really needed. Create one of the ruled surfaces, as you described, and then construct an iso-curve down its middle. A lot faster and more reliable than intersection.


Re: Measure tube length

Honored Contributor
Honored Contributor
Thanks @FrankSwinks I will pass that one along to the user to test.
NX 11 | Teamcenter 11 | Windows 10

Re: Measure tube length

Siemens Phenom Siemens Phenom
Siemens Phenom

Here's an alternative program. It uses SNAP functions. But, even if you don't have a SNAP license, you could use the same basic logic with NX Open, though you'd have some re-coding to do.


It handles surfaces of type cylinder, torus, or b-surface, and it outputs cumulative length as you select faces

It can handle b-surfaces imported from other systems where either the u-direction or the v-direction might run along the tube.


' Constructs center-line curves of tube-like surfaces, and measures their length
' Usage: run the program and select faces of type cylinder, torus, or b-surface

Option Infer On
Imports Snap, Snap.Create, Snap.UI, Snap.NX.ObjectTypes
Public Class MyProgram
   Public Shared Sub Main

      ' Create a selection dialog and set the filter
      Dim dialog = Selection.SelectObject("Select a b-surface tube face")
      dialog.SetFaceFilter(SubType.FaceBsurface, SubType.FaceCylinder, SubType.FaceTorus)

      Dim face As NX.Face = Nothing
      Dim spine As NX.Curve = Nothing

      Dim curLength As Double = 0
      Dim cumLength As Double = 0

      InfoWindow.WriteLine(" ")
      InfoWindow.WriteLine("     Current      Cumulative")
      InfoWindow.WriteLine("     =======      ==========")

         ' Display the dialog and get faces
         Dim result = dialog.Show()

         If result.Response < 4 Then Exit Do   ' User pressed OK, Back, or Cancel

         face = result.Object
         If face IsNot Nothing Then spine = Centerline(face)

         If spine IsNot Nothing Then
            curLength = spine.ArcLength
            cumLength = cumLength + curLength
         End If

         Dim curLengthString = string.Format("{0,12:F3}", curLength)	
         Dim cumLengthString = string.Format("{0,16:F3}", cumLength)

         InfoWindow.WriteLine(curLengthString & cumLengthString)

      Loop Until face Is Nothing

   End Sub

   Public Shared Function Centerline(face As NX.Face) As NX.Curve

      Dim spine As NX.Curve = Nothing

      If face.ObjectSubType = SubType.FaceCylinder  Then spine =   CylinderCenterline(CType(face, Snap.NX.Face.Cylinder))
      If face.ObjectSubType = SubType.FaceTorus     Then spine =      TorusCenterline(CType(face, Snap.NX.Face.Torus))
      If face.ObjectSubType = SubType.FaceBsurface  Then spine =   BsurfaceCenterline(CType(face, Snap.NX.Face.Bsurface))
      Return spine

   End Function

   Public Shared Function BsurfaceCenterline(face As NX.Face.Bsurface) As NX.Spline

      ' Determine which is the "tube" direction (u or v).  For tubes created in NX, 
      ' we always have dir = 2, but for surfaces imported from other systems, it could be either.
      Dim dir As Integer = GetTubeDirection(face)

      ' Create two curves running along the tube, on diametrically opposite sides
      Dim side1 As NX.Spline = Nothing
      Dim side2 As NX.Spline = Nothing

      If dir = 2  ' The u = constant iso-curves run along the tube
         side1 = face.IsoCurveU(0.25)(0)
         side2 = face.IsoCurveU(0.75)(0)
      End If

      If dir = 1  ' The v = constant iso-curves run along the tube
         side1 = face.IsoCurveV(0.25)(0)
         side2 = face.IsoCurveV(0.75)(0)
      End If

      Dim centerline As NX.Spline = Nothing

      If dir <> 0
         ' Create a ruled surface between the two side iso-curves
         Dim cross As NX.Ruled = Ruled(side1, side2)
         Dim crossSurf As Snap.NX.Face.Bsurface = cross.Faces(0)
         ' The tube centerline is the center curve of the ruled surface
         centerline = crossSurf.IsoCurveV(0.5)(0)
      End If
      Return centerline

   End Function

   Public Shared Function CylinderCenterline(face As NX.Face.Cylinder) As NX.Line

      Dim box = face.BoxUV
      Dim v0 As Double = box.MinV
      Dim v1 As Double = box.MaxV

      Dim p0, q0, c0, p1, q1, c1 As Position

      ' Points p and q are diametrically opposite, and c is their mid-point, so is on the centerline
      p0  = face.Position(90, v0)   :   q0  = face.Position(270, v0)   :   c0 = 0.5*(p0 + q0)
      p1  = face.Position(90, v1)   :   q1  = face.Position(270, v1)   :   c1 = 0.5*(p1 + q1)

      Return Snap.Create.Line(c0, c1)

   End Function

   Public Shared Function TorusCenterline(face As NX.Face.Torus) As NX.Arc

      Dim box = face.BoxUV
      Dim u0 As Double = box.MinU
      Dim u1 As Double = box.MaxU
      Dim um As Double = 0.5*(u0 + u1)

      Dim p0, q0, c0, p1, q1, c1, pm, qm, cm As Position

      ' Points p and q are on opposite sidesof torus tube, and c is on the torus centerline
      p0  = face.Position(u0, 90)   :   q0  = face.Position(u0, 270)   :   c0 = 0.5*(p0 + q0)
      pm  = face.Position(um, 90)   :   qm  = face.Position(um, 270)   :   cm = 0.5*(pm + qm)
      p1  = face.Position(u1, 90)   :   q1  = face.Position(u1, 270)   :   c1 = 0.5*(p1 + q1)

      Return Snap.Create.Arc(c0, cm, c1)

   End Function

   ''' <summary>Determines which direction (u or v) runs along the tube</summary>
   ''' <param name="face">The b-surface</param>
   ''' <returns>Direction indicator</returns>
   ''' <remarks>
   '''    dir = 1 means the iso-curves v = constant run along the tube, u = constant curves are circles
   '''    dir = 2 means the iso-curves u = constant run along the tube, v = constant curves are circles
   '''    dir = 0 means the b-surface doesn't look much like a tube at all
   ''' </remarks>
   Private Shared Function GetTubeDirection(face As NX.Face.Bsurface) As Integer

      Dim p00 = face.Position(0,0)   :   Dim p01 = face.Position(0,1)
      Dim p10 = face.Position(1,0)   :   Dim p11 = face.Position(1,1)

      Dim distU0 = Snap.Position.Distance(p00, p01)   'Distance between end-points of edge u = 0
      Dim distU1 = Snap.Position.Distance(p10, p11)   'Distance between end-points of edge u = 1
      Dim distV0 = Snap.Position.Distance(p00, p10)   'Distance between end-points of edge v = 0
      Dim distV1 = Snap.Position.Distance(p01, p11)   'Distance between end-points of edge v = 1

      Dim eps As Double = 0.0001

      Dim dir As Integer = 0
      If distU0 < eps And distU1 < eps Then dir = 1    ' edges u=0 and u=1 are closed (circles) 
      If distV0 < eps And distV1 < eps Then dir = 2    ' edges v=0 and v=1 are closed (circles) 

      Return dir

   End Function

End Class