Copy Rooms Across Projects

Copy Rooms Across Projects

floretti
Advocate Advocate
5,247 Views
13 Replies
Message 1 of 14

Copy Rooms Across Projects

floretti
Advocate
Advocate

Good morning all (from Australia),

I work in retail and all our rooms are standardised and carry some data. Once we start a new refurb we need grab the old store 3D model and amongst other things, replace all rooms by the latest we have in our template. We've been doing this manually for many years but I'd like to automate that task by replacing matching room names.

 

Attempt 1: ElementTransformUtils
I managed to achieve that programatically creating a new project from our template and using ElementTransformUtils to copy the rooms from it. The challenge I had with this approach is that the rooms kept on pasting on the same level (ground) regardless of the active view (probably expected since I used the CopyElements method, doc to doc).

 

Attempt 2: Change level property
After some research I found an article where someone showed we need to change the level of the elements post pasting but the example was for columns and rooms don't accept level changes once they are placed (why is that by the way?).

 

Attempt 3: PostableCommand
I then moved on to PostableCommand to try and copy/paste aligned to current view but Revit didn't like it and threw a "Revit does not support more than one command are posted". I'm actually not sure I'm using it right in the way of swapping documents for each action. How would I make a selection in the newDoc below? I'm not sure how to make it the active document and swap back. Thank you for reading.

 

RevitPostableCommandError.png

 

 

// Create new file from template
Document newDoc = app.NewProjectDocument(TemplateLocation);

// Make a selection or rooms
var selector = uidoc.Selection;  // I doubt this is working as uidoc refers to the active document, not the newDoc.
selector.SetElementIds(copyRoomIds);

// Copy to clipboard
RevitCommandId copyToClip = RevitCommandId.LookupPostableCommandId(PostableCommand.CopyToClipboard);
uiapp.PostCommand(copyToClip);

// Paste aligned to active view
RevitCommandId pasteAligned = RevitCommandId.LookupPostableCommandId(PostableCommand.AlignedToCurrentView);
uiapp.PostCommand(pasteAligned);

 

0 Likes
Accepted solutions (2)
5,248 Views
13 Replies
Replies (13)
Message 2 of 14

RPTHOMAS108
Mentor
Mentor
Accepted solution

Have you tried the overload:

ElementTransformUtils.CopyElements(View, ICollection<Of ElementId>, View, Transform, CopyPasteOptions)

 

You can copy between documents with this. Would not go down the post command route. Would also be considering how I can extract the data from the rooms and transfer that if all else fails.

 

0 Likes
Message 3 of 14

floretti
Advocate
Advocate
Interesting, thank you. I'll definitely give it a go.
0 Likes
Message 4 of 14

floretti
Advocate
Advocate

Unfortunately it didn't work and I got the error below: "Some of the elements cannot be copied, because they belong to a different document."

 

My element collection has only room Ids from a specific phase in the model, nothing else.

 

FabioLorettiOliveira_0-1629249944631.png

 

This is what I used to collect the source view (I tested it prior and it found the view ok):

ViewPlan roomView = new FilteredElementCollector(doc).
			OfClass(typeof(ViewPlan)).
			Cast<ViewPlan>().
			Where(x => x.Name == "Rooms, Egress & Callouts (Refurb)").
			First<ViewPlan>();

 

And this to copy/paste the elements:

ElementTransformUtils.CopyElements(roomView, copyRoomIds, doc.ActiveView, null, null);

 

0 Likes
Message 5 of 14

floretti
Advocate
Advocate

I also just found this article saying the Copy view to view overload should only be used for view specific elements, which is not the case for Rooms.

0 Likes
Message 6 of 14

floretti
Advocate
Advocate

I did some testing and the Copy view to view overload works for rooms within the same document. I might be able to achieve the end goal by using the doc to doc overload first then the view to view second.

 

I realise it there is also the option of transferring all the data from the template rooms but this will involve some serious work. Let's leave this option as last resort.

