I made a button to create linear dimensions from parallel elements. It technically works, but the created dimensions are not visible in any view. RevitLookup shows a BoundingBox and a Total Length parameter of 0. The dimension’s Line property shows a reasonable Origin and Direction. What am I missing?
You can paste this into RevitPythonShell and it should run.
from Autodesk.Revit.DB import (
Transaction, ReferenceArray, Reference,
Line, XYZ, Options, ElementId,
Dimension, Grid,
)
from Autodesk.Revit.UI.Selection import ObjectType, ISelectionFilter
from pyrevit import HOST_APP, forms, script
from System.Collections.Generic import List
class Parallel(ISelectionFilter):
def __init__(self, element):
if hasattr(element, 'Normal'):
self.Normal = element.Normal
elif hasattr(element, 'Curve'):
self.Normal = element.Curve.Direction
elif hasattr(element, 'Location'):
self.Normal = element.Location.Curve.Direction
else:
raise ValueError('Element does not have known direction attribute')
def AllowElement(self, element):
if isinstance(element, Dimension):
return False
if hasattr(element, 'Normal'):
if element.Normal.CrossProduct(self.Normal).IsAlmostEqualTo(XYZ.Zero):
return True
else:
return False
elif hasattr(element, 'Curve'):
return element.Curve.Direction.CrossProduct(self.Normal).IsAlmostEqualTo(XYZ.Zero)
elif hasattr(element, 'Location'):
return element.Location.Curve.Direction.CrossProduct(self.Normal).IsAlmostEqualTo(XYZ.Zero)
return False
def AllowReference(self, reference, point):
return False
# projection of u onto v
def project(u, v):
return v.Multiply(u.DotProduct(v) / v.DotProduct(v))
def reject(u, v):
return u.Subtract(project(u, v))
def get_curve(element):
if hasattr(element, 'Curve'):
return element.Curve
elif hasattr(element, 'Location'):
return element.Location.Curve
else:
raise ValueError('Element does not have known direction attribute')
uidoc = HOST_APP.uiapp.ActiveUIDocument
doc = uidoc.Document
sel = uidoc.Selection
base_ref = sel.PickObject(ObjectType.Element, 'Select first element to dimension')
base_element = doc.GetElement(base_ref)
try:
refs = sel.PickObjects(ObjectType.Element, Parallel(base_element), 'Select elements to dimension', List[Reference]([base_ref]))
except Exception as e:
print(e)
script.exit()
if len(refs) < 2:
forms.alert('Please select at least two elements.')
script.exit()
elements = [(x, doc.GetElement(x)) for x in refs]
dimension_point = sel.PickPoint('Select where to place the dimensions')
view_normal = uidoc.ActiveView.UpDirection.CrossProduct(uidoc.ActiveView.RightDirection)
first_curve = get_curve(doc.GetElement(refs[0]))
r1 = reject(dimension_point.Subtract(first_curve.Origin), first_curve.Direction)
rejection = reject(r1, view_normal)
# get line along which to place dimensions
# hack to flatten into current view
# TODO: fix this so it works for elevations
z = uidoc.ActiveView.SketchPlane.GetPlane().Origin.Z
pt = XYZ(dimension_point.X, dimension_point.Y, z)
rejection = XYZ(rejection.X, rejection.Y, 0)
the_line = Line.CreateUnbound(pt, rejection)
# build reference array of elements to dimension
ref_array = ReferenceArray()
for ref, element in elements:
try:
if isinstance(element, Grid):
ref_array.Append(ref)
else:
options = Options()
options.ComputeReferences = True
options.IncludeNonVisibleObjects = True
options.View = uidoc.ActiveView
geometry = element.get_Geometry(options)
geometry_instance = next(iter(geometry))
instance_geometry = geometry_instance.GetInstanceGeometry()
ig_list = list(instance_geometry)
ig_lines = [x for x in ig_list if isinstance(x, Line)]
ref_array.Append(ig_lines[0].Reference)
# ig = next(iter(ig_list))
# symbol_geometry = list(ig.SymbolGeometry)
# symbol_lines = [x for x in symbol_geometry if isinstance(x, Line)]
# symbol_line = next(iter(symbol_lines))
# ref_array.Append(symbol_line)
except:
print('error finding ', ref)
ref_array.Append(ref)
with Transaction(doc, 'Create dimensions') as t:
t.Start()
the_dimension = doc.Create.NewDimension(uidoc.ActiveView, the_line, ref_array)
t.Commit()
sel.SetElementIds(List[ElementId]([the_dimension.Id]))
print(the_dimension.Id)