Open Families from a Directory, Purge a Category, Load and Save

python

#1

The following graph will load a family from a directory, delete all unused Family and Family Types of a Category, then Save and/or Load the family into the current project.

Here is the core code in the “Open Document & Clean” node:

import System
import clr
clr.AddReference("RevitNodes")
import Revit
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
clr.AddReference("RevitAPI")
clr.AddReference('DSCoreNodes')
from DSCore import *
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
import sys
pyt_path = r'C:\Program Files (x86)\IronPython 2.7\Lib'
sys.path.append(pyt_path)

currDoc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
app = uiapp.Application

paths = IN[0]
if not isinstance(paths, list): paths = [paths]
cats = List.Flatten([IN[1]],1)

save = IN[2]
load = IN[3]

class FamilyOption(IFamilyLoadOptions):
    def OnFamilyFound(self, familyInUse, overwriteParameterValues):
        overwriteParameterValues = True
        return True

    def OnSharedFamilyFound(
            self, sharedFamily, familyInUse, source, overwriteParameterValues):
        source = FamilySource.Family
        overwriteParameterValues = True
        return True

delIds = []
errorReport = None
try:
	for path in paths:
		doc = app.OpenDocumentFile(path)
		for cat in cats:
			trans = Transaction(doc,'del')
			trans.Start()

			allElements = (FilteredElementCollector(doc).OfClass(FamilySymbol).OfCategory(System.Enum.ToObject(BuiltInCategory, cat.Id)).ToElements())
			allFamilyIds = [x.Family.Id for x in allElements]
			allTypeIds = [x.Id for x in allElements]
			
			placedElements = (FilteredElementCollector(doc).OfClass(FamilyInstance).OfCategory(System.Enum.ToObject(BuiltInCategory, cat.Id)).WhereElementIsNotElementType().ToElements())
			placedElementTypeIds = set([x.get_Parameter(BuiltInParameter.ELEM_TYPE_PARAM).AsElementId() for x in placedElements])
			placedElementTypes = [doc.GetElement(x) for x in placedElementTypeIds]
			placedFamilyIds = [x.Family.Id for x in placedElementTypes]
			
			diffTypeIds = list(set(allTypeIds).difference(placedElementTypeIds))
			diffFamilyIds = list(set(allFamilyIds).difference(placedFamilyIds))

			dels = List.Join(diffTypeIds,diffFamilyIds)
			delIds.append(dels)

			for id in dels:
				doc.Delete(id)
			
			trans.Commit()
			trans.Dispose()
			
		if load:
			doc.LoadFamily(currDoc,FamilyOption())
		
		if save:
			opt = SaveAsOptions()
			opt.OverwriteExistingFile = True
			opt.Compact = True
			opt.MaximumBackups = 1
			doc.SaveAs(path,opt)	
			doc.Close(False)
		else:
			doc.Close(False)
			
except:
	import traceback
	errorReport = traceback.format_exc()

if errorReport is None:
    OUT = delIds
else:
    OUT = errorReport

Thanks go out to @erfajo, @JacobSmall, @Konrad_K_Sobon and others!


Check for unused families not purged
Orchid package possibilities
Deleting model line inside family