Announcements
Attention for Customers without Multi-Factor Authentication or Single Sign-On - OTP Verification rolls out April 2025. Read all about it here.

Copying elements, types and parameters

franjavigarciavalencia
Enthusiast

Copying elements, types and parameters

franjavigarciavalencia
Enthusiast
Enthusiast

Hello

 

I am trying to copy certain elements (instances) from one project into another. The types from the copied project will already exist and be loaded into the new one.

 

I have managed to copy the elements in their correct location using ElementTransformUtils.CopyElements(), but I am struggling with copying the type parameters (like, for example, the Description and the Type Mark) and the instance parameters (like the Comments or the Mark).

 

The idea is to process all kinds of instances, may they be system types or family symbols, and I have tried using Element.GetOrderedParameters() and LookupParameter("ParameterName") in both types and elements and setting them from the copy project to the paste project using Parameter.AsValueString() and Parameter.SetValueString() respectively.

 

So here goes the question:

Is it possible to copy these type and instance parameters without having to look for them by name, and in a generic manner without having to make distinctions between types and symbols?

If so, any and all tips would be appreciated.

 

Thanks

0 Likes
Reply
Accepted solutions (2)
3,072 Views
7 Replies
Replies (7)

naveen.kumar.t
Autodesk Support
Autodesk Support

Hi @franjavigarciavalencia ,

I don't see any problem in copying the element and its instance parameter value from one document to another. 

 

When I try to copy the element from one document to another document, I see along with the element, the element's instance parameter, and its value is also copied.

 

I tried to copy the element's type parameter and its value from one document to another Via UI. I have no luck.

 

please be aware that the Revit API hardly ever supports any functionality that is not also available in the user interface.

 

Therefore, if the UI does not support this, the API will probably not do so either.

 

So, it will always help to research the optimal manual approach to a solution first, before attacking the task programmatically.

 

I hope this clarifies.

 


Naveen Kumar T
Developer Technical Services
Autodesk Developer Network

Sean_Page
Collaborator
Collaborator
Accepted solution

I have several routines that I use to.copy Loadable as well as system family Types from template or linked models and all of the Parameters always come with them. Perhaps it would help to get the instance, then it's type and copy the type and then the instance?

Sean Page, AIA, NCARB, LEED AP
Partner, Computational Designer, Architect

jeremy_tammik
Autodesk
Autodesk
Accepted solution

I just came across this thread in another conversation:

 

https://forums.autodesk.com/t5/revit-api-forum/phasecreated-amp-phasedemolished-after-using-copyelem...

 

I'll add the suggestion that I made there here as well:

 

I believe that when you collect a bunch of elements and copy them all together in one single operation, Revit will try to maintain and restore all their mutual relationships in the target database. Therefore, it might help if you add all possible references these elements have to other source database elements to the set of elements to copy. These references will include the element instances themselves, their types, phases, levels, views, materials, and whatever other objects you are interested in. Then you will have to test and see what Revit can do to try to avoid creating duplicates of them in the target database and map them to existing target objects instead.

 

This behaviour is hinted at in the list of extensible storage features:

   

https://thebuildingcoder.typepad.com/blog/2011/06/extensible-storage-features.html#7

  

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open

gjordanp
Contributor
Contributor
I would like to open this thread.
I'm finding copyElement method really slow. When I call it in a foreach function it is like it will refresh UI in every call. So copyElements seems to be the solution. But I'm having problems because returnIds do not map 1.by 1 to inputIds.

So, is there a way to make it match 1 to 1 or to make single copy to refresh at the end of the transaction?

Regards
0 Likes

jeremy_tammik
Autodesk
Autodesk

Yes, the input and output collections are unsorted, so they do not match their elements one-to-one.

  

Two things to try come to mind:

  

  • Use some other kind of identification marker id on your input elements that is included in the copy, so you can match them yourself afterwards
  • Use a transaction group wrapping individual calls to CopyElement in subtransactions

  

The latter might enable using CopyElement one by one and yet retain the speed of one single top-lvele transaction.

  

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open

gjordanp
Contributor
Contributor

Thanks Jeremy! Didn't though about the first one. I'll try both and let you know

 

Regards 

0 Likes

gjordanp
Contributor
Contributor

Hi Jeremy,

 

