Patching a point cloud using Python


#1

Hi, I’m trying to import a point cloud and then patch it using Python, but I am having trouble figuring out how to either control the settings using rs.Command or use a point cloud with Rhino.Geometry.Brep.CreatePatch(). I need to use point clouds because I intend to work with hundreds of thousands of points eventually. Any advice?

Here’s my script:

import rhinoscriptsyntax as rs
import Rhino

pointcloud = rs.Command("-_Import C:\Temp\pointcloud.xyz _Enter")

rs.Command("-_Patch pointcloud")

I haven’t figured out the synatx for the settings for Patch via rs.Command(). I tried the following for example with no success:

rs.Command("-_Patch pointcloud PointSpacing=1 _USpans=4 _VSpans=4 _Stiffness=4")

or

rs.Command("-_Patch pointcloud 1 4 4 4")

With Rhino.Geometry.Brep.CreatePatch(), my GeometryBase is not an IEnumerable. Is this because it is a point cloud and not a list or array of points? Any advice?

Rhino.Geometry.Brep.CreatePatch(pointcloud, 4, 4)

or

Rhino.Geometry.NurbsSurface.CreateFromPoints(pointcloud, 4, 4, 3, 3) 

And here is a small ascii point cloud to import for testing: pointcloud.zip (200 Bytes)

Thanks, Brendan


#2

Hi Brendan, depending on the pointclouds you are trying to patch, i think using _Patch command might not give you the results you´re expecting. It is not suited for hundrets of thousands of points. The pointcloud you have provided looks more arbitrary. You might get better results using _MeshPatch but it depends on the pointclouds you pass to it.

rs.Command will not return an object, instead it returns the command result as boolean which is either True or False, so you cannot pass that to the patch command. See the python help file how to run command scripts using rs.Command. One way to do it using rs.Command, is shown below, it creates a nurbs patch from your pointcloud and selects the result if there is one.


import rhinoscriptsyntax as rs
import Rhino

def TestPatchPtCloud():
    # import pointcloud from file
    cmd_result = rs.Command("-_Import C:\Temp\pointcloud.xyz _Enter")
    if not cmd_result == True: return

    # select pointcloud
    objects = rs.LastCreatedObjects(select=True)
    if not objects: return

    pointcloud = objects[0]

    cmd = "-_Patch"
    cmd = cmd + " _PointSpacing 0.01"
    cmd = cmd + " _USpans 10"
    cmd = cmd + " _VSpans 10"
    cmd = cmd + " _Stiffness 8"
    cmd = cmd + " _Enter _Enter"

    cmd_result = rs.Command(cmd)
    if cmd_result == True:
        objects = rs.LastCreatedObjects(select=True)
        if not objects: return 

        patch_srf = objects[0]
        rs.UnselectObject(pointcloud)
        rs.SelectObject(patch_srf)
    else:
        print "no patch created from poincloud"

if __name__=="__main__":
    TestPatchPtCloud()

c.


#3

Thank you very much! I really appreciate it. I will try this approach. However, I do have one question.

Why can’t this be a long string? Why concatenate?

cmd = "-_Patch"
cmd = cmd + " _PointSpacing 0.01"
cmd = cmd + " _USpans 10"
cmd = cmd + " _VSpans 10"
cmd = cmd + " _Stiffness 8"
cmd = cmd + " _Enter _Enter"

Why I want to use patch rather than a mesh:
I’m exporting digital elevation models from GIS as point clouds and I’ve found that patch with a good boundary produces excellent results for anything less than 250K points. I use the RhinoTerrain plugin’s terrain mesh for larger point clouds. But terrains seem to look better as NURBS surfaces. I can create a good boundary with a 3d convex hull in GIS. Or I could use RhinoTerrain to mesh the point cloud, generate a boundary curve, discard the mesh, and then use the boundary for patching.


#4

There’s no reason why you can’t use one long string, the concatenation helps for two things:

  1. Keep the line length down (recommended max. 80 characters)

  2. In this case, as these represent individual command options that you might want to change later, it’s a lot easier to find them in the script if you break them out individually as Clement did.

Also as a tip, you can concatenate in Python this way:

cmd = "-_Patch"
cmd += " _PointSpacing 0.01"
cmd += " _USpans 10"
cmd += " _VSpans 10"
cmd += " _Stiffness 8"
cmd += " _Enter _Enter

But you could also do

cmd = "-_Patch _PointSpacing 0.01 _USpans 10 _VSpans 10 _Stiffness 8 _Enter _Enter"

if you don’t mind the line length. Some commands have a LOT of options and the lines get very long.

HTH, --Mitch


#5

Thanks for the explanation and the tip.