Copying from Document doesn't overwrite the element types

Hello all,

I tried to copy elements from a Revit Link and A Revit document from the background including option to overwrite existing elements definition or types in the current active revit project file. When try with a Revit document in the background it doesn’t overwrite the existing, it renames the existing adding a sequence number at the end as suffix and also duplicates family types. Although if copying from a link it overwrites, why is that? Is there any option to overwrite existing elements when copying from a Document?

Hard to see where the issue is without the code and a data set.

Are you using the same load options in both cases?

1 Like

that is how revit treats copy between files. you will have to load the families in question into your project dont have a solution for you in dynamo. sry

I mean I can copy from link in the way I need but not from a Document, what means your comment about that?

In my experience most objects behave this way, or sometimes even do not copy. The best approach I’ve found to be absolutely sure to update to the new type copied in is:

  1. Temporarily rename type in project to replace
  2. Copy in new type
  3. Swap all old types to new type
  4. Delete old type

Not simple for some cases (e.g. view templates, stacked walls etc.), but haven’t seen a sure way to replace one with the other. The Revit API and Revit don’t behave as such such so not sure a simple method is available.

In the case of loadable families, they are a bit easier. You can use IFamilyLoadOption interface to specify the overwrite behavior. Not like this for system families however.

1 Like

what i mean is if you have to seperate revit files open and try to copy between them revit behaves exactly the way you describe.

if you have the same file linked in to the project and you use bind link it will instead write over if prompt to do so.

what i am trying to say is you need to get your script to either bind the elements from your link to your project or load the families you want from a folder system (for instance you saved all families in the project to a folder on desktop)

why the comments are so negative? I had good experience with Revit Links but not with Document in background to try to copy things, I would like to know if the options or method to copy should be different to make it work as copying from links.

I am not going to use Bind anymore because all the bind elements appear moved vertically unknown distance from the original and Autodesk never resolved this, I wrote a claim and had videocall more than year ago about this behaviour.

not really sure what in my comments you percive as negative, just stating this is how Revit behaves. and you would have to change your approch of solving the problem.

The best method for copy in background for me is this approach, I assume you’ve got that part sorted already though. If I come across better inbuilt ways versus rename/reassign/delete I’ll return to this thread, but for now it’s the best I’ve known of. I know other tools such Ideate Style Manager work that way also for style consolidation so I assume it’s probably the best option for now.

3 Likes

Post some code so we can have a look at what the issue is. Things like category, units, element associations, style, etc. all impact the action of ‘copying’ significantly. Otherwise all the community can do is guess, and guesses by their nature will come across as less helpful and will feel more negative.

One thought you could try without posting the code… since you have copying elements from links working, why not link the document into the project you want to copy into instead of opening it in the background, then copy the element from the link, and then unload the link.

1 Like

I was thinking the same, but wanted to try both cases as sometimes I cannot edit or add links to the Revit files, so open document in Background.

Here a sample of the code I was writting and ended in this questions, if you understand it and can give a solution from this I would appreciate it.

You need to feed Input 0 with a Document and input 1 with elements to copy from the document

import clr
clr.AddReference('RevitServices')
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *
from System.Collections.Generic import List
clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.Elements)

# Get the current document
doc = DocumentManager.Instance.CurrentDBDocument

# Get the input documents and elements
inputdocs = UnwrapElement(IN[0])
elements_inputs = UnwrapElement(IN[1])

# Custom handler for duplicate types
class CustomCopyHandler(IDuplicateTypeNamesHandler):
    def OnDuplicateTypeNamesFound(self, args):
        return DuplicateTypeAction.UseDestinationTypes

options = CopyPasteOptions()
options.SetDuplicateTypeNamesHandler(CustomCopyHandler())

OUT = []

if len(inputdocs) == 1 and not any(isinstance(item, list) for item in elements_inputs):
    # IN[0] is a single item and IN[1] is a flattened list
    doc_or_link = inputdocs[0]
    elements_input = elements_inputs

    # Check if it's a RevitLinkInstance
    if isinstance(doc_or_link, RevitLinkInstance):
        linkDoc = doc_or_link.GetLinkDocument()
        tf1 = doc_or_link.GetTotalTransform()
    else:
        # It's a Document
        linkDoc = doc_or_link
        tf1 = Transform.Identity

    # Gather the ElementIds directly from the list
    eId = List[ElementId]()
    for e in elements_input:
        eId.Add(e.Id)

    TransactionManager.Instance.EnsureInTransaction(doc)
    try:
        # Copy the elements from linkDoc to the current document
        copy = ElementTransformUtils.CopyElements(linkDoc, eId, doc, tf1, options)
    except Exception as e:
        OUT.append(str(e))
    else:
        for i in copy:
            e = doc.GetElement(i)
            if e is not None:
                OUT.append(e.ToDSType(False))
    finally:
        TransactionManager.Instance.TransactionTaskDone()

else:
    # IN[0] is a list of items and IN[1] can be either a list of sublists or a flattened list
    for doc_or_link, elements_input in zip(inputdocs, elements_inputs):
        # Check if it's a RevitLinkInstance
        if isinstance(doc_or_link, RevitLinkInstance):
            linkDoc = doc_or_link.GetLinkDocument()
            tf1 = doc_or_link.GetTotalTransform()
        else:
            # It's a Document
            linkDoc = doc_or_link
            tf1 = Transform.Identity

        if isinstance(elements_input, list):
            # Input is a list of sublists
            for sublist in elements_input:
                # Gather the ElementIds from each sublist
                eId = List[ElementId]()
                for e in sublist:
                    eId.Add(e.Id)

                TransactionManager.Instance.EnsureInTransaction(doc)
                try:
                    # Copy the elements from linkDoc to the current document
                    copy = ElementTransformUtils.CopyElements(linkDoc, eId, doc, tf1, options)
                except Exception as e:
                    OUT.append(str(e))
                else:
                    for i in copy:
                        e = doc.GetElement(i)
                        if e is not None:
                            OUT.append(e.ToDSType(False))
                finally:
                    TransactionManager.Instance.TransactionTaskDone()
        else:
            # Input is a flattened list
            # Gather the ElementIds directly from the list
            eId = List[ElementId]()
            for e in elements_input:
                eId.Add(e.Id)

            TransactionManager.Instance.EnsureInTransaction(doc)
            try:
                # Copy the elements from linkDoc to the current document
                copy = ElementTransformUtils.CopyElements(linkDoc, eId, doc, tf1, options)
            except Exception as e:
                OUT.append(str(e))
            else:
                for i in copy:
                    e = doc.GetElement(i)
                    if e is not None:
                        OUT.append(e.ToDSType(False))
            finally:
                TransactionManager.Instance.TransactionTaskDone()

OUT
1 Like

I don’t see any reason why these would perform differently offhand. I might find time to check this out later this week, but… as you are modifying the active document, I don’t see why you couldn’t first link the source model into the document, then transform them over (as that is what works).

2 Likes