Pipe Network along water drop path

By Augusto Goncalves

In one of my regular Civil 3D API training the following discussion came up: how can we automate the creation of a pipe network? As you might already know, automate a process requires a very well defined rule for it, otherwise we cannot program it.

So, in this case, they just need to create a Pipe Network from one high point to another lower point. After some discussion, we agreed that a interesting first attempt could be along the water drop, which will give us a path with minimum cuts on the terrain.

This is not a ultimate solution, it still requires adjustments. For instance, the water drop path can circle around and give us a very long path, or reach a big slope, or many other issues… so please feel free to comment and suggest!

Sure we can do a similar with regular Water Drop features, creating an Alignment from the pline and using it to the network. But here we can define a distance between structs that may not follow the original path, align them and, of course, automate the whole process.

This sample requires a tin surface, a empty network already created (just to simplify) and a starting point. This first part of the sample will perform the operation.

Private Sub CreateNetworkAlongWaterDropPath( _

                           networkName As String, _

                           surfaceId As ObjectId, _

                           initialPoint As Point3d)

  Dim db As Database = Application. _

    DocumentManager.MdiActiveDocument.Database

  Using trans As Transaction = db. _

    TransactionManager.StartTransaction

    Try

 

      ‘ abrir a superficie

      Dim surface As TinSurface = trans.GetObject( _

        surfaceId, OpenMode.ForRead)

 

      ‘ get the plines from the initial point

      Dim idPlines As ObjectIdCollection = surface. _

        Analysis.CreateWaterdrop( _

        initialPoint.Convert2d(New Plane()), _

        Autodesk.Civil.WaterdropObjectType.Polyline3D)

 

      ‘ open the pline that will be the path

      ‘ here we’ll simplify and get the first

      ‘ pline of the collection, but keep in mind

      ‘ that a water drop can return multiple

      Dim idPline As ObjectId = idPlines.Item(0)

      Dim pline As Polyline3d = trans.GetObject( _

        idPline, OpenMode.ForRead)

 

      ‘ get the network by name

      Dim rede As Network = Nothing

      Dim civilDoc As CivilDocument = _

        CivilApplication.ActiveDocument

      For Each idRede As ObjectId In _

        civilDoc.GetPipeNetworkIds()

        rede = trans.GetObject(idRede, _

                               OpenMode.ForRead)

        If (rede.Name.Equals(networkName)) _

          Then Exit For

      Next

      ‘ and upgrade to write

      rede.UpgradeOpen()

 

      ‘ get the part family and size for

      ‘ pipes and structs

      Dim idStructFamily As ObjectId = _

        SelectPartFamily( _

          rede.PartsListId, _

          DomainType.Structure)

      Dim idStructSize As ObjectId = _

        SelectPartSize(idStructFamily)

 

      Dim idPipeFamily As ObjectId = _

        SelectPartFamily( _

          rede.PartsListId, _

          DomainType.Pipe)

      Dim idPipeSize As ObjectId = _

        SelectPartSize(idPipeFamily)

 

      ‘ iterate through the pline

      Dim previousPoint As Point3d = pline.GetPointAtDist(0)

      Dim previousStructPoint As ObjectId = ObjectId.Null

      Dim distanceBetweenStruct As Double = 100

      For distanceAtPline As Double = 0 To pline.Length _

        Step distanceBetweenStruct

 

        ‘ point at the current distance

        Dim currentPoint As Point3d = _

          pline.GetPointAtDist(distanceAtPline)

 

        ‘ let’s align the struct with the pline

        Dim angle As Double = _

          pline.GetFirstDerivative(currentPoint). _

          AngleOnPlane(New Plane())

        Dim idStruct As ObjectId

        rede.AddStructure(idStructFamily, _

                          idStructSize, _

&#160
;                         currentPoint,

                          angle,

                          idStruct, True)

 

 

        If (distanceAtPline > 1) Then ‘ skipt the first

          ‘ create a line segment

          Dim pipeLineSegment As New LineSegment3d( _

            previousPoint, currentPoint)

 

          ‘ create the pipe using the line segment

          Dim pipeId As ObjectId

          rede.AddLinePipe(idPipeFamily, _

                           idPipeSize, pipeLineSegment, _

                           pipeId, True)

 

          ‘ open the pipe to connect to the structs

          Dim pipe As Pipe = trans.GetObject(pipeId, _

                                             OpenMode.ForWrite)

          ‘ start struct

          pipe.ConnectToStructure(ConnectorPositionType.Start, _

                                  previousStructPoint, True)

          ‘ end struct

          pipe.ConnectToStructure(ConnectorPositionType.End, _

                                  idStruct, True)

        End If

        previousStructPoint = idStruct

        previousPoint = currentPoint

      Next

 

      ‘ erase the plines…

      For Each id As ObjectId In idPlines

        trans.GetObject(id, OpenMode.ForWrite).Erase()

      Next

 

      ‘ commit changes

      trans.Commit()

    Catch

      ‘ something went wrong…

      trans.Abort()

    End Try

  End Using

End Sub

And the result is a network as shown below, with the structs aligned.

full_network

network_detail

Now we need a code responsible for the user interface: selections. The following code sample do it.

<CommandMethod("createNetworkAlongWaterDropPath")> _