0 Likes
Message 7 of 14

jeremy_tammik
Alumni
Alumni

Probably Richard final suggestion is the most promising approach: "Would also be considering how I can extract the data from the rooms and transfer that if all else fails."

 

What defines your rooms? 

 

Are you aware of the NewRooms2 method?

 

https://www.revitapidocs.com/2022/dde5849a-c78b-d2c4-20c3-cdd2e121ec54.htm

 

It can create new rooms in each plan circuit in the entire model, so creating the rooms is trivial.

 

Populating them with the desired data may be trivial as well, depending on your requirements and input data.

 

Look at the AddSpaceAndZone Revit SDK sample to understand how it can be used.

  

Jeremy Tammik Developer Advocacy and Support + The Building Coder + Autodesk Developer Network + ADN Open
0 Likes
Message 8 of 14

floretti
Advocate
Advocate

@jeremy_tammik , thanks for the suggestions. Unfortunately even after automation there will be a certain level of manual intervention because not all rooms will be found as the non-standard rooms are not supposed to be in the template anymore. The original idea to copy/paste from the template is aimed at making life a bit easier for the users to do that last part as the end result would look similar to the template, which they are used to and it's easier to find the rooms (refer to image below of how they laid out).

 

FabioLorettiOliveira_0-1629284367543.png

 

I managed to make all parts work in isolation but unfortunately not together yet. All the rooms are getting pasted into the ground floor level of my project but when I use the return value of the first ElementTransformUtils.CopyElements (doc to doc overload) to feed the second (view to view)  I get the error shown in my first message.

 

I've already tested the view to view overload of ElementTransformUtils.CopyElements on rooms in a simple testing environment and it works perfectly. Something is causing the error and I haven't figured it out yet.

 

See code snippets below.

 

 

 

// Create new project from template
Document newDoc = app.NewProjectDocument(TemplateLocation);

// Create list of roomIds to be copied
roomCol = new FilteredElementCollector(newDoc).
				OfClass(typeof(SpatialElement)).
				ToElements();

var copyRoomIds = new List<ElementId>();

foreach (Room room in roomCol)
{
	if (RoomPhasePar(room).AsValueString() == "New / Refurb")
		copyRoomIds.Add(room.Id);
}

ICollection<ElementId> copiedRoomIds;

// Copy/paste rooms from template
using (var t2 = new Transaction(doc))
{
	t2.Start("Copy rooms");
	copiedRoomIds = ElementTransformUtils.CopyElements(newDoc, copyRoomIds, doc, null, null);
	t2.Commit();
}
newDoc.Close(false);


// Copy rooms from ground to active view
var roomSample = copiedRoomIds.First<ElementId>();
var copiedRoom = doc.GetElement(roomSample) as Room;
var copiedRoomLevelId = copiedRoom.Level.Id;

// get me any view with the same base level as the copied rooms
var sourceView = new FilteredElementCollector(doc).
					 OfClass(typeof(ViewPlan)).
					 Cast<ViewPlan>().
					 Where(x => x.GenLevel.Id == copiedRoomLevelId).
					 First<ViewPlan>();


using (var t3 = new Transaction(doc))
{
	t3.Start("Replace rooms");

	// This is where the error comes up
	ElementTransformUtils.CopyElements(sourceView, copiedRoomIds,
						doc.ActiveView, null, null);

	t3.Commit();
}

 

 

0 Likes
Message 9 of 14

franciscopossetto
Advocate
Advocate
Accepted solution

Hey @floretti ,

 

I am not sure if I understood what you need to achieve with this code, but I did some modifications, and works correctly on my side. I was able to copy rooms from the template to the current document.

 

I have added some comments to show you the differences.

 

UIApplication uiApp = commandData.Application;
UIDocument uiDoc = uiApp.ActiveUIDocument;
Application app = uiApp.Application;
Document doc = uiDoc.Document;

string TemplateLocation = @"C:\Template1.rte";

// Open the template
Document templateDoc = app.OpenDocumentFile(TemplateLocation);

