Structural column dimensions

I created a script to place structural column face–to–nearest grid dimensions. It works fine for rectangular columns in the X and Y directions, but it’s not working for rotated columns or grids. Please help me.

-- coding: utf-8 --
import clr
clr.AddReference(‘RevitAPI’)
clr.AddReference(‘RevitAPIUI’)
clr.AddReference(‘System.Windows.Forms’)
clr.AddReference(‘System.Drawing’)

from Autodesk.Revit.DB import *
from Autodesk.Revit.UI import *
from System.Collections.Generic import List
from System.Windows.Forms import Form, Label, TextBox, Button, DialogResult, FormStartPosition
from System.Drawing import Point, Size

Show offset popup

class OffsetInputForm(Form):
def init(self):
self.Text = “Column to Grid Offset”
self.Size = Size(250, 130)
self.StartPosition = FormStartPosition.CenterScreen

    self.label = Label()
    self.label.Text = "Offset in mm:"
    self.label.Location = Point(10, 20)
    self.label.Size = Size(100, 20)
    self.Controls.Add(self.label)

    self.textbox = TextBox()
    self.textbox.Text = "500"
    self.textbox.Location = Point(110, 18)
    self.textbox.Size = Size(100, 20)
    self.Controls.Add(self.textbox)

    self.ok_button = Button()
    self.ok_button.Text = "OK"
    self.ok_button.Location = Point(40, 60)
    self.ok_button.Click += self.on_ok
    self.Controls.Add(self.ok_button)

    self.cancel_button = Button()
    self.cancel_button.Text = "Cancel"
    self.cancel_button.Location = Point(120, 60)
    self.cancel_button.Click += self.on_cancel
    self.Controls.Add(self.cancel_button)

    self.Result = None

def on_ok(self, sender, args):
    self.Result = self.textbox.Text
    self.DialogResult = DialogResult.OK
    self.Close()

def on_cancel(self, sender, args):
    self.DialogResult = DialogResult.Cancel
    self.Close()

Show dialog and get offset

form = OffsetInputForm()
if form.ShowDialog() != DialogResult.OK:
raise Exception(“User cancelled offset input.”)

try:
offset_mm = float(form.Result)
except:
TaskDialog.Show(“Invalid Input”, “Please enter a numeric offset.”)
raise

offset_ft = offset_mm / 304.8
short_tol = 0.01

doc = revit.ActiveUIDocument.Document
view = doc.ActiveView

def get_visible_columns():
return FilteredElementCollector(doc, view.Id)
.OfCategory(BuiltInCategory.OST_StructuralColumns)
.WhereElementIsNotElementType().ToElements()

def get_visible_grids():
return FilteredElementCollector(doc, view.Id)
.OfCategory(BuiltInCategory.OST_Grids)
.WhereElementIsNotElementType().ToElements()

def is_inclined_column_geometry(column):
try:
options = Options()
options.IncludeNonVisibleObjects = True
options.ComputeReferences = False
geometry = column.get_Geometry(options)
for geo in geometry:
if isinstance(geo, Solid):
for edge in geo.Edges:
p1 = edge.AsCurve().GetEndPoint(0)
p2 = edge.AsCurve().GetEndPoint(1)
direction = (p2 - p1).Normalize()
if abs(direction.Z) > 0.1 and abs(direction.Z) < 0.9:
return True
except:
pass
return False

def create_dimension_with_cut_paste(view, dim_line, ref_array):
dim = doc.Create.NewDimension(view, dim_line, ref_array)
dim_ids = ListElementId
ElementTransformUtils.CopyElements(doc, dim_ids, XYZ(0, 0, 0))
doc.Delete(dim.Id)

def create_perpendicular_dimension(view, face_ref, face_normal, grid_ref, base_point, offset_ft):
try:
face_normal = face_normal.Normalize()
up = XYZ.BasisZ
dim_dir = face_normal.CrossProduct(up).Normalize()
offset_point = base_point + face_normal.Multiply(offset_ft)
p1 = offset_point - dim_dir.Multiply(5)
p2 = offset_point + dim_dir.Multiply(5)

    if p1.DistanceTo(p2) > short_tol:
        dim_line = Line.CreateBound(p1, p2)
        ref_array = ReferenceArray()
        ref_array.Append(grid_ref)
        ref_array.Append(face_ref)
        create_dimension_with_cut_paste(view, dim_line, ref_array)
