Create surface from point cloud

Hi, I am trying to fit a surface to a point cloud using Python scripting. Using the Patch command from the viewport I can successfully fit a surface to the point cloud (~500000 points, see below image).

I am trying to replicate the same in my Python script. This is the script I am using:

import rhinoscriptsyntax as rs
import Rhino.Geometry as rg
import csv

—Load point cloud from CSV—
def importPointCloudfromCSV():
filter = “CSV file (.csv)|.csv|.txt|All Files (.)|.*||”
filename = rs.OpenFileName(“Open Point File”, filter)
if not filename: return
cloud = rg.PointCloud()
with open(filename) as csvfile:
reader = csv.reader(csvfile)
for row in reader:
x = float(row[0])
y = float(row[1])
z = float(row[2])
cloud.Add(rg.Point3d(x,y,z)) #add to pointcloud
return cloud

#—Visualize point cloud in viewport—
def visualizePointCloud(cloud, color):
cloud_points = rs.PointCloudPoints(cloud)
for i in range(0,len(cloud_points)):
offset = rg.Point3d(0,0,0)
point_id = rs.AddPoint(cloud_points[i]+offset)
rs.ObjectColor(point_id, (color,0,0))

#—Fit surface to point cloud—
def fitSurface(cloud, u_degree=3, v_degree=3, tolerance=0.01):
surface = rs.AddPatch(cloud, u_degree, v_degree, tolerance)
print surface
return surface

if( name == “main” ):
cloud = importPointCloudfromCSV()
visualizePointCloud(cloud, int(0))
surface = fitSurface(cloud)

I import the point cloud from a csv file, and visualize it. This goes well. I use the AddPatch function (AddPatch) to fit the surface but it returns null. I tried multiple code variations and also with much simpler set of points, but the AddPatch function always returns null.

I also tried using a Brep.CreatePatch method (https://developer.rhino3d.com/api/rhinocommon/rhino.geometry.brep/createpatch) as an alternative solution, but with this one I did not succeed in providing the arguments in the right format, leading to errors such as:

Message: Error in IEnumeratorOfTWrapper.Current. Could not cast: Rhino.Geometry.GeometryBase in Rhino.Geometry.PointCloudItem

Can you help in finding a way to fit a surface to the point cloud using the AddPatch and/or Brep.CreatePatch command?

Thanks!

1 Like

Hi I normally use Delaunay Triangulation.

Someone has written a handy script for this:

Let’s see how it works for you.

Cheers

1 Like

Hi @Gregor_Ruta,

to use Brep.CreatePatch you’ll need to pass a System.Collections.Generic.List containing GeometryBase like Rhino.Geometry.Point. Note that Rhino.Geometry.Point3d does not work.

If you have a point cloud object in the document, you can pass it’s geometry directly to Brep.CreatePatch to fit a patch surface to it like below:

import Rhino
import scriptcontext
import rhinoscriptsyntax as rs

def DoSomething():
    
    cloud_id = rs.GetObject("PointCloud", rs.filter.pointcloud, True, False)
    if not cloud_id: return
    
    cloud = rs.coercegeometry(cloud_id)
    tolerance = scriptcontext.doc.ModelAbsoluteTolerance
    brep = Rhino.Geometry.Brep.CreatePatch([cloud], 3, 3, tolerance)
    if brep:
        scriptcontext.doc.Objects.AddBrep(brep)
        scriptcontext.doc.Views.Redraw()
    
DoSomething()

_
c.

2 Likes

Thank you so much Clement!

Very useful! Thanks!