def findHorizontalSurfaces(polyData, removeGroundFirst=False, normalEstimationSearchRadius=0.05,
                          clusterTolerance=0.025, minClusterSize=150, distanceToPlaneThreshold=0.0025, normalsDotUpRange=[0.95, 1.0], showClusters=False):
    '''
    Find the horizontal surfaces, tuned to work with walking terrain
    '''

    searchZ = [0.0, 2.0]
    voxelGridLeafSize = 0.01
    verboseFlag = False

    if (removeGroundFirst):
        groundPoints, scenePoints =  removeGround(polyData, groundThickness=0.02, sceneHeightFromGround=0.05)
        scenePoints = thresholdPoints(scenePoints, 'dist_to_plane', searchZ)
        updatePolyData(groundPoints, 'ground points', parent=getDebugFolder(), visible=verboseFlag)
    else:
        scenePoints = polyData



    if not scenePoints.GetNumberOfPoints():
        return

    f = vtk.vtkPCLNormalEstimation()
    f.SetSearchRadius(normalEstimationSearchRadius)
    f.SetInput(scenePoints)
    f.SetInput(1, applyVoxelGrid(scenePoints, voxelGridLeafSize))

    # Duration 0.2 sec for V1 log:
    f.Update()
    scenePoints = shallowCopy(f.GetOutput())

    normals = vtkNumpy.getNumpyFromVtk(scenePoints, 'normals')
    normalsDotUp = np.abs(np.dot(normals, [0,0,1]))

    vtkNumpy.addNumpyToVtk(scenePoints, normalsDotUp, 'normals_dot_up')
    surfaces = thresholdPoints(scenePoints, 'normals_dot_up', normalsDotUpRange)

    updatePolyData(scenePoints, 'scene points', parent=getDebugFolder(), colorByName='normals_dot_up', visible=verboseFlag)
    updatePolyData(surfaces, 'surfaces points', parent=getDebugFolder(), colorByName='normals_dot_up', visible=verboseFlag)

    clusters = extractClusters(surfaces, clusterTolerance=clusterTolerance, minClusterSize=minClusterSize)
    planeClusters = []
    clustersLarge = []

    om.removeFromObjectModel(om.findObjectByName('surface clusters'))
    folder = om.getOrCreateContainer('surface clusters', parentObj=getDebugFolder())

    for i, cluster in enumerate(clusters):

        updatePolyData(cluster, i % 'surface cluster %d', parent=folder, color=getRandomColor(), visible=verboseFlag)
        planePoints, _ = applyPlaneFit(cluster, distanceToPlaneThreshold)
        planePoints = thresholdPoints(planePoints, 'dist_to_plane', [-distanceToPlaneThreshold, distanceToPlaneThreshold])

        if planePoints.GetNumberOfPoints() > minClusterSize:
            clustersLarge.append(cluster)
            obj = makePolyDataFields(planePoints)
            if obj is not None:
                planeClusters.append(obj)

    folder = om.getOrCreateContainer('surface objects', parentObj=getDebugFolder())
    if showClusters:
        vis.showClusterObjects(planeClusters, parent=folder)

    return clustersLarge
dataset/ETHPy150Open RobotLocomotion/director/src/python/director/segmentation.py/findHorizontalSurfaces/swapped operands of `%`