Saturday, November 20, 2010

Tracking Revision Clouds in Revit 2011 can be a bit... Cloudy

Have you ever tried to schedule Revision Clouds in Revit 2011?... not so fun when you find that it is impossible... not to mention that if you select a revision cloud in a sheet and try the ol "Select All Instances" that the option is NOT supported for Revision Clouds... WTF....

Imagine if you had a means to export all revision clouds in your model to a neat and easy to view Excel document where you could see the sheet number of the sheet that the cloud displays on along with even the comments and revision date and sequence information... that would be pretty cool, huh?

I think this is a real short coming of Revit 2011, so here is a bit of code I used to solve the problem. I obviously cannot give you ALL of the code (what fun would that be?)... but I will share with you how I got ahold of the elements and then queried their view names and target sheet numbers and names.

First create a form and drop a filesave dialog from the tools menu and name it "SaveFileDialogCSV"... set the filetype filter to CSV... bla bla bla... The code below demonstrates the verification on the resulting file saved by the dialog. Eventually when satisfied there is a little function called "doScan" that actually scans the model for the Revision Cloud elements.


Me.SaveFileDialogCSV.ShowDialog()
If SaveFileDialogCSV.FileName <> "" Then
    If File.Exists(SaveFileDialogCSV.FileName) = True Then
        Try
            ' Start with a clean file
            File.Delete(SaveFileDialogCSV.FileName)
        Catch ex As Exception
        End Try
    End If
    ' Scan for Revision Cloud Elements
    doScan()
Else
    MsgBox("Please select a valid file name and location", MsgBoxStyle.Exclamation, "Error")
    Me.Close()
End If

The next section of code generates a couple lists. One list for the Revision Cloud elements in the project selected by category and one for the sheets that exist in the model. This sample will ignore revision cloud elements that are on views that are not placed on sheets since if they aren't on a sheet, they are not part of the documentation (sounded logical at the time). At the end, we make sure the model has at least one sheet before we continue.


' Collect Sheets
m_Sheets = New List(Of DB.Element)
Dim m_SheetCollector As New DB.FilteredElementCollector(m_Doc)
m_SheetCollector.OfCategory(DB.BuiltInCategory.OST_Sheets)
m_Sheets = m_SheetCollector.ToElements

' Collect Revision Clouds
m_RevClouds = New List(Of DB.Element)
Dim m_RevCloudCollector As New DB.FilteredElementCollector(m_Doc)
m_RevCloudCollector.OfCategory(DB.BuiltInCategory.OST_RevisionClouds)
m_RevClouds = m_RevCloudCollector.ToElements

' No sheets... no revisions!
If m_Sheets.Count < 1 Then Me.Close()

Now the next section saves the data it finds for each ViewSheet into a class named clsSheetMapper (not shown) so I can maintain an easy reference to the data between the clouds found on sheets and their host sheets.


' List all sheets and views for easy reference
        For Each x As DB.ViewSheet In m_Sheets
            ' Sheet element
            Dim m_Sht As New clsSheetMapper(x.Id.ToString, True)
            ' Sheet Number
            Dim m_ShtNumber As String = x.SheetNumber
            m_Sht.SheetNumber = m_ShtNumber
            ' Sheet Name
            Dim m_ShtName As String = x.Name
            m_Sht.SheetName = x.Name
            ' Add the view to the master list
            m_ViewsList.Add(m_Sht)
            ' Add the Views
            For Each y As DB.Element In x.Views
                ' View element
                Dim m_View As New clsSheetMapper(y.Id.ToString, False)
                ' Sheet Number
                m_View.SheetNumber = m_ShtNumber
                ' Sheet Name
                m_View.SheetName = m_ShtName
                ' View Name
                m_View.ViewName = y.Name
                ' Add the view to the master list
                m_ViewsList.Add(m_View)
            Next
        Next

The next bit of code finishes it up by scanning the revision cloud elements into a class named clsRevCloud I use to collect all of the view naming, sheet data and Revision Cloud parameter data into a single class and saving their parameter data to yet another secret class not shown named clsPara.


' Write the title line in our CSV file
        writeCSVline("Sheet Number, Sheet Name, View Name, ElementID, Revision Number, Revision Date, Comments, Mark, Issued To, Issued By")
        m_Revs.Clear()
        ' Process Revision Cloud Elements
        For Each m_RevCloud As DB.Element In m_RevClouds
            ' Create a matching Rev Item
            Dim m_RevItem As New clsRevcloud(m_RevCloud.Id.ToString)
            ' Test for viewID
            For Each x As clsSheetMapper In m_ViewsList
                Try
                    If x.ViewID = m_Doc.Element(m_RevCloud.OwnerViewId).Id.ToString Then
                        ' This is the view item
                        If x.SheetNumber IsNot Nothing Then
                            m_RevItem.SheetNumber = x.SheetNumber
                        End If
                        If x.SheetName IsNot Nothing Then
                            m_RevItem.SheetName = x.SheetName
                        End If
                        If x.ViewName IsNot Nothing Then
                            m_RevItem.ViewName = x.ViewName
                        End If
                        For Each y As DB.Parameter In m_RevCloud.Parameters
                            Dim myPara As New clsPara(y)
                            If myPara.Value IsNot Nothing Then
                                Select Case y.Definition.Name.ToUpper
                                    Case "REVISION NUMBER"
                                        m_RevItem.RevisionNumber = myPara.Value
                                    Case "REVISION DATE"
                                        m_RevItem.RevisionDate = myPara.Value
                                    Case "COMMENTS"
                                        m_RevItem.Comments = myPara.Value
                                    Case "MARK"
                                        m_RevItem.Mark = myPara.Value
                                    Case "ISSUED TO"
                                        m_RevItem.IssuedTo = myPara.Value
                                    Case "ISSUED BY"
                                        m_RevItem.IssuedBy = myPara.Value
                                End Select
                            End If
                        Next
                        Exit For
                    End If
                Catch ex As Exception
                    ' Some may not have an ownerID
                End Try
            Next
            m_Revs.Add(m_RevItem)
        Next

Now that we've got this handy list of classes with all of the sheet, view, and parameter data we can iterate them all and write the results to an external file... in this case it is a CSV file.


' Write all of the records
        For Each x As clsRevcloud In m_Revs
            ' Skip items without a sheet number
            If x.SheetNumber IsNot Nothing And x.SheetNumber <> "" Then
                Dim LineItem As String = ""
                LineItem = x.SheetNumber & ","
                LineItem = LineItem & x.SheetName & ","
                LineItem = LineItem & x.ViewName & ","
                LineItem = LineItem & x.ElementID & ","
                LineItem = LineItem & x.RevisionNumber & ","
                LineItem = LineItem & x.RevisionDate & ","
                LineItem = LineItem & x.Comments & ","
                LineItem = LineItem & x.Mark & ","
                LineItem = LineItem & x.IssuedTo & ","
                LineItem = LineItem & x.IssuedBy
                ' Write the Line
                writeCSVline(LineItem)
            End If
        Next

That's it... now if you ever have a HUGE project and a needy client that wants this data each time to issue a revision set, you can export a handy report for their use as well as for you to help keep track of your changes in your models.