Point Cloud Client

Point Cloud Client

The point cloud client API supports read and modification of point cloud instances within Revit. The points supplied by the point cloud instances come from the point cloud engine, which is either a built-in engine within Revit, or a third party engine loaded as an application. A client point cloud API application doesn’t need to be concerned with the details of how the engine stores and serves points to Revit. Instead, the client API can be used to create point clouds, manipulate their properties, and read the points found matching a given filter.

The main classes related to point clouds are:

Creating a Point Cloud

To create a new point cloud in a Revit document, create a PointCloudType and then use it to create a PointCloudInstance. The static PointCloudType.Create() method requires the engine identifier, as it was registered with Revit by a third party, or the file extension of the point cloud file, if it is a supported file type. It also requires a file name or the identification string for a non-file based engine. In the following sample, a pcg file is used to create a point cloud in a Revit document.

Code Region: Create a point cloud from an rcsrcs file

private PointCloudInstance CreatePointCloud(Document doc)
{
    PointCloudType type = PointCloudType.Create(doc, "rcs", "c:\\32_cafeteria.rcs");
    return (PointCloudInstance.Create(doc, type.Id, Transform.Identity));
}

Figure: Point Cloud from 32_cafeteria.rcs

Accessing Points in a Point Cloud

There are two ways to access the points in a point cloud:

  1. Iterate the resulting points directly from the PointCollection return using the IEnumerable<CloudPoint> interface
  2. Get a pointer to the point storage of the collection and access the points directly in memory in an unsafe interface

Either way, the first step to access a collection of points from the PointCloudInstance is to use the method

  • PointCloudInstance.GetPoints(PointCloudFilter filter, double averageDistance, int numPoints)

Note that as a result of search algorithms used by Revit and the point cloud engine, the exact requested number of points may not be returned.

Although the second option involves dealing with pointers directly, there may be performance improvements when traversing large buffers of points. However, this option is only possible from C# and C++/CLI.

The following two examples show how to iterate part of a point cloud using on one of these two methods.

Code Region: Reading point cloud points by iteration

private void GetPointCloudDataByIteration(PointCloudInstance pcInstance, PointCloudFilter pointCloudFilter)
{
    // read points by iteration
    double averageDistance = 0.001;
    PointCollection points = pcInstance.GetPoints(pointCloudFilter, averageDistance, 10000); // Get points.  Number of points is determined by the needs of the client
    foreach (CloudPoint point in points)
    {
        // Process each point
        System.Drawing.Color color = System.Drawing.ColorTranslator.FromWin32(point.Color);
        String pointDescription = String.Format("({0}, {1}, {2}, {3}", point.X, point.Y, point.Z, color.ToString());
    }
}

Code Region: Reading point cloud points by pointer

public unsafe void GetPointCloudDataByPointer(PointCloudInstance pcInstance, PointCloudFilter pointCloudFilter)
{
    double averageDistance = 0.001;
    PointCollection points = pcInstance.GetPoints(pointCloudFilter, averageDistance, 10000);
    CloudPoint* pointBuffer = (CloudPoint*)points.GetPointBufferPointer().ToPointer();
    int totalCount = points.Count;
    for (int numberOfPoints = 0; numberOfPoints < totalCount; numberOfPoints++)
    {
        CloudPoint point = *(pointBuffer + numberOfPoints);
        // Process each point
        System.Drawing.Color color = System.Drawing.ColorTranslator.FromWin32(point.Color);
        String pointDescription = String.Format("({0}, {1}, {2}, {3}", point.X, point.Y, point.Z, color.ToString());
    }
}

Filters

Filters are used both to limit the volume which is searched when reading points, and also to govern the display of point clouds. A PointCloudFilter can be created based upon a collection of planar boundaries. The filter will check whether a point is located on the “positive” side of each input plane, as indicated by the positive direction of the plane normal. Therefore, such filter implicitly defines a volume, which is the intersection of the positive half-spaces corresponding to all the planes. This volume does not have to be closed, but it will always be convex.

The display of point clouds can be controlled by assigning a filter to:

  • PointCloudInstance.SetSelectionFilter()

Display of the filtered points will be based on the value of the property:

  • PointCloudInstance.FilterAction

If it is set to None, the selection filter is ignored. If it is set to Highlight, points that pass the filter are highlighted. If it is set to Isolate, only points that pass the filter will be visible.

The following example will highlight a subset of the points in a point cloud based on its bounding box.

Code Region: Reading point cloud points by pointer

// Filter will match 1/8 of the overall point cloud
// Use the bounding box (filter coordinates are in the coordinates of the model)
BoundingBoxXYZ boundingBox = pointCloudInstance.get_BoundingBox(null);
List<Plane> planes = new List<Plane>();
XYZ midpoint = (boundingBox.Min + boundingBox.Max) / 2.0;

// X boundaries
planes.Add(app.Create.NewPlane(XYZ.BasisX, boundingBox.Min));
planes.Add(app.Create.NewPlane(-XYZ.BasisX, midpoint));

// Y boundaries
planes.Add(app.Create.NewPlane(XYZ.BasisY, boundingBox.Min));
planes.Add(app.Create.NewPlane(-XYZ.BasisY, midpoint));

// Z boundaries
planes.Add(app.Create.NewPlane(XYZ.BasisZ, boundingBox.Min));
planes.Add(app.Create.NewPlane(-XYZ.BasisZ, midpoint));

// Create filter
PointCloudFilter filter = PointCloudFilterFactory.CreateMultiPlaneFilter(planes);
pointCloudInstance.FilterAction = SelectionFilterAction.Highlight;

This is the result when the sample above is run on a small pipe point cloud:

Figure: Point cloud with selection filter

The Selection.PickBox() method which invokes a general purpose two-click editor that lets the user to specify a rectagular area on the screen can be used in conjuction with a PointCloudFilter by using the resulting PickedBox to generate the planar boundaries of the filter.

Scans

An .rcp file can contain multiple scans. The method PointCloudInstance.GetScans() returns a list of scan names which can be used to set visibility and fixed color overrides independently for each scan in the PointCloudInstance. PointCloudInstance.ContainsScan() indicates whether the given scan name is contained in the point cloud instance while PointCloudInstance.GetScanOrigin() will return the origin of the given scan in model coordinates.

Overrides

Point cloud override settings assigned to a given view can be modified using the Revit API. These settings correspond to the settings on the Point Clouds tab of the Visibility/Graphics Overrides task pane in the Revit UI. Overrides can be applied to an entire point cloud instance, or to specific scans within that instance. Options for the overrides include setting visibility for scans in the point cloud instance, setting it to a fixed color, or to color gradients based on elevation, normals, or intensity. The property PointCloudInstance.SupportsOverrides identifies point clouds which support override settings (clouds which are based on .rcp or .rcs files).

The following classes are involved in setting the overrides for point clouds:

  • PointCloudOverrides - Used to get or set the PointCloudOverrideSettings for a PointCloudInstance.
  • PointCloudOverrideSettings - Used to get or set the visibility, color mode, and PointCloudColorSettings for a PointCloudInstance or one of its scans.
  • PointCloudColorSettings - Used to assign specific colors for certain color modes to a PointCloudInstance element, or one of its scans. Does not apply if the PointCloudColorMode is NoOverride or Normals.