I’ve been searching through the forum for a way to extract ceiling grid lines, but I haven’t found a clear solution yet.
I’m currently working in Revit 2023. My ceiling has two grid patterns: one above the structure and one below it. What I need is to retrieve both sets of grid lines and then align the top grid lines to match the bottom ones.
I tried the Sparrow package, but it only returns the bottom grid lines. From what I understand, starting in Revit 2025 it’s possible to access ceiling grid lines through the Revit API (and via the Rhythm package), but these also seem to return only the bottom grid lines.
So my questions are:
Is it possible in Revit 2023 to access and align the top ceiling grid lines to the bottom ones using Dynamo or any workaround?
If not, does the Revit 2025 API actually allow access to both top and bottom ceiling grid lines, and has anyone successfully aligned them?
Any insight or example would be greatly appreciated. I attached my compund ceiling.
yes genius loci have some nodes for get reference from grid lines and for dimension, it was that method i use before it comes with api for split ceiling in patterns…know it was dirty but works
PS sparrow have some nodes as well for pattern lines…but it isnt so stable…IMO and doesnt work if perimeter curves is curved
Hi Jacob. In the image im showing the top face of the ceiling and the bottom face. Both of them have the same finish pattern but I move the grids on the top one. I want to know a way to align the top grid lines to the bottom, to make them equal.
I understand that I have to get the grid references to make an alignment but how I get those refereces?
Hi Sovitek. Yes thats the problem. But projecting them I only get the lines, not the references to align, maybe there’s something i dont see. I think I have to try Genius Loci nodes. I will try later, thanks.
So… Is one of those view a plan view looking down at the ceiling and the other a ceiling plan view looking up at the ceiling? They’re both named “level 1” so I don’t know which view you’re in.
yeah give it try, and you could try just created projected curves as model/detail curves and dimension/reference them and delete in same run…hahahh…not at dyn in the moment, so just a guess you know all that xmas run
Well I could get the bottom ceiling grid references using Compound Pattern Reference, but not the top grid references.
As a workaround, I manually create a dimensions between top grid lines and extract their references. Then, using Dimension ByReferences, I create a dimension between the top grid reference and the bottom grid reference.
Even with both references and the resulting dimension, I don’t know how to align or move the top grid to match the bottom grid. I also tried setting the generated dimension value to zero, but couldn’t make it work.
I’ve attached the Dynamo file, Revit file, and images. Any ideas would be appreciated.
Yeah as mention, last time i play around with it i could only get ref from bottom, not at dynamo today and probably first next week, and i can take a look if you not have find a solution, but no guarantee i can do it
Grabs the top and bottom faces and then pulls the hatch line references
Based on the Genius Loci nodes with some clean ups and the Building Coder link I posted above
import clr
clr.AddReference("RevitAPI")
from Autodesk.Revit.DB import *
clr.AddReference("RevitServices")
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
def get_grid_count(item, face_ref):
face_geom = item.GetGeometryObjectFromReference(face_ref)
material = doc.GetElement(face_geom.MaterialElementId)
pattern_type = doc.GetElement(material.SurfaceForegroundPatternId)
pattern = pattern_type.GetFillPattern()
return pattern.GridCount
def get_stable_ref(face_ref, grid_count):
stable_ref = face_ref.ConvertToStableRepresentation(doc)
ref_strings = [
f"{stable_ref}/{a + 2 * b * grid_count}" for a in range(1, 3) for b in range(2)
]
return [
Reference.ParseFromStableRepresentation(doc, ref_string)
for ref_string in ref_strings
]
elements = UnwrapElement(IN[0]) if isinstance(IN[0], list) else [UnwrapElement(IN[0])]
align_to_bottom = IN[1]
if not align_to_bottom:
align_to_bottom = True # For later use
for item in elements:
top_face = next(iter(HostObjectUtils.GetTopFaces(item)))
bottom_face = next(iter(HostObjectUtils.GetBottomFaces(item)))
top_grid_count = get_grid_count(item, top_face)
bottom_grid_count = get_grid_count(item, bottom_face)
top_refs = get_stable_ref(top_face, top_grid_count)
bottom_refs = get_stable_ref(bottom_face, bottom_grid_count)
TransactionManager.Instance.EnsureInTransaction(doc)
# Do alignment in here
TransactionManager.Instance.TransactionTaskDone()
OUT = top_refs, bottom_refs
I’m able to get both references. In the script I create two ref planes in X and Y direction to align their references (rpRef) to the top grid references (top_refs). Then align the rpRef to the bottom_refs.
This works but it deppends of how the ceiling is drawn I think. I have to get the direction of the top_refs and bottom_refs to classify them and align the correct rpRef.
I attached what Im trying (it didn’t worked). How I can separate the top_refs and bottom_refs in X and Y to have correct alignment?
import clr
# ----------------------------
# Revit API
# ----------------------------
clr.AddReference("RevitAPI")
from Autodesk.Revit.DB import *
# ----------------------------
# Revit Services
# ----------------------------
clr.AddReference("RevitServices")
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
view = doc.ActiveView
# ------------------------------------------------
# Get grid count from surface pattern
# ------------------------------------------------
def get_grid_count(item, face_ref):
face_geom = item.GetGeometryObjectFromReference(face_ref)
material = doc.GetElement(face_geom.MaterialElementId)
pattern_type = doc.GetElement(material.SurfaceForegroundPatternId)
pattern = pattern_type.GetFillPattern()
return pattern.GridCount
# ------------------------------------------------
# Hatch references (stable references)
# ------------------------------------------------
def get_pattern_refs(face_ref, grid_count):
stable = face_ref.ConvertToStableRepresentation(doc)
refs = []
for b in range(grid_count):
for a in range(1, 3):
idx = a + 2 * b * grid_count
refs.append(
Reference.ParseFromStableRepresentation(
doc, stable + "/" + str(idx)
)
)
return refs
# ------------------------------------------------
# Create a valid vertical ReferencePlane
# ------------------------------------------------
def create_vertical_refplane(origin, direction, view):
dir_xy = XYZ(direction.X, direction.Y, 0).Normalize()
# Horizontal base line
p0 = origin
p1 = origin.Add(dir_xy.Multiply(10.0))
# Vertical cut vector
cutVec = XYZ.BasisZ
return doc.Create.NewReferencePlane(p0, p1, cutVec, view)
# ------------------------------------------------
# INPUT
# ------------------------------------------------
elements = UnwrapElement(IN[0]) if isinstance(IN[0], list) else [UnwrapElement(IN[0])]
# ------------------------------------------------
# MAIN
# ------------------------------------------------
TransactionManager.Instance.EnsureInTransaction(doc)
created_planes = []
for item in elements:
# Faces
top_face_ref = next(iter(HostObjectUtils.GetTopFaces(item)))
bottom_face_ref = next(iter(HostObjectUtils.GetBottomFaces(item)))
top_face = item.GetGeometryObjectFromReference(top_face_ref)
# Pattern
grid_count = get_grid_count(item, top_face_ref)
top_refs = get_pattern_refs(top_face_ref, grid_count)
bottom_refs = get_pattern_refs(bottom_face_ref, grid_count)
origin = top_face.Origin
# =================================================
# X DIRECTION
# =================================================
refs_top_X = top_refs[0:2]
refs_bot_X = bottom_refs[0:2]
rp_X = create_vertical_refplane(origin, XYZ.BasisX, view)
rpRef_X = rp_X.GetReference()
for t_ref, b_ref in zip(refs_top_X, refs_bot_X):
doc.Create.NewAlignment(view, t_ref, rpRef_X)
doc.Create.NewAlignment(view, b_ref, rpRef_X)
created_planes.append(rp_X)
# =================================================
# Y DIRECTION (cross pattern)
# =================================================
if grid_count > 1:
refs_top_Y = top_refs[2:4]
refs_bot_Y = bottom_refs[2:4]
rp_Y = create_vertical_refplane(origin, XYZ.BasisY, view)
rpRef_Y = rp_Y.GetReference()
for t_ref, b_ref in zip(refs_top_Y, refs_bot_Y):
doc.Create.NewAlignment(view, t_ref, rpRef_Y)
doc.Create.NewAlignment(view, b_ref, rpRef_Y)
created_planes.append(rp_Y)
TransactionManager.Instance.TransactionTaskDone()
# ------------------------------------------------
# OUTPUT
# ------------------------------------------------
OUT = created_planes