Sunday, January 30, 2011

Pientines Day!

I know most people relate falling in love with February 14th. ...being the geek at heart that I am, I think this holiday should be relocated to March 14...
That's right, 3/14.. or 3.14!! It's only one month exactly from the ever so improperly commercialized love holiday of 2.14!!!



Write your senators and let's get this taken care of once and for all!!! We all owe our livelihoods to simple arithmetic whether we know it or not and should celebrate our love of understanding it!!

And ladies... if you feel the same way, let's talk!!

Tuesday, January 25, 2011

Top 10 Excuses All BIM Managers Hate

Do you have any users that refuse to follow the modernized BIM way of doing things and insist on using their outdated "proven" 2D garbage ways of doing things, yet complain about how the whole BIM craze is oversold and not worth their trouble? Do you remember the excuses they offer?... Do you think they are as funny as I do?...

Hopefully after reading this post you will stop wanting to stuff your head in a garbage disposal and dumping a gallon of boiling bleach in your wounds:


10. ) "If Revit can't handle an exploded 3D AutoCAD mesh of my custom imported roofing structure, then we need to find a better software to help us get our $hit done!!!" [slamming fists on table and storming out of the room]

9. ) "What is wrong with having a pile of elements off to the side of my building on each of the 63 levels of my model? It makes it easier for me to grab and place them where I need them in my design.... I didn't know that would upset the construction bid consultant"

8. ) "I turn my model background black so I can see my yellow walls better..."
7. ) Consultant: "I couldn't print my sheets because I didn't know where your firm's standard pen table was..."

6. ) "Drafting elevations in AutoCAD is so much easier... how are you supposed to reference in the plan view so you know where everything lines up in elevation?... I would have been done days ago in AutoCAD, sorry."

5. ) "I don't Sync to Central because every time I do, all this other crap pops up in my drawing that get in the way..."

4. ) "I was cleaning the rooms out of my schedule to display the rooms only on level 4 and now they are all gone in the model... I didn't know that would delete them from the model"
3. ) "If I knew you wanted to use Navisworks on this project, I would have not built all 127 lighting fixture families as 2D... DAMMIT... tell me next time!!!!"



2. ) "Drafted my door schedule in lines and text because I didn't know how else to get my drafted doors to show up in the schedule..."



And the number one excuse I hear that never fails to cheer me up....

1. ) "If this were anything like AutoCAD, I'd be done with my plan views and ready to start manually drafting my sections, elevations, and details... this crap is SLOW!"

Wednesday, January 19, 2011

Batch Family Fun for Everyone!!! Part 1

I bet you've been waking up recently in the middle of the night dreaming about how you could jockey the Revit API to batch process families, haven't you?... Well you're in luck because that's exactly what this post is for.

There's obviously a whole load of topics to dive into on batch processing families, so to keep it short and sweet I'll touch on how to open a family, add a shared parameter with a set value and close the family with the saved values. Later posts will build on even cooler family API processing ideas.

The first thing you will need to accomplish is get a reference to the local Revit application and document using a class that implements the IExternalCommand interface. The code belows shows the beginning of such a class...


