6 mars 2025

[Dynamo += Python] Exemple création de filtre

 



Quelques Exemples de création de filtres avec l'API Revit



#DynamoBIM #Python #Filter #RevitAPI     #AutodeskExpertElite #AutodeskCommunity 

if this article is not in your language, use the Google Translate widget ⬈ (bottom of page for Mobile version )


Dans Revit, les filtres de vue permettent de contrôler l'affichage des éléments en fonction de critères spécifiques, facilitant ainsi l'analyse et la gestion des modèles BIM. L'API Revit offre des outils pour automatiser la création et la gestion de ces filtres.

Cet article détaille la mise en place de Filtres de Vue via l’API Revit en utilisant Python (IronPython ou Python.NET), notamment sur la création de règles imbriquées (ET/OU) qui peut s'avérer être un casse-tête.


Voyons quelques exemples,


  • Exemple de création d'un filtre simple



     
    
    import clr
    import sys
    import System
    clr.AddReference('ProtoGeometry')
    from Autodesk.DesignScript.Geometry import *
    import Autodesk.DesignScript.Geometry as DS
    
    #import Revit API
    clr.AddReference('RevitAPI')
    import Autodesk
    from Autodesk.Revit.DB import *
    import Autodesk.Revit.DB as DB
    
    #import net library
    from System import Array
    from System.Collections.Generic import List, IList, Dictionary
    
    #import transactionManager and DocumentManager (RevitServices is specific to Dynamo)
    clr.AddReference('RevitServices')
    import RevitServices
    from RevitServices.Persistence import DocumentManager
    from RevitServices.Transactions import TransactionManager
    
    doc = DocumentManager.Instance.CurrentDBDocument
    uiapp = DocumentManager.Instance.CurrentUIApplication
    uidoc = uiapp.ActiveUIDocument
    app = uiapp.Application
    sdkNumber = int(app.VersionNumber)
    
    	
    def get_ParameterId_byName(lst_paraIds, para_name):
    	dictBip = {ElementId(bip) : bip for bip in System.Enum.GetValues(BuiltInParameter)}
    	for pId in lst_paraIds:
    		if doc.GetElement(pId) is not None and doc.GetElement(pId).Name == para_name:
    			return pId
    		elif pId in dictBip and DB.LabelUtils.GetLabelFor(dictBip.get(pId)) == para_name:
    			return pId
    		else: pass
    	return ElementId.InvalidElementId
    				
    
    toList = lambda x : x if hasattr(x, '__iter__') else [x]
    
    #Preparing input from dynamo to revit
    categories = toList(UnwrapElement(IN[0]))
    lstCatIds = List[ElementId]([c.Id for c in categories])
    parameter_Name = IN[1]
    parameter_value = IN[2]
    filter_Name = IN[3]
    
    TransactionManager.Instance.EnsureInTransaction(doc)
    lstParameterIds = DB.ParameterFilterUtilities.GetFilterableParametersInCommon(doc,lstCatIds)
    #
    paraId = get_ParameterId_byName(lstParameterIds, parameter_Name)
    if paraId != ElementId.InvalidElementId:
    	rule = ParameterFilterRuleFactory.CreateEqualsRule(paraId, parameter_value, True)
    	elementFilter = ElementParameterFilter(rule)
    	filter = DB.ParameterFilterElement.Create(doc,filter_Name, lstCatIds, elementFilter)
    
    
    TransactionManager.Instance.TransactionTaskDone()
    
    OUT = paraId
    
    ... 
         Étapes :
      • Récupération des paramètres filtrables communs aux catégories sélectionnées avec ParameterFilterUtilities.GetFilterableParametersInCommon().
      • Recherche de l’ID du paramètre ciblé via la fonction get_ParameterId_byName().
      • Création d'une règle de filtrage avec ParameterFilterRuleFactory.CreateEqualsRule().
      • Génération d'un filtre d’éléments (ElementParameterFilter) appliqué aux catégories définies.
      • Et enfin, on crée un ParameterFilterElement et l’ajoute au document actif 
    • Création d'un filtre avec imbrication de plusieurs règles



     ...
    
    import clr
    import sys
    import System
    clr.AddReference('ProtoGeometry')
    from Autodesk.DesignScript.Geometry import *
    import Autodesk.DesignScript.Geometry as DS
    
    #import Revit API
    clr.AddReference('RevitAPI')
    import Autodesk
    from Autodesk.Revit.DB import *
    import Autodesk.Revit.DB as DB
    #import net library
    from System.Collections.Generic import List
    
    clr.AddReference('RevitNodes')
    import Revit
    clr.ImportExtensions(Revit.GeometryConversion)
    clr.ImportExtensions(Revit.Elements)
    
    #import transactionManager and DocumentManager (RevitServices is specific to Dynamo)
    clr.AddReference('RevitServices')
    import RevitServices
    from RevitServices.Persistence import DocumentManager
    from RevitServices.Transactions import TransactionManager
    
    doc = DocumentManager.Instance.CurrentDBDocument
    
    
    def get_Filter_by_name(nameFilter, lstRvt_Categories, parameterName):
        """
        Get or create a ParameterFilterElement with the specified name, categories, and parameter name.
    
        Parameters:
            nameFilter (str): The name of the filter.
            lstRvt_Categories (list): List of Revit categories.
            parameterName (str): Name of the parameter.
    
        Returns:
            ParameterFilterElement: The created or existing parameter filter element.
        """
        # if exist get it
        filter_by_Name = System.Predicate[System.Object](lambda x : x.Name == nameFilter)
        filter_ = List[Element](FilteredElementCollector(doc).OfClass(ParameterFilterElement)).Find(filter_by_Name)
        if filter_ is not None:
            return filter_
        # else create it
        else:
            iListBic = List[ElementId]([cat.Id for cat in lstRvt_Categories ])
            # search the parametere Element
            filterParabyName = System.Predicate[System.Object](lambda x : x.Name == parameterName)
            param_elem = List[DB.Element](FilteredElementCollector(doc).OfClass(ParameterElement).WhereElementIsNotElementType()).Find(filterParabyName)
            if param_elem is None:
                param_elem = List[DB.Element](FilteredElementCollector(doc).OfClass(SharedParameterElement).WhereElementIsNotElementType()).Find(filterParabyName)
            if param_elem is not None: 
                # create 1st filter
                #
                filterRuleA = ParameterFilterRuleFactory.CreateContainsRule(ElementId(BuiltInParameter.KEYNOTE_PARAM), "IWS-01", False)
                filterA = ElementParameterFilter(filterRuleA)
                #
                # create 2nd filter by multi-rules
                subFilterB = List[ElementFilter]()
                subrulesB = List[FilterRule]()
                subrulesB.Add(FilterCategoryRule(List[ElementId]([lstRvt_Categories[0].Id])))
                subrulesB.Add(ParameterFilterRuleFactory.CreateNotContainsRule(param_elem.Id, "Y", False))
                subFilterB.Add(ElementParameterFilter(subrulesB))
                #
                subrulesB = List[FilterRule]()
                subrulesB.Add(FilterCategoryRule(List[ElementId]([lstRvt_Categories[1].Id])))
                subrulesB.Add(ParameterFilterRuleFactory.CreateContainsRule(param_elem.Id, "Y", False))
                subFilterB.Add(ElementParameterFilter(subrulesB))
                filterB = LogicalOrFilter(subFilterB)
                # compute the main filter
                mainFilterAB = LogicalAndFilter(filterA, filterB)
                # compute the ParameterFilterElement 
                filter_ = ParameterFilterElement.Create(doc, nameFilter, iListBic, mainFilterAB)
                return filter_
    
    
    lstRvt_Categories = UnwrapElement(IN[0])
    nameFilter = IN[1]
    parameterName = IN[2]
    #Do some action in a Transaction
    TransactionManager.Instance.EnsureInTransaction(doc)
    
    OUT = get_Filter_by_name(nameFilter, lstRvt_Categories, parameterName)
    
    TransactionManager.Instance.TransactionTaskDone()
    
    ... 
        Étapes :
      • Recherche d'un filtre existant par son nom, à défaut, on en crée un nouveau.
      • Identification du paramètre cible via un FilteredElementCollector() sur ParameterElement et SharedParameterElement.
      • on définit une première règle avec CreateContainsRule() pour filtrer par une valeur spécifique.
      • Puis on définit un second filtre avec plusieurs règles imbriquées (LogicalOrFilter et LogicalAndFilter).
      • Et enfin, on génère un ParameterFilterElement et l’applique aux catégories définies.
    • Un autre exemple en créant un filtre de 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)).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)).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)).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
    
    ...
        Étapes :
      • Récupération des phases de début et de fin sélectionnées.
      • on définit des noms pour les filtres : future_phase et current_phase.
      • Récupération  le paramètre PHASE_CREATED via ParameterValueProvider().
      • Création une règle FilterElementIdRule pour identifier les éléments appartenant à une phase future.
      • Ensuite, on supprime les filtres existants du document si nécessaire.
      • On regroupe les phases futures et actuelles avec LogicalAndFilter().
      • Et finit par ajouter les filtres à la vue active et applique un style graphique ( OverrideGraphicSettings ) à la phase actuelle.

    • Note :
    pour inverser une règle, il faut utiliser le constructeur FilterInverseRule 





    « Seul un esprit éduqué peut comprendre une pensée différente de la sienne sans devoir l’accepter. » Aristote

    0 commentaires:

    Enregistrer un commentaire