I attached my code to work with the first option you suggested. It works perfectly fine when originDocument is different than destinationDocument, but when I'm trying to copy in the same document, "Mark" parameter values are not copied to the copied elements. Even that I have verify in the line before the copyElements, that the elements to be copied have the Mark Parameter Value.

¿Any Thoughts?

 

using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Structure;
using Autodesk.Revit.DB.Visual;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using RevitMV.Auth.services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Controls;

namespace RevitMV
{
[Transaction(TransactionMode.Manual)]
class RB_LS_CopyPasteLosas : MN_MasterClass
{
public override Result ExecuteTool(ExternalCommandData commandData, ref string message, ElementSet elements)
{

UIApplication rvtUIApp = commandData.Application;
UIDocument rvtUIDoc = rvtUIApp.ActiveUIDocument;
Autodesk.Revit.ApplicationServices.Application revitApp = rvtUIApp.Application;
Document m_rvtDoc = rvtUIDoc.Document;
List<View> openViews = GetAllOpenViews(rvtUIApp);


try
{
View originView;
View destinationView;
IList<Reference> refs;
Document originDoc;
Document destinationDoc;
XYZ puntoInicio;
XYZ puntoFinal;
int copiedBarsCount = 0;
int pastedBarsCount = 0;

List<ElementId> detailItemBarras_list = new List<ElementId>();
List<List<ElementId>> rebarToCopy_list = new List<List<ElementId>>();
List<ElementId> rebarToCopy_list_flat = new List<ElementId>();
List<ElementId> rbcCopiedIds = new List<ElementId>();
List<ElementId> rbCopiedIds = new List<ElementId>();

using (Transaction trans1 = new Transaction(m_rvtDoc))
{
trans1.Start("CopyPaste - Copiar Barras");

Selection sel = rvtUIDoc.Selection;
ElementoSimboloFiltro selFilter = new ElementoSimboloFiltro();


refs = sel.PickObjects(ObjectType.Element, selFilter, "Elija las barras a aplicar CopyPaste");


copiedBarsCount = refs.Count;

//Ocultamos los rebars para mejorar seleccion e puntos
RB_LS_ArmarLosas.HideCategoryTemporary(m_rvtDoc, BuiltInCategory.OST_Rebar);

//Seleccionamos punto de origen
Selection selection1 = rvtUIDoc.Selection;
puntoInicio = selection1.PickPoint("Seleccione punto de origen, Se copiara desde el punto de origen al punto de destino");
originDoc = rvtUIApp.ActiveUIDocument.Document;
originView = originDoc.ActiveView;

//Buscamos los detail item y los Rebars a ser copiados.
foreach (var reference in refs)
{
//Elemento simbolico de losas
Element detailItemBarras = originDoc.GetElement(reference.ElementId) as Element;
//Obtenemos los rebar containers
List<RebarContainer> rebarContainerList = RB_LS_ArmarLosas.GetRebarContainersFromSymbol(originDoc, detailItemBarras);
List<Rebar> rebarList = RB_LS_ArmarLosas.GetRebarFromSymbol(originDoc, detailItemBarras);
//Creamos la lista de ids de los rebar containers
List<ElementId> rebarContainersToCopy = rebarContainerList.Select(rc => rc.Id).ToList();
List<ElementId> rebarToCopy = rebarList.Select(rb => rb.Id).ToList();

detailItemBarras_list.Add(detailItemBarras.Id);
rebarToCopy_list.Add(rebarContainersToCopy.Count > 0 ? rebarContainersToCopy : rebarToCopy);
}

 

rebarToCopy_list_flat = rebarToCopy_list.SelectMany(innerList => innerList).ToList();

//CopyElement Entrega los elementos copiados en desorden, por lo que:
//Agregamos parametro para identificar las barras copiadas, en el parametro Mark se agrega el indice de la lista.
detailItemBarras_list.ForEach(e => originDoc.GetElement(e).LookupParameter("Mark").Set(detailItemBarras_list.IndexOf(e).ToString()));
//Agregamos parametro para identificar las barras copiadas, en el parametro Mark se agrega el indice de la lista
rebarToCopy_list_flat.ForEach(e => originDoc.GetElement(e).LookupParameter("Mark").Set(rebarToCopy_list_flat.IndexOf(e).ToString()));

 


var openDocuments = GetAllOpenDocumnets(rvtUIApp);
//Cuadro de dialogo para seleccion vista de destino
var dlg = new RB_DG_LS_CopyPaste(openDocuments);
dlg.ShowDialog();

if (dlg.DialogResult == false) return Result.Failed;

destinationView = dlg.SelectedView;
destinationDoc = destinationView.Document;

//Se muestran rebars nuevamente
RB_LS_ArmarLosas.DeactivateTemporaryView(m_rvtDoc);

//Make visible Mark Values for next transaction
originDoc.Regenerate();

trans1.Commit();
}

//Activamos el documento de destino
if (destinationDoc.PathName != originDoc.PathName)
{
rvtUIDoc=new UIDocument(destinationView.Document);
rvtUIApp.OpenAndActivateDocument(destinationDoc.PathName);
}
else
{
destinationDoc = originDoc;
}
//Change la vista activa
rvtUIDoc.ActiveView = destinationView;
rvtUIDoc.RefreshActiveView();

//Hacemos la seleccion de destino
Selection selection2 = rvtUIDoc.Selection;
puntoFinal = selection2.PickPoint("Seleccione punto de destino, Se copiara desde el punto de origen al punto de destino");
destinationDoc = rvtUIApp.ActiveUIDocument.Document;

 

using (Transaction trans2 = new Transaction(destinationDoc))
{
try
{
trans2.Start("CopyPaste - Pegar Barras");

 

destinationDoc.Regenerate();

//transformation
Transform transform = Transform.CreateTranslation(new XYZ(puntoFinal.X - puntoInicio.X, puntoFinal.Y - puntoInicio.Y, destinationView.GenLevel.ProjectElevation - originView.GenLevel.ProjectElevation));
Transform transformSymbol = Transform.CreateTranslation(new XYZ(puntoFinal.X - puntoInicio.X, puntoFinal.Y - puntoInicio.Y, 0));

//Copypasteoptiones
CopyPasteOptions copyPasteOptions = new CopyPasteOptions();

//Copiamos los symbolos de las losas
List<ElementId> simbCopiedId_list = ElementTransformUtils.CopyElements(originView, detailItemBarras_list, destinationView, transformSymbol, copyPasteOptions).ToList();

//Copiamos los Rebar
rbcCopiedIds = ElementTransformUtils.CopyElements(originDoc, rebarToCopy_list_flat, destinationDoc, transform, copyPasteOptions).ToList();

//Ordenamos los ids copiados por el parametro Mark
simbCopiedId_list = simbCopiedId_list.OrderBy(e => int.Parse(destinationDoc.GetElement(e).LookupParameter("Mark").AsValueString())).ToList();

//Ordenamos los ids copiados por el parametro Mark, producto que CopyElement devuelve una lista desordenada.
rbcCopiedIds = rbcCopiedIds.OrderBy(e => int.Parse(destinationDoc.GetElement(e).LookupParameter("Mark").AsValueString())).ToList();

//Eliminamos el Mark para el documento de destino.
rbcCopiedIds.ForEach(e => destinationDoc.GetElement(e).LookupParameter("Mark").Set(""));
simbCopiedId_list.ForEach(e => destinationDoc.GetElement(e).LookupParameter("Mark").Set(""));


//Reconstruimos las listas de los ids copiados
List<List<ElementId>> rbcCopiedIds_list = new List<List<ElementId>>();
int index = 0;
foreach (var simbCopiedId in simbCopiedId_list)
{
List<ElementId> rbcCopiedIds_aux = new List<ElementId>();

rbcCopiedIds_aux = rbcCopiedIds.GetRange(index, rebarToCopy_list[index].Count);

rbcCopiedIds_list.Add(rbcCopiedIds_aux);

index += rebarToCopy_list[index].Count;
}


//Asignamos los hosts y los UID a los rebar containers y rebar
pastedBarsCount = 0;

List<ElementId> simbolsToDelete = new List<ElementId>();
List<ElementId> rebarToDelete = new List<ElementId>();

foreach (var simbCopiedId in simbCopiedId_list)
{
FamilyInstance copiedSymbolElement = destinationDoc.GetElement(simbCopiedId) as FamilyInstance;
List<Floor> losas_host = RB_LS_ArmarLosas.GetLosaHostFromSymbol(destinationDoc, copiedSymbolElement);
if (losas_host.Count == 0)
{
//Borramos los elementos copiados si no tienen host
simbolsToDelete.Add(simbCopiedId);
rebarToDelete.AddRange(rbcCopiedIds_list[simbCopiedId_list.IndexOf(simbCopiedId)]);
continue;
}

Floor losaHost = losas_host?.First();


foreach (ElementId rbcId in rbcCopiedIds_list[simbCopiedId_list.IndexOf(simbCopiedId)])
{
Element rebarCopied = destinationDoc.GetElement(rbcId);
if (rebarCopied is RebarContainer rbcCopied)
{
rbcCopied.SetHostId(destinationDoc, losaHost.Id);
FN_Rebar.AssignRbcParam(rbcCopied, FN_params.RB_uId, copiedSymbolElement.UniqueId, ParamType.s);
rbcCopied.SetUnobscuredInView(destinationView, true);
}
else if (rebarCopied is Rebar rbCopied)
{
rbCopied.SetHostId(destinationDoc, losaHost.Id);
rbCopied.LookupParameter(FN_params.RB_uId).Set(copiedSymbolElement.UniqueId);
rbCopied.SetUnobscuredInView(destinationView, true);
}
}
pastedBarsCount++;
}

//Borrar elementos sin host
destinationDoc.Delete(simbolsToDelete);
destinationDoc.Delete(rebarToDelete);

trans2.Commit();
}
catch (Exception e)
{
LoggerMain.Logger.Error(e, "Error al hacer CopyPaste Losas");
TaskDialog.Show("Error", e.Message);
}
}

using (Transaction trans3=new Transaction(originDoc))
{
trans3.Start("Borramos parametro Mark de barras y simbolos de Origen");

try
{
////Borramos el parametro Mark para el documento de origen.
rebarToCopy_list_flat.ForEach(e => originDoc.GetElement(e).LookupParameter("Mark").Set(""));
detailItemBarras_list.ForEach(e => originDoc.GetElement(e).LookupParameter("Mark").Set(""));
}
catch (Exception e)
{
LoggerMain.Logger.Error(e, "Error al borrar el Mark");
TaskDialog.Show("Error", e.Message);
}

trans3.Commit();
}


if (destinationView.Document != originDoc)
{
rvtUIDoc = new UIDocument(destinationView.Document);
rvtUIApp.OpenAndActivateDocument(destinationDoc.PathName);
}
//Change view
rvtUIDoc.ActiveView = destinationView;
rvtUIDoc.RefreshActiveView();

//Mensaje final
TaskDialog.Show("Copy Paste exitoso", "Barras copiadas: " + copiedBarsCount + "\nBarras pegadas: " + pastedBarsCount);

}
catch (Exception e)
{

LoggerMain.Logger.Fatal(e, "Error al hacer CopyPaste Losas");
TaskDialog.Show("Error", e.Message);
return Result.Failed;
}


LoggerMain.ProcesoExitosoInfo();
return Result.Succeeded;
}

public class ElementoSimboloFiltro : ISelectionFilter
{
public bool AllowElement(Element elem)
{
if (elem.Category != null)
{
if (elem.Name.Contains("SPR_SYM_Losa") || elem.Name.Contains("Armaduras con empalmes"))
{
return true;
}
}
return false;
}
public bool AllowReference(Reference reference, XYZ xyz)
{
return true;
}
}

public List<View> GetAllOpenViews(UIApplication uiApp)
{
List<View> openViews = new List<View>();

foreach (Document doc in uiApp.Application.Documents)
{
// Get the active document
UIDocument uiDoc = new UIDocument(doc);

// Get all open UIViews
IList<UIView> uiViews = uiDoc.GetOpenUIViews();

foreach (UIView uiView in uiViews)
{
// Get the view ID from the UIView and convert it to a View object
View view = doc.GetElement(uiView.ViewId) as View;
if (view != null)
{
openViews.Add(view);
}
}
}

return openViews;
}

public List<Document> GetAllOpenDocumnets(UIApplication uiApp)
{
List<Document> openDocs = new List<Document>();

foreach (Document doc in uiApp.Application.Documents)
{
openDocs.Add(doc);
}

return openDocs;
}
}
}

 

0 Likes