Public Class ScribblesForBlog

    Private m_Manager As FamilyManager = Nothing
    Private m_App As UIApplication
    Private m_Doc As Document = Nothing
    Private m_SharedParamFile As DefinitionFile

    ''' <summary>
    ''' General Class Constructor
    ''' </summary>
    ''' <param name="CmdData"></param>
    ''' <remarks></remarks>
    Public Sub New(ByVal CmdData As ExternalCommandData)
        m_Doc = CmdData.Application.ActiveUIDocument.Document
        m_App = CmdData.Application
        If m_Doc.IsFamilyDocument Then m_Manager = m_Doc.FamilyManager
        ' Get a reference to the active shared parameter file if one exists
        Try
            m_SharedParamFile = m_App.Application.OpenSharedParameterFile
        Catch ex As Exception
            ' It is possible to have an empty value here (No Active Shared Parameter File)
        End Try
    End Sub

End Class

The next thing we need is a quick and simple means of opening and closing external family files by calling their file paths as an argument to open the file. The functions below will open and close the active family respectively:


''' <summary>
    ''' Open an external family file and set the active doc reference to this family
    ''' </summary>
    ''' <param name="m_FileName">Full path to a valid rfa file</param>
    ''' <returns>Set the document object to this family on success</returns>
    ''' <remarks>www.RevitNet.blogspot.com RULES</remarks>
    Public Function OpenExternalFamily(ByVal m_FileName As String) As Boolean
        Try
            ' Open the family and set the active document object to the family
            m_Doc = m_App.Application.OpenDocumentFile(m_FileName)

            ' Verify the active document is the correct family (paranoia)
            If m_Doc.IsFamilyDocument And m_Doc.PathName.ToUpper = m_FileName.ToUpper Then
                ' Update the reference to the active family manager
                m_Manager = m_Doc.FamilyManager
                ' We're done, success
                Return True
            End If
            ' If we got to this line then something failed
            m_Manager = Nothing
            Return False
        Catch ex As Exception
            Return False
        End Try
    End Function

    ''' <summary>
    ''' Close the current family file
    ''' </summary>
    ''' <param name="p_SaveFile">Set to True will save the file on close</param>
    ''' <returns>Optional save, default is YES</returns>
    ''' <remarks></remarks>
    Public Function CloseActiveFamily(Optional ByVal p_SaveFile As Boolean = True) As Boolean
        Try
            ' This should only run on family files
            If m_Doc.IsFamilyDocument Then
                ' True means to save the file 
                m_Doc.Close(p_SaveFile)
            End If
            ' We're done, success
            Return True
        Catch ex As Exception
            Return False
        End Try
    End Function

Now that we can open and close the families... lets add a shared parameter! That would be exciting, right? We can open a shared parameter using:


''' <summary>
    ''' Open as set the shared parameter file
    ''' </summary>
    ''' <param name="p_FileName">Full path to the shared parameter file</param>
    ''' <remarks></remarks>
    Public Sub OpenSharedParameterFile(ByVal p_FileName As String)
        If IO.File.Exists(p_FileName) Then
            Try
                m_App.Application.SharedParametersFilename = p_FileName
                m_SharedParamFile = m_App.Application.OpenSharedParameterFile
            Catch ex As Exception
                ' Should never fail... maybe a poorly formatted shared parameter file?
            End Try
        End If
    End Sub

And now for some real excitement! The code below will search your active shared parameter file for a specific parameter by name and then add it to the family and set a value to it!:


''' <summary>
    ''' Add a shared parameter to the current family and use a string
    ''' to set its value. A double formatted parameter can use 9'-4" (architectural) format
    ''' </summary>
    ''' <param name="SharedParameterName">The Name of the parameter to find and add</param>
    ''' <returns>True on Success</returns>
    ''' <remarks></remarks>
    Public Function AddSharedParameter(ByVal SharedParameterName As String, _
                                       ByVal SharedParameterValue As String, _
                                       ByVal isInstParameter As Boolean) As Boolean
        Try
            ' Make sure we are working with a valid family document
            If m_Doc.IsFamilyDocument Then
                ' make sure we have a valid shared parameter file
                If m_SharedParamFile IsNot Nothing Then
                    ' Iterate the Parameter Groups
                    For Each group As DefinitionGroup In m_SharedParamFile.Groups
                        ' Iterate the Parameters in the Group
                        For Each def As ExternalDefinition In group.Definitions
                            ' Do we have a match?
                            If def.Name.ToUpper <> SharedParameterName.ToUpper Then Continue For
                            ' We found the parameter that we're after, 
                            ' does it already exist in the family?
                            Dim param As FamilyParameter = m_Manager.Parameter(def.Name)
                            ' If we have a valid parameter object,
                            ' then it exists in the family (no need to add it)
                            If param IsNot Nothing Then
                                ' Start a new Family transaction
                                Dim m_TransFam As New Transaction(m_Doc, "Family Transaction")
                                m_TransFam.Start()
                                Try
                                    ' Set the value from string...
                                    '9'-6" can set to a double or a string
                                    m_Manager.SetValueString(param, SharedParameterValue)
                                    m_TransFam.Commit()
                                Catch ex As Exception
                                    ' Roll back on failure
                                    m_TransFam.RollBack()
                                End Try

                            Else ' Need to add the parameter...
                                ' Start a new Family transaction
                                Dim m_TransFam As New Transaction(m_Doc, "Family Transaction")
                                ' Add the parameter as type or instance
                                If param.IsInstance = isInstParameter Then
                                    m_TransFam.Start()
                                    Try ' First add the parameter
                                        m_Manager.AddParameter(def, def.ParameterGroup, isInstParameter)
                                        Dim fParam As FamilyParameter = m_Manager.Parameter(def.Name)
                                        If fParam IsNot Nothing Then
                                            ' Set the value from string...
                                            '9'-6" can set to a double or a string
                                            m_Manager.SetValueString(param, SharedParameterValue)
                                        End If
                                        m_TransFam.Commit()
                                    Catch ex As Exception
                                        ' Roll back on failure
                                        m_TransFam.RollBack()
                                    End Try

                                End If
                            End If
                        Next
                    Next
                End If
            End If
            Return True
        Catch ex As Exception
            ' Something did not go according to plan if we make it here
            Return False
        End Try
    End Function

So that's the basics! You now know how to open a family and add a shared parameter to it... Look for more batch family capabilities in future posts!

Tuesday, January 4, 2011

Visual Studio 2010 Revit 2011 Addin Templates

Have you begun using Visual Studio 2010 for your Addin development yet? Well if you have, then this post is for you! Just don't forget to always set your .NET Framework to 3.5

As you begin to develop with the Revit API, it can be annoying to have to duplicate your addin setup code and references to the Revit API. Did you know that you can create custom addin templates for your projects with all references and boiler plate code prepopulated? Just think of all the women that you can impress at the bar with a story about how you can do this!!!

Create a project with no special functionality but with all required references to the Revit API along with a basic command class setup the way you like and an application class as well. This will help make it easier to use the same template for both commands and applications. Links to the prebuilt template files that I use are at the bottom of this post.

You should maintain separate templates for each flavor of Revit that you develop for since the paths to the API references are different.


The provided "Command" class


'.NET common used namespaces
Imports System
Imports System.Windows.Forms
Imports System.Collections.Generic

'Revit.NET common used namespaces
Imports Autodesk.Revit.ApplicationServices
Imports Autodesk.Revit.Attributes
Imports Autodesk.Revit.DB
Imports Autodesk.Revit.UI
Imports Autodesk.Revit.UI.Selection

&lt;Transaction(TransactionMode.Automatic)> _
&lt;Regeneration(RegenerationOption.Manual)> _
Public Class Commands
    Implements IExternalCommand

    ''' &lt;summary>
    ''' Main entry point for every external command.
    ''' &lt;/summary>
    ''' &lt;param name="commandData">Provides access to the Revit app and docs&lt;/param>
    ''' &lt;param name="message">Return message&lt;/param>
    ''' &lt;param name="elements">elements&lt;/param>
    ''' &lt;returns>Cancelled, Failed or Succeeded Result code.&lt;/returns>
    Public Function Execute(ByVal commandData As ExternalCommandData, _
                            ByRef message As String, _
                            ByVal elements As ElementSet) As Result Implements IExternalCommand.Execute
        Try
            ' Add your code here


            Return Result.Succeeded
        Catch ex As Exception
            ' Add failure handling here

            Return Result.Failed
        End Try

    End Function
