La Classe FilteredElementCollector permet de rechercher une collection
d'éléments à l'aide de méthodes et/ou de filtres.
Voici un récapitulatif et quelques exemples sur son utilisation.
- Les constructeurs
- Les Méthodes
- Les QuickFilter
Les filtres rapides fonctionnent sur une classe à faible mémoire qui a une
interface limitée pour lire les propriétés des éléments.
- Les SlowFilter
Les filtres lents exigent que l'élément soit obtenu et développé en
mémoire d'abord.
- Les LogicalFilter
Il s'agit de filtres qui ont pour but de combiner des Filtres entre eux
(ET / OU)
Quelques exemples en Python
- Exemple 1 : Convertir l'Enumerable en liste (Element ou ElementId)
méthodes ToElementIds() ou ToElements()
listElems = FilteredElementCollector(doc).OfClass(FamilyInstance).WhereElementIsNotElementType().ToElements()
listElemIds = FilteredElementCollector(doc).OfClass(FamilyInstance).WhereElementIsNotElementType().ToElementIds()
- Exemple 2 : Obtenir le 1er Élément d'une recherche
firstElem = FilteredElementCollector(doc).OfClass(FamilyInstance).WhereElementIsNotElementType().FirstElement()
- Exemple 3 : (QuickFilter) Recherche par sous projet
elementWorksetFilter = ElementWorksetFilter(workset.Id)
fecbyWkset = FilteredElementCollector(doc).WherePasses(elementWorksetFilter).ToElements()
- Exemple 4 : (QuickFilter) Recherche Elements rattachées à une Vue (Owned)
myelectrical_view = doc.ActiveView
# get all elements view dependent from this view
# wires, tags, textNote, etc..
fecbyWkset = FilteredElementCollector(doc).OwnedByView(myelectrical_view.Id).ToElements()
- Exemple 5 : (QuickFilter) Recherche par multi-catégories et par multi-Classe
#Create Multi category filter
#need import List from System.Collections.Generic
cat_list = [BuiltInCategory.OST_ElectricalFixtures, BuiltInCategory.OST_GenericModel]
typed_list = List[BuiltInCategory](cat_list)
filtercat = ElementMulticategoryFilter(typed_list)
fecMultiCat = FilteredElementCollector(doc).WherePasses(filtercat).WhereElementIsNotElementType().ToElements()
#multi-Classe
TypedClasses = List[System.Type]()
TypedClasses.Add(DB.MEPCurve)
# or
TypedClasses = List[System.Type]([clr.GetClrType([DB.MEPCurve)])
multiClassFilter = ElementMulticlassFilter(TypedClasses)
wantedElementes = FilteredElementCollector(doc).WherePasses(multiClassFilter).ToElements()
OUT = wantedElementes
- Exemple 6 : (SlowFilter) Recherche en construisant un filtre de paramètre
#Create parameter value filter
pvp = ParameterValueProvider(ElementId(BuiltInParameter.ALL_MODEL_TYPE_NAME))
evaluator = FilterStringContains()
rule = FilterStringRule(pvp, evaluator, "Reservation", False)
filter = ElementParameterFilter(rule)
fecparafilter = FilteredElementCollector(doc).WherePasses(filter).WhereElementIsNotElementType().ToElements()
- Exemple 7 : Utilisation de la classe ParameterFilterRuleFactory
comparaison des 2 méthodes
import clr
import System
from System.Collections.Generic import List
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
doc = DocumentManager.Instance.CurrentDBDocument
phases = List[Phase](doc.Phases)
phaseSelect = phases.Find(lambda x : x.Name == "Nouvelle construction")
pvp = ParameterValueProvider(ElementId(BuiltInParameter.PHASE_CREATED))
evaluator = FilterNumericEquals()
rule = FilterElementIdRule(pvp, evaluator, phaseSelect.Id)
filter = ElementParameterFilter(rule)
## OR USING ParameterFilterRuleFactory CLASS ##
rule = ParameterFilterRuleFactory.CreateEqualsRule(ElementId(BuiltInParameter.PHASE_CREATED), phaseSelect.Id)
filter = ElementParameterFilter(rule)
fecmultiplefilter = FilteredElementCollector(doc).WherePasses(filter).WhereElementIsNotElementType().ToElements()
OUT = fecmultiplefilter
.
.
- Exemple 8 : (QuickFilter + SlowFilter) Recherche par cumul de filtres
#Create Multi category filter
cat_list = [BuiltInCategory.OST_ElectricalFixtures, BuiltInCategory.OST_GenericModel]
typed_list = List[BuiltInCategory](cat_list)
filtercat = ElementMulticategoryFilter(typed_list)
#Create parameter value filter
pvp = ParameterValueProvider(ElementId(BuiltInParameter.ALL_MODEL_TYPE_NAME))
evaluator = FilterStringContains()
rule = FilterStringRule(pvp, evaluator, "Reservation", False)
filter = ElementParameterFilter(rule)
fecmultiplefilter = FilteredElementCollector(doc).WherePasses(filtercat).WherePasses(filter).WhereElementIsNotElementType().ToElements()
-
Exemple 9 : Filtrer des éléments ou un paramètre partagé est
présent
import clr clr.AddReference('ProtoGeometry') from Autodesk.DesignScript.Geometry import * clr.AddReference('RevitAPI') import Autodesk from Autodesk.Revit.DB import * clr.AddReference('RevitServices') import RevitServices from RevitServices.Persistence import DocumentManager doc = DocumentManager.Instance.CurrentDBDocument fRule = SharedParameterApplicableRule("nameOfSharedParameter") filter = ElementParameterFilter(fRule) fec = FilteredElementCollector(doc).WherePasses(filter).ToElements() OUT = fec
- Exemple 10 : Filtre inversé avec multi-Classes et Catégories
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
doc = DocumentManager.Instance.CurrentDBDocument
inverted = True
class_list = [DB.RevitLinkInstance, DB.ImportInstance]
typed_list = List[System.Type]([clr.GetClrType(t) for t in class_list])
filterClass = ElementMulticlassFilter(typed_list, inverted)
#
filterCam = ElementCategoryFilter(BuiltInCategory.OST_Cameras, inverted)
#
filterAnd = LogicalAndFilter(filterClass, filterCam)
#
allElements = FilteredElementCollector(doc, c_view.Id).WhereElementIsNotElementType().WherePasses(filterAnd).ToElements()
-
- Exemple 11 : Rajouter des filtres avec des fonctions
2 alternatives à ceci (avec une potentielle erreur si la collection est vide, "IndexError: list index out of range")
scheduleFiltereds = FilteredElementCollector(newdoc).OfCategory(BuiltInCategory.OST_Schedules).ToElements()
scheduleFiltered = [x for in scheduleFiltereds if x.IsTemplate ][0]
- La première solution consiste à utiliser les Predicates :Predicate[Primitive](lambda x: True)
#filtered List
schedulesFiltered = FilteredElementCollector(newdoc).OfCategory(BuiltInCategory.OST_Schedules).ToElements().FindAll(lambda x : x.IsTemplate)
#équivalent en c# avec System.Linq
#schedulesFiltered = FilteredElementCollector(newdoc).OfCategory(BuiltInCategory.OST_Schedules).ToElements(x => x.IsTemplate)
#filtered List and get the first element
scheduleFiltered = FilteredElementCollector(newdoc).OfCategory(BuiltInCategory.OST_Schedules).ToElements().Find(lambda x : x.IsTemplate)
#filtered List and get the last element
scheduleFiltered = FilteredElementCollector(newdoc).OfCategory(BuiltInCategory.OST_Schedules).ToElements().FindLast(lambda x : x.IsTemplate)
def getfilterByName(nameFilter):
collfilter = FilteredElementCollector(doc).OfClass(FilterElement).ToElements()
if collfilter:
filterSelect = [x for x in collfilter if x.Name == nameFilter]
if filterSelect:
return filterSelect[0]
else: return None
peut s'écrire comme ceci
def getfilterByName(nameFilter):
filterSelect = FilteredElementCollector(doc).OfClass(FilterElement).ToElements().Find(lambda x : x.Name == nameFilter)
return filterSelect
OU Comme ceci avec un itérateur et une valeur par défaut
filtersElems = FilteredElementCollector(doc).OfClass(FilterElement).ToElements()
filterSelect = next((x for x in filtersElems if x.Name == nameFilter), None)
if filterSelect is not None:
OUT = filterSelect
Note 1 :
les méthodes suivantes,
Exists(Predicate)Find(Predicate)
FindAll(Predicate)
FindLast(Predicate)
sont des méthodes de la classe List (qui est une implémentation de l’interface IList), il est donc nécessaire d'établir une conversion ou bien
d'appliquer les méthodes ToElements() ou ToElementIds() qui font le boulot.
petite aparté sur PythonNet
avec le moteur CPython3 et le paquet
PythonNet il est nécessaire de
passer par un cast pour utiliser ces
méthodes (IronPython fait
automatiquement la conversion)
#need import Predicate Class
import System
from System import Predicate
def getfilterByName(nameFilter):
#cast lambda Function
filterFunc = Predicate[System.Object](lambda x : x.Name == nameFilter)
filterSelect = FilteredElementCollector(doc).OfClass(FilterElement).ToElements().Find(filterFunc)
return filterSelect
un exemple avec des conversions de Type et utilisation de la méthode
FindAll()
:
Cependant même avec le Package PythonNet l'ajout de conversion et de
méthodes peuvent être possible en modifiant le package
- La deuxième solution consiste à utiliser les LINQ types comme en C#, il est nécessaire pour cela d'importer l'extension System.Linq
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
newdoc = DocumentManager.Instance.CurrentDBDocument
import clr
clr.AddReference("System.Core")
import System
clr.ImportExtensions(System.Linq)
scheduleFiltered = FilteredElementCollector(newdoc).OfCategory(BuiltInCategory.OST_Schedules).Where(lambda x : x.IsTemplate).ToList()
OUT = scheduleFiltered
Note cette extension n'existe pas à ce jour avec le package PythonNnet
- Exemple 11 : Recherche d'éléments dans une maquette liée
linkinstance = UnwrapElement(IN[0])
doclink = linkinstance.GetLinkDocument()
colllink = FilteredElementCollector(doclink).WhereElementIsNotElementType().ToElements()
- Exemple 12 : Recherche avec combinaison de filtres logique OU (OR)
dans l'exemple ci-dessous on recherche les éléments d'une maquette liée
seulement dans la vue active
#written by Cyril P
import clr
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
doc = DocumentManager.Instance.CurrentDBDocument
def gen_PairPts(*args):
"""generator for point pair loop
"""
for idx, pt in enumerate(args):
try: yield pt, args[idx + 1]
except : yield pt, args[0]
def solid_fromBBX(bbox):
pt0 = XYZ( bbox.Min.X, bbox.Min.Y, bbox.Min.Z )
pt1 = XYZ( bbox.Max.X, bbox.Min.Y, bbox.Min.Z )
pt2 = XYZ( bbox.Max.X, bbox.Max.Y, bbox.Min.Z )
pt3 = XYZ( bbox.Min.X, bbox.Max.Y, bbox.Min.Z )
#create generator
pairPts = gen_PairPts(pt0, pt1, pt2, pt3)
#Create loop, still in BBox coords
edges = List[Curve]()
for pt1, pt2 in pairPts:
edges.Add(Line.CreateBound( pt1, pt2 ))
height = bbox.Max.Z - bbox.Min.Z
baseLoop = CurveLoop.Create( edges )
loopList = List[CurveLoop]()
loopList.Add( baseLoop )
preTransformBox = GeometryCreationUtilities.CreateExtrusionGeometry( loopList, XYZ.BasisZ, height )
transformBox = SolidUtils.CreateTransformed( preTransformBox, bbox.Transform )
return transformBox
lnkInstance = UnwrapElement(IN[0])
transf =lnkInstance.GetTotalTransform()
actView = doc.ActiveView
doclnk = lnkInstance.GetLinkDocument()
#get bootom and top Elevation of active viewrange
viewRange = actView.GetViewRange()
topClipPlaneId = viewRange.GetLevelId(PlanViewPlane.TopClipPlane)
topClipPlane = doc.GetElement(topClipPlaneId)
topOffset = viewRange.GetOffset(PlanViewPlane.TopClipPlane)
bttmClipPlaneId = viewRange.GetLevelId(PlanViewPlane.BottomClipPlane)
bttmClipPlane = doc.GetElement(bttmClipPlaneId)
bttmOffset = viewRange.GetOffset(PlanViewPlane.BottomClipPlane)
bbxActView = actView.CropBox
#set min and max from active ViewRange
bbxActView.Min = XYZ(bbxActView.Min.X, bbxActView.Min.Y, bttmClipPlane.ProjectElevation + bttmOffset)
bbxActView.Max = XYZ(bbxActView.Max.X, bbxActView.Max.Y, topClipPlane.ProjectElevation + topOffset)
bbxActView.Transform = transf.Inverse
# method 1 (better result but slow)
solidbbx = solid_fromBBX(bbxActView)
filterSolid = ElementIntersectsSolidFilter(solidbbx)
fecWalls = FilteredElementCollector(doclnk).OfClass(Wall).WherePasses(filterSolid).ToElements()
# method 2 (faster but less precision)
myOutLn = Outline(bbxActView.Min, bbxActView.Max)
# #create LogicalOrFilter with BoundingBox
filterBbxInside = BoundingBoxIsInsideFilter(myOutLn)
filterBbxInters = BoundingBoxIntersectsFilter(myOutLn)
filterBbx = LogicalOrFilter(filterBbxInside, filterBbxInters)
fecWalls = FilteredElementCollector(doclnk).OfClass(Wall).WherePasses(filterBbx).ToElements()
OUT = fecRoom
- Exemple 13 : Utiliser le filtre directement sur un Élément
dans l'exemple ci-dessous on teste le filtre directement un élément sans passer un FilteredElementCollector avec la méthode PassesFilter
#written by Cyril P
my_element = UnwrapElement(IN[0])
myOutLn = Outline(bbxActView.Min, bbxActView.Max)
#create LogicalOrFilter with BoundingBox
filterBbxInside = BoundingBoxIsInsideFilter(myOutLn)
filterBbxInters = BoundingBoxIntersectsFilter(myOutLn)
filterBbx = LogicalOrFilter(filterBbxInside, filterBbxInters)
# test the filter
if filterBbx.PassesFilter(my_element):
# do this
#
.
Pour cela :
- on récupère la Sélection Active du projet courant avec la propriété Selection (objet UIDocument )
-
puis on lui applique la méthode SetElementIds(
)
Exemple :
import clr
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication
uidoc = uiapp.ActiveUIDocument
workset = UnwrapElement(IN[0])
elementWorksetFilter = ElementWorksetFilter(workset.Id)
fecbyWksetId = FilteredElementCollector(doc).WherePasses(elementWorksetFilter).ToElementIds()
selectElemId = uidoc.Selection.GetElementIds(fecbyWksetId)
OUT = selectElemId
0 commentaires:
Enregistrer un commentaire