NOTE: UPDATED For REVIT 2024 refer Below
In this video, you will learn how to split structural columns by levels without using the out-of-the-box command or manually but using Dynamo!!
[Note: Some changes in the dynamo Script and Python Script(Use below One). Also, refer to the image below]
Python Script:[updated for Revit 2024]
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript import Geometry as geom
clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.Elements)
clr.ImportExtensions(Revit.GeometryConversion)
clr.AddReference("RevitAPI")
from Autodesk.Revit.DB import *
# Convert to list if not list...
def tolist(obj1):
if hasattr(obj1,"__iter__"): return obj1
else: return [obj1]
# Gets the centreline of the column...
def GetColumnCentreline(e):
crv = None
fs = e.Symbol
fm = fs.Family
if not fm.GetType() == DirectShape:
if not fm.IsInPlace:
if e.IsSlantedColumn:
try:
crv = e.Location.Curve.ToProtoType()
except:
return
else:
loc = e.Location.Point.ToPoint()
bLev = (e.Document.GetElement(e.get_Parameter(BuiltInParameter.FAMILY_BASE_LEVEL_PARAM).AsElementId()).Elevation + e.get_Parameter(BuiltInParameter.FAMILY_BASE_LEVEL_OFFSET_PARAM).AsDouble()) * ft2mm
tLev = (e.Document.GetElement(e.get_Parameter(BuiltInParameter.FAMILY_TOP_LEVEL_PARAM).AsElementId()).Elevation + e.get_Parameter(BuiltInParameter.FAMILY_TOP_LEVEL_OFFSET_PARAM).AsDouble()) * ft2mm
crv = geom.Line.ByStartPointEndPoint(geom.Point.ByCoordinates(loc.X,loc.Y,bLev), geom.Point.ByCoordinates(loc.X,loc.Y,tLev))
return crv
# Convert Level to DS Plane...
def LevelToPlane(l):
pt = geom.Point.ByCoordinates(0,0,round(l.Elevation * ft2mm,0)+offset)
n = geom.Vector.ZAxis()
return geom.Plane.ByOriginNormal(pt,n)
# Get the nearest Level above in list of Levels to gien Elevation...
def NearestLevelAbove(elev,lvls):
lvlAbv = None
for l in lvls:
if round(l.Elevation*ft2mm,0) > elev:
lvlAbv = l
break
return lvlAbv
# Get the nearest Level in list of Levels to gien Elevation...
def NearestLevel(elev, lvls):
return min(lvls, key=lambda x:abs(round(x.Elevation*ft2mm,0)-elev))
# Calculates the location to split column with parameterised column length (between 0 & 1)...
def CalculateSplitParameter(col,lvls):
# Switch out for mathematical method to speed up computation...
# abs(NewColBaseElevation-LevelAboveElevation)/NewCol length should give split parameter...
if col:
crv = GetColumnCentreline(col)
elev = round(crv.StartPoint.Z,0)
l = NearestLevelAbove(elev,lvls)
x = geom.Geometry.Intersect(crv,LevelToPlane(l))
if x:
x = x[0]
return geom.Curve.ParameterAtPoint(crv,x)
return None
# IN Variables...
run = tolist(IN[0])[0]
columns = tolist(UnwrapElement(IN[1]))
lvls = tolist(UnwrapElement(IN[2]))
offset = 0
if IN[3]:
offset = tolist(IN[3])[0]
# OUT Variables...
outList = []
# Main Body...
if run:
ft2mm = 304.8
lvls = sorted(lvls, key=lambda x: x.Elevation)
# Start Transaction to allow for Document modification...
TransactionManager.Instance.EnsureInTransaction(doc)
for c in columns:
# Ensure only Structural Columns are used (modify if Arch Columns category is required)
if c.Category.Name == Category.GetCategory(doc,BuiltInCategory.OST_StructuralColumns).Name:
arr = []
arr.append(c)
newCol = None
crv = GetColumnCentreline(c)
bLvlIndex = lvls.index(NearestLevel(crv.StartPoint.Z,lvls))
tLvlIndex = lvls.index(NearestLevel(crv.EndPoint.Z,lvls))
i = bLvlIndex
while i <= tLvlIndex:
try:
if not newCol:
p = CalculateSplitParameter(c,lvls)
newCol = doc.GetElement(c.Split(p))
arr.append(newCol)
else:
p = CalculateSplitParameter(newCol,lvls)
newCol = doc.GetElement(newCol.Split(p))
arr.append(newCol)
except Exception as ex:
arr.append(str(ex))
i = i+1
outList.append(arr)
else:
outList.append("Element is not of Category Structural Column")
TransactionManager.Instance.TransactionTaskDone()
OUT = outList
else:
OUT = "Please set Run to True"