Convex hull of set of points lying on a 3D plane

Hi, How do I find the boundary of point cloud lying on a 3D plane. This plane is not parallel to XY or YZ or ZX planes. I am looking for the polygon on the plane that surrounds the point cloud. vtkConvexHull2D is supressing the z-coordinates.

We don’t have a filter that easily projects points to a plane, but that is what’s required before you can use vtkConvexHull2D.

The closest thing I can think of would be to use vtkPCAStatistics to compute the first two eigenvectors of your point cloud and use these as the x and y axes of the projected cloud.

Did you try: Filters/Points/vtkProjectPointsToPlane?

1 Like

Derp. I have not seen that one before.

Thanks Will. That worked.
After I compute the ConvexHull2D, I project it back to the plane.

I see problem with ConvexHull2D in some cases when the point cloud is on vatical plane which is parallel to YZ or ZX planes.

I’m not sure what the issue is, is it the vtkProjectPointsToPlane filter? Can you share a snippet of code?

Will, Here is the code. Basically I have points on a plane and I need t find the boundary polygon.

def ProjectPointsToPlane(polyData, origin = (0,0,0), normal = (0,0,1)):

p2plaFilter = vtk.vtkProjectPointsToPlane()
return p2plaFilter.GetOutput()

def GetConvexHull2D(pointCloudPolyData):

#PolyData holds the point cloud in a plane
points = pointCloudPolyData.GetPoints()
numPoints = points.GetNumberOfPoints()

#Plane normal and origin
pt0 = points.GetPoint(0)
pt1 = points.GetPoint(int(numPoints/2))
pt2 = points.GetPoint(numPoints-1)

planeNormal = [0,0,1]
planeOrigin = (pt1[0], pt1[1], pt1[2])
vtk.vtkTriangle.ComputeNormal(pt0, pt1, pt2, planeNormal)

#Project the points to XY plane
projectedPolyData = ProjectPointsToPlane(pointCloudPolyData, (0,0,0), (0, 0, 1))

hull = vtk.vtkConvexHull2D()
hull.SetHullShape(1) #0: BoundingRectangle or 1: ConvexHull.

#Project back the hull to original plane
hullPolyData = ProjectPointsToPlane(hull.GetOutput(), planeOrigin, (0, 0, 1))
return hullPolyData

def CreateHullFromJOBFile(renderer, jobFileName):

mapper = ReadJOBFiles([jobFileName])
if type(mapper) is str: 


actor = vtk.vtkActor()