// Get the view of where the rooms are.
ViewPlan roomView = new FilteredElementCollector(templateDoc).OfClass(typeof(ViewPlan)).Cast<ViewPlan>().Where(x => x.Name == "ViewWithRooms").First();

// Collect all rooms ids.
var roomCol = new FilteredElementCollector(templateDoc).OfClass(typeof(SpatialElement)).ToElements();
var copyRoomIds = new List<ElementId>();
foreach (Autodesk.Revit.DB.Architecture.Room room in roomCol) if(room is Room) copyRoomIds.Add(room.Id);

// Copy the rooms into the current document.
using (Transaction t = new Transaction(doc, "Copy Rooms"))
{
    t.Start();
        ElementTransformUtils.CopyElements(roomView, copyRoomIds, doc.ActiveView, null, null);
    t.Commit();
}

//Close the template.          
templateDoc.Close();

return Autodesk.Revit.UI.Result.Succeeded;

 

 

Executing this code from the Addin manager I had some problems with transactions (maybe you can improve it). If you add it on the Ribbon as Command it will work as expected.

 

I hope it helps,

Kind regards.

 

Github:
https://github.com/franpossetto
0 Likes
Message 10 of 14

floretti
Advocate
Advocate

@franciscopossetto , thank you for the suggestions, I definitely tried your changes but ended up with the same error "Some elements cannot be copied because they belong to a different document".

 

My end goal is to copy all rooms from the template into the user's active view. The rooms are being copied successfully but not landing on the right level, they always land on ground floor since the template has them on ground floor.

 

I'm trying to use the ElementTransformUtils.CopyElements(view to view overload) to copy them from ground floor to the user's active view within the same project file but that's where the error is coming up.

0 Likes
Message 11 of 14

floretti
Advocate
Advocate

Ok, after more investigation I noticed not all copied elements are valid elements. I checked using the below:

                foreach (var item in copiedRoomIds)
                {
                    var elem = doc.GetElement(item);

                    try
                    {
                        console.ShowMessage(elem.ToString());
                    }
                    catch
                    {
                        console.ShowMessage("error");
                    }
                }

 

And this is the result, which clearly shows I can't use all the output from the CopyElements.

FabioLorettiOliveira_0-1629333018481.png

 

I'm now trying to eliminate the bad apples using the below but my validRoomIds is coming up null. Any suggestions of what can be wrong in what I'm trying? I've also tried .IsValidObject but it's also throwing an exception, that's why I resorted to exception handling but I'm open to suggestions. Thank you.

List<ElementId> validRoomIds = null;

foreach (var item in copiedRoomIds)
{
	var elem = doc.GetElement(item);

	try
	{
		validRoomIds.Add(elem.Id);
	}
	catch
	{
		continue;
	}
}

 

0 Likes
Message 12 of 14

franciscopossetto
Advocate
Advocate

Weird, I am copying the rooms on different views and always are copied in the level that is associated with the destination view. Could you share the template file or reproduce it as an example that you can share? Regarding the no valid rooms, did you check on the model which elements they are?

Github:
https://github.com/franpossetto
0 Likes
Message 13 of 14

RPTHOMAS108
Mentor
Mentor

One thing you can try is UIApplication.OpenAndActivateDocument for the template document rather than opening in the background. Then set view you are taking rooms from as active view to regenerate it.

 

I noticed in another situation I got invalid elements when getting geometry from newly created views, so maybe the view things come from need to be regenerated. Rooms are odd in that you can always see them in plan but only appear in other views when bounded.

0 Likes
Message 14 of 14

floretti
Advocate
Advocate

Wow, I can't believe it, it all just worked now and I found the mistake. I think I looked at this code for way too long.

 

I took screenshots of my previous posts to show where the problem was. I was trying to collect the source view from the wrong document, oh my...

 

I appreciate your help everyone. Have a great weekend and stay safe.

 

FabioLorettiOliveira_0-1629369522728.png