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:
' Get the list of rooms
Dim m_Collector As New FilteredElementCollector(m_Doc)
m_Collector.OfCategory(BuiltInCategory.OST_Rooms)
Dim m_Rooms As New List(Of Element)
m_Rooms = m_Collector.ToElements
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 boundaries
For Each 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.
' Avoid unplaced rooms
If x.Area < 1 Then Continue For
' Stopwatcher - This comes FIRST
Dim m_StopWatch As New Stopwatch
m_StopWatch.Reset()
m_StopWatch.Start()
' This is the path to our family template
m_FamDoc = m_App.NewFamilyDocument("C:\Documents and Settings\All Users\Application Data\" & _
"Autodesk\RAC 2011\Imperial Templates\Specialty Equipment.rft")
' The "C:\My Families\" directory needs to exist first obviously
m_FamDoc.SaveAs("C:\My Families\" & x.UniqueId.ToString & ".rfa")
The next snip shows where we create a transaction for both the main model as well as the family document
' Start a new Model Transaction
Dim m_Trans As New Transaction(m_Doc, "My Rooms to Masses - By Boundary")
m_Trans.Start()
' Start a new Family Transaction
Dim m_TransFam As New Transaction(m_FamDoc, "Transaction in Family Document")
m_TransFam.Start()
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 name
Dim m_para As New clsPara(x.Parameter("Department"))
Dim m_SubCatName As String = "My_Rooms"
If m_para.Value <> "" Then m_SubCatName = "My_Rooms_" & m_para.Value
' Subcategory named by Department
Dim m_Subcategory As Category = Nothing
Try
' 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 already
Dim m_NameMap As CategoryNameMap = m_SECategory.SubCategories
For Each x1 As Category In m_NameMap
If x1.Name = m_SubCatName Then
m_Subcategory = x1
Exit For
End If
Next
End Try
' Material named by Department
Dim m_Material As Material = Nothing
Try
' 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)
End Try
' 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!
' Get the room boundary
Dim m_Boundary As Architecture.BoundarySegmentArrayArray = x.Boundary
If m_Boundary Is Nothing Then Continue For
' The array of boundary curves
Dim m_CurveArray As New CurveArray
' Iterate to gather the curve objects
For i = 0 To m_Boundary.Size - 1
' Boundary segments array
Dim m_SegAray As Architecture.BoundarySegmentArray = m_Boundary.Item(i)
' Segments Array
For ii = 0 To m_SegAray.Size - 1
Dim m_Seg As Architecture.BoundarySegment = m_SegAray.Item(ii)
' Add the segment curve to the array
m_CurveArray.Append(m_Seg.Curve)
Next
Next
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:
' Simple insertion point
Dim pt1 As New XYZ(0, 0, 0)
' Our normal point that points the extrusion directly up
Dim ptNormal As New XYZ(0, 0, 1)
' The plane to extrude the mass from
Dim m_Plane As Plane = m_AppCreate.NewPlane(ptNormal, pt1)
Dim m_SketchPlane As SketchPlane = m_FamDoc.FamilyCreate.NewSketchPlane(m_Plane)
' Need to add the CurveArray to the final requirement to generate the form
Dim m_CurveArArray As New CurveArrArray
m_CurveArArray.Append(m_CurveArray)
Now we can generate the form and add the extrusion to out subcategory representing the department:
' Extrude the form
Dim m_Extrusion As Extrusion = m_FamDoc.FamilyCreate.NewExtrusion(True, m_CurveArArray, m_SketchPlane, 8)
Try
m_Extrusion.Subcategory = m_Subcategory
Catch ex As Exception
End Try
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 Model
Dim 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 generate
Dim 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:
' Commit the Model Transaction
m_Trans.Commit()
' Elapsed Time Per Element
m_StopWatch.Stop()
' Report the elapsed time
MsgBox(m_StopWatch.Elapsed.TotalSeconds.ToString & " Seconds!", MsgBoxStyle.Information, "Elapsed Time!")
Now check out the results....!!! A fully 3D schedulable room mass (as a specialty equipment form)...