I have a question for some of you familiar with the Revit API and python:
I used the spring node package in dynamo to create a fairly large series of free-form objects, each in its own family. How FamilyInstance.ByGeometry works, it takes a list of solids and creates a family instance for each template family file. The result is not bad. (spring nodes can be found here: https://github.com/dimven/SpringNodes )
However, the drawback is that now I have about 200 separate copies, so making changes to each of them is rather painful. At first, I thought that it would be possible to use dynamo to create a new subcategory and set the solid within each instance of the family into this new subcategory. Unfortunately, I realized that this is not possible, since the dynamo cannot be opened in two different Revit environments (the project I'm working on and each instance of the family). This makes me see if I can do this with python.
I used python in a rhino and can get along well, but I'm still learning the Revit API. But basically my idea was as follows: 1. select a series of family instances in the Revit project environment 2. Swipe through each instance 3. save it in the specified location 4. create a new subcategory in each family instance (the subcategory will be the same for all selected family instances ) 5. select the solid in each instance 6. install the solid in this newly created subcategory 7. Close the family instance and save
My question for you sounds like it's possible based on your knowledge of the Revit API?
Thanks so much for your time and advice.
UPDATE:
I found a section in the revit api that describes what I want to do: http://help.autodesk.com/view/RVT/2015/ENU/?guid=GUID-FBF9B994-ADCB-4679-B50B-2E9A1E09AA48
I made the first pass when pasting this into the python code of a dynamo node. The rest of the code works fine except for adding a new im section (see below). Sorry variables, I just stick to the logic of the original author of the code I'm cracking:
(Note: variables enter arrays)
#set subcategory try:
Any help or advice with this section of code would be greatly appreciated.
UPDATE: See the full code below for the context of this section:
#Copyright(c) 2015, Dimitar Venkov # @5devene, dimitar.ven@gmail.com import clr import System from System.Collections.Generic import * pf_path = System.Environment.GetFolderPath(System.Environment.SpecialFolder.ProgramFilesX86) import sys sys.path.append("%s\IronPython 2.7\Lib" %pf_path) import traceback clr.AddReference('ProtoGeometry') from Autodesk.DesignScript.Geometry import * clr.AddReference("RevitServices") import RevitServices from RevitServices.Persistence import DocumentManager from RevitServices.Transactions import TransactionManager doc = DocumentManager.Instance.CurrentDBDocument app = DocumentManager.Instance.CurrentUIApplication.Application clr.AddReference("RevitAPI") from Autodesk.Revit.DB import * from Autodesk.Revit.DB.Structure import StructuralType clr.AddReference("RevitNodes") import Revit clr.ImportExtensions(Revit.Elements) clr.ImportExtensions(Revit.GeometryConversion) def tolist(obj1): if hasattr(obj1,"__iter__"): return obj1 else: return [obj1] def output1(l1): if len(l1) == 1: return l1[0] else: return l1 def PadLists(lists): len1 = max([len(l) for l in lists]) for i in xrange(len(lists)): if len(lists[i]) == len1: continue else: len2 = len1 - len(lists[i]) for j in xrange(len2): lists[i].append(lists[i][-1]) return lists class FamOpt1(IFamilyLoadOptions): def __init__(self): pass def OnFamilyFound(self,familyInUse, overwriteParameterValues): return True def OnSharedFamilyFound(self,familyInUse, source, overwriteParameterValues): return True geom = tolist(IN[0]) fam_path = IN[1] names = tolist(IN[2]) category = tolist(IN[3]) material = tolist(IN[4]) isVoid = tolist(IN[5]) subcategory = tolist(IN[6]) isRvt2014 = False if app.VersionName == "Autodesk Revit 2014": isRvt2014 = True units = doc.GetUnits().GetFormatOptions(UnitType.UT_Length).DisplayUnits factor = UnitUtils.ConvertToInternalUnits(1,units) acceptable_views = ["ThreeD", "FloorPlan", "EngineeringPlan", "CeilingPlan", "Elevation", "Section"] origin = XYZ(0,0,0) str_typ = StructuralType.NonStructural def NewForm_background(s1, name1, cat1, isVoid1, mat1, subcat1): t1 = TransactionManager.Instance TransactionManager.ForceCloseTransaction(t1) famdoc = doc.Application.NewFamilyDocument(fam_path) message = None temp_path = System.IO.Path.GetTempPath() sat_path = "%s%s.sat" % (temp_path, name1) try: if factor != 1: s1 = s1.Scale(factor) sat1 = Geometry.ExportToSAT(s1, sat_path) satOpt = SATImportOptions() satOpt.Placement = ImportPlacement.Origin satOpt.Unit = ImportUnit.Foot view_fec = FilteredElementCollector(famdoc).OfClass(View) view1 = None for v in view_fec: if str(v.ViewType) in acceptable_views: view1 = v break t1.EnsureInTransaction(famdoc) satId = famdoc.Import(sat1, satOpt, view1) opt1 = Options() opt1.ComputeReferences = True el1 = famdoc.GetElement(satId) geom1 = el1.get_Geometry(opt1) enum = geom1.GetEnumerator() enum.MoveNext() geom2 = enum.Current.GetInstanceGeometry() enum2 = geom2.GetEnumerator() enum2.MoveNext() s1 = enum2.Current famdoc.Delete(satId) TransactionManager.ForceCloseTransaction(t1) System.IO.File.Delete(sat_path) except: message = traceback.format_exc() pass if message == None: try: save_path = "%s%s.rfa" % (temp_path, name1) SaveAsOpt = SaveAsOptions() SaveAsOpt.OverwriteExistingFile = True t1.EnsureInTransaction(famdoc) #set the category try: fam_cat = famdoc.Settings.Categories.get_Item(cat1.Name) famdoc.OwnerFamily.FamilyCategory = fam_cat except: pass s2 = FreeFormElement.Create(famdoc,s1) if isVoid1: void_par = s2.get_Parameter("Solid/Void") void_par.Set(1) void_par2 = famdoc.OwnerFamily.get_Parameter("Cut with Voids When Loaded") void_par2.Set(1) else: #voids do not have a material value try: mat_fec = FilteredElementCollector(famdoc).OfClass(Material) for m in mat_fec: if m.Name == mat1: fam_mat = m break mat_par = s2.get_Parameter("Material") mat_par.Set(fam_mat.Id) except: pass #set subcategory try: #create new sucategory fam_subcat = document.Settings.Categories.NewSubcategory(document.OwnerFamily.FamilyCategory, get_Item(subcat1.Name)) #assign the mataterial(fam_mat.Id) to the subcategory fam_subcat.Material = famdoc.GetElement(fam_mat.Id) #assign the subcategory to the element (s2) s2.Subcategory = fam_subcat except: pass TransactionManager.ForceCloseTransaction(t1) famdoc.SaveAs(save_path, SaveAsOpt) family1 = famdoc.LoadFamily(doc, FamOpt1()) famdoc.Close(False) System.IO.File.Delete(save_path) symbols = family1.Symbols.GetEnumerator() symbols.MoveNext() symbol1 = symbols.Current t1.EnsureInTransaction(doc) if not symbol1.IsActive: symbol1.Activate() inst1 = doc.Create.NewFamilyInstance(origin, symbol1, str_typ) TransactionManager.ForceCloseTransaction(t1) return inst1.ToDSType(False), family1.ToDSType(False) except: message = traceback.format_exc() return message else: return message def NewForm_background_R16(s1, name1, cat1, isVoid1, mat1, subcat1): t1 = TransactionManager.Instance TransactionManager.ForceCloseTransaction(t1) famdoc = doc.Application.NewFamilyDocument(fam_path) message = None temp_path = System.IO.Path.GetTempPath() sat_path = "%s%s.sat" % (temp_path, name1) try: if factor != 1: s1 = s1.Scale(factor) sat1 = Geometry.ExportToSAT(s1, sat_path) satOpt = SATImportOptions() satOpt.Placement = ImportPlacement.Origin satOpt.Unit = ImportUnit.Foot view_fec = FilteredElementCollector(famdoc).OfClass(View) view1 = None for v in view_fec: if str(v.ViewType) in acceptable_views: view1 = v break t1.EnsureInTransaction(famdoc) satId = famdoc.Import(sat1, satOpt, view1) opt1 = Options() opt1.ComputeReferences = True el1 = famdoc.GetElement(satId) geom1 = el1.get_Geometry(opt1) enum = geom1.GetEnumerator() enum.MoveNext() geom2 = enum.Current.GetInstanceGeometry() enum2 = geom2.GetEnumerator() enum2.MoveNext() s1 = enum2.Current famdoc.Delete(satId) TransactionManager.ForceCloseTransaction(t1) System.IO.File.Delete(sat_path) except: message = traceback.format_exc() pass if message == None: try: save_path = "%s%s.rfa" % (temp_path, name1) SaveAsOpt = SaveAsOptions() SaveAsOpt.OverwriteExistingFile = True t1.EnsureInTransaction(famdoc) #set the category try: fam_cat = famdoc.Settings.Categories.get_Item(cat1.Name) famdoc.OwnerFamily.FamilyCategory = fam_cat except: pass s2 = FreeFormElement.Create(famdoc,s1) if isVoid1: void_par = s2.LookupParameter("Solid/Void") void_par.Set(1) void_par2 = famdoc.OwnerFamily.LookupParameter("Cut with Voids When Loaded") void_par2.Set(1) else: #voids do not have a material value try: mat_fec = FilteredElementCollector(famdoc).OfClass(Material) for m in mat_fec: if m.Name == mat1: fam_mat = m break mat_par = s2.LookupParameter("Material") mat_par.Set(fam_mat.Id) except: pass #apply same subcategory code as before #set subcategory try: #create new sucategory fam_subcat = famdoc.Settings.Categories.NewSubcategory(fam_cat, get_Item(subcat1.Name)) #assign the mataterial(fam_mat.Id) to the subcategory fam_subcat.Material = famdoc.GetElement(fam_mat.Id) #assign the subcategory to the element (s2) s2.Subcategory = fam_subcat except: pass TransactionManager.ForceCloseTransaction(t1) famdoc.SaveAs(save_path, SaveAsOpt) family1 = famdoc.LoadFamily(doc, FamOpt1()) famdoc.Close(False) System.IO.File.Delete(save_path) symbols = family1.GetFamilySymbolIds().GetEnumerator() symbols.MoveNext() symbol1 = doc.GetElement(symbols.Current) t1.EnsureInTransaction(doc) if not symbol1.IsActive: symbol1.Activate() inst1 = doc.Create.NewFamilyInstance(origin, symbol1, str_typ) TransactionManager.ForceCloseTransaction(t1) return inst1.ToDSType(False), family1.ToDSType(False) except: message = traceback.format_exc() return message else: return message if len(geom) == len(names) == len(category) == len(isVoid) == len(material) == len(subcategory): if isRvt2014: OUT = output1(map(NewForm_background, geom, names, category, isVoid, material, subcategory)) else: OUT = output1(map(NewForm_background_R16, geom, names, category, isVoid, material, subcategory)) elif len(geom) == len(names): padded = PadLists((geom, category, isVoid, material, subcategory)) p_category = padded[1] p_isVoid = padded[2] p_material = padded[3] p_subcategory = padded [4] if isRvt2014: OUT = output1(map(NewForm_background, geom, names, p_category, p_isVoid, p_material, p_subcategory)) else: OUT = output1(map(NewForm_background_R16, geom, names, p_category, p_isVoid, p_material, subcategory)) else: OUT = "Make sure that each geometry\nobject has a unique family name."
Update:
It was possible to make it work:
try: