Create filter with Python

Hi !
I made my first script in Python.
I duplicate a 3D view, and apply some filters according to an iteration.
It almost work, but it still have two things to fix :

  • I wan’t to make a filter “not equals of true”. How to make it ?
  • The program works : it duplicates “x” views, create “x” filters and apply them to the right view. But filters aren’t applied : I have to get on each filter to validate it before the view applied the modification. Does i forgot a line “valid filter” or someone like this ?
    This is my Python script :
# Charger les bibliothèques DesignScript et Standard Python
import sys
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

# Charger l'API Revit
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *

clr.AddReference('RevitAPIUI')
from Autodesk.Revit.UI import *
import Autodesk

clr.AddReference('RevitNodes')
from Revit.Elements import *

# Charger RevitServices (DocumentManager pour l'acces document actuel / TransactionManager pour la modification)
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

# Importer les fonctions natives .NET
from System.Collections.Generic import List

# Les entrées effectuées dans ce noeud sont stockées sous forme de liste dans les variables IN.
dataEnteringNode = IN

# Convertir le parametre doc récupéré comme entier, en ElementId et obtenir le ParamererElement correspondant au document courant
doc = DocumentManager.Instance.CurrentDBDocument
valuesList = IN[0]
paramID_Debut = ElementId(IN[1])
paramID_Fin = ElementId(IN[2])
paramID_Chantier = ElementId(IN[3])
filterNameList = IN[4]
#Unwrap permet d'accéder à la liste des éléments de la vue
myView = UnwrapElement(IN[5])
pattern = IN[6]

#Type de duplication de la vue : Avec les détails
optionDuplicate = Autodesk.Revit.DB.ViewDuplicateOption.WithDetailing
red = Color(255,0,0)

#Obtenir la définition du paramètre. Récupérer le BindingMap qui relie les paramètres à leurs définitions, et récupérer la liaison du paramètre fourni.
paramElem = doc.GetElement(paramID_Debut)
definition = paramElem.GetDefinition()
binding_map = doc.ParameterBindings
binding = binding_map.Item[definition]

#Récupérer les catégories du paramètres, puisles ID
category_set = binding.Categories.GetEnumerator()
cat_ids = [cat.Id for cat in category_set]

#Convertir la liste en liste .NET pour la suite
cat_ids_list = List[ElementId](cat_ids)

#Retirer les catégories non incluables dans les filtres
cat_ids_valid = ParameterFilterUtilities.RemoveUnfilterableCategories(cat_ids_list)

#Creation des valeurs de parametres
pStart = ParameterValueProvider (paramID_Debut)
pEnd = ParameterValueProvider (paramID_Fin)
pChantier = ParameterValueProvider (paramID_Chantier)

#Récupération des filtres déjà existants dans le projet
FiltersList = list(FilteredElementCollector(doc).OfClass(ParameterFilterElement).ToElements())
FiltersName = [i.Name for i in FiltersList]
mesFiltres = []

#Ouverture des modifications dans le fichier
TransactionManager.Instance.EnsureInTransaction(doc)

#Creation des filtres dans Revit suivant le nombre de phases
for myValue in valuesList :
	#Récupération des noms de filtres à créer
	phaseEnCours = filterNameList[0]+str(myValue)
	postPhase = filterNameList[1]+str(myValue)
	
	#Duplication de la vue de base
	newViewID = View.Duplicate(myView, optionDuplicate)
	newView = doc.GetElement(newViewID)
	try :
		newView.Name = myView.Name+"_"+str(myValue)
		mesFiltres.Add("Vue créée : "+newView.Name)
	except : 
		mesFiltres.Add("Vue non renommée : "+newView.Name)
	
	#Création du filtre "en cours" s'il n'est pas déjà existant
	if phaseEnCours not in FiltersName :
		#Creation des conditions de filtres
		xStart_enCours = FilterElementIdRule (pStart, FilterNumericLessOrEqual(), ElementId(myValue))
		xEnd_enCours = FilterElementIdRule (pEnd, FilterNumericGreaterOrEqual(), ElementId(myValue))
		#xChantier ne doit pas etre egal a vrai
		#A CHANGER
		xChantier = FilterElementIdRule (pChantier, FilterNumericEquals(), ElementId(1))
		
		#Creation du filtre de phase en cours
		xrule_enCours = []
		xrule_enCours.Add(ElementParameterFilter(xStart_enCours))
		xrule_enCours.Add(ElementParameterFilter(xEnd_enCours))
		xrule_enCours.Add(ElementParameterFilter(xChantier))
		#Convertion en liste .NET de ElementFilter
		ruleList_enCours = List[ElementFilter](xrule_enCours)
		#Application de la règle AND / OR pour le cumul des filtres
		myRule_enCours = LogicalAndFilter(ruleList_enCours)
		#Création du filtre dans Revit
		filter_current = ParameterFilterElement.Create(doc, phaseEnCours, cat_ids_valid, myRule_enCours)
	#Sinon récupération du filtre déjà existant
	else :
		for f in FiltersList:
			if f.Name == phaseEnCours :
				filter_current = f
	#Ajout du filtre à la vue
	newView.AddFilter(filter_current.Id)
	
	#Application de remplacement de vue sur les filtres
	over = newView.GetFilterOverrides(filter_current.Id)

	#Hachurage de l'élément coupé
	over.SetCutForegroundPatternId(pattern)
	over.SetCutForegroundPatternColor(red)
	
	#Hachurage de l'élément vu
	over.SetSurfaceForegroundPatternId(pattern)
	over.SetSurfaceForegroundPatternColor(red)
	newView.SetFilterOverrides(filter_current.Id,over)
	mesFiltres.Add(phaseEnCours)
		
	#Création du filtre "en cours" s'il n'est pas déjà existant
	if postPhase not in FiltersName :
		#Creation des conditions de filtres
		xStart_Post = FilterElementIdRule (pStart, FilterNumericGreater(), ElementId(myValue))
		xEnd_Post = FilterElementIdRule (pEnd, FilterNumericLess(), ElementId(myValue))
		xChantier = FilterElementIdRule (pChantier, FilterNumericEquals(), ElementId(1))
		
		#Creation du filtre élément à masquer
		xrule_Post = []
		xrule_Post.Add(ElementParameterFilter(xEnd_Post))
		xrule_Post.Add(ElementParameterFilter(xChantier))
		#Convertion en liste .NET de ElementFilter
		ruleList_Post = List[ElementFilter](xrule_Post)
		#Application de la règle AND / OR pour le cumul des filtres
		myRule_Post = LogicalAndFilter(ruleList_Post)
		#Creation du filtre post chantier à masquer et à ajouter au précédent
		xrule_Post2 = []
		xrule_Post2.Add(ElementParameterFilter(xStart_Post))
		xrule_Post2.Add(myRule_Post)
		#Convertion en liste .NET de ElementFilter
		ruleList_Post2 = List[ElementFilter](xrule_Post2)
		#Application de la règle AND / OR pour le cumul des filtres
		myRule_Post2 = LogicalOrFilter(ruleList_Post2)
		#Création du filtre dans Revit
		filter_post = ParameterFilterElement.Create(doc, postPhase, cat_ids_valid, myRule_Post2)
	else :
		for f in FiltersList:
			if f.Name == postPhase :
				filter_post = f
	#Ajout du filtre à la vue
	newView.AddFilter(filter_post.Id)
	newView.SetFilterVisibility(filter_post.Id, 0)
	mesFiltres.Add(postPhase)

#Fin des modifications dans le fichier
TransactionManager.Instance.TransactionTaskDone()

# Affectez la sortie à la variable OUT.
OUT = mesFiltres

I want to apologize for my bad english, that’s not my mother langage and i don’t practice a lot. Thank you for your solicitude.
Mélanie

Hello, you can take a look on this side, you should find your happiness I think
Cordially
christian.stan

1 Like

Hello @Mel59 and welcome

difficult to answer without having exactly the input data (post a screenshot :wink:),

here is an example if it can help you

test filter phases


# Import DesignScript and Standard Python libraries
import sys
import clr
import System
from System.Collections.Generic import List

# Import native .NET functions
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

# Import Revit API
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
import Autodesk.Revit.DB as DB

# Import RevitServices (DocumentManager for accessing the current document / TransactionManager for modifications)
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager

doc = DocumentManager.Instance.CurrentDBDocument

phase_Debut = UnwrapElement(IN[0])
phase_Fin = UnwrapElement(IN[1])

# Get the active view of the document
myView = doc.ActiveView

# Filter names
name_filter_future = "future_phase"
name_filter_current = "current_phase"

# List of element categories for the filter
cat_ids_list = List[ElementId]([ElementId(BuiltInCategory.OST_Walls)])

# Begin the transaction for modifications in the document
TransactionManager.Instance.EnsureInTransaction(doc)

# Get the "Phase Created" parameter (BuiltinParameter.PHASE_CREATED)
pvp = ParameterValueProvider(ElementId(BuiltInParameter.PHASE_CREATED))

# Create the filter for future elements
rule_future = FilterElementIdRule(pvp, FilterNumericGreater(), phase_Fin.Id)
future_filter = ElementParameterFilter(rule_future)

# Delete the existing filter with the same name if it exists
filter_find = System.Predicate[System.Object](lambda x: x.Name == name_filter_future)
filter_ = List[DB.Element](FilteredElementCollector(doc).OfClass(ParameterFilterElement).ToElements()).Find(filter_find)
if filter_ is not None:
    doc.Delete(filter_.Id)
    doc.Regenerate()

# Create the filter for future elements in Revit
future_Elem_Filter = ParameterFilterElement.Create(doc, name_filter_future, cat_ids_list, future_filter)

# Create the filter for current elements
rule_start = FilterElementIdRule(pvp, FilterNumericGreaterOrEqual(), phase_Debut.Id)
rule_end = FilterElementIdRule(pvp, FilterNumericLessOrEqual(), phase_Fin.Id)
combined_rules = List[ElementFilter]()
combined_rules.Add(ElementParameterFilter(rule_start))
combined_rules.Add(ElementParameterFilter(rule_end))
current_filter = LogicalAndFilter(combined_rules)

# Delete the existing filter with the same name if it exists
filter_find = System.Predicate[System.Object](lambda x: x.Name == name_filter_current)
filter_ = List[DB.Element](FilteredElementCollector(doc).OfClass(ParameterFilterElement).ToElements()).Find(filter_find)
if filter_ is not None:
    doc.Delete(filter_.Id)
    doc.Regenerate()

# Create the filter for current elements in Revit
current_Elem_Filter = ParameterFilterElement.Create(doc, name_filter_current, cat_ids_list, current_filter)

# Add the filters to the view
myView.AddFilter(future_Elem_Filter.Id)
myView.SetFilterVisibility(future_Elem_Filter.Id, 0)
myView.AddFilter(current_Elem_Filter.Id)

# Modify the display settings of the current filter
red = Color(255, 0, 0)
filter_pattern = System.Predicate[System.Object](lambda x: x.GetFillPattern().IsSolidFill)
solidFillPattern = List[DB.Element](FilteredElementCollector(doc).OfClass(FillPatternElement).ToElements()).Find(filter_pattern)
ovg = OverrideGraphicSettings()
ovg.SetSurfaceForegroundPatternId(solidFillPattern.Id)
ovg.SetSurfaceForegroundPatternColor(red)
myView.SetFilterOverrides(current_Elem_Filter.Id, ovg)

# Finish the transaction
TransactionManager.Instance.TransactionTaskDone()

# Assign the output value
OUT = 0
2 Likes

Hi !
Thank’s for help, but i still not see what’s wrong in my script…
(I will upgrade it later, but i don’t understand all your fonctions for the moment, like how you get “PHASE_CREATED” or the “lambda:”)
Here is what i’m done in Dynamo if you see the problem ?

can you share the dyn file and a sample rvt file to test ?

Sure, the site doesn’t allow me to upload files because i’m new. So i made a wetransfer link to share my files :
Lien pour les fichiers

I test it on Revit 2022.

Hi,

yours parameters are type of Integer (StorageType), you can’t use FilterElementIdRule

Example, instead of
xStart_enCours = FilterElementIdRule(pStart, FilterNumericLessOrEqual(), ElementId(myValue))
you have to use
xStart_enCours = FilterIntegerRule(pStart, FilterNumericLessOrEqual(), myValue)

Hi,
Thank you for this precision. I’ve changed it, and it works very well!
Thanks for your help !

Do you know what is the command to create a filter “not equals to true” (false or empty) ?

There is a constructor to reverse a rule

FilterInverseRule