FilteredElementCollector uitgelegd, met Python-voorbeelden
Elk Revit-script begint met elementen zoeken. Zo werkt de collector, welke filters je nodig hebt, en waarom je soms opeens te veel of helemaal niets vindt.
Kort antwoord: FilteredElementCollector(doc) zoekt elementen in het model. Je geeft één of meer filters mee, zoals .OfCategory(BuiltInCategory.OST_Doors) of .OfClass(Wall), en meestal .WhereElementIsNotElementType() om de types weg te laten. Daarna lees je het resultaat uit met ToElements(), FirstElement(), GetElementCount() of een for-loop.
Wat de collector doet
Een Revit-model is één grote verzameling elementen: muren, deuren, leidingen, maar ook aanzichten, niveaus en types. Met de FilteredElementCollector vraag je het model om precies het stukje dat je nodig hebt. Je begint altijd zo:
from Autodesk.Revit.DB import FilteredElementCollector, BuiltInCategory
doc = __revit__.ActiveUIDocument.DocumentZonder filter mag je een collector niet uitlezen. Revit stopt dan met The collector does not have a filter applied. Extraction or iteration of elements is not permitted without a filter. Je moet dus altijd zeggen wat je zoekt.
Filteren op categorie: OfCategory
De categorie is wat je in Revit bij Visibility/Graphics ziet: deuren, muren, leidingen. In code is dat een BuiltInCategory: OST_Doors, OST_Walls, OST_PipeCurves (leidingen), OST_CurtainWallPanels (panelen van een vliesgevel). Dit is de filter die je het vaakst gebruikt.
Typen of exemplaren?
De klassieke valkuil. Een categorie bevat ook de types: de deurtypes uit je familie tellen mee als je niets zegt. Op het nagebootste kantoormodel ziet dat er zo uit:
from Autodesk.Revit.DB import FilteredElementCollector, BuiltInCategory
doc = __revit__.ActiveUIDocument.Document
alles = (FilteredElementCollector(doc)
.OfCategory(BuiltInCategory.OST_Doors)
.GetElementCount())
deuren = (FilteredElementCollector(doc)
.OfCategory(BuiltInCategory.OST_Doors)
.WhereElementIsNotElementType()
.GetElementCount())
print("Met typen erbij: {}".format(alles))
print("Alleen deuren: {}".format(deuren))Met typen erbij: 17
Alleen deuren: 13Wil je juist de types (bijvoorbeeld alle wandtypes), gebruik dan WhereElementIsElementType().
Filteren op klasse: OfClass
Met OfClass filter je op het soort object in de API. OfClass(Wall) geeft alleen echte muren, geen wandtypes, want die zijn van de klasse WallType:
from Autodesk.Revit.DB import FilteredElementCollector, Wall
doc = __revit__.ActiveUIDocument.Document
namen = set()
for wand in FilteredElementCollector(doc).OfClass(Wall):
namen.add(wand.Name)
for naam in sorted(namen):
print(naam)Binnenwand 100 metal stud
Buitenwand 300 kalkzandsteenBij een muur geeft Name de naam van zijn wandtype. Daarom staan er twee namen, ook al zijn het twintig muren.
Uitlezen: ToElements, FirstElement, GetElementCount
ToElements(): een lijst met alle elementen. Handig als je ze vaker nodig hebt;len()werkt erop.FirstElement(): alleen het eerste element, ofNoneals er niets is.GetElementCount(): alleen het aantal. Sneller dan alles ophalen en tellen.ToElementIds(): alleen deElementId's, bijvoorbeeld om een selectie te maken.- Een
for-loop direct over de collector, als je elk element één keer langsloopt.
Filteren op een parameterwaarde
Je kunt de collector ook laten filteren op de waarde van een parameter, bijvoorbeeld alle leidingen dikker dan 32 mm. Dat gaat met een regel en WherePasses. Let op: Revit rekent intern in voet, dus de grens reken je eerst om.
from Autodesk.Revit.DB import *
doc = __revit__.ActiveUIDocument.Document
# Regel: diameter groter dan 32 mm (Revit rekent intern in voet)
grens = UnitUtils.ConvertToInternalUnits(32, UnitTypeId.Millimeters)
regel = ParameterFilterRuleFactory.CreateGreaterRule(
ElementId(BuiltInParameter.RBS_PIPE_DIAMETER_PARAM), grens, 1e-6)
dik = (FilteredElementCollector(doc)
.OfCategory(BuiltInCategory.OST_PipeCurves)
.WhereElementIsNotElementType()
.WherePasses(ElementParameterFilter(regel))
.GetElementCount())
print("Leidingen dikker dan 32 mm: {}".format(dik))Leidingen dikker dan 32 mm: 20Het getal 1e-6 is de marge voor afrondingsverschillen bij kommagetallen.
Valkuil: OfClass(Panel) en OfClass(Mullion)
Panelen en roeden van een vliesgevel lijken een eigen klasse te hebben, maar OfClass(Panel) geeft een fout:
Autodesk.Revit.Exceptions.ArgumentException: Input type(Autodesk.Revit.DB.Panel) is of an element type that exists in the API, but not in Revit's native object model. Try using Autodesk.Revit.DB.FamilyInstance instead, and then post-processing the results to find the elements of interest.Gebruik voor panelen en roeden de categorie:
from Autodesk.Revit.DB import FilteredElementCollector, BuiltInCategory
doc = __revit__.ActiveUIDocument.Document
panelen = (FilteredElementCollector(doc)
.OfCategory(BuiltInCategory.OST_CurtainWallPanels)
.WhereElementIsNotElementType()
.ToElements())
print("Panelen: {}".format(len(panelen)))Panelen: 608Voor roeden is de categorie OST_CurtainWallMullions.
Snelheid: laat de collector het werk doen
In een groot model scheelt het veel of je eerst alle elementen ophaalt en dan in Python filtert, of dat je de collector meteen het goede laat zoeken. Filter dus zo veel mogelijk in de collector (categorie, klasse, parameterregel) en loop pas daarna in Python door wat er over is. Je code wordt er ook korter van.
Alle methodes van de collector staan in de Revit API-documentatie op revitapidocs.com.