Select all pipe networks and merge into a new pipe network

How did you select all the pipe networks and merge them into another pipe network?

Example:
I have a pipe network called “PIPE-01” and another pipe network called “PIPE-02” and I want to merge these two pipe networks into a pipe network called “PIPE-ALL”

important: I have more than 100 pipe networks created and I would like to merge them all into just one via dynamo

I doubt if this is commonly possible. The merge function within Civil3D is not described in the API reference.

One thing to try:

  1. Parse out all the parts of the existing network
  2. Generate new parts in the new network based on the location and information of each part.
  3. Delete the old parts.
    Review for data fidelity (geometry comparison and data comparison)

Searching I saw that we have this API
https://help.autodesk.com/view/CIV3D/2023/ENU/?guid=90ba51f0-38b7-09c2-6285-c093f9a61271

but I’m not knowing how to implement it … could you guide me?

That’s a solution. The problem is that we are talking about almost 100 culverts lol. I would like to avoid doing this kind of work using dynamo.

That’s it though - Dynamo can do all of those steps. You can even have one graph process all the files into a .csv, then read the CSV into a second graph and generate the parts of the new pipe network.

1 Like

I think that might work. I’ll have a look at it tomorrow, Nice challenge :wink:

1 Like

Or today… couldnt resist:

This seems to work, I did have to hit the refresh button before I saw the results in the toolspace as well. Mind that in the documentation there are a few remarks (wich I did not encounter in this super class example I used):


Copy paste the script in a python node and just hit run :slight_smile:

# Load the Python Standard and DesignScript Libraries
import sys
import clr

# Add Assemblies for AutoCAD and Civil3D
clr.AddReference('AcMgd')
clr.AddReference('AcCoreMgd')
clr.AddReference('AcDbMgd')
clr.AddReference('AecBaseMgd')
clr.AddReference('AecPropDataMgd')
clr.AddReference('AeccDbMgd')

# Import references from AutoCAD
from Autodesk.AutoCAD.Runtime import *
from Autodesk.AutoCAD.ApplicationServices import *
from Autodesk.AutoCAD.EditorInput import *
from Autodesk.AutoCAD.DatabaseServices import *
from Autodesk.AutoCAD.Geometry import *

# Import references from Civil3D
from Autodesk.Civil.ApplicationServices import *
from Autodesk.Civil.DatabaseServices import *

# The inputs to this node will be stored as a list in the IN variables.
dataEnteringNode = IN

adoc = Application.DocumentManager.MdiActiveDocument
cdoc = CivilApplication.ActiveDocument
editor = adoc.Editor

pnws = cdoc.GetPipeNetworkIds()
res = []
run = IN[0]

with adoc.LockDocument():
    with adoc.Database as db:

        with db.TransactionManager.StartTransaction() as t:
            cnt = 1
            base_pnw = pnws[0]
            for id in pnws:
                if not cnt == 0:
                    pnw = t.GetObject(id, OpenMode.ForWrite)
                    pipes = pnw.GetPipeIds()
                    structs = pnw.GetStructureIds()
                    
                    pnw.MoveParts(pipes, base_pnw)
                    pnw.MoveParts(structs, base_pnw)
                cnt += 1
            # Place your code below
            # 
            #

            # Commit before end transaction
            pnw = t.GetObject(base_pnw, OpenMode.ForRead)
            basename = pnw.Name

            t.Commit()
            #pass

# Assign your output to the OUT variable.
OUT = basename

2 Likes

good job
But this Method loses Connect with Structures
So , you need to ConnectToStructure Method



2 Likes

@geert.drijfhout & @hosneyalaa Can you both help us to find a solution for this comman task (merging multiple pipe networks) & the result pipe network to be all connected?

1 Like

It proposes a new challenge… will look into this later. thank you for testing and mentioning the solution as well

Great find on the MoveParts method!

This should re-make the connections, with full annotations to help answer any questions too:

# Import the CLR for access to .net libraries
import sys, clr

# Add Assemblies for AutoCAD
clr.AddReference('AcMgd')
clr.AddReference('AcDbMgd')
# Import references from AutoCAD
from Autodesk.AutoCAD.ApplicationServices import Application
from Autodesk.AutoCAD.DatabaseServices import OpenMode

# Add Assemblies for Civil3D
clr.AddReference('AeccDbMgd')
# Import references from Civil3D
from Autodesk.Civil.ApplicationServices import CivilApplication
from Autodesk.Civil.DatabaseServices import ConnectorPositionType

# get the ObjectId of the target network from the Dynamo environment
targetNetwork = IN[0].InternalObjectId 

#get the other networks in the civil document
cvlDoc = CivilApplication.ActiveDocument #get the civil document
pipeNetworkIds = [i for i in cvlDoc.GetPipeNetworkIds()] #the the pipe network ids as a list 
pipeNetworkIds.Remove(targetNetwork) #remove the target network from the list

