Monday, February 28, 2011

I got a little lazy and preoccupied yesterday so cut the post short on you, but you have to admit the suspense was pretty exciting! As I promised in yesterday's post on Convert Rooms to 3D Masses, this post will be the main meat of the whole utility.

My Test model contains five rooms boundarized by most of the common conditions that exist in a real design model. Some are partially surrounded by room separation lines, one entirely surrounded by room separation lines, one with a curved wall, etc.

Text first thing we need is a complete list collection of the rooms in our model. The code below does this for us and puts the list of room elements into m_Rooms:

Now we can start iterating our collection of rooms in a For Each loop with the beginning of that shown here:

' Iterate the list and gather a list of boundariesForEach x As Architecture.Room In m_Rooms

This next group of code shows how we will avoid working on unplaced rooms by making sure the Area is larger than 1. The second portion shows how we start the stop watch object used to quantify the time that it takes to generate a mass from each room. Then the path to our specialty equipment family template and the saveas function is called to give the family a name. Make sure that the directory being called already exists for this sample to work.

Now in this next portion, we will create a new subcategory named using the department of the room and material named equally that we will apply to the extrusion that we build the room with. This is handy to display the masses in color related to their department assignment.

' Get the department nameDim m_para AsNew clsPara(x.Parameter("Department"))
Dim m_SubCatName AsString = "My_Rooms"If m_para.Value <> ""Then m_SubCatName = "My_Rooms_" & m_para.Value
' Subcategory named by DepartmentDim m_Subcategory As Category = NothingTry' Try to create the subcategory if it does not exist
m_Subcategory = m_FamDoc.Settings.Categories.NewSubcategory(m_SECategory, m_SubCatName)
Catch ex As Exception
' Get the subcategory object since it exists alreadyDim m_NameMap As CategoryNameMap = m_SECategory.SubCategories
ForEach x1 As Category In m_NameMap
If x1.Name = m_SubCatName Then
m_Subcategory = x1
ExitForEndIfNextEndTry' Material named by DepartmentDim m_Material As Material = NothingTry' Try to create the material if it does not exist
m_Material = m_FamDoc.Settings.Materials.AddWood(m_SubCatName)
Catch ex As Exception
' Get the material object since it exists already
m_Material = m_FamDoc.Settings.Materials.Item(m_SubCatName)
EndTry' Apply the material to the subcategory
m_Subcategory.Material = m_Material

Now for the part where we get the room boundary into a curve array that we will eventually use to extrude as a form representing a room element. The snip below iterates through the room boundary objects returning a CurveArray which just so happens to be the second to last process to get us to out required argument that we need to generate the 3D form, CurveArrArray!

The snip below shows how we build up the workplane that is required to extrude the form from in our family template. We then append the CurveArray to the final argument required to extrude our form... CurveArrArray:

The next snip shows how we load the family into the project and place it into the model at 0,0,0 so our coordinates used to generate the form will line up right where the room needs to be:

' Commit the Family Transaction
m_TransFam.Commit()
' Load the Family into the ModelDim m_NewFamily As Family = m_FamDoc.LoadFamily(m_Doc)
' Create a reference to the latest family (we just created it)Dim m_FamilySymbolSetIterator As FamilySymbolSetIterator = m_NewFamily.Symbols.ForwardIterator()
m_FamilySymbolSetIterator.MoveNext()
Dim m_FamSymbol As FamilySymbol = TryCast(m_FamilySymbolSetIterator.Current, FamilySymbol)
' Place the Family at 0,0,0 since we used the same coordinates as the rooms to generateDim m_FamilyInstance As FamilyInstance = m_Doc.Create.NewFamilyInstance(New XYZ(0, 0, 0), m_FamSymbol, [Structure].StructuralType.NonStructural)

So that's about it.... now we just need to cleanup and close the stopwatch objects and report the timing to the user:

Sunday, February 27, 2011

Well, it has been quite a while since I shared something pertinent to anytime of code or .NET. I've been busy with less exciting things and haven't really had the time, but that's about to change!

This post will touch on how to solve a common problem where designers want to see how a room looks in full 3D while in the programming (Room and Area Programming) stages to help figure out the relationships from one room to others. This is difficult to do with traditional rooms that Revit creates, mainly because they aren't real physical objects (and you cannot see the damn things in 3D).

Here is what my test model looks like with five simple rooms placed in. One surrounded entirely by room separation lines, one with curved walls, and some others for verification and proof that the tool will actually work in most conditions.

Create a new .NET 3.5 class project in Visual Studio 2010. You'll need to build in the Command class on your own this time... Add a form object and name it Form_Main. Add the following referenced to your project and import their name spaces as shown below:

As you can see in the listing above, our variable requirements are actually quite simple. We're mainly concerned with document and application objects that are required to generate families in Revit.

The next item we'll code in is the base class constructor. Now keep in mind that one argument is required to generate an instance of this class, IExternalCommand. This argument is the same as the one required in the IExternalCommand's Execute function. The Constructor is shown here:

Now that we have all of the main framework ready to go, we can dig down into how the families are built using data from the room elements in the model. Create a new subroutine named GenerateMasses. This subroutine is where all the magic happens.

Before we get back into filling in the functionality in this subroutine, let's get the button assignments in our form out of the way. Double click each of the buttons in the form designer to autogenerate their click event functions and add the following very simple code to these functions:

Now let's focus the rest of this post on what's missing!.... haha I know, you'll have to wait until tomorrow to see the ending. So stay tuned and come back tomorrow for the meat of this idea finalized into true usable code! Tomorrow's post will be on the completion of the GenerateMasses subroutine.

Friday, February 18, 2011

I realize that I haven't posted any API stuff lately. I've been tied up with the BETA's as well as writing the API chapter for the next installment of "Mastering Autodesk Revit Architecture 2012"... Look for an essential post later this month on converting rooms to masses without tessellation (super fast).

It's amazing how much of a BIM Manager's time is taken up daily to cater to the occasional user's laziness or lack of fear. If BIM Manager's were more like Chuck Norris, our jobs would be amazingly more efficient and productive [wink]... So here are the top ten reasons on why I think Chuck Norris would be an excellent BIM Manager:

10.) User's would never miss a deadline for fear that they might have to become victim to his wrath

9.) Plotter's would never fail or run out of paper where Chuck Norris is BIM Manager

8.) Getting user's to pay attention in training sessions would never be easier

7.) Why?... Chuck Norris, that's why!

6.) Chuck Norris doesn't miss deadlines because they work only within HIS schedule!

5.) Chuck Norris could improve the functionality of Revit simply by starring it down

4.) All constraints would always be satisfied or die a painful round-house death

3.) No Revit model under Chuck Norris' responsibility would ever think of containing an error or perform slowly

2.) Chuck Norris would tell families to build themselves, and they would