Copy, paste in place and change to a different type with python

Hi all,
I am trying to do is (as the title specifies) copy, paste in place and change to a different type with python from selected model elements. I have found that “Springs” node does a similar thing but I would like to make the color coded changes in the script.


Unfortunately, I have not got any experience with python and would not know how to do these.
Could anyone please help?.

import clr

clr.AddReference('RevitServices')
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument

clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *

from System.Collections.Generic import List

clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

def singleton(x):
    if hasattr(x,'__iter__'): return x[0]
    else : return x

def tolist(x):
    if hasattr(x,'__iter__'): return x
    else : return [x]

#Want to change the below source for active view
source = UnwrapElement(singleton(IN[0]) )
#Want to change the below dest for active view as well
dest = UnwrapElement(singleton(IN[1]) )
#want to change the elements "from IN[0]" should be as simple as swapping "2" for "0" right?
elements = UnwrapElement(tolist(IN[2]) )
#Want to swap the type for the new name in "IN[1]"
tf1 = singleton(IN[3])

if tf1 is not None:
    tf1 = tf1.ToTransform(True)

eId = List[ElementId](e.Id for e in elements if hasattr(e, "Id") )

TransactionManager.Instance.EnsureInTransaction(doc)
copy = ElementTransformUtils.CopyElements(source, eId, dest, tf1, None)
TransactionManager.Instance.TransactionTaskDone()

OUT = [doc.GetElement(i).ToDSType(False) for i in copy]

Hello,
is the goal of the script to change a type to another type of the same category? if so, do the existing types and the new types have the same type of host (unhosted family or face based family) ?

This doesn’t have to be done all at once and can still be accomplished without Python. You would just use your active view for the source and destination and then change the types after the elements are copied.

I’d also point out that views are only necessary for view specific elements. If you’re not copying annotations you probably have the wrong node.

Hi
@c.poupin, yes the goal is to change a Wall (Basic) to a Wall (Curtain)
@Nick_Boyts thank you for the input. However, I have been trying to find nodes that do this and it has become kind of tedious trying to find them. Furthermore, I would like to understand more about python and it would be useful to know how to transform/edit the code in the future so I know where to go and what to edit :wink: :nerd_face: So editing the current node would be both beneficial currently and in the future. Also, how do you know the node is only for annotations? :thinking: no wonder it was not working :sweat_smile:

Learning Python is a great next step in learning Dynamo. I would suggest getting familiar with revitapidocs and this thread:


Start looking through other posts in the forum dealing with copy/pasting elements. There area quite a few. Don’t worry if they’re about copying between documents or using specific copy settings, the process is the same. RevitAPIDocs is a great place to figure out exactly what you need to provide in your code.

As I said, only annotation elements are view specific. Everything else just has a location in the project.

1 Like

@Nick_Boyts yeah it make sense that the walls are location based. I guess I was thinking on graphs I’ve made that selects all elements in view only :yum:
I’ll have a look to the primer though. Great source :+1:

@JocoYo
if you want to learn Python, modifying (or copying and pasting) other people’s scripts is not the best way forward. :wink:
At the beginning yes it can be beneficial for learning but little by little it will be better to start from a blank sheet, while keeping an eye on the other scripts which can always serve as sources of inspiration.

to return to the initial request, copy-paste is not necessary to change a Type of Wall
the Revit API allow this
https://www.revitapidocs.com/2020/0c0d155f-5b2c-c09f-d7d4-41a8600560eb.htm
change wall Type

to return all elements in view you need to use this FilteredElementCollector class with this method
https://www.revitapidocs.com/2020/6359776d-915e-f8a2-4147-b31024671ee1.htm

an example of solution

2 Likes

@c.poupin Thanks that is grant and I will transcribe all the scripts I want to edit as you said and I had seen the RevitAPI but had no clue what I was looking at :pleading_face:. However, a little thing that I have probably not been clear about. I need to keep both the Curtain wall and the Wall I am coping, so the coping step need to be kept and the reason I would like to specify the type for the new wall in the 2nd input. Is that even possible?

@JocoYo
in this case you need both method :
ElementTransformUtils.CopyElements() method → to copy Walls as same location
and
WallType Property → to change to Curtain wall

@c.poupin I’m a bit lost.

import sys
import clr

clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument

clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *

from System.Collections.Generic import List

clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)

def newWall(x):
    if hasattr(x,'__iter__'): return x[1]
    else : return x

def tolist(x)
    if hasattr(x,'__iter__'): return x
    else : return [x]

wallReplace = UnwrapElement(IN[0])
newWall = UnwrapElement(IN[1])

fecW = FilteredElemntCollector(doc, doc.ActiveView.Id).OfClass(Wall).ToElements()
outchange = []
if w in fecW is not None:
    w = w.ToTransform(True)
eId = List[ElementId](e.Id for e in elements if hasattr(e, "Id"))
TransactionManager.Instance.EnsureInTransaction(doc)
copy = ElementTransformUtils.CopyElements(eId, )
for w in fecW
    if w.CurtainGrid is None:
        w.WallType = wallReplace
        outchanged.append(w)
TransactionManager.Instance.TransactionTaskDone()

OUT = outchange 

I think I am changing and copying the same wall and seems wrong. :sweat_smile:
Also, I have been looking at the Revit API “Wall Property” and the Syntax you pointed to, shows #public WallType WallTpye {set;} but when trying it does not work nor is in any of the codes I have ever seen. Does any webpage contain the python version?

@JocoYo
try this

import sys
import clr

clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument

clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *

import System 
from System.Collections.Generic import List

toDoList = lambda x : x if hasattr(x, '__iter__') else [x]
lstWall = toDoList(UnwrapElement(IN[0]))
wallToPlace = UnwrapElement(IN[1])
#
outchanged = []
TransactionManager.Instance.EnsureInTransaction(doc)
for w in lstWall:
	if w.CurtainGrid is None:
		eId = List[ElementId]([w.Id])
		newwallSetId = ElementTransformUtils.CopyElements(doc, eId, XYZ.Zero)
		for newwallId in newwallSetId:
			newwall = doc.GetElement(newwallId)
			newwall.WallType = wallToPlace
		outchanged.append(newwall)
TransactionManager.Instance.TransactionTaskDone()		

OUT = outchanged
2 Likes

@c.poupin
That did not work
Is telling me #IronPythonEvaluator.EvaluateIronPythonScript operation failed. unexpected token ‘x’


Why would that be?

there is an syntax error at the lambda function (lambda not lamdba)

1 Like

@c.poupin Thank you very much for the help. Really appreciate it