' ' (C) Copyright 2003-2019 by Autodesk, Inc. ' ' Permission to use, copy, modify, and distribute this software in ' object code form for any purpose and without fee is hereby granted ' provided that the above copyright notice appears in all copies and ' that both that copyright notice and the limited warranty and ' restricted rights notice below appear in all supporting ' documentation. ' ' AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL ITS FAULTS. ' AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF ' MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC. ' DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE ' UNINTERRUPTED OR ERROR FREE. ' ' Use, duplication, or disclosure by the U.S. Government is subject to ' restrictions set forth in FAR 52.227-19 (Commercial Computer ' Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) ' (Rights in Technical Data and Computer Software), as applicable. ' Imports System Imports System.IO Imports System.Collections Imports System.Windows.Forms Imports Autodesk.Revit Imports Autodesk.Revit.DB.Events Imports Autodesk.Revit.DB Imports Autodesk.Revit.UI Imports Autodesk.Revit.DB.Structure Imports Autodesk.Revit.Creation ' Create Beams, Columns & Braces according to user's input information _ _ _ Public Class Command Implements IExternalCommand 'ToDo: Add Implements Clauses for implementation methods of these interface(s) Private m_revit As Autodesk.Revit.UI.UIApplication = Nothing Private m_columnMaps As New ArrayList 'list of columns' type Private m_beamMaps As New ArrayList 'list of beams' type Private m_braceMaps As New ArrayList 'list of braces' type Private levels As New SortedList 'list of list sorted by their elevations Private m_matrixUV(,) As Autodesk.Revit.DB.UV '2D coordinates of matrix ''' ''' list of all type of columns ''' ''' ''' ''' Public ReadOnly Property ColumnMaps() As ArrayList Get Return m_columnMaps End Get End Property ''' ''' list of all type of beams ''' ''' ''' ''' Public ReadOnly Property BeamMaps() As ArrayList Get Return m_beamMaps End Get End Property ''' ''' list of all type of braces ''' ''' ''' ''' Public ReadOnly Property BraceMaps() As ArrayList Get Return m_braceMaps End Get End Property ''' ''' Implement this method as an external command for Revit. ''' ''' An object that is passed to the external application ''' which contains data related to the command, ''' such as the application object and active view. ''' A message that can be set by the external application ''' which will be displayed if a failure or cancellation is returned by ''' the external command. ''' A set of elements to which the external application ''' can add elements that are to be highlighted in case of failure or cancellation. ''' Return the status of the external command. ''' A result of Succeeded means that the API external method functioned as expected. ''' Cancelled can be used to signify that the user cancelled the external operation ''' at some point. Failure should be returned if the application is unable to proceed with ''' the operation. Public Function Execute(ByVal revit As Autodesk.Revit.UI.ExternalCommandData, ByRef message As String, ByVal elements As Autodesk.Revit.DB.ElementSet) As Autodesk.Revit.UI.Result Implements Autodesk.Revit.UI.IExternalCommand.Execute m_revit = revit.Application Dim tran As Autodesk.Revit.DB.Transaction = New Autodesk.Revit.DB.Transaction(m_revit.ActiveUIDocument.Document, "CreateBeamsColumnsBraces") tran.Start() Try 'if initialize failed return Result.Failed Dim initializeOK As Boolean = Initialize() If Not initializeOK Then tran.RollBack() Return Autodesk.Revit.UI.Result.Failed End If Dim displayForm As New CreateBeamsColumnsBracesForm(Me) Using (displayForm) If displayForm.ShowDialog() <> DialogResult.OK Then tran.RollBack() Return Autodesk.Revit.UI.Result.Cancelled End If End Using tran.Commit() Return Autodesk.Revit.UI.Result.Succeeded Catch ex As Exception message = ex.Message tran.RollBack() Return Autodesk.Revit.UI.Result.Failed End Try End Function ''' ''' check the number of floors is less than the number of levels, ''' create beams, columns abd braces according to selected types ''' ''' type of column ''' type of beam ''' type of brace ''' number of floor ''' number of floors is less than the number of levels and create successfully then return true ''' Public Function AddInstance(ByVal columnObject As Object, ByVal beamObject As Object, ByVal braceObject As Object, ByVal floorNumber As Integer) As Boolean 'whether floor number less than levels number If floorNumber >= levels.Count Then Autodesk.Revit.UI.TaskDialog.Show("Revit", "The number of levels must be added.", "Revit") Return False End If Dim columnSymbol As Autodesk.Revit.DB.FamilySymbol = Nothing If TypeOf columnObject Is Autodesk.Revit.DB.FamilySymbol Then columnSymbol = columnObject End If Dim beamSymbol As Autodesk.Revit.DB.FamilySymbol = Nothing If TypeOf beamObject Is Autodesk.Revit.DB.FamilySymbol Then beamSymbol = beamObject End If Dim braceSymbol As Autodesk.Revit.DB.FamilySymbol = Nothing If TypeOf braceObject Is Autodesk.Revit.DB.FamilySymbol Then braceSymbol = braceObject End If 'any symbol is null then the command failed If columnSymbol Is Nothing OrElse beamSymbol Is Nothing OrElse braceSymbol Is Nothing Then Return False End If Try For k As Integer = 0 To floorNumber - 1 'iterate levels from lower one to higher Dim baseLevel As Autodesk.Revit.DB.Level = levels.GetByIndex(k) Dim topLevel As Autodesk.Revit.DB.Level = levels.GetByIndex((k + 1)) 'place column of this level Dim point2D As Autodesk.Revit.DB.UV For Each point2D In m_matrixUV PlaceColumn(point2D, columnSymbol, baseLevel, topLevel) Next point2D Dim matrixXSize As Integer = m_matrixUV.GetLength(0) 'length of matrix's x range Dim matrixYSize As Integer = m_matrixUV.GetLength(1) 'length of matrix's y range 'iterate coordinate both in x direction and y direction and create beams and braces For j As Integer = 0 To matrixYSize - 1 For i As Integer = 0 To matrixXSize - 1 'create beams and braces in x direction If i <> matrixXSize - 1 Then PlaceBrace(m_matrixUV(i, j), m_matrixUV(i + 1, j), baseLevel, topLevel, braceSymbol, True) End If 'create beams and braces in y direction If j <> matrixYSize - 1 Then PlaceBrace(m_matrixUV(i, j), m_matrixUV(i, j + 1), baseLevel, topLevel, braceSymbol, False) End If Next i Next j For j As Integer = 0 To matrixYSize - 1 For i As Integer = 0 To matrixXSize - 1 'create beams and braces in x direction If i <> matrixXSize - 1 Then PlaceBeam(m_matrixUV(i, j), m_matrixUV(i + 1, j), baseLevel, topLevel, beamSymbol) End If 'create beams and braces in y direction If j <> matrixYSize - 1 Then PlaceBeam(m_matrixUV(i, j), m_matrixUV(i, j + 1), baseLevel, topLevel, beamSymbol) End If Next i Next j Next k Catch Return False End Try Return True End Function ''' ''' generate 2D coordinates of matrix according to parameters ''' ''' Number of Columns in the X direction ''' Number of Columns in the Y direction ''' Distance between columns ''' Public Sub CreateMatrix(ByVal xNumber As Integer, ByVal yNumber As Integer, ByVal distance As Double) m_matrixUV = New Autodesk.Revit.DB.UV(xNumber - 1, yNumber - 1) {} Dim i As Integer For i = 0 To xNumber - 1 Dim j As Integer For j = 0 To yNumber - 1 m_matrixUV(i, j) = New Autodesk.Revit.DB.UV(i * distance, j * distance) Next j Next i End Sub ''' ''' iterate all the symbols of levels, columns, beams and braces ''' ''' A value that signifies if the initialization was successful for true or failed for false ''' Private Function Initialize() As Boolean Try 'get elements in the document which type == Level or type == Family Dim filter1 As Autodesk.Revit.DB.ElementClassFilter Dim filter2 As Autodesk.Revit.DB.ElementClassFilter filter1 = New Autodesk.Revit.DB.ElementClassFilter(GetType(Autodesk.Revit.DB.Level)) filter2 = New Autodesk.Revit.DB.ElementClassFilter(GetType(Autodesk.Revit.DB.Family)) Dim orFilter As Autodesk.Revit.DB.LogicalOrFilter orFilter = New Autodesk.Revit.DB.LogicalOrFilter(filter1, filter2) Dim collector As Autodesk.Revit.DB.FilteredElementCollector collector = New Autodesk.Revit.DB.FilteredElementCollector(m_revit.ActiveUIDocument.Document) collector.WherePasses(orFilter) Dim i As IEnumerator i = collector.GetElementIterator i.Reset() Dim moreElement As Boolean = i.MoveNext() While moreElement Dim o As Object = i.Current 'add level to list Dim level As Autodesk.Revit.DB.Level level = Nothing If TypeOf o Is Autodesk.Revit.DB.Level Then level = CType(o, Autodesk.Revit.DB.Level) End If ' If Not (level Is Nothing) Then levels.Add(level.Elevation, level) GoTo nextLoop End If Dim f As Autodesk.Revit.DB.Family = Nothing If TypeOf o Is Autodesk.Revit.DB.Family Then f = o End If If f Is Nothing Then GoTo nextLoop End If Dim symbol As Object Dim symbolId As ElementId For Each symbolId In f.GetFamilySymbolIds() symbol = m_revit.ActiveUIDocument.Document.GetElement(symbolId) Dim familyType As Autodesk.Revit.DB.FamilySymbol = symbol ' If familyType Is Nothing Then GoTo nextLoop End If If familyType.Category Is Nothing Then GoTo nextLoop End If 'add symbols of beams and braces to lists Dim categoryName As String = familyType.Category.Name If "Structural Framing" = categoryName Then m_beamMaps.Add(New SymbolMap(familyType)) m_braceMaps.Add(New SymbolMap(familyType)) ElseIf "Structural Columns" = categoryName Then m_columnMaps.Add(New SymbolMap(familyType)) End If Next symbolId nextLoop: moreElement = i.MoveNext() End While Catch Return False End Try Return True End Function ''' ''' create column of certain type in certain position ''' ''' 2D coordinate of the col umn ''' type of column ''' the base level of the column ''' the top level of the column ''' Private Sub PlaceColumn(ByVal point2D As Autodesk.Revit.DB.UV, ByVal columnType As Autodesk.Revit.DB.FamilySymbol, ByVal baseLevel As Autodesk.Revit.DB.Level, ByVal topLevel As Autodesk.Revit.DB.Level) 'create column of certain type in certain level and start point Dim point As New Autodesk.Revit.DB.XYZ(point2D.U, point2D.V, 0) Dim structuralType As Autodesk.Revit.DB.Structure.StructuralType structuralType = Autodesk.Revit.DB.Structure.StructuralType.Column If Not (columnType.IsActive) Then columnType.Activate() End If Dim column As Autodesk.Revit.DB.FamilyInstance = m_revit.ActiveUIDocument.Document.Create.NewFamilyInstance(point, columnType, topLevel, structuralType) 'set baselevel & toplevel of the column If Not (column Is Nothing) Then Dim baseLevelParameter As Parameter = column.Parameter(Autodesk.Revit.DB.BuiltInParameter.FAMILY_BASE_LEVEL_PARAM) Dim topLevelParameter As Parameter = column.Parameter(Autodesk.Revit.DB.BuiltInParameter.FAMILY_TOP_LEVEL_PARAM) Dim topOffsetParameter As Parameter = column.Parameter(BuiltInParameter.FAMILY_TOP_LEVEL_OFFSET_PARAM) Dim baseOffsetParameter As Parameter = column.Parameter(BuiltInParameter.FAMILY_BASE_LEVEL_OFFSET_PARAM) If Not (baseLevelParameter Is Nothing) Then Dim baseLevelId As Autodesk.Revit.DB.ElementId baseLevelId = baseLevel.Id baseLevelParameter.Set(baseLevelId) End If If Not (topLevelParameter Is Nothing) Then Dim topLevelId As Autodesk.Revit.DB.ElementId topLevelId = topLevel.Id topLevelParameter.Set(topLevelId) End If If Not (topOffsetParameter Is Nothing) Then topOffsetParameter.Set(0.0) End If If Not (baseOffsetParameter Is Nothing) Then baseOffsetParameter.Set(0.0) End If End If End Sub ''' ''' create beam of certain type in certain position ''' ''' one point of the location line in 2D ''' another point of the location line in 2D ''' the base level of the beam ''' the top level of the beam ''' type of beam ''' Private Sub PlaceBeam(ByVal point2D1 As Autodesk.Revit.DB.UV, ByVal point2D2 As Autodesk.Revit.DB.UV, ByVal baseLevel As Autodesk.Revit.DB.Level, ByVal topLevel As Autodesk.Revit.DB.Level, ByVal beamType As Autodesk.Revit.DB.FamilySymbol) Dim height As Double = topLevel.Elevation Dim startPoint As New Autodesk.Revit.DB.XYZ(point2D1.U, point2D1.V, height) Dim endPoint As New Autodesk.Revit.DB.XYZ(point2D2.U, point2D2.V, height) Dim line As Line = Autodesk.Revit.DB.Line.CreateBound(startPoint, endPoint) Dim structuralType As Autodesk.Revit.DB.Structure.StructuralType = Autodesk.Revit.DB.Structure.StructuralType.Beam If Not (beamType.IsActive) Then beamType.Activate() End If m_revit.ActiveUIDocument.Document.Create.NewFamilyInstance(line, beamType, topLevel, structuralType) End Sub ''' ''' create brace of certain type in certain position between two adjacent columns ''' ''' one point of the location line in 2D ''' another point of the location line in 2D ''' the base level of the brace ''' the top level of the brace ''' type of beam ''' whether the location line is in x direction ''' Private Sub PlaceBrace(ByVal point2D1 As Autodesk.Revit.DB.UV, ByVal point2D2 As Autodesk.Revit.DB.UV, ByVal baseLevel As Autodesk.Revit.DB.Level, ByVal topLevel As Autodesk.Revit.DB.Level, ByVal braceType As Autodesk.Revit.DB.FamilySymbol, ByVal isXDirection As Boolean) 'get the start points and end points of location lines of two braces Dim topHeight As Double = topLevel.Elevation Dim baseHeight As Double = baseLevel.Elevation Dim middleElevation As Double = (topHeight + baseHeight) / 2 Dim middleHeight As Double = (topHeight + baseHeight) / 2 Dim startPoint As New Autodesk.Revit.DB.XYZ(point2D1.U, point2D1.V, middleElevation) Dim endPoint As New Autodesk.Revit.DB.XYZ(point2D2.U, point2D2.V, middleElevation) Dim middlePoint As Autodesk.Revit.DB.XYZ If isXDirection Then middlePoint = New Autodesk.Revit.DB.XYZ((point2D1.U + point2D2.U) / 2, point2D2.V, topHeight) Else middlePoint = New Autodesk.Revit.DB.XYZ(point2D2.U, (point2D1.V + point2D2.V) / 2, topHeight) End If 'create two brace and set their location line Dim structuralType As Autodesk.Revit.DB.Structure.StructuralType = Autodesk.Revit.DB.Structure.StructuralType.Brace Dim levelId As Autodesk.Revit.DB.ElementId = topLevel.Id Dim startLevelId As Autodesk.Revit.DB.ElementId = baseLevel.Id Dim endLevelId As Autodesk.Revit.DB.ElementId = topLevel.Id Dim line1 As Line = Autodesk.Revit.DB.Line.CreateBound(startPoint, middlePoint) If Not (braceType.IsActive) Then braceType.Activate() End If Dim firstBrace As Autodesk.Revit.DB.FamilyInstance = m_revit.ActiveUIDocument.Document.Create.NewFamilyInstance(line1, braceType, baseLevel, structuralType) Dim referenceLevel1 As Parameter = firstBrace.Parameter(BuiltInParameter.INSTANCE_REFERENCE_LEVEL_PARAM) If Not (referenceLevel1 Is Nothing) Then referenceLevel1.Set(levelId) End If Dim line2 As Line = Autodesk.Revit.DB.Line.CreateBound(endPoint, middlePoint) Dim secondBrace As Autodesk.Revit.DB.FamilyInstance = m_revit.ActiveUIDocument.Document.Create.NewFamilyInstance(line2, braceType, baseLevel, structuralType) Dim referenceLevel2 As Parameter = secondBrace.Parameter(BuiltInParameter.INSTANCE_REFERENCE_LEVEL_PARAM) If Not (referenceLevel2 Is Nothing) Then referenceLevel2.Set(levelId) End If End Sub End Class ''' ''' assistant class contains the symbol and its name ''' ''' Public Class SymbolMap Private m_symbolName As String = "" Private m_symbol As Autodesk.Revit.DB.FamilySymbol = Nothing ''' ''' constructor without parameter is forbidden ''' ''' Private Sub New() End Sub ''' ''' constructor ''' ''' family symbol ''' Public Sub New(ByVal symbol As Autodesk.Revit.DB.FamilySymbol) m_symbol = symbol Dim familyName As String = "" If Not (symbol.Family Is Nothing) Then familyName = symbol.Family.Name End If m_symbolName = familyName + " : " + symbol.Name End Sub Public ReadOnly Property SymbolName() As String Get Return m_symbolName End Get End Property Public ReadOnly Property ElementType() As Autodesk.Revit.DB.FamilySymbol Get Return m_symbol End Get End Property End Class