How to find empty spaces?


is this even resolvable? how can i detect “white spaces”. One Modelrule is that every “space” is coverd by construction or space(rooms)? Can i do that just a visual setting by hand?



1 Like

Think it will be a tough one, looking forward for good ideas here;)

Our client proves us via Solibri, it is part of his rulesettings. I try as good as possible to manage it in nativ inviroment.

Hmm, tough one, but wouldn’t the manual method you have shown above be more effective?

Here is my schematic idea for doing this, though, via dynamo.

  1. Get all the wall interior and exterior location lines.
  2. Find the intersection point between these location lines.
  3. Use the intersection points to create polycurves/polygons.
  4. Get the perimeter curves of all the rooms/spaces in view.
  5. Use the does.intersect node to determine if the polycurves/polygons in 3 intersect with the polygons/solids made from the room curves.

The polygons not intersecting with the room curves would be the empty spaces. You could then place rooms/spaces at the centre points of the non-intersecting polygons. :thinking::thinking:

Interesting thread here that might help. I’ve become interested in this. Haha.


Here is a way there probably coulds work in some cases…its dirty and should not run on big projects;)


Hacked this together during a call earlier; not entirely perfect but it should help you out. Added the room creation as ‘fixing the problem’ is often the end goal, but the points should ‘find the problem locations’ which is the end goal.

The big benefit here is that there is ZERO geometry effort beyond converting some UVs into points (quick and easy), as it utilizes the PlanTopology class of the Revit API - the non-geometric set of relationships formed by the ‘cells’ created by geometry at a given level. There are a LOT of uses for this class (identification of required separation for noise/fire/air/smell/contamination/whatnot as one example), so worth studying up on this class if it’s something you deal with and you’re into automation.

#### sets up the Dynamo Python environment ####
import clr #imports the common language runtime (CLR) into the Dynamo Python environment
clr.AddReference("RevitNodes") #adds the Revit Nodes library to the CLR
import Revit #imports the Revit class into the Dynamo Python environment
clr.ImportExtensions(Revit.Elements) #adds the RevitElements conversion library to the CLR
clr.ImportExtensions(Revit.GeometryConversion) #adds the Dynamo geometry converstion library to the CLR
clr.AddReference("RevitServices") #adds the Revit services library to the CLR
import RevitServices #imports the RevitServices clas to the Dynamo Python environment
from RevitServices.Persistence import DocumentManager #imports the DocumentManager class into the Dynamo Python environment
clr.AddReference("RevitAPI") #adds the RevitAPI to the CLR
import Autodesk #imports the Autodesk class into the Dynamo Python environment
from Autodesk.Revit.DB import  UV,XYZ,FilteredElementCollector,BuiltInCategory, PlanTopology #imports the needed parts from the Revit API into the Dynamo Python environment

#### preps the inputs and global variables ####
doc = DocumentManager.Instance.CurrentDBDocument #sets the doc varaible to the currently active document
phase = UnwrapElement(IN[0]) #sets the phase variable to the phase given in IN[0] from the Dynamo environment
lvls = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Levels).WhereElementIsNotElementType() #sets the lvls variable to the list of levels in the project via a filtered element collector
pointsNeedingRoom = [] #sets the pointsNeedingRoom varaible to an empty list

#### functional coding happens here ####
for lvl in lvls: #for every level in the lvls varible perform the offset lines below
	topo = doc.PlanTopology[lvl,phase] #gets the plantopology for the level at the phase given in the input
	circuits = topo.Circuits #gets the plan circuits (closed spaces) in the plan topology
	noRoom = [c for c in circuits if not c.IsRoomLocated] #gets the list of circuits with no room in them
	rmLocs = [c.GetPointInside() for c in noRoom] #gets a UV point in the empty circuit
	elev = lvl.Elevation #gets the elevation of the current level
	pnts = [XYZ(loc.U, loc.V, elev+0.1).ToPoint() for loc in rmLocs ] #builds a new Dynamo point using the deconstructed UV values and a slightly elevated level elevation
	pointsNeedingRoom.append(pnts) #appends the list of points into the pointsNeedignRoom variable

#### returns the results into the Dynamo environment
OUT = zip(lvls,pointsNeedingRoom) #sends a [level: points] pairing to the Dynamo environment


Hi Jacob. Awesome stuff.
Is this one of the newly exposed classes?

Nope - been around since at least 2017.