#begin to merge parts into the target network
adoc = Application.DocumentManager.MdiActiveDocument #get the active Autocad document
with adoc.LockDocument(): #lock the document 
	with adoc.Database as db: #get the database 
		with db.TransactionManager.StartTransaction() as t: #start a transaction
			for network in pipeNetworkIds: #for every pipe network id
				net = t.GetObject(network, OpenMode.ForWrite) #get the network for writing back
				strs = net.GetStructureIds() #get the object ids of structuresin the network
				pipes = net.GetPipeIds() #get the object ids of pipes in the network
				pipesList = [t.GetObject(i, OpenMode.ForWrite) for i in pipes] #get the pipe elements in the network for writing back
				startStructures = [i for i in [p.StartStructureId for p in pipesList]] #get the start structure for each pipe
				endStructures = [i for i in [p.EndStructureId for p in pipesList]] #get the end structure of each pipe
				connections = zip(startStructures, endStructures) #join the start and end structures into a list
				net.MoveParts(pipes, targetNetwork) #move the pipes to the target network 
				net.MoveParts(strs, targetNetwork) #move the structures to the target network
				for p, strs in zip(pipesList, connections): #for each set of pipe and connections
				    p.ConnectToStructure(ConnectorPositionType.Start,strs[0], True) #connect the pipe to the start structure
				    p.ConnectToStructure(ConnectorPositionType.End,strs[1], True) #connect the pipe to the end structure
			t.Commit() #commit the transaction after all networks have been processed

OUT = "Networks merged." #inform the user in the Dynamo environment
2 Likes

wow, great work Jacob. Last question that pops up: does this handle potential duplicate names for pipes/structures? otherwise it would require to add source pipe network name in the pipe/struct name.

1 Like

I didn’t check that; my guess is if it fails it would do so at the move step, but it may increment the name to the next available. Any renaming would likely detrimental to adjacent workflows, so likely best to clean up your naming across all networks before you shift the values.

If you were in a tight squeeze though, you could always append the previous network name to the string as a prefix or suffix, which wouldn’t be too hard to do via nodes in another graph.

1 Like

Excellent!! Glad to hear you got the solution! You guys are awesome! Congratulations.

I ran the code and got some errors…

As the errors appeared, I solved them and the result of the code looked like this:

image

# Import the CLR for access to .net libraries
import sys, clr

# Add Assemblies for AutoCAD
clr.AddReference('AcMgd')
clr.AddReference('AcDbMgd')
# Import references from AutoCAD
from Autodesk.AutoCAD.ApplicationServices import Application
from Autodesk.AutoCAD.DatabaseServices import OpenMode

# Add Assemblies for Civil3D
clr.AddReference('AeccDbMgd')
# Import references from Civil3D
from Autodesk.Civil.ApplicationServices import CivilApplication
from Autodesk.Civil.DatabaseServices import ConnectorPositionType

# get the ObjectId of the target network from the Dynamo environment
targetNetwork = IN[0].InternalObjectId 

#get the other networks in the civil document
cvlDoc = CivilApplication.ActiveDocument #get the civil document
pipeNetworkIds = [i for i in cvlDoc.GetPipeNetworkIds()] #the the pipe network ids as a list 
pipeNetworkIds.remove(targetNetwork) #remove the target network from the list

#begin to merge parts into the target network
adoc = Application.DocumentManager.MdiActiveDocument #get the active Autocad document
with adoc.LockDocument(): #lock the document 
	with adoc.Database as db: #get the database 
		with db.TransactionManager.StartTransaction() as t: #start a transaction
			for network in pipeNetworkIds: #for every pipe network id
				net = t.GetObject(network, OpenMode.ForWrite) #get the network for writing back
				strs = net.GetStructureIds() #get the object ids of structuresin the network
				pipes = net.GetPipeIds() #get the object ids of pipes in the network
				pipesList = [t.GetObject(i, OpenMode.ForWrite) for i in pipes] #get the pipe elements in the network for writing back
				startStructures = [i for i in [p.StartStructureId for p in pipesList]] #get the start structure for each pipe
				endStructures = [i for i in [p.EndStructureId for p in pipesList]] #get the end structure of each pipe
				connections = zip(startStructures, endStructures) #join the start and end structures into a list
				net.MoveParts(pipes, targetNetwork) #move the pipes to the target network 
				net.MoveParts(strs, targetNetwork) #move the structures to the target network
				for p, strs in zip(pipesList, connections): #for each set of pipe and connections
				    p.ConnectToStructure(ConnectorPositionType.Start,strs[0], True) #connect the pipe to the start structure
				    p.ConnectToStructure(ConnectorPositionType.End,strs[1], True) #connect the pipe to the end structure
			t.Commit() #commit the transaction after all networks have been processed

OUT = "Networks merged." #inform the user in the Dynamo environment

But there is an error that, unfortunately, I am not able to resolve.

image

I did some research, and it looks like it’s a “common” problem, but I still couldn’t find a solution. Could you help me, or guide me, telling me how I could solve this problem?

I’d like to say that I don’t know much compared to you guys… but I’m always looking to learn! I have some interesting notions in the python language, but, for sure, there is a lot that I still need to learn.

My sincere thanks in advance!

Basically you get that error whenever your script bugs out before the end of the “with”.
It bugs out (I believe) because you try to merge referenced pipe networks. These pipe networks are not in the civil document itself so you cant preform these actions in them.

I suppose you could try promoting into active drawing.

1 Like

Alright, problem solved! After solving the last problem I mentioned, the problem of needing to rename all pipes and structure appeared.

Thank you very much!