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!!
Python Script:
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, ex: arr.append(ex.message) 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"