Hi,
I’m trying to make a way to easily reload Cloud Revit links to Local ones. I had assumed LoadFrom would be the best bet but I’ve always been given a internal error.
I’ve got code to find cloud links and local, creates a new link and deletes the cloud version, however this is changing the positions of the objects in the 3d view.
Very new to this so any help would be amazing. Code below.
import os
import Autodesk.Revit.DB as DB
import Autodesk.Revit.UI as UI
import System.IO as IO
from Autodesk.Revit.Exceptions import InvalidOperationException, ArgumentException, ArgumentNullException, FileAccessException, FileArgumentNotFoundException
from pyrevit import forms
def relink_files(doc, new_folder_path):
# Start a transaction to remove cloud links
t = DB.Transaction(doc, "Remove Cloud Links")
t.Start()
# Loop through all Revit link types in the document
revit_link_types = DB.FilteredElementCollector(doc).OfClass(DB.RevitLinkType).ToElements()
# defaultconfig = DB.WorksetConfiguration()
for revit_link_type in revit_link_types:
try:
ext_resource_ref = revit_link_type.GetExternalResourceReferences()
keys = ext_resource_ref.Keys
gotFile = False
for key in keys:
reference = ext_resource_ref[key]
dictinfo = reference.GetReferenceInformation()
# if 'ForgeDmItemUrn' in dictinfo:
#need to check if its cloud or not ?
revit_link_file_name = reference.GetResourceShortDisplayName()
new_revit_link_path = find_file_in_folder(new_folder_path, revit_link_file_name)
if new_revit_link_path:
model_path = DB.ModelPathUtils.ConvertUserVisiblePathToModelPath(new_revit_link_path)
model_exists = False
# Check if the model already exists in the document
existing_link_types = DB.FilteredElementCollector(doc).OfClass(DB.RevitLinkType).ToElements()
if 'Path' in dictinfo:
for link_type in existing_link_types:
try:
if link_type != revit_link_type:
same_ext_resource_ref = link_type.GetExternalResourceReferences()
same_keys = same_ext_resource_ref.Keys
for same_key in same_keys:
same_reference = same_ext_resource_ref[same_key]
same_dictinfo = same_reference.GetReferenceInformation()
if 'Path' in same_dictinfo:
if dictinfo['Path'] == same_dictinfo['Path']:
model_exists = True
break
except InvalidOperationException:
pass
if not model_exists:
gotFile = True
# Create a new instance of RevitLinkOptions
link_options = DB.RevitLinkOptions(True)
# Create a new instance of RevitLinkType
link_type = DB.RevitLinkType.Create(doc, model_path, link_options)
# Append the link instance to the element list
link_instance = DB.RevitLinkInstance.Create(doc, link_type.ElementId)
if gotFile:
doc.Delete(revit_link_type.Id)
except InvalidOperationException:
pass
# Commit the transaction
t.Commit()
def find_file_in_folder(folder_path, file_name):
for root, dirs, files in os.walk(folder_path):
for file in files:
if file == file_name:
newFile = IO.Path.Combine(root, file)
return newFile
return None
new_folder_path = forms.pick_folder(title="Select Folder to Relink Files")
if new_folder_path:
relink_files(__revit__.ActiveUIDocument.Document, new_folder_path)
Hello, check how those models are inserted into host file (by internal origin, project base point or by shared coordinates) that would be the most probable cause of displacement of models.
However maybe you should look for a way to implement “reload from” as this way you won’t miss copy/monitor links, dimensions or view settings of linked elements. In this link you can find description of simmilar issue: https://thebuildingcoder.typepad.com/blog/2016/08/automatically-reload-links-after-migration.html
Thanks, I’ve looked at the code and found all the links I need to change are Nested, however every time I use LoadFrom it just comes back as InvalidOperationException.
Not sure how the models are inserted, believe we are given the files (very new to revit).
Is there a way of copying the origin etc from 1 revit link to another ?
If this is what you are trying to achieve, you can’t. Or at least not without opening (in the background or not) the Revit Linked files at the first level / directly linked to the Master file
Why not? Theoretical conversation never hurst Sure it’s may be more suited for main Revit API Forum but we also can share some ideas
If I had to work on it, I would try in zero-doc state use TransmissionData class, first to map this matrioshka. Then from the “deepest” model start to SetDesiredReferenceData while climbing up.
I meant that it would require a lot of messages and typing.
Definitely the way to go.
I did approach the thing with the TransmissionData for a client once, and managed to repath links for 10s of thousands files in minutes.
Thanks for replying ! Been working in 3ds Max most of my life but now been tasked to try make some revit tools, one being a quick way to relink revit links since the reload from is a very manual task. So sorry if my revit knowledge is low
Currently the file I’ve been given is (nearly) all Not Loaded Cloud revit links (BIM 360). So we have the files locally and basically just need to relink them to those local versions (easily said than done )
Is there any examples on TransmissionData ?
Ok, maybe I’m doing something wrong, but all the TransmissionData is giving me every file that isn’t the Cloud BIM360 ones
Its getting all the absolute paths but not the cloud ?
central_model_path = DB.ModelPathUtils.ConvertUserVisiblePathToModelPath(doc.PathName)
# Access the TransmissionData for the central model
transmission_data = DB.TransmissionData.ReadTransmissionData(central_model_path)
if transmission_data is None:
print("No transmission data found. This document might not have linked files or transmission data is not available.")
else:
# Start a transaction (if required)
t = DB.Transaction(doc, "Relink BIM 360 Links to Local Paths")
t.Start()
# Iterate through all references in the TransmissionData
for ext_ref_id in transmission_data.GetAllExternalFileReferenceIds():
ext_ref = transmission_data.GetLastSavedReferenceData(ext_ref_id)
current_path = DB.ModelPathUtils.ConvertModelPathToUserVisiblePath(ext_ref.GetPath())
Also tried putting in the full path to the main file incase doc.PathName was wrong, but still not working. Code doesn’t look much different to the github sent.
Just so I’m a bit clearer. We basically have a bunch of these Not Loaded BIM360. If I manually hit Reload from, I can choose the file locally, but I have to do each file one by one. So I’m trying to see if I can batch this process. ExternalResources gives me a list of the cloud files, but due to them being nested (I’m assuming), I can’t use the LoadFrom.
TransmissionData seems to only get the files locally stored, not anything from BIM360.
Hopefully this explains more on what I want to achieve.
ok,
if I understand you right, they are not nested per se
also, using the external ressources lets you adress and change the filepath to these links/ressources without having to open the files.
a simpler reloadfrom, if done per opened file can be achieved with the LoadFrom (Or ReloadFrom) method
here is an old snippet
for i in selected_links:
linkType = doc.GetElement(link_dict[i].GetTypeId())
raw_path = path.join(selected_directory, i)
selected_links_path = DB.FilePath(raw_path)
# reload link from selected path
try:
linkType.LoadFrom(selected_links_path, None)
print(i + " reloaded from " + raw_path)
except Exception as e:
print(i+" Error")
there are also plenty of addins to do that
free, using the transmissiondata:
ok,
if I understand you right, they are not nested per se
also, using the external ressources lets you adress and change the filepath to these links/ressources without having to open the files.
a simpler reloadfrom, if done per opened file can be achieved with the LoadFrom method
for i in selected_links:
linkType = doc.GetElement(link_dict[i].GetTypeId())
raw_path = path.join(selected_directory, i)
selected_links_path = DB.FilePath(raw_path)
# reload link from selected path
try:
linkType.LoadFrom(selected_links_path, None)
print(i + " reloaded from " + raw_path)
except Exception as e:
print(i+" Erreur")and it needs to be wrapped in a transaction
Thanks, I’ve just tried the External Access Links Manager, but it does the same thing I’m having issues with TransmissionData. Its picking up only the local files, not the BIM360. So I can’t relink them to the local one.
I’ll look at the others in a mo, but assuming they might be the same.
Strangely the LinkReloader is also giving an Internal Error so starting to think its the RevitLink. But that also doesn’t explain why Reload From works .
Very confused