Purge unused Line Pattern and Fill Pattern

Hi all,

In our template there are a lot of unused Line Patterns and Fill Patterns Revit natively cannot purge.
Not only import CAD-lines but all that is not in use. Tried searching for multiple topics / scripts but didn’t seem to have a working one.
What script are you using? Do you have an active link?

Thank you,

This is a complex task that takes more than a few basic nodes. Revit has no exposed way to ask if a line/fill pattern is in use, what you have to actually do is check the properties of everything that could use them, then finally report back at the end the difference between all used patterns and all patterns to get unused.

They can be used in many places that are complex to scrape, such as overrides, family patterns/category overrides, materials, filled region types etc. I’d suggest looking into Ideate style manager unless you’re up to diving into this one head first - the cost of a seat per year is likely less than the time investment making a dynamo routine of this nature would take.

If keen to try in Dynamo just begin with a small task - get all the patterns in filled region types. That’s one of the easier targets to check, but will be a good indicator of how feasible pursuing the rest of the task would take.

Thank you for your reply. I’ll have a go from there, thanks.

A workaround is to temporarily remove the patterns and analyze the modified elements with app.DocumentChanged (however, this can take some time, so it’s not the ideal solution).

Here’s a simple test/prototyping with WinForms.

Code PythonNet3
import clr
import sys
import System
from System import EventHandler, Uri
clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
import Autodesk.Revit.DB as DB
from Autodesk.Revit.DB.Events import DocumentChangedEventArgs

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

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)


clr.AddReference('System.Drawing')
clr.AddReference('System.Windows.Forms')
import System.Drawing
import System.Windows.Forms

from System.Drawing import *
from System.Windows.Forms import *

clr.AddReference("System.Core")
clr.ImportExtensions(System.Linq)

class PurgePatternForm(Form):
    def __init__(self, app, name_pattern="Wood"):
        super().__init__()
        self._app = app
        self.name_pattern = name_pattern
        self.ext_event = None
        self.event_unregister = None
        self.out_data = []
        self.InitializeComponent()
    
    def InitializeComponent(self):
        self._buttonOK = System.Windows.Forms.Button()
        self._richTextBox1 = System.Windows.Forms.RichTextBox()
        self.SuspendLayout()
        self.FormClosing += self.Form1_FormClosing
        #
        self.handler_ModifEvent = EventHandler[DocumentChangedEventArgs](self.ModifEvent)
        self._app.DocumentChanged += self.handler_ModifEvent
        #
        # buttonOK
        self._buttonOK.Anchor = System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right | System.Windows.Forms.AnchorStyles.Top 
        self._buttonOK.Location = System.Drawing.Point(120, 8)
        self._buttonOK.Name = "buttonOK"
        self._buttonOK.Size = System.Drawing.Size(95, 35)
        self._buttonOK.TabIndex = 2
        self._buttonOK.Text = "Search"
        self._buttonOK.Click += self.ButtonOKClick
        # 
        # richTextBox1
        self._richTextBox1.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right
        self._richTextBox1.Location = System.Drawing.Point(8, 50)
        self._richTextBox1.Name = "richTextBox1"
        self._richTextBox1.Size = System.Drawing.Size(330, 190)
        self._richTextBox1.TabIndex = 0
        self._richTextBox1.Text = f"Searching unsued Pattern '{self.name_pattern}'\n\n"
        # 
        # Form35
        self.ClientSize = System.Drawing.Size(346, 250)
        self.Controls.Add(self._buttonOK)
        self.Controls.Add(self._richTextBox1)
        self.Name = "Unused"
        self.Text = "Unused Pattern"
        self.ResumeLayout(False)

    def ButtonOKClick(self, sender, e):
        #
        if self.ext_event is not None:
            self.ext_event.Raise()
    
    def ModifEvent(self, sender, e):
        # prevent if unregister  event failed
        if self.Controls.Count > 0 and all(not x.IsDisposed for x in self.Controls):
            doc = e.GetDocument()
            deleteId = next((x for x in e.GetDeletedElementIds()), None)
            lst_ModifiedElementIds = [x for x in e.GetModifiedElementIds()]
            if deleteId is not None:
                self.out_data.append([deleteId, f" → Count dependent Elements {len(lst_ModifiedElementIds)}"]) 
            
    def ShowResult(self):
        results = [doc.GetElement(xId).Name + count_str for xId, count_str in self.out_data]
        self._richTextBox1.Text += "\n".join(results)
        self._richTextBox1.SelectionStart = len(self._richTextBox1.Text)
        self._richTextBox1.ScrollToCaret()
        try:
            Application.DoEvents()
        except Exception as ex:
            print(ex)
        self.Activate()  
            
    def Form1_FormClosing(self, sender, e):
        try:
            self.ext_event.Dispose()
            self.event_unregister.Raise()
        except Exception as ex:
            print(ex)
        

class ModExternalEvent(IExternalEventHandler):
    __namespace__ = "ModExternalEvent_tEfYX0DHEr9Z"
    def __init__(self, form):
        super().__init__()
        self.form = form
        
    def Execute(self, _uiap):
        _uidoc = _uiap.ActiveUIDocument
        _doc = _uidoc.Document
        _view = _doc.ActiveView
        #
        tg = TransactionGroup(doc, 'Test')
        tg.Start()
        try:
            #processing
            fill_paterns = FilteredElementCollector(doc).OfClass(FillPatternElement)\
                            .Where(System.Func[System.Object, System.Boolean](lambda x: self.form.name_pattern in x.Name))\
                            .ToList()
            #
            for fill_patern in fill_paterns:
                tx = Transaction(_doc)
                tx.Start("delete_temp")
                doc.Delete(fill_patern.Id)
                tx.Commit() 

        except Exception as ex:
            print(ex)
        finally:
            tg.RollBack()
            self.form.ShowResult()
    
    def GetName(self):
        return "Test External Event"
        
        
class EventUnRegisterHandler(IExternalEventHandler):
    __namespace__ = "EventRegisterHandler_jude0oEr" 
    def __init__(self, form):
        super().__init__()
        self.form = form

    def Execute(self, _uiap):        
        try:
            print("start remove Event")
            _uidoc = _uiap.ActiveUIDocument
            _doc = _uidoc.Document
            _view = _doc.ActiveView
            #processing
            self.form._app.DocumentChanged -= self.form.handler_ModifEvent 
            self.form.event_unregister.Dispose()
            print("end remove Event")
        except Exception as ex:
            print(ex)

    def GetName(self):
        return "EventRegisterHandler" 

name_pattern = IN[0]

TransactionManager.Instance.ForceCloseTransaction()

objForm = PurgePatternForm(app, name_pattern)
#
obj_handler = ModExternalEvent(objForm)    
ext_event = ExternalEvent.Create(obj_handler)
#
obj_handlerUnRegister = EventUnRegisterHandler(objForm)    
ext_eventUnRegister = ExternalEvent.Create(obj_handlerUnRegister)  
#
objForm.ext_event = ext_event
objForm.event_unregister = ext_eventUnRegister
objForm.Show()