Automate Revit Levels from Point Clouds using Dynamo

Hi,
I saw a video on Youtube in which the author talk about creating levels inside a project using the point clouds but the author did not go to anything inside the script or make a demo video of dynamo about that, so I want to ask if anyone knows about this topic can help me?

I attached a photo of dynamo player of this project.

My guess is the author takes all points and splits them into 100mm or so layers based on their z height, then counts the number of points per layer. They take the average amount per layer, and the maximum point count and pick a likely division in that range to indicate a likely level which would logically have a lot of points. Their sensitivity value probably increases the tolerance for this ‘clamping’ point.

Alternatively they may check for a layer that has at least one point in an XY grid in a layer and assume that a layer with that much coverage is likely a level.

The Sastrugi package has nodes for dealing with point clouds and their coordinates.

To handle large clouds it looks like the author also initially decimates/reduces the points to a manageable number. My personal trick to doing this is to round point values (xyz) to the nearest X where X is a point division then using text matching in an equivalent array of values, check which have matches in your cloud. Filter the matches and turn them back to points.

2 Likes

Thanks for your reply,

i’m starting with the Sastrugi Package to select the point cloud of the project but i have some problem with the 2nd script about Scope Box to just select the point cloud of the house.

Do you have any idea about that?


https://www.youtube.com/watch?v=7QgZW89f36k

Unfortunately I’m not overly familiar with point cloud API and sastrugi personally (I use Rhino and grasshopper for cloud processing). Hopefully someone else can assist further.

1 Like

Hi @toan-nghia.le
can you share this video?

You can get each plane from point cloud by using RANSAC method then create levels at each plane did you predict from point cloud.
As @GavinCrump refer you can use RANSAC method from Sastrugi package @Ewan_Opie

3 Likes

Thank you so much.

1 Like

Hi @RMohareb ,
you will find below the video that i mentionned on the top.

1 Like

@toan-nghia.le
Here is an example of the workflow @GavinCrump is describing, hopefully this is helpful in your endeavors. :wink:


# Load the Python Standard and DesignScript Libraries
import sys
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

import math

def indices(lst, element):
    result = []
    offset = -1
    while True:
        try:
            offset = lst.index(element, offset+1)
        except ValueError:
            return result
        result.append(offset)
        
pts = IN[0]
levelElevations = []

# Build a list of Z slice indices
zList = []
for p in pts:
	zList.append(p.Z)
# Lowest and Highest Z Values in cloud	
maxZ = int(math.floor(max(zList)))
minZ = int(math.floor(min(zList)))

# Slice the points based on their Z value into divisions (div) mm
sliceZ = []
div = 200
numSlice = int(math.floor((maxZ-minZ) / div))
ptSlices = []

for n in range(numSlice):
	slice = []
	zBottom = minZ+(div*n)
	zTop = zBottom+div
	pZList = []
	if len(pts) > 0:
		for p in pts:
			# If a point Z is in range of this slice add it to the slice list
			if p.Z > zBottom and p.Z < zTop:
				slice.append(p)
				pts.remove(p)
				pZList.append(p.Z)
	
	# Best fit plane through points (Floors will be horiz)
	planeNorm = Plane.ByBestFitThroughPoints(slice).Normal
	planeX = int(round(Vector.Normalized(planeNorm).X,1))
	planeY = int(round(Vector.Normalized(planeNorm).Y,1))
	planeZ = int(round(Vector.Normalized(planeNorm).Z,1))
	if planeX > -0.1 and planeX < 0.1 and planeY > -0.1 and planeY < 0.1:
		if planeZ > 0.9 or planeZ < -0.9:
			isHoriz = True
		else:
			isHoriz = False
	
	if isHoriz:
		# Determine the best Z to use for a level
		roundedZ = []
		tol2 = 10
		for pZ in pZList:
			roundedZ.append(round(pZ/tol2)*tol2)
		# Most frequent Z
		freq = max(set(roundedZ), key = roundedZ.count)
		i = roundedZ.index(freq)
		levelElevations.append(pZList[i])
		
	else:
		pass
		

OUT = levelElevations
	

PointCloudLevels.dyn (11.2 KB)

3 Likes

hi @Ewan_Opie
Many thanks for your help.

It gave me a lot of motivation to keep going.

When i try to pick point clouds in 3D view of Revit, i got a warning and i don’t know how to handle it, can you give me some advice? pls

Here is the photo of the warning.

This may be due to when you executed the Dynamo graph, try rotating the view slightly then ‘Refresh’ to run the graph again.

Alternatively, try using the Intersecting Element node and a Wall/Column/Generic Model Mass to collect the points.

2 Likes


Hello again,

Sorry to bother you again. I’ve been very busy with work lately so I just had time to try the solution you suggested, I tried it but still the same error occurs.

Hope you can give me some advice, i’m not sure where this error comes from my points cloud?

Thanks in advance.

Hi @toan-nghia.le
You should be using the Wall as the FilterElement, not the Pointcloud Instance.
Give that a try and see if it returns the Points.

2 Likes

Thank you so much for replying to me.
I tried the way you said by choosing the wall as the FilterElement but the result is the same. There’s always this error from Dynamo.
Do you have other ideas?


Are you able to send me some sample files to check your base data?
Then I may be able to deconstruct what the issue may be.

1 Like

Yes, can you give me your mail pls?

1 Like