End Class


The provided "Application" class


'.NET common used namespaces
Imports System.Windows.Forms
Imports System.Collections.Generic

'Revit.NET common used namespaces
Imports Autodesk.Revit.ApplicationServices
Imports Autodesk.Revit.Attributes
Imports Autodesk.Revit.DB
Imports Autodesk.Revit.UI
Imports Autodesk.Revit.UI.Selection

&lt;Transaction(TransactionMode.Automatic)> _
 &lt;Regeneration(RegenerationOption.Manual)> _
Class Application
    Implements IExternalApplication
    ''' &lt;summary>
    ''' Implement the external application when Revit starts
    ''' before a file or default template is actually loaded.
    ''' &lt;/summary>
    ''' &lt;param name="application">Contains the controlled application.&lt;/param>
    ''' &lt;returns>Return the status &lt;/returns>
    Public Function OnStartup(ByVal application As UIControlledApplication) _
                    As Result Implements IExternalApplication.OnStartup
        ' Add your code here


        ' Return Success
        Return Result.Succeeded
    End Function

    ''' &lt;summary>
    ''' Implement the external application when Revit is about to exit.
    ''' Any documents must have been closed before this method is called.
    ''' &lt;/summary>
    ''' &lt;param name="application">Contains the controlled application.&lt;/param>
    ''' &lt;returns>Return the status&lt;/returns>
    Public Function OnShutdown(ByVal application As UIControlledApplication) _
                    As Result Implements IExternalApplication.OnShutdown

        ' Add your code here


        ' Return Success
        Return Result.Succeeded
    End Function
End Class

All you have to do is export a project as a template (the result will be a zip file) and place them under your current user's profile at:
"%USERPROFILE%\Documents\Visual Studio 2010\Templates\ProjectTemplates\Visual Basic".

It is important to place your templates into a sub directory (we'll name ours "Revit 2011") and to NOT unzip the template files. Leave the zip files intact and this will work just fine. Your directory structure should look something like the image below.


Links to the above mentioned templates can be found here (for those that do not want or know how to create their own):