Hi everyone,
My goal is to create ceilings from walls by projecting their bases onto the XY plane, joining the surfaces, and subtracting them from a large rectangle to get the inner surfaces (discarding the largest outer surface). This method works, but when windows are added, multiple base surfaces per wall are generated. There’s overlap in the window areas, and the script fails for walls with windows.
Apparently, Surface.ByUnion joins them,
but Explode fails. I’m not sure whether the problem is caused by the overlap or the rectangle subtraction method. Is there a way to ignore the surfaces created by windows while keeping those from doors? Or maybe there´s another method to get the inner curves.
Thanks!
Not sure what the end goal is - my gut tells me you’re attempting to put a ceiling together that fills the entire room. If so you’ll likely get better performance by using the geometry which already exists - the boundaries of the rooms.
All ElementsOfCategory
(Room) > Room.Boundaries
(finish face) > PolyCurve.ByGroupedCurves
> start the ceiling creation from the curve loops.
If you don’t have rooms you can leverage the plan topology class in the Revit API, but that will require stepping into scripting or coding.
If you must stick with geometry (I’d avoid it), then you likely need to revise the gathering method. I can’t tell as you haven’t shown your geometry selection method, but I’m guessing you’re filtering the bottom surface by pulling the surfaces which have a maximum point that aligns tot he wall’s minimum point, or otherwise pulling in just the bottom face of the wall. Instead I’d do something like this:
From your wall selection > Element.Solids
> List.Flatten
> Solid.ByUnion
> Geometry.Explode
> Face.NormalAtParameter
(0.5,0.5) > Vector.Z
> ~=
-1 > List.FilterByBoolMask
where the list is the result of the geometry.explode and the mas is the results of the almost equal node > Surface.PerimeterCurves
> Curve.PullOntoPlane
> PolyCurve.ByGroupedCurves
> Surface.ByPatch
> Surface.ByUnion > Surface.PerimeterCurves
. You’ll need to filter out the exterior loop, but all the interior loops will be for a ceiling excepting any walls forming a mechanical chase (I don’t see any in your imagery).
1 Like
Hello, have you ever tried using the room boundaries?
1 Like
Hi Jacob, I know this can be done with rooms, but sometimes I work on projects where they aren’t modeled or are created at the very end. I know there are add-ins that can do this quickly using rooms, such as PyArchitect.
I don’t have much experience with Revit API coding yet, but it’s something I want to learn and improve on.
Also, I had previously tried with Solid.ByUnion, but I hadn’t thought of projecting onto the XY plane. I first obtained the base surfaces (from walls, windows, and doors), as shown in the previous image, and projected them onto the XY plane. Then I realized that Surface.ByUnion wasn’t properly merging them, because when I thickened the surfaces with Surface.Thicken, some grew upward and others downward.
So instead, I thickened them on both sides, joined the solids with Solid.ByUnion, and then intersected the result with the XY plane to get a single, perfectly unified surface. I discarded the exterior curve and also considered adding a mechanical chase to handle cases where curves are nested inside other curves.
Thanks for your suggestions—you gave me the idea I needed.
Hi Hayet, yes, I’ve also worked with rooms—it’s definitely much faster.
In this case, though, my goal is to do it through walls, since many times I don’t have the rooms available. When I do have them, I try to use add-ins, but thanks for sharing your workflow 
If that’s the case, now is a good time to learn as it will be both significantly faster and more reliable.
The class you need is this: Revit API 2026 Documentation, which in CPython (the default Python engine which ships with all supported Revit releases) is accessed on the document from something like doc.get_PlanTopology(lvl, phase)
. From there you can extract the circuit, and iterate over that to pull the room in the topology, or create one if it doesn’t exist yet. After that, pull the room boundaries, and you should be off to the races.
Certainly not a need for now - you can always come back to this - but worth knowing if you want to look into it now.
Best,
-jacob