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:
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
There are two ways to access the points in a point cloud:
Either way, the first step to access a collection of points from the PointCloudInstance is to use the method
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 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:
Display of the filtered points will be based on the value of the property:
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.
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.
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: