Hi
I am trying to extend some earlier code I have written to quickly design drainage works in Civil3d without going outside the program.
The reason I want to do this is when initally designing a new network we do not need a full blown SSA analysis or storm sewer analysis besides neither of these programs import and export process have ever worked well in the metric world or us anyway.
So what I do at the moment is have parcels with userdefined properties for all my catchment drainage information and use area label expressions to calculate out my flows from each catchment. I link these parcels to structures by changing the name of the parcel to the strucutre it is going to and just adding a counter along the lines of -(1) to the end of the name of each addition parcel that needs to drain to the same structure.
This gives me a nice table of data in the toolspace vista for the parcels for all the catchment data and flows as per the image below. The last colum being named test but is actually the flow in l/s for the wastewater in this image.
On the pipes in the network I have expressions that calculate the basic flow capacity of each pipe using manning or cole-brook white equation and display that data in a pipe label.
So at the moment to check the cumvlative flow at each structure I just right click and copy the Parcel (Catchment) data from the toolspace vista and paste it into excel and then if all the catchments are labelled sequencially tally up the flows above a certain structure number. Then jump back into civi3d and check the pipe capacity in that location is ok.
Now what I want to do is eliminate this step with some code that does this for me. Basically I am wanting to load the drainage network layout data in to some kind of class that I can quickly search and do some of the basic things SSA does like.
1. Highlight all pipes and structures connected to this structure upstream.
2. Highlight all the parcels catchments connected above this point.
3. Accumalate all the catchment flows from parcels above a certain point and assign it to a property of the structures out going pipe so it can be seen in a pipe label.
Now I have done some googling and it looks like a BW-tree alogthirm is the sort of thing I need. Has any one done something along these lines in Civil3d or using functionalility build into the Civil3d the API. From memory I few years ago the only thing you could find was the shortest path.
Any thoughts and suggestions appriciated.
Regards
Justin Ralston
Jeff
Thanks for the reply this should be reasonable easy without having to reinvent the wheel.
Since posting this on Saturday moring I have done some more research over the weekend and think the name of the alogthrim we are after in a class is a N-ary tree as from each outlet in the drianage system you have a tree that can have multipile childern. Althrough in each drawing you may have multipile trees.
I did find that the C# Cookbook has an example of an N-ary tree and you can download the code examples from the book here.
Now just how you load the drainage network data into the tree and search and find paths in it is another problem.
Maybe one of the Autodesk Infrastrucutre Modeeling Devblog guys like Augusto or Partha may like to take on the challenge and help us out with an example and a blog post which would make interesting reading.
Justin
Hi Justin,
This sounds interesting and tricky... 🙂
Playing with Pipe Networks can take some cool directions, like this http://adndevblog.typepad.com/infrastructure/2013/03/pipe-network-along-water-drop-path.html and a sample I did for AU2010 (CP322) that you can find below.
This AU sample may help on your point #1 and get started on point #2, although the Parcel API requires some COM objects, but it's there. The #3 seems more a result of the first two points... am I right?
Finally, the image you send is a little difficult to read, can you submit as an attachment (in full resolution)? Will give some extra thinking time 🙂
Cheers!
Augusto
Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.Civil.ApplicationServices
Imports Autodesk.Civil.PipeNetwork.DatabaseServices
Imports Autodesk.Civil.PipeNetwork.DatabaseServices.Styles
Imports Autodesk.AutoCAD.GraphicsInterface
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.Geometry
''' <summary>
''' Show the pipe network flow based on Pipe.FlowDirection and Pipe/Structure connections.
''' How to use: run 'SHOWFLOW' command, mouse over a pipe/structure, it will appear some
''' arrows (FlowDirection to one structure to another) or lines (FlowDirection bidirectional)
''' </summary>
''' <remarks></remarks>
Public Class ShowPipeNetworkFlow
<CommandMethod("showFlow")> _
Public Sub showFlowDirection()
Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor
'start the point monitor
AddHandler ed.PointMonitor, New PointMonitorEventHandler(AddressOf pointMonitorFlowDirection)
'trick to let the point monitor running
ed.GetPoint("Click on screen to exit")
'finish the point monitor
RemoveHandler ed.PointMonitor, AddressOf pointMonitorFlowDirection
End Sub
Private geo As ViewportGeometry
Private trans As Transaction
Public Sub pointMonitorFlowDirection(ByVal sender As Object, ByVal e As PointMonitorEventArgs)
'get the entity over the aperture
Dim pickEnts As FullSubentityPath() = e.Context.GetPickedEntities()
If (pickEnts.Length = 0) Then Return
Dim entIds As ObjectId() = pickEnts(0).GetObjectIds()
If (entIds.Length = 0) Then Return
Dim db As Database = Application.DocumentManager.MdiActiveDocument.Database
Try
trans = db.TransactionManager.StartTransaction
'is it a pipe or structure?
Dim p As Part = TryCast(trans.GetObject(entIds(0), OpenMode.ForRead), Part)
If (p Is Nothing) Then
trans.Commit() 'faster than abort
Return
End If
'store the curret draw context (will be used later)
geo = e.Context.DrawContext.Geometry
If (p.Domain = DomainType.Pipe) Then
NextPipe(p, e.Context.RawPoint)
Else
NextStruct(p)
End If
trans.Commit() 'faster than abort
Finally
'always dispose
'as we store and reuse the transaction, we cannot use the Using keyword here
'so it is required an explicit dispose
trans.Dispose()
End Try
End Sub
Public Sub NextPipe(ByVal p As Pipe, ByVal drawFlowFrom As Point3d)
'get the base curve that represents this pipe
'unfortunatelly the Pipe.BaseCurve property is not working yet,
'therefore this is not working for curved pipes.
'let's create a base LINE
Dim baseCurve As Curve
If p.FlowDirection = FlowDirectionType.StartToEnd Then
baseCurve = New Line(p.StartPoint, p.EndPoint)
Else
baseCurve = New Line(p.EndPoint, p.StartPoint)
End If
'get the length of the curve
Dim length As Double = baseCurve.GetDistanceAtParameter(baseCurve.EndParam)
'determine where start drawing the arrows, close to the mouse cursor (aperture)
Dim startLength As Double = baseCurve.GetDistAtPoint(baseCurve.GetClosestPointTo(drawFlowFrom, False))
'if this pipe is bidirectional, then start at 0 (ignore line above)
If (p.FlowDirection = FlowDirectionType.Bidirectional) Then startLength = 0.0
'iterate through the pipe length
For i As Double = startLength To length Step 2.0
Dim pointOverPipe As Point3d = baseCurve.GetPointAtDist(i)
Dim directionAtPoint As Vector3d = baseCurve.GetFirstDerivative(pointOverPipe)
Select Case p.FlowDirection
Case FlowDirectionType.Bidirectional
DrawLineAtPoint(geo, pointOverPipe, directionAtPoint)
Case FlowDirectionType.StartToEnd
DrawArrowAtPoint(pointOverPipe, directionAtPoint)
Case FlowDirectionType.EndToStart
DrawArrowAtPoint(pointOverPipe, directionAtPoint)
End Select
Next
'determine the next structure, following the flow
Select Case p.FlowDirection
Case FlowDirectionType.Bidirectional 'both directions
NextStruct(trans.GetObject(p.EndStructureId, OpenMode.ForRead))
NextStruct(trans.GetObject(p.StartStructureId, OpenMode.ForRead))
Case FlowDirectionType.StartToEnd
NextStruct(trans.GetObject(p.EndStructureId, OpenMode.ForRead))
Case FlowDirectionType.EndToStart
NextStruct(trans.GetObject(p.StartStructureId, OpenMode.ForRead))
End Select
End Sub
Public Sub DrawArrowAtPoint(ByVal p As Point3d, ByVal v As Vector3d)
v = v.MultiplyBy(1 / v.Length) 'turn into unit length vector
'directions of the arrow
Dim leftSide As Vector3d = v.RotateBy(2 * Math.PI / 3, Vector3d.ZAxis)
Dim rightSide As Vector3d = v.RotateBy(4 * Math.PI / 3, Vector3d.ZAxis)
'draw the arrow
geo.WorldLine(p, p.Add(leftSide))
geo.WorldLine(p, p.Add(rightSide))
End Sub
Public Sub DrawLineAtPoint(ByVal geo As ViewportGeometry, ByVal p As Point3d, ByVal v As Vector3d)
v = v.MultiplyBy(1 / v.Length) 'turn into unit length vector
'two perpendicular vectos
Dim leftSide As Vector3d = v.RotateBy(Math.PI / 2, Vector3d.ZAxis)
Dim rightSide As Vector3d = v.RotateBy(3 * Math.PI / 2, Vector3d.ZAxis)
'draw the line
geo.WorldLine(p.Add(rightSide), p.Add(leftSide))
End Sub
Public Sub NextStruct(ByVal s As [Structure])
'find the next pipe for each connected pipe
For pIndex As Integer = 0 To s.ConnectedPipesCount - 1
Dim p As Pipe = trans.GetObject(s.ConnectedPipe(pIndex), OpenMode.ForRead)
'determine where will flow from this pipe
'these 2 'ifs' could be one, but left as two to understanding it better
If p.StartStructureId.Equals(s.ObjectId) And p.FlowDirection = FlowDirectionType.StartToEnd Then
NextPipe(p, s.Location)
ElseIf p.EndStructureId.Equals(s.ObjectId) And p.FlowDirection = FlowDirectionType.EndToStart Then
NextPipe(p, s.Location)
End If
Next
End Sub
End Class
Can't find what you're looking for? Ask the community or share your knowledge.