Public Sub CmdCreateNetworkAlongWaterDropPath()

   Dim ed As Editor = Application. _

     DocumentManager.MdiActiveDocument.Editor

 

   ‘ ask the user for the network

   Dim networkName As String = SelectNetwork()

   If (String.IsNullOrWhiteSpace(networkName)) _

     Then Exit Sub

 

   ‘ select the surface

   Dim opSelSurface As New  _

     PromptEntityOptions("Select a TinSurface: ")

   opSelSurface.SetRejectMessage _

     ("Only TinSurface")

   opSelSurface.AddAllowedClass _

     (GetType(TinSurface), True)

   Dim resSurface As PromptEntityResult = _

     ed.GetEntity(opSelSurface)

   If (resSurface.Status <> PromptStatus.OK) _

     Then Exit Sub

 

   ‘ select the initial point

   Dim resInitialPoint As PromptPointResult = _

     ed.GetPoint("Select initial point: ")

   If (resInitialPoint.Status <> PromptStatus.OK) _

     Then Exit Sub

 

   CreateNetworkAlongWaterDropPath( _

     networkName, _

     resSurface.ObjectId, _

     resInitialPoint.Value)

End Sub

This code requires some ‘utility’ functions for selections, which basically use a form to ask for information using a Combo Box list.

form

Private Function SelectNetwork() As String

  Dim frm As New FormSelect

  Dim db As Database = Application.DocumentManager. _

    MdiActiveDocument.Database

  Using trans As Transaction = db.TransactionManager.StartTransaction

    Dim civilDoc As CivilDocument = CivilApplication.ActiveDocument

    For Each idRede As ObjectId In civilDoc.GetPipeNetworkIds()

      Dim rede As Network = trans.GetObject(idRede, OpenMode.ForRead)

      frm.cboOptions.Items.Add(rede.Name)

    Next

  End Using

 

  If (frm.cboOptions.Items.Count = 0) Then

    Application.DocumentManager.MdiActiveDocument. _

      Editor.WriteMessage("No networks available")

    Return String.Empty

  End If

  frm.cboOptions.SelectedIndex = 0

  If (Application.ShowModalDialog(frm) _

      <> Windows.Forms.DialogResult.OK) _

    Then

    Return String.Empty

  End If

  Return frm.cboOptions.SelectedItem

End Function

 

Private Function SelectPartFamily(idPartList As ObjectId, _

                          &#16
0;   domainType
As DomainType) As ObjectId

  Dim db As Database = Application.DocumentManager. _

    MdiActiveDocument.Database

  Using trans As Transaction = db.TransactionManager.StartTransaction

    Dim partList As PartsList = trans.GetObject(idPartList, _

                                                OpenMode.ForRead)

    Dim idsPartFamily As ObjectIdCollection = _

      partList.GetPartFamilyIdsByDomain(domainType)

 

    Dim frm As New FormSelect

    For Each partFamilyId As ObjectId In idsPartFamily

      Dim family As PartFamily = trans.GetObject(partFamilyId, _

                                                 OpenMode.ForRead)

      frm.cboOptions.Items.Add(family.Name)

    Next

    frm.cboOptions.SelectedIndex = 0

    Application.ShowModalDialog(frm)

    Dim partFamName As String = frm.cboOptions.SelectedItem

    For Each idFamilia As ObjectId In idsPartFamily

      Dim pFamily As PartFamily = trans.GetObject(idFamilia, _

                                              OpenMode.ForRead)

      If (partFamName.Equals(pFamily.Name)) Then Return idFamilia

    Next

  End Using

End Function

 

Private Function SelectPartSize(idFamily As ObjectId) As ObjectId

  Dim db As Database = Application.DocumentManager. _

    MdiActiveDocument.Database

  Using trans As Transaction = db.TransactionManager.StartTransaction

    Dim frm As New FormSelect

    Dim partFam As PartFamily = trans.GetObject(idFamily, _

                                                OpenMode.ForRead)

    For i As Integer = 0 To partFam.PartSizeCount – 1

      Dim size As PartSize = trans.GetObject(partFam.Item(i), _

                                                OpenMode.ForRead)

      frm.cboOptions.Items.Add(size.Name)

    Next

    frm.cboOptions.SelectedIndex = 0

    Application.ShowModalDialog(frm)

    Dim selectedSize As String = frm.cboOptions.SelectedItem

    For i As Integer = 0 To partFam.PartSizeCount – 1

      Dim size As PartSize = trans.GetObject(partFam.Item(i), _

                                             OpenMode.ForRead)

      If (size.Name.Equals(selectedSize)) Then Return size.ObjectId

    Next

  End Using

End Function


Comments

2 responses to “Pipe Network along water drop path”

  1. looking at the code, you are iterate through the pline to create the network. In 2015 API is there a method to simply create a network from pline? if yes, are there any samples on how to create a pipe network from a pline in C#. Is there a list somewhere of all the methods, functions etc.

  2. Malcolm
    In fact this code is not following the PLINE at every point, but only at specific parameters…
    But if you need to follow the PLINE, use as shown at http://adndevblog.typepad.com/infrastructure/2012/06/do-you-want-to-programmatically-convert-polyline-to-civil-3d-alignment-object.html
    Regards,
    Augusto Goncalves

Leave a Reply to MalcolmCancel reply

Discover more from Autodesk Developer Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading