Hi @jacob.small, thanks for the comments. I tried in the same way and found that if condition was not satisfied later I modified the RFA filepath to be same of SAT filepath.
Now I’m getting error on below line stating rfa file doesn’t exists. I want to create empty rfa file with the given name is it possible?
Yes. This is the API call, though you may want to look into copying a single RFA a few times on disc that has all your configurations and resources completely setup in it rather than using a template (or convert the RFA to RFT).
If you want a sample of how it is utilized, look into the springs package. That said, for what you are doing, use the springs package or the FamilyType.ByGeometry node which is out of the box - no need to reinvent the wheel here. Once you have the families in the document you can save them out.
Hi @jacob.small , I have modified the codes and trying to do the same operation, but I’m getting below warning. Can you help to identify what is causing the error. I tried manually loading all the .sat files using ImportCAD icon in Revit and everything worked properly.
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
clr.AddReference('RevitAPI')
clr.AddReference('RevitAPIUI')
import Autodesk
from Autodesk.Revit.DB import *
from Autodesk.Revit.UI import *
clr.AddReference('RevitServices')
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
import os
uiapp = Autodesk.Revit.UI.ExternalCommandData.Application
doc = DocumentManager.Instance.CurrentDBDocument
TransactionManager.Instance.EnsureInTransaction(doc)
def sat_to_rfa(sat_file_path, rfa_file_path, rfa_file_name):
"""Convert a SAT file to a RFA file"""
# Create the document and the application
app = Autodesk.Revit.ApplicationServices.Application.Create
familyDoc = doc.Application.NewFamilyDocument(r"C:/ProgramData/Autodesk/RVT 2021/Family Templates/English-Imperial/Specialty Equipment.rft")
options = SATImportOptions()
options.Placement = ImportPlacement.Origin
options.Unit = ImportUnit.Foot
doc.Import(sat_file_path, options,familyDoc)
# Save the family document
doc.SaveAs(rfa_file_name)
# Close the family document
doc.Close()
# Set the paths for the input SAT files and output RFA files
sat_folder_path = r'C:\Users\vramyaa\Revit\input'
rfa_folder_path = r'C:\Users\vramyaa\Revit\output'
sat_files = os.listdir(sat_folder_path)
rfa_files = os.listdir(rfa_folder_path)
# Loop through all the SAT files in the folder
for sat_file_name in sat_files:
if sat_file_name.endswith('.sat'):
sat_file_path = os.path.join(sat_folder_path, sat_file_name)
# Generate the corresponding RFA file path
rfa_file_name = sat_file_name[:-4] + '.rfa'
rfa_file_path = os.path.join(rfa_folder_path, rfa_file_name)
# Convert the SAT file to the RFA file
sat_to_rfa(sat_file_path, rfa_file_path, rfa_file_name)
OUT = sat_files,rfa_files,sat_folder_path, rfa_folder_path, rfa_file_name, rfa_file_path
You’ll need to manage your transactions, first full closing all of the transactions, then starting a new one, then doing the import in the family, then commit that transaction, then load the family into the project (assuming that was a goal as well).
Note that you should only be using th SAT import options, not the DWG ones as you don’t have a DWG; CAD in this instance of the Revit user interface doesn’t mean AutoCAD, but any one of many computer aided drawing formats.
@jacob.small, thanks for your guidance I have updated the code to commit and start the particular process but I’m getting error with file saving functionality. It throws warning that the file already exists however the output folder is empty
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
clr.AddReference('RevitAPI')
clr.AddReference('RevitAPIUI')
import Autodesk
from Autodesk.Revit.DB import *
from Autodesk.Revit.UI import *
clr.AddReference('RevitServices')
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
import os
uiapp = Autodesk.Revit.UI.ExternalCommandData.Application
doc = DocumentManager.Instance.CurrentDBDocument
TransactionManager.Instance.EnsureInTransaction(doc)
Save_Option = SaveAsOptions()
Save_Option.OverwriteExistingFile = True
Save_Option.Compact = True
Save_Option.MaximumBackups = 3
updated = []
def sat_to_rfa(sat_file_path, rfa_file_path, rfa_file_name):
"""Convert a SAT file to a RFA file"""
# Create the document and the application
app = Autodesk.Revit.ApplicationServices.Application.Create
familyDoc = doc.Application.NewFamilyDocument(r"C:/ProgramData/Autodesk/RVT 2021/Family Templates/English-Imperial/Specialty Equipment.rft")
trans = Transaction(familyDoc, "test");
trans.Start()
shapeImporter = ShapeImporter()
shapeImporter.InputFormat = ShapeImporterSourceFormat.SAT
shapes = shapeImporter.Convert(familyDoc, sat_file_path)
trans.Commit()
trans.Dispose()
# Save the family document
familyDoc.SaveAs(rfa_file_path)
#close the family document
familyDoc.Close(True)
# Set the paths for the input SAT files and output RFA files
sat_folder_path = r'C:\Users\vramyaa\Revit\input'
rfa_folder_path = r'C:\Users\vramyaa\Revit\output'
sat_files = os.listdir(sat_folder_path)
rfa_files = os.listdir(rfa_folder_path)
# Loop through all the SAT files in the folder
for sat_file_name in sat_files:
if sat_file_name.endswith('.sat'):
sat_file_path = os.path.join(sat_folder_path, sat_file_name)
# Generate the corresponding RFA file path
rfa_file_name = sat_file_name[:-4] + '.rfa'
rfa_file_path = os.path.join(rfa_folder_path, rfa_file_name)
updated.append(rfa_file_path)
# Convert the SAT file to the RFA file
sat_to_rfa(sat_file_path, rfa_file_path, rfa_file_name)
OUT = sat_files,rfa_files,sat_folder_path, rfa_folder_path, updated
If my line counts are right and I am understanding your code’s intent, this error is at the save as action of the definition where you are attempting to save the family over the family you are already in. That is something that Revit prevents to keep you from corrupting data if memory serves.
Read the message carefully - it’s asking for a SaveOptions object which you’ve had similar objects in the form of a SaveAsOptions elsewhere in the code. You are providing a string, specifically the path you want the document to be saved to. The good news is we can simplify this.
Rather than giving an answer, I’m going to try a bit of teaching you how to explore effectively on your own, as you’re SUPER close and this is a really useful skill.
Go to RevitAPIdocs.com, set the version at the top to the version you’re authoring in, and search for the “Save” and hit return. You should have something like 152 results which is a lot. Significantly more than I’d want to look over anyway, so let’s try a new search.
The main function types in the Revit API are classified as methods (actions), constructors (make new stuff), and properties (information about an object). Saving a document isn’t making a new document, nor is it getting or setting information about an object, so let’s assume it’s a method for now. Searching “save method” does in fact give better results - 53 in total, and the top hit looks promising as it’s a method in the Autodesk.Revit.DB.Document class, and we want to save a document.
Clicking that to see what we can learn about it, you’ll notice that on the left we have been ported to the save method of the document class, with all other methods of the class also expanded. There are also two save methods shown in this panel under the “Save Method” tree. "Save Method, and “Save Method (SaveOptions)”. The later sounds familiar to the error we got before, so you could look into that, but the version without save options is interesting as well, as it indicates there is no additional information provided - we can just open and close the parenthesis with nothing internal to it.
Be sure to read the remarks and exceptions here, as there are a few more “gotcha” moments which may trip you up.
Hi @jacob.small, this is latest code I have tried. For this I’m getting the error unable to close all open transactions phases. Also I have attached two files for your reference.
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
clr.AddReference('RevitAPI')
clr.AddReference('RevitAPIUI')
import Autodesk
from Autodesk.Revit.DB import *
from Autodesk.Revit.UI import *
clr.AddReference('RevitServices')
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
import os
uiapp = Autodesk.Revit.UI.ExternalCommandData.Application
doc = DocumentManager.Instance.CurrentDBDocument
def sat_to_rfa(sat_file_path, rfa_file_path, rfa_file_name):
"""Convert a SAT file to a RFA file"""
# Create the document and the application
app = Autodesk.Revit.ApplicationServices.Application.Create
familyDoc = doc.Application.NewFamilyDocument(r"C:/ProgramData/Autodesk/RVT 2021/Family Templates/English-Imperial/Specialty Equipment.rft")
TransactionManager.Instance.EnsureInTransaction(familyDoc)
shapeImporter = ShapeImporter()
shapeImporter.InputFormat = ShapeImporterSourceFormat.SAT
shapes = shapeImporter.Convert(familyDoc, sat_file_path)
# Save the family document
Option = SaveAsOptions()
Option.OverwriteExistingFile = True
Option.Compact = True
Option.MaximumBackups = 3
familyDoc.SaveAs(rfa_file_name, Option)
TransactionManager.Instance.ForceCloseTransaction()
familyDoc.Close(False)
# Set the paths for the input SAT files and output RFA files
sat_folder_path = r'C:\Users\vramyaa\Revit\input'
rfa_folder_path = r'C:\Users\vramyaa\Revit\output'
sat_files = os.listdir(sat_folder_path)
rfa_files = os.listdir(rfa_folder_path)
# Loop through all the SAT files in the folder
for sat_file_name in sat_files:
if sat_file_name.endswith('.sat'):
sat_file_path = os.path.join(sat_folder_path, sat_file_name)
# Generate the corresponding RFA file path
rfa_file_name = sat_file_name[:-4] + '.rfa'
rfa_file_path = os.path.join(rfa_folder_path, rfa_file_name)
# Convert the SAT file to the RFA file
sat_to_rfa(sat_file_path, rfa_file_path, rfa_file_name)
TransactionManager.Instance.TransactionTaskDone()
OUT = sat_files,rfa_files,sat_folder_path, rfa_folder_path, rfa_file_name, rfa_file_path
This should accomplish what you’re after. I recommend annotating your code similar to how I have done here next time out so that you are forced to think through what each line is doing.
############################################################
########## configure the Dynam python environment ##########
############################################################
import clr, os # import the CLR (Common language Runtime) and OS modules
clr.AddReference('RevitAPI') #add the Revit API library to the CLR
from Autodesk.Revit.DB import FilteredElementCollector, ImportPlacement, ImportUnit, SATImportOptions, SaveAsOptions, Transaction, View #import the reelevant sectiosn of the Revit API
clr.AddReference('RevitServices') #add the Revit services library to the CLR
from RevitServices.Persistence import DocumentManager #import the document manager
from RevitServices.Transactions import TransactionManager #import the transaciton manager
############################################################
################# get the active applicton #################
############################################################
app = DocumentManager.Instance.CurrentUIApplication.Application #gets the application
############################################################
############ inputs from the Dynamo environment ############
############################################################
satDir = IN[0] #the directory with the SAT files
rfaDir = IN[1] #the directory for the RFA files
famTemplatePath = IN[2] #the template path to use
############################################################
################## get the sat file paths ##################
############################################################
satPaths = [ "{0}\{1}".format(satDir,f) for f in os.listdir(satDir) if ".sat" in f ]
############################################################
########## create and configure the SaveAsOptions ##########
############################################################
saveOptions = SaveAsOptions() #start a new save as options object
saveOptions.OverwriteExistingFile = True #overwrite any existing file
saveOptions.Compact = True #compact the file
saveOptions.MaximumBackups = 1 #set the number of backups to 1 - you're making a new file so really this could be zero, but that's not an allowed value
############################################################
######## create and configure the SATImportOptions ########
############################################################
satOpt = SATImportOptions() #start a new sat import options object
satOpt.Placement = ImportPlacement.Origin #set the import placement to the origin
satOpt.Unit = ImportUnit.Foot #set the import unit to feet
############################################################
# NOTE: you might want to not always use feet, but
# instead pull the units from the SAT itself and find
# the assocaited value for the import unit. Look into
# the SAT file format and ImportUnit class of the
# Revit API for information on how to do so.
############################################################
############################################################
############# setup the OUT variable as a list #############
############################################################
results = [] #an empty list for now
############################################################
###### iterate the sat files to generate new families ######
############################################################
for satPath in satPaths: #for every SAT path in the list of sat paths
# Get the rfa path, and start a new family document
rfaPath = satPath[:-4].replace(satDir,rfaDir)+".rfa" #take the SAT path and replace the directory with the RFA directory, and the .sat extention with the .rfa extension
doc = app.NewFamilyDocument(famTemplatePath) #start a new document from the family template path
#start a new transaction in the family document
transaction = Transaction(doc,"import sat") #build a new transaction
transaction.Start() #start the transaction
#get the first 3d view we can find as we'll need a view to run the import in
view_fec = FilteredElementCollector(doc).OfClass(View) #get all views in the file
view1 = [v for v in view_fec if str(v.ViewType) == 'ThreeD' and not v.IsTemplate] #for each view in the collector, filter out any which are not a ThreeD type or are a template
#if a 3d view was found perform the following
if len(view1) >0:
view1 = view1[0] #set view1 to the first view found
#import the SAT and commit the change
satImport = doc.Import(satPath,satOpt, view1) # import the SAT geometry
transaction.Commit() #commit the transaction
#save the family and close it
doc.SaveAs(rfaPath, saveOptions) #save the familyw tih the previously defined options
doc.Close(False) #close the family document
results.append(rfaPath) #append the rfa extension to the results list
#otherwise
else:
results.append("No 3d view was found. Please pick a new family template.") #append a message to the results list
############################################################
####### return the results to the Dynamo environment #######
############################################################
OUT = results #set the OUT varaible to the results list