except Exception as e:
    print("⛔ Inclined dimension error: {}".format(e))

Start transaction

t = Transaction(doc, “Column to Grid Dimensions”)
t.Start()

try:
columns = get_visible_columns()
grids = get_visible_grids()

for column in columns:
    location = column.Location
    if not isinstance(location, LocationPoint):
        continue
    col_point = location.Point
    bbox = column.get_BoundingBox(view)
    if not bbox:
        continue

    is_inclined = is_inclined_column_geometry(column)

    options = Options()
    options.ComputeReferences = True
    options.IncludeNonVisibleObjects = True
    geo_elem = column.get_Geometry(options)

    face_refs_x = []
    face_refs_y = []

    solid = None
    for g in geo_elem:
        if isinstance(g, Solid) and g.Faces.Size > 0:
            solid = g
            break
        elif isinstance(g, GeometryInstance):
            for sg in g.GetInstanceGeometry():
                if isinstance(sg, Solid) and sg.Faces.Size > 0:
                    solid = sg
                    break
    if not solid:
        continue

    for face in solid.Faces:
        if isinstance(face, PlanarFace):
            normal = face.FaceNormal
            if abs(normal.X) > 0.9:
                face_refs_x.append((face.Reference, normal))
            elif abs(normal.Y) > 0.9:
                face_refs_y.append((face.Reference, normal))

    closest_grid_x, min_dx = None, float('inf')
    closest_grid_y, min_dy = None, float('inf')

    for grid in grids:
        curve = grid.Curve
        if not curve:
            continue
        vec = curve.GetEndPoint(1) - curve.GetEndPoint(0)
        proj = curve.Project(col_point)
        if not proj:
            continue

        if abs(vec.X) > abs(vec.Y):  # horizontal grid
            dist = abs(proj.XYZPoint.Y - col_point.Y)
            if dist < min_dy:
                min_dy = dist
                closest_grid_y = (grid, proj.XYZPoint)
        else:  # vertical grid
            dist = abs(proj.XYZPoint.X - col_point.X)
            if dist < min_dx:
                min_dx = dist
                closest_grid_x = (grid, proj.XYZPoint)

    if face_refs_x and closest_grid_x:
        if is_inclined:
            create_perpendicular_dimension(view, face_refs_x[0][0], face_refs_x[0][1],
                                           Reference(closest_grid_x[0]), closest_grid_x[1], offset_ft)
        else:
            try:
                ref_array = ReferenceArray()
                ref_array.Append(Reference(closest_grid_x[0]))
                ref_array.Append(face_refs_x[0][0])
                y = bbox.Min.Y - offset_ft
                dim_line = Line.CreateBound(XYZ(bbox.Min.X, y, 0), XYZ(bbox.Max.X, y, 0))
                if dim_line.Length > short_tol:
                    create_dimension_with_cut_paste(view, dim_line, ref_array)
            except Exception as e:
                print("⛔ X-dim error: {}".format(e))

    if face_refs_y and closest_grid_y:
        if is_inclined:
            create_perpendicular_dimension(view, face_refs_y[0][0], face_refs_y[0][1],
                                           Reference(closest_grid_y[0]), closest_grid_y[1], offset_ft)
        else:
            try:
                ref_array = ReferenceArray()
                ref_array.Append(Reference(closest_grid_y[0]))
                ref_array.Append(face_refs_y[0][0])
                x = bbox.Min.X - offset_ft
                dim_line = Line.CreateBound(XYZ(x, bbox.Min.Y, 0), XYZ(x, bbox.Max.Y, 0))
                if dim_line.Length > short_tol:
                    create_dimension_with_cut_paste(view, dim_line, ref_array)
            except Exception as e:
                print("⛔ Y-dim error: {}".format(e))

t.Commit()

except Exception as e:
t.RollBack()
TaskDialog.Show(“Error”, “Failed to create column-grid dimensions:\n{}”.format(str(e)))