Files
2021-04-20 11:36:21 +02:00

476 lines
21 KiB
VB.net

'
' (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
<Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)> _
<Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)> _
<Autodesk.Revit.Attributes.Journaling(Autodesk.Revit.Attributes.JournalingMode.NoCommandData)> _
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
''' <summary>
''' list of all type of columns
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public ReadOnly Property ColumnMaps() As ArrayList
Get
Return m_columnMaps
End Get
End Property
''' <summary>
''' list of all type of beams
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public ReadOnly Property BeamMaps() As ArrayList
Get
Return m_beamMaps
End Get
End Property
''' <summary>
''' list of all type of braces
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public ReadOnly Property BraceMaps() As ArrayList
Get
Return m_braceMaps
End Get
End Property
''' <summary>
''' Implement this method as an external command for Revit.
''' </summary>
''' <param name="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.</param>
''' <param name="message">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.</param>
''' <param name="elements">A set of elements to which the external application
''' can add elements that are to be highlighted in case of failure or cancellation.</param>
''' <returns>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.</returns>
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
''' <summary>
''' check the number of floors is less than the number of levels,
''' create beams, columns abd braces according to selected types
''' </summary>
''' <param name="columnObject">type of column</param>
''' <param name="beamObject">type of beam</param>
''' <param name="braceObject">type of brace</param>
''' <param name="floorNumber">number of floor</param>
''' <returns>number of floors is less than the number of levels and create successfully then return true</returns>
''' <remarks></remarks>
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
''' <summary>
''' generate 2D coordinates of matrix according to parameters
''' </summary>
''' <param name="xNumber">Number of Columns in the X direction</param>
''' <param name="yNumber">Number of Columns in the Y direction</param>
''' <param name="distance">Distance between columns</param>
''' <remarks></remarks>
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
''' <summary>
''' iterate all the symbols of levels, columns, beams and braces
''' </summary>
''' <returns>A value that signifies if the initialization was successful for true or failed for false</returns>
''' <remarks></remarks>
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
''' <summary>
''' create column of certain type in certain position
''' </summary>
''' <param name="point2D">2D coordinate of the col umn</param>
''' <param name="columnType">type of column</param>
''' <param name="baseLevel">the base level of the column</param>
''' <param name="topLevel">the top level of the column</param>
''' <remarks></remarks>
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
''' <summary>
''' create beam of certain type in certain position
''' </summary>
''' <param name="point2D1">one point of the location line in 2D</param>
''' <param name="point2D2">another point of the location line in 2D</param>
''' <param name="baseLevel">the base level of the beam</param>
''' <param name="topLevel">the top level of the beam</param>
''' <param name="beamType">type of beam</param>
''' <remarks></remarks>
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
''' <summary>
''' create brace of certain type in certain position between two adjacent columns
''' </summary>
''' <param name="point2D1">one point of the location line in 2D</param>
''' <param name="point2D2">another point of the location line in 2D</param>
''' <param name="baseLevel">the base level of the brace</param>
''' <param name="topLevel">the top level of the brace</param>
''' <param name="braceType">type of beam</param>
''' <param name="isXDirection">whether the location line is in x direction</param>
''' <remarks></remarks>
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
''' <summary>
''' assistant class contains the symbol and its name
''' </summary>
''' <remarks></remarks>
Public Class SymbolMap
Private m_symbolName As String = ""
Private m_symbol As Autodesk.Revit.DB.FamilySymbol = Nothing
''' <summary>
''' constructor without parameter is forbidden
''' </summary>
''' <remarks></remarks>
Private Sub New()
End Sub
''' <summary>
''' constructor
''' </summary>
''' <param name="symbol">family symbol</param>
''' <remarks></remarks>
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