
Introduzione ai Collector di Elementi#
Il FilteredElementCollector è la base di qualsiasi automazione in Revit. Ogni volta che hai bisogno di lavorare con elementi — muri, porte, finestre, viste — devi prima trovarli nel modello. Il collector è lo strumento che lo fa.
Analogia pratica: Immagina il tuo modello Revit come un enorme magazzino. Il FilteredElementCollector è il sistema di ricerca automatizzato che trova esattamente ciò che ti serve, senza dover cercare manualmente.
Questa guida ti mostra 35+ modi diversi di filtrare elementi, dai filtri base (categoria) a quelli avanzati (geometria, parametri, posizione).
Questo è il secondo articolo di una serie in tre parti sullo sviluppo con Revit API:
- Primi Passi con l'Automazione BIM
- Raccolta Elementi con FilteredElementCollector (questo articolo)
- Metodi di Selezione UI
Perché Usare Collector Invece di Selezione Manuale?#
Scenario tipico senza automazione:
- Apri Revit
- Selezioni manualmente 50 muri
- Cambi un parametro su ciascuno
- Ripeti per ogni piano del progetto
Con un collector:
- Uno script trova automaticamente tutti i muri che soddisfano criteri precisi
- Modifica tutti in un'unica operazione
- Può essere ripetuto istantaneamente su altri progetti
Vantaggi chiave:
- Precisione — nessun elemento dimenticato
- Velocità — secondi invece di minuti/ore
- Riutilizzo — stesso script per progetti diversi
- Documentazione — il codice documenta esattamente cosa è stato fatto
Librerie e Setup Richiesti#
Prima di iniziare, ogni script Python in Dynamo che usa Revit API deve iniziare con queste righe:
1import clr2clr.AddReference("RevitAPI")3from Autodesk.Revit.DB import *4clr.AddReference('RevitServices')5from RevitServices.Persistence import DocumentManager6
7doc = DocumentManager.Instance.CurrentDBDocumentCosa fa questo codice:
clr.AddReference— carica le librerie Revit nel Pythonfrom Autodesk.Revit.DB import *— importa tutte le classi Revit API (Wall, Door, FilteredElementCollector, ecc.)DocumentManager— fornisce accesso al file Revit correntedoc— la variabile che userai per accedere al modello
Nota: Copia questo blocco all'inizio di ogni nodo Python Script in Dynamo.
Ottenere Informazioni sull'Applicazione Revit#
Puoi recuperare varie proprietà dell'applicazione Revit usando l'oggetto Application:
1app = doc.Application2version_info = f"""3Numero Versione: {app.VersionNumber}4Nome Versione: {app.VersionName}5Build Versione: {app.VersionBuild}6Numero Sub Versione: {app.SubVersionNumber}7Prodotto: {app.Product}8Lingua: {app.Language}9Cartella Dati Utente: {app.CurrentUsersDataFolderPath}10"""11print(version_info)Raccolta delle Categorie del Modello#
Per iniziare a lavorare con gli elementi Revit, è utile comprendere le categorie disponibili:
1from Autodesk.Revit.DB import CategoryType2
3# Ottieni tutte le categorie4all_categories = doc.Settings.Categories5
6# Filtra per categorie del modello7model_categories = [c for c in all_categories if c.CategoryType == CategoryType.Model]8
9# Stampa i nomi delle categorie10for category in model_categories:11 print(category.Name)Tipi di Categoria#
Nel Revit API, categorie e tipi sono identificati da valori enumerati. Ecco come lavorare con essi:
1door_category = Category.GetCategory(doc, BuiltInCategory.OST_Doors)2sub_categories = door_category.SubCategories3
4print(f"La categoria 'Porte' ha {sub_categories.Size} sottocategorie:")5for sub_category in sub_categories:6 print(f"- {sub_category.Name}")Modifiche in Revit 2022#
Revit 2022 ha introdotto identificatori a 64 bit per le categorie built-in:
1door_category_type_id = Category.GetBuiltInCategoryTypeId(BuiltInCategory.OST_Doors)2print(f"Il TypeId per la categoria 'Porte' è: {door_category_type_id}")Filtrare per Classe di Elemento#
Comprendere Classi vs Categorie#
Concetto fondamentale: In Revit API, "Classe" e "Categoria" sono due cose diverse, e la confusione tra le due è l'errore più comune per i principianti.
- Classe = Il tipo di oggetto nel codice (es:
Wall,Floor,FamilyInstance) - Categoria = Il gruppo funzionale che vedi nell'interfaccia Revit (es: "Muri", "Pavimenti", "Porte")
Esempio pratico:
- Una porta è un
FamilyInstance(classe) della categoria "Porte" (BuiltInCategory.OST_Doors) - Una finestra è un
FamilyInstance(classe) della categoria "Finestre" (BuiltInCategory.OST_Windows) - Un muro è un
Wall(classe) della categoria "Muri" (BuiltInCategory.OST_Walls)
Quando filtrare per classe:
- Quando vuoi tutti gli elementi di quel tipo di oggetto
- Per operazioni specifiche al tipo di classe (es: solo
Wallha.Flip())
Quando filtrare per categoria:
- Quando vuoi distinguere tra oggetti simili (porte vs finestre, entrambi FamilyInstance)
- Per leggere parametri specifici della categoria
Usando la Scorciatoia OfClass#
Il modo più semplice per filtrare per classe è usare il metodo OfClass:
1# Ottieni tutti i muri (istanze + tipi)2walls = FilteredElementCollector(doc).OfClass(Wall).ToElements()3
4# Ottieni solo i tipi di pavimento (non le istanze)5floor_types = FilteredElementCollector(doc).OfClass(FloorType).ToElements()6
7# Ottieni tutte le istanze di famiglia (porte, finestre, mobili, ecc.)8family_instances = FilteredElementCollector(doc).OfClass(FamilyInstance).ToElements()Cosa significa .ToElements()?
Il collector non trova immediatamente tutti gli elementi — li "promette". .ToElements() dice al collector di eseguire effettivamente la ricerca e restituire la lista completa.
Alternative a .ToElements():
.FirstElement()— restituisce solo il primo elemento trovato (più veloce).GetElementCount()— conta gli elementi senza caricarli (molto veloce).ToElementIds()— restituisce solo gli Id invece degli oggetti completi (leggero)
Principali Classi del Revit API#
Ecco le classi più comunemente usate per il filtraggio:
| Classe | Descrizione |
|---|---|
Wall | Elementi muro |
Floor | Elementi pavimento |
Ceiling | Elementi controsoffitto |
FamilyInstance | Tutti gli elementi basati su famiglia |
Level | Elementi livello |
Grid | Linee di griglia |
View3D | Viste 3D |
ViewPlan | Viste di pianta |
ViewSection | Viste di sezione |
ViewSheet | Tavole |
Material | Materiali |
Family | Famiglie caricate |
Filtri Rapidi Essenziali#
I filtri rapidi sono valutati direttamente in memoria senza aprire i dati completi dell'elemento. Questo li rende estremamente veloci — anche su modelli enormi.
Differenza tra Tipi e Istanze#
Concetto cruciale in Revit:
- Tipo (Type) = Il template riutilizzabile (es: "Porta 90x210cm")
- Istanza (Instance) = Ogni singola porta fisica posizionata nel modello
Ogni istanza ha un tipo genitore. Cambiare un tipo modifica tutte le sue istanze.
Esempi pratici:
1# SOLO TIPI — Ottieni i template di elementi (es: tipi di muro, tipi di porte)2types = FilteredElementCollector(doc).WhereElementIsElementType().ToElements()3
4# SOLO ISTANZE — Ottieni gli elementi fisici posizionati nel modello5instances = FilteredElementCollector(doc).WhereElementIsNotElementType().ToElements()6
7# COMBINATI — Ottieni solo le istanze di una categoria specifica8door_instances = FilteredElementCollector(doc) \9 .OfCategory(BuiltInCategory.OST_Doors) \10 .WhereElementIsNotElementType() \11 .ToElements()Quando serve questa distinzione:
- Modificare proprietà del tipo (es: cambiare il materiale di default)
- Contare quanti elementi fisici ci sono nel modello
- Leggere parametri di istanza (es: altezza di ogni singola porta)
Filtrare per Categoria#
La categoria è il modo più comune di filtrare — corrisponde a ciò che vedi nell'interfaccia Revit:
1# Ottieni tutte le porte (istanze + tipi)2doors = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Doors).ToElements()3
4# Ottieni tutti i muri5walls = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Walls).ToElements()6
7# Ottieni tutte le finestre8windows = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Windows).ToElements()Nota importante: Le BuiltInCategory sono nomi in inglese anche nella versione italiana di Revit:
OST_Doors= PorteOST_Walls= MuriOST_Windows= FinestreOST_Floors= PavimentiOST_StructuralColumns= Pilastri Strutturali
Lista completa delle BuiltInCategory
Combinare Filtri Rapidi#
Puoi concatenare più filtri per risultati più precisi:
1# Ottieni tutte le istanze di porte (non tipi di porte)2door_instances = FilteredElementCollector(doc) \3 .OfCategory(BuiltInCategory.OST_Doors) \4 .WhereElementIsNotElementType() \5 .ToElements()6
7# Ottieni tutti i tipi di muro8wall_types = FilteredElementCollector(doc) \9 .OfClass(WallType) \10 .WhereElementIsElementType() \11 .ToElements()Filtrare per Valori dei Parametri#
Una delle funzionalità più potenti è il filtraggio per valori dei parametri:
1from Autodesk.Revit.DB import FilteredElementCollector, BuiltInParameter2from Autodesk.Revit.DB import ParameterValueProvider, FilterStringRule3from Autodesk.Revit.DB import FilterStringEquals, ElementParameterFilter4
5# Crea un provider di valore parametro6provider = ParameterValueProvider(ElementId(BuiltInParameter.ALL_MODEL_MARK))7
8# Crea una regola di filtro (elementi dove Contrassegno è uguale a "A1")9rule = FilterStringRule(provider, FilterStringEquals(), "A1", False)10
11# Crea e applica il filtro12param_filter = ElementParameterFilter(rule)13
14elements = FilteredElementCollector(doc) \15 .OfCategory(BuiltInCategory.OST_Walls) \16 .WherePasses(param_filter) \17 .ToElements()Filtrare per Livello#
Filtrare elementi associati a un livello specifico:
1# Prima, ottieni il livello per cui vuoi filtrare2levels = FilteredElementCollector(doc).OfClass(Level).ToElements()3target_level = None4
5for level in levels:6 if level.Name == "Livello 1":7 target_level = level8 break9
10if target_level:11 # Crea un filtro di livello12 level_filter = ElementLevelFilter(target_level.Id)13 14 # Ottieni tutti gli elementi su quel livello15 elements_on_level = FilteredElementCollector(doc) \16 .WherePasses(level_filter) \17 .ToElements()18 19 print(f"Trovati {len(elements_on_level)} elementi su {target_level.Name}")Elementi all'interno di una BoundingBox#
Trovare elementi che sono completamente all'interno di una bounding box definita:
1from Autodesk.Revit.DB import BoundingBoxContainsPointFilter, Outline2
3# Definisci gli angoli della bounding box4min_point = XYZ(0, 0, 0)5max_point = XYZ(100, 100, 30) # piedi6
7# Crea un outline dai punti8outline = Outline(min_point, max_point)9
10# Crea il filtro bounding box11bb_filter = BoundingBoxIsInsideFilter(outline)12
13# Raccogli elementi dentro la box14elements_in_box = FilteredElementCollector(doc) \15 .WherePasses(bb_filter) \16 .ToElements()17
18print(f"Trovati {len(elements_in_box)} elementi dentro la bounding box")Filtri Logici#
Combinare filtri usando operazioni logiche:
1from Autodesk.Revit.DB import LogicalAndFilter, LogicalOrFilter2
3# Crea filtri individuali per categoria4wall_filter = ElementCategoryFilter(BuiltInCategory.OST_Walls)5floor_filter = ElementCategoryFilter(BuiltInCategory.OST_Floors)6door_filter = ElementCategoryFilter(BuiltInCategory.OST_Doors)7
8# Combina con logica OR (muri O pavimenti O porte)9or_filter = LogicalOrFilter([wall_filter, floor_filter, door_filter])10
11# Ottieni tutti i muri, pavimenti e porte12combined_elements = FilteredElementCollector(doc) \13 .WherePasses(or_filter) \14 .WhereElementIsNotElementType() \15 .ToElements()16
17print(f"Trovati {len(combined_elements)} muri, pavimenti e porte")Filtro di Esclusione#
Creare un filtro che esclude elementi specifici:
1from Autodesk.Revit.DB import ExclusionFilter2
3# Ottieni gli ID degli elementi da escludere4elements_to_exclude = [ElementId(12345), ElementId(67890)]5
6# Crea filtro di esclusione7exclusion_filter = ExclusionFilter(elements_to_exclude)8
9# Raccogli tutti i muri eccetto quelli esclusi10filtered_walls = FilteredElementCollector(doc) \11 .OfClass(Wall) \12 .WherePasses(exclusion_filter) \13 .ToElements()Filtrare Elementi Visibili nella Vista#
Raccogliere elementi visibili in una vista specifica:
1# Ottieni la vista attiva2active_view = doc.ActiveView3
4# Raccogli elementi visibili in questa vista5visible_elements = FilteredElementCollector(doc, active_view.Id) \6 .WhereElementIsNotElementType() \7 .ToElements()8
9print(f"Trovati {len(visible_elements)} elementi visibili in {active_view.Name}")Filtri Rapidi vs Filtri Lenti#
Comprendere la differenza è cruciale per le prestazioni:
Filtri Rapidi (Veloci)#
Valutati a livello di elemento senza aprire i dati dell'elemento:
OfClass()OfCategory()WhereElementIsElementType()WhereElementIsNotElementType()
Filtri Lenti (Più Potenti)#
Richiedono che i dati dell'elemento siano aperti:
ElementParameterFilterBoundingBoxFilterElementIntersectsFilter
Best Practice: Applica sempre prima i filtri rapidi, poi quelli lenti:
1# BUONO: Filtro rapido prima, poi filtro lento2elements = FilteredElementCollector(doc) \3 .OfCategory(BuiltInCategory.OST_Walls) \4 .WhereElementIsNotElementType() \5 .WherePasses(slow_filter) \6 .ToElements()7
8# CATTIVO: Filtro lento su tutto il database9elements = FilteredElementCollector(doc) \10 .WherePasses(slow_filter) \11 .ToElements()Best Practice per le Prestazioni#
-
Usa prima i filtri rapidi — Sono valutati prima che i dati dell'elemento vengano caricati
-
Limita lo scope — Usa collector specifici per vista quando possibile:
Python1FilteredElementCollector(doc, view.Id) -
Usa
FirstElement()per risultati singoli:Python1first_wall = FilteredElementCollector(doc).OfClass(Wall).FirstElement() -
Usa
GetElementCount()per conteggi:Python1wall_count = FilteredElementCollector(doc).OfClass(Wall).GetElementCount() -
Evita collector ripetuti — Memorizza i risultati in cache quando li riutilizzi:
Python1walls = list(FilteredElementCollector(doc).OfClass(Wall).ToElements())
Prossimi Passi#
Continua il tuo viaggio con Revit API nel prossimo articolo di questa serie:
- Precedente: Primi Passi con l'Automazione BIM
- Prossimo: Metodi di Selezione UI
Questions or Feedback?
I'd love to hear your thoughts on this article. Reach out directly and let's start a conversation.
Follow me on LinkedIn for more BIM tips and updates
