Hi,
Is it possible to check if a wall is supported by a roof, floor, beam, another wall or structure from a linked model? Sometimes there will be a tolerance gap of 15-20mm between the wall and supporting structure.
You could do a check where you get the underside level of the wall, then take the gap away. (A minus B equals new level)
Then do a check for the slab level and see it it matches.
This will probably be a less computation intense calculation than trying to modify geometry and clashing them etc
Agree with @Brendan_Cassidy - geometry tends to be heavy and inconsistent. But as a general suggestion, Iâd stay away from bounding boxes for anything other than relative location and closeness. Youâre in a pretty old version of Dynamo by the looks of it, where bounding boxes are globally aligned, so anything outside of 90 degree increments is going to be skewed. Newer versions have an option for locally aligned bounding boxes.
Hi @Nick_Boyts, if there is a âfloating wallâ, will the base level method identify the wall as being supported even though it isnât?
Can the bounding box be extended?
You seem to be doing something very similar to this thread, just in the opposite direction. See my response there for how you could identify âintersectionsâ (you can include your tolerance) before you double check that floors actually exist at those locations.
Your case might actually be a bit simpler, because you can group walls and floors by level and then pull the wall centerlines onto the floor surface for intersections. If the walls donât intersect or they were located outside your tolerance, they arenât supported.
Hi @Nick_Boyts Iâve filtered the bottom face of the wall and the top face of the floor and used Surface.Thicken node for the tolerance. But the result is false? Iâm not sure what Iâm doing wrong.
Is Wall Supported script.dyn (54.4 KB)
I had some code sitting in my library that I have tweaked for you to review @_INN
This may assist in your workflow and integrating combined check cases can simplify things. This was only prepared for non-slope edited Floorâs and single âbottom-faceâ wall configurations.
In any case, hope this sparks some thoughts. ![]()
WallBaseSupportCheckWithReport.dyn (20.0 KB)
Hi @Ewan_Opie, Thank you for sending this. Iâve tested the script and it is incorrectly flagging the walls as unsupported. Iâve attached the model for your review.
Is Wall Supported R25.rvt (2.5 MB)
Itâs nearly impossible to follow a graph without knowing whatâs passing through it. Can you repost this with all the node preview bubbles pinned? What version of Revit/Dynamo are you in? Are you testing with a ârealâ project or a small test file? If you can share a small test file with instances that are not working correctly, we can look into the specific case.
Hi @Nick_Boyts, Updated image below.
Upgraded to Revit 26. Model test file attached.
Is Wall Supported - Test File.rvt (2.5 MB)
Your list structures are a bit of a mess. You have a lot of nested lists in nested lists where you donât need them. Youâre also flattening where it doesnât make sense. This is causing you to end up with mismatch list structures when you go to filter surfaces for intersections. For a start, Element.Faces already gives you surfaces - thereâs no need to convert to topological faces and then back to surfaces with extra list dimensions. Youâre also thickening all the wall surfaces instead of just the bottom face. This is giving you one âbottomâ for each surface of the wall - not what you want. Once you have the directionally appropriate surface from each element, you can fully flatten your lists (since you have basic wall and floor geometry only). Try all that and see where it gets you.
EDIT: The other thing I noticed was that youâre only thickening the surface by 20mm when your Wall is offset by 15mm. The Surface.Thicken node extrudes the surface in both directions by equal amounts. Meaning your bottom of wall only dropped 10mm.
Hereâs a cleaned up version that works.
Is Wall Supported script.dyn (42.3 KB)
Ah, have a look at this variation of the code from earlier. If that doesnât work keep persevering, youâll get there ![]()
import clr
clr.AddReference('RevitAPI')
from Autodesk.Revit.DB import *
from Autodesk.Revit.DB import XYZ
clr.AddReference('RevitNodes')
import Revit
clr.ImportExtensions(Revit.GeometryConversion)
# inputs
walls = IN[0] if isinstance(IN[0], list) else [IN[0]]
floor = IN[1]
z_tol_mm = IN[2]
threshold = IN[3]
# revit internal units are decimal feet
z_tol_ft = z_tol_mm / 304.8
def get_bottom_face(wall):
rw = wall.InternalElement
opt = Options()
opt.ComputeReferences = True
opt.DetailLevel = ViewDetailLevel.Fine
for obj in rw.get_Geometry(opt):
solid = None
if isinstance(obj, GeometryInstance):
for o in obj.GetInstanceGeometry():
if isinstance(o, Solid) and o.Volume > 0:
solid = o
break
elif isinstance(obj, Solid) and obj.Volume > 0:
solid = obj
if solid is None:
continue
for face in solid.Faces:
# bottom face normal points straight down
if isinstance(face, PlanarFace) and face.FaceNormal.Z < -0.99:
return face
return None
def get_top_face(floor):
rf = floor.InternalElement
opt = Options()
opt.ComputeReferences = True
opt.DetailLevel = ViewDetailLevel.Fine
rf.get_Geometry(opt)
refs = HostObjectUtils.GetTopFaces(rf)
if refs:
return rf.GetGeometryObjectFromReference(refs[0])
return None
def face_boundary(face):
# just want the outer loop
loops = face.GetEdgesAsCurveLoops()
if not loops:
return []
return [c.GetEndPoint(0) for c in loops[0]]
def flatten_to_z(pts, z):
return [XYZ(p.X, p.Y, z) for p in pts]
def poly_area(pts):
# shoelace via cross product
if len(pts) < 3:
return 0
total = XYZ(0, 0, 0)
o = pts[0]
for i in range(1, len(pts) - 1):
v1 = pts[i].Subtract(o)
v2 = pts[i+1].Subtract(o)
c = v1.CrossProduct(v2)
total = XYZ(total.X + c.X, total.Y + c.Y, total.Z + c.Z)
return total.GetLength() / 2.0
def clip_polygon(subject, clip):
# Sutherland-Hodgman - clips subject poly against clip poly
# both must be at the same Z
def inside(p, a, b):
return (b.X - a.X) * (p.Y - a.Y) - (b.Y - a.Y) * (p.X - a.X) >= 0
def intersect_edges(a, b, c, d):
A1, B1 = b.Y - a.Y, a.X - b.X
C1 = A1 * a.X + B1 * a.Y
A2, B2 = d.Y - c.Y, c.X - d.X
C2 = A2 * c.X + B2 * c.Y
det = A1 * B2 - A2 * B1
if abs(det) < 1e-10:
return a
return XYZ((B2*C1 - B1*C2)/det, (A1*C2 - A2*C1)/det, a.Z)
out = list(subject)
for i in range(len(clip)):
if not out:
break
inp = list(out)
out = []
a, b = clip[i], clip[(i+1) % len(clip)]
for j in range(len(inp)):
cur, prev = inp[j], inp[j-1]
if inside(cur, a, b):
if not inside(prev, a, b):
out.append(intersect_edges(prev, cur, a, b))
out.append(cur)
elif inside(prev, a, b):
out.append(intersect_edges(prev, cur, a, b))
return out
results = []
floor_face = get_top_face(floor)
if floor_face is None:
OUT = "couldn't get floor top face"
else:
fz = floor_face.Origin.Z
floor_pts = flatten_to_z(face_boundary(floor_face), fz)
for wall in walls:
try:
wface = get_bottom_face(wall)
if wface is None:
results.append({
"Wall": str(wall),
"Within Z Tol": False,
"Wall Base Z (m)": None,
"Floor Top Z (m)": round(fz * 0.3048, 4),
"Z Distance (mm)": None,
"Wall Base Area (m2)": None,
"Overlap Area (m2)": None,
"Overlap %": None,
"Is Supported": False,
"Note": "no bottom face found",
})
continue
wz = wface.Origin.Z
zdist = wz - fz
in_tol = 0 <= zdist <= z_tol_ft
if not in_tol:
results.append({
"Wall": str(wall),
"Within Z Tol": False,
"Wall Base Z (m)": round(wz * 0.3048, 4),
"Floor Top Z (m)": round(fz * 0.3048, 4),
"Z Distance (mm)": round(zdist * 304.8, 2),
"Wall Base Area (m2)": None,
"Overlap Area (m2)": None,
"Overlap %": None,
"Is Supported": False,
"Note": "wall base outside z tolerance",
})
continue
# project wall base down to floor z and clip against floor boundary
wpts = flatten_to_z(face_boundary(wface), fz)
wall_area = poly_area(wpts)
clipped = clip_polygon(wpts, floor_pts)
overlap = poly_area(clipped) if len(clipped) >= 3 else 0
pct = overlap / wall_area if wall_area > 0 else 0
supported = pct >= threshold
results.append({
"Wall": str(wall),
"Within Z Tol": True,
"Wall Base Z (m)": round(wz * 0.3048, 4),
"Floor Top Z (m)": round(fz * 0.3048, 4),
"Z Distance (mm)": round(zdist * 304.8, 2),
"Wall Base Area (m2)": round(wall_area * 0.092903, 4),
"Overlap Area (m2)": round(overlap * 0.092903, 4),
"Overlap %": round(pct * 100, 2),
"Is Supported": supported,
"Note": "OK" if supported else "insufficient overlap",
})
except Exception as e:
results.append({"Wall": str(wall), "Is Supported": False, "Error": str(e)})
OUT = results







