Thursday, 4 December 2008

Finding Filters

I needed to get some information on Filters setup by users. It wasn't immediately apparent how or whether I could do this with the API, so I used a technique that I have used frequently in such circumstances.

Create an empty Revit model, and use the API to list all elements in the model. Save this list, and then add to your model the element/item/object/feature you're interested in - in this case a filter. Now once again produce a full element list using the API.

The difference between your second list and your first list will enable you to identify your element by id. Then, armed with this information you can delve further by listing its parameters.

For a filter I found this:

ELEM_CATEGORY_PARAM_MT Category ElementId read-only -1
ELEM_CATEGORY_PARAM Category ElementId read-only -1
DESIGN_OPTION_ID Design Option ElementId read-only -1
PHASE_DEMOLISHED Phase Demolished ElementId read-write -1
PHASE_CREATED Phase Created ElementId read-write -1
ELEMENT_LOCKED_PARAM Locked Integer read-write 0
ELEM_DELETABLE_IN_FAMILY Deletable Integer read-write 1
UNIFORMAT_DESCRIPTION Assembly Description String read-only
UNIFORMAT_CODE Assembly Code String read-write
ID_PARAM Id ElementId read-only Symbol 'Filter 1' 123245
EDITED_BY Edited by String read-only
ELEM_PARTITION_PARAM Workset Integer read-write 0
ELEM_FAMILY_AND_TYPE_PARAM Family and Type ElementId read-only -1
ELEM_FAMILY_PARAM Family ElementId read-only -1
ELEM_TYPE_PARAM Type ElementId read-only -1
SYMBOL_FAMILY_AND_TYPE_NAMES_PARAM Family and Type String read-only Filters: Filter 1
SYMBOL_FAMILY_NAME_PARAM Family Name String read-only Filters
SYMBOL_FAMILY_NAME_PARAM Family Name String read-only Filters
SYMBOL_NAME_PARAM Type Name String read-only Filter 1
SYMBOL_NAME_PARAM Type Name String read-only Filter 1
SYMBOL_ID_PARAM Type Id ElementId read-only -1

So, to identify filters in your model you can use the SYMBOL_FAMILY_NAME_PARAM like below. Iterate through all elements, check the SYMBOL_FAMILY_NAME_PARAM value, and where it is 'Filters', then you have found a filter:

Dim elementIterator As Autodesk.Revit.ElementIterator
elementIterator = revitApp.ActiveDocument.Elements

While (elementIterator.MoveNext())

'filters are a symbol, so start here,
'rather than paramcheck every element
If TypeOf elementIterator.Current Is Autodesk.Revit.Symbol Then

Dim symbol As Autodesk.Revit.Symbol = elementIterator.Current

' then test SYMBOL_FAMILY_NAME_PARAM for 'Filters'.
If ParameterChecker(symbol, "testCondition", "SYMBOL_FAMILY_NAME_PARAM", "Filters") Then
'we have found a filter!
End If

End If
End While

The function ParameterChecker looks like below. I adapted this from the Revit API intro to perform three different functions. 'testCondition' tests a named paramater for a specified value and returns true or false. 'getValue' returns the value of a named parameter. 'fullReport' lists all parameters and values for a named element.

Public Shared Function ParameterChecker(ByVal elem As Autodesk.Revit.Element, ByVal task As String, ByVal paramName As String, Optional ByVal value As String = "")
Dim _ParamEnums As New ArrayList
Dim _ParamTypes As New ArrayList
Dim _ParamValues As New ArrayList

' Takes some time, so change cursor
Dim oldCursor As Cursor = Cursor.Current
Cursor.Current = Cursors.WaitCursor

Dim fis() As System.Reflection.FieldInfo = GetType(BuiltInParameter).GetFields
For Each fi As System.Reflection.FieldInfo In fis
' See if this is an enum (a literal value set at compile time)
If fi.IsLiteral Then
Dim enumInt As Integer = CType(fi.GetValue(Nothing), Integer)
Dim enumBip As BuiltInParameter = enumInt
Dim param As Parameter = elem.Parameter(enumBip)
If Not (param Is Nothing) Then ' this check is much faster than throwing an exception for each invalid param!
Select Case param.StorageType

Case StorageType.Double

Case StorageType.Integer

Case StorageType.String

Case StorageType.ElementId

Case StorageType.None
' nothing
Case Else
' nothing
End Select
End If
Catch ex As Exception
End Try
End If 'isLiteral
Next fi ' looping field infos

' Revert the cursor
Cursor.Current = oldCursor

'KIS for now - in future may display in an user-friendly form...
Dim msg As String = "Number of valid Params  = " & _ParamEnums.Count & ", " & _ParamTypes.Count & ", " & _ParamValues.Count

msg = "Valid Params for this element: "
Dim iNum As Integer = _ParamValues.Count
For i As Integer = 0 To iNum - 1
msg += vbCrLf & "  " & _ParamEnums(i) & ", " & _ParamTypes(i) & ": " & _ParamValues(i)
If task = "testCondition" Then
If _ParamEnums(i) = paramName And _ParamValues(i) = value Then
Return True
End If
ElseIf task = "getValue" Then
If _ParamEnums(i) = paramName Then
Return _ParamValues(i)
End If

ElseIf task = "fullReport" Then
WriteOutput(vbCrLf & "  " & _ParamEnums(i) & ", " & _ParamTypes(i) & ": " & _ParamValues(i))

End If


End Function

So this is how you might identify if a model has filters applied, and you can get the name of the filter too. But for me this isn't enough, as I want to know what categories are included and what its rules are.

Its now on the API wish-list as PR #154826 [API wish: API access to filters in Revit model] :)

No comments:

Post a Comment

Comments are moderated, so you'll have to wait a little bit before they appear!