应用程序名称:PointCloudEngine

Revit 平台:所有版本

Revit 版本:2012.0

首次发布版本:2012.0

编程语言:C#

技能水平:高级

类别:几何

类型:外部命令

主题:点云引擎示例

摘要:

该示例提供了各种自定义点云引擎的示例。

类:

Autodesk.Revit.DB.PointClouds.IPointCloudAccess

Autodesk.Revit.DB.PointClouds.IPointCloudEngine

Autodesk.Revit.DB.PointClouds.IPointSetIterator

Autodesk.Revit.DB.PointClouds.CloudPoint

Autodesk.Revit.DB.PointClouds.PointCloudFilter

Autodesk.Revit.DB.PointCloudType

Autodesk.Revit.DB.PointCloudInstance

项目文件:

FileBasedPointCloud.cs

PointCloudAccessBase.cs

PointCloudCellStorage.cs

PointCloudEngineSample.cs

PredefinedPointCloud.cs

PredefinedPointCloudEngine.cs

XmlUtils.cs

描述:

1.此示例提供了几个点云引擎的变体。在所有情况下,点云本身由单元格表示:

  a.一个单元格是由两个点定义的有界矩形3D空间(在点云坐标系中)。

  b.点在沿着单元格的主轴运行的边界线上计算。

  c.点可以是规则的或者有一些随机因素。

  d.给定单元格中的所有点都被分配相同的颜色。

  e.给定点云允许有多个单元格。

 

2.预定义的点云实现提供了非基于文件的点云示例。在非基于文件的点云中,Revit的用户界面不能创建和管理这些点云。应用程序必须提供创建所需实例的能力。

 

预定义点云

3.提供了基于文件的点云实现。文件格式是XML的特定格式,在其中指定了每个单元格的边界点、颜色和随机化选项。还可以指定点云的整体比例。XML文件应类似于此:

<PointCloud>

   <Scale value="2.5"/>

   <Cell>

      <LowerLeft X="-30" Y="-30" Z="0" />

      <UpperRight X="30" Y="30" Z="200" />

      <Color value="#000000" />

      <Randomize value="True" />

   </Cell>

   <Cell>

      <LowerLeft X="-30" Y="-10" Z="10" />

      <UpperRight X="-29" Y="10" Z="150" />

      <Color value="#CC3300" />

      <Randomize value="False" />

   </Cell>

 </PointCloud>

 

基于文件的点云

4.实现的最复杂部分包含在PointCloudAccessBase.ReadSomePoints()方法中。这提供了IPointCloudAccess.ReadPoints()IPointSetIterator.ReadPoints()的实现,在其中Revit请求通过给定筛选器的点的缓冲区。这是Revit提供点进行显示、选择、对齐和其他操作的方法。

说明:

1.您可以使用添加预定义实例插件命令实例化已定义的点云实例。

2.您可以使用添加随机实例插件命令实例化一个随机版本。

3.您可以使用在转换中添加随机实例插件命令实例化一个带有非默认转换的实例。

4.您还可以通过以下方式实例化基于文件的点云:

a.从插入选项卡中选择点云

b.在文件选取对话框中,将文件类型更改为点云(* .xml)

c.浏览到sample目录中的tower.xml(或另一个正确构建的XML文件)并选择它。

5.您可以使用序列化点云(实用程序)插件命令编写默认的XML文件。该文件将写入C:\ 文件夹中。

源代码

完整的源代码请加入QQ群649037449,在群文件中下载RevitSDK.exe,解压后在文件夹中搜索本文中应用程序名称即可获得完整源码

FileBasedPointCloud.cs

//
// (C) Copyright 2003-2019 by Autodesk, Inc.
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
//
// Use, duplication, or disclosure by the U.S. Government is subject to
// restrictions set forth in FAR 52.227-19 (Commercial Computer
// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
// (Rights in Technical Data and Computer Software), as applicable.
//

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using System.Text;
using System.IO;

using Autodesk.Revit.DB;
using Autodesk.Revit.DB.PointClouds;

namespace Revit.SDK.Samples.CS.PointCloudEngine
{
    /// <summary>
    /// An implementation for a file-based point cloud.
    /// </summary>
    /// <example>
    /// The file format is based upon XML.  A sample XML looks like:
    /// <code>
    ///    <PointCloud>
    ///      <Scale value="2.5"/>
    ///      <Cell>
    ///        <LowerLeft X="-30" Y="-30" Z="0" />
    ///        <UpperRight X="30" Y="30" Z="200" />
    ///        <Color value="#000000" />
    ///        <Randomize value="True" />
    ///      </Cell>
    ///      <Cell>
    ///         <LowerLeft X="-30" Y="-10" Z="10" />
    ///         <UpperRight X="-29" Y="10" Z="150" />
    ///         <Color value="#CC3300" />
    ///         <Randomize value="False" />
    ///       </Cell>
    ///    </PointCloud>
    /// </code>
    /// The scale value applies to the entire point cloud.  One or more cell values should be supplied,
    /// with the coordinates of the opposing corners, a color, and an option whether or not to randomize 
    /// the generated points.
    /// </example>
    class FileBasedPointCloud : PointCloudAccessBase, IPointCloudAccess
    {
        #region  Class Member Variables
        String m_fileName;
        #endregion

        #region Class Methods
        /// <summary>
        /// Constructs a new XML-based point cloud access.
        /// </summary>
        /// <param name="fileName">The full path to the file.</param>
        public FileBasedPointCloud(String fileName)
        {
            m_fileName = fileName;

            Setup();
        }

        /// <summary>
        /// Sets up the file-based point cloud.
        /// </summary>
        private void Setup()
        {
            if (File.Exists(m_fileName))
            {
                StreamReader reader = new StreamReader(m_fileName);
                XDocument xmlDoc = XDocument.Load(new XmlTextReader(reader));
                reader.Close();

                SetupFrom(xmlDoc.Element("PointCloud"));
            }
        }
        #endregion

        #region IPointCloudAccess Members

        /// <summary>
        /// The implementation of IPointCloudAccess.GetName().
        /// </summary>
        /// <returns>The name (the file name).</returns>
        public String GetName()
        {
            return m_fileName;
        }

        /// <summary>
        /// The implementation of IPointCloudAccess.GetColorEncoding()
        /// </summary>
        /// <returns>The color encoding.</returns>
        public PointCloudColorEncoding GetColorEncoding()
        {
            return PointCloudColorEncoding.ABGR;
        }

        /// <summary>
        /// The implementation of IPointCloudAccess.CreatePointSetIterator().
        /// </summary>
        /// <param name="rFilter">The filter.</param>
        /// <param name="viewId">The view id (unused).</param>
        /// <returns>The new iterator.</returns>
        public IPointSetIterator CreatePointSetIterator(PointCloudFilter rFilter, ElementId viewId)
        {
            return new PointCloudAccessBase.PointCloudAccessBaseIterator(this, rFilter);
        }

        /// <summary>
        /// The implementation of IPointCloudAccess.CreatePointSetIterator().
        /// </summary>
        /// <param name="rFilter">The filter.</param>
        /// <param name="density">The density.</param>
        /// <param name="viewId">The view id (unused).</param>
        /// <returns>The new iterator.</returns>
        public IPointSetIterator CreatePointSetIterator(PointCloudFilter rFilter, double density, ElementId viewId)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// The implementation of IPointCloudAccess.GetExtent().
        /// </summary>
        /// <returns>The extents of the point cloud.</returns>
        public Outline GetExtent()
        {
            return GetOutline();
        }

        /// <summary>
        /// The implementation of IPointCloudAccess.GetOffset().
        /// </summary>
        /// <remarks>This method is not used by Revit and will be removed in a later pre-release build.</remarks>
        /// <returns>Zero.</returns>
        public XYZ GetOffset()
        {
            return XYZ.Zero;
        }

        /// <summary>
        /// The implementation of IPointCloudAccess.GetUnitsToFeetConversionFactor().
        /// </summary>
        /// <returns>The scale.</returns>
        public double GetUnitsToFeetConversionFactor()
        {
            return GetScale();
        }

        /// <summary>
        /// The implementation of IPointCloudAccess.ReadPoints().
        /// </summary>
        /// <param name="rFilter">The filter.</param>
        /// <param name="viewId">The view id (unused).</param>
        /// <param name="buffer">The point cloud buffer.</param>
        /// <param name="nBufferSize">The maximum number of points.</param>
        /// <returns>The number of points read.</returns>
        public int ReadPoints(PointCloudFilter rFilter, ElementId viewId, IntPtr buffer, int nBufferSize)
        {
            int read = ReadSomePoints(rFilter, buffer, nBufferSize, 0);

            return read;
        }

        /// <summary>
        /// The implementation of IPointCloudAccess.Free().
        /// </summary>
        public void Free()
        {
           throw new NotImplementedException();
        }

        #endregion
    }
}

PointCloudAccessBase.cs

//
// (C) Copyright 2003-2019 by Autodesk, Inc.
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
//
// Use, duplication, or disclosure by the U.S. Government is subject to
// restrictions set forth in FAR 52.227-19 (Commercial Computer
// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
// (Rights in Technical Data and Computer Software), as applicable.
//

using System;
using System.Collections.Generic;
using System.Xml.Linq;
using System.Linq;

using Autodesk.Revit.DB;
using Autodesk.Revit.DB.PointClouds;
using Autodesk.Revit.UI;



namespace Revit.SDK.Samples.CS.PointCloudEngine
{
    /// <summary>
    ///  The base class for all IPointCloudAccess implementations in this sample.
    /// </summary>
    public class PointCloudAccessBase
    {
        #region  Class Member Variables
        private double m_scale = 1.0;
        private List<PointCloudCellStorage> m_storedCells;
        private Outline m_outline = null;
        #endregion

        #region Class Methods
        /// <summary>
        /// Constructs a new instance of the base class.
        /// </summary>
        protected PointCloudAccessBase()
        {
            m_storedCells = new List<PointCloudCellStorage>();
        }

        /// <summary>
        /// Adds a new cell to the point cloud.
        /// </summary>
        /// <param name="lowerLeft">The lower left point.</param>
        /// <param name="upperRight">The upper right point.</param>
        /// <param name="color">The color.</param>
        /// <param name="randomize">True to randomize point number and location, false for a regular arrangement of points.</param>
        protected void AddCell(XYZ lowerLeft, XYZ upperRight, int color, bool randomize)
        {
            PointCloudCellStorage storage = new PointCloudCellStorage(lowerLeft, upperRight, color, randomize);
            storage.GeneratePoints();
            m_storedCells.Add(storage);

            AddCellToOutline(storage);
        }

        /// <summary>
        /// Adds a new cell to the point cloud.
        /// </summary>
        /// <param name="lowerLeft">The lower left point.</param>
        /// <param name="upperRight">The upper right point.</param>
        /// <param name="color">The color.</param>
        protected void AddCell(XYZ lowerLeft, XYZ upperRight, int color)
        {
            AddCell(lowerLeft, upperRight, color, false);
        }

        /// <summary>
        /// Adds a cell to the stored outline of the point cloud.  If the cell boundaries extend beyond the current outline, the outline 
        /// is adjusted.
        /// </summary>
        /// <param name="storage"></param>
        private void AddCellToOutline(PointCloudCellStorage storage)
        {
            XYZ lowerLeft = storage.LowerLeft;
            XYZ upperRight = storage.UpperRight;
            if (m_outline == null)
                m_outline = new Outline(lowerLeft, upperRight);
            else
            {
                XYZ minimumPoint = m_outline.MinimumPoint;

                m_outline.MinimumPoint = new XYZ(Math.Min(minimumPoint.X, lowerLeft.X),
                                                Math.Min(minimumPoint.Y, lowerLeft.Y),
                                                Math.Min(minimumPoint.Z, lowerLeft.Z));

                XYZ maximumPoint = m_outline.MaximumPoint;
                m_outline.MaximumPoint = new XYZ(Math.Max(maximumPoint.X, upperRight.X),
                                                Math.Max(maximumPoint.Y, upperRight.Y),
                                                Math.Max(maximumPoint.Z, upperRight.Z));
            }
        }

        /// <summary>
        /// Gets the outline calculated from all cells in the point cloud.
        /// </summary>
        /// <returns></returns>
        protected Outline GetOutline()
        {
            return m_outline;
        }

        /// <summary>
        /// Gets the scale stored for this point cloud.
        /// </summary>
        /// <returns></returns>
        protected double GetScale()
        {
            return m_scale;
        }

        /// <summary>
        /// Saves the contents of the point cloud into an XML element.
        /// </summary>
        /// <param name="rootElement">The XML element in which to save the point cloud properties.</param>
        public virtual void SerializeObjectData(XElement rootElement)
        {
            XElement scaleElement = XmlUtils.GetXElement(m_scale, "Scale");
            rootElement.Add(scaleElement);
            
            int count = m_storedCells.Count;
            for (int i = 0; i < count; i++)
            {
                XElement cellElement = new XElement("Cell");
                m_storedCells[i].SerializeObjectData(cellElement);
                rootElement.Add(cellElement);
            }
        }

        /// <summary>
        /// The internal implementation for point cloud read requests from Revit.  
        /// </summary>
        /// <remarks>Both IPointCloudAccess.ReadPoints() and IPointSetIterator.ReadPoints() are served by this method.</remarks>
        /// <param name="rFilter">The point cloud filter.</param>
        /// <param name="buffer">The point cloud buffer.</param>
        /// <param name="nBufferSize">The maximum number of points in the buffer.</param>
        /// <param name="startIndex">The start index for points.  Pass 0 if called from IPointCloudAccess.ReadPoints() or if this is the first 
        /// call to IPointSetIterator.ReadPoints().  Pass the previous cumulative number of read points for second and successive calls to 
        /// IPointSetIterator.ReadPoints().</param>
        /// <returns>The number of points read.</returns>
        protected unsafe int ReadSomePoints(PointCloudFilter rFilter, IntPtr buffer, int nBufferSize, int startIndex)
        {
            // Get the pointer to the buffer.
            CloudPoint* cpBuffer = (CloudPoint*)buffer.ToPointer();
            int pointIndex = 0;
            int currentIndex = startIndex;
            int totalPoints = 0;
            int startCell = 0;
            Outline fullOutline = GetOutline();

            // Test each cell until the first cell with needed points is found.
            for (int i = 0; i < m_storedCells.Count; i++)
            {
                PointCloudCellStorage cell = m_storedCells[i];

                // Pass the cell outline to the filter.
                int filterResult = rFilter.TestCell(cell.LowerLeft, cell.UpperRight);

                // Filter result == -1 means the cell is completely out of scope for the filter.
                if (filterResult == -1)
                    continue;

                // The cell is at least partially in scope.  If the cell has more points than
                // the number read in previous calls, we should start with this cell.
                // If it has less points than the number read, the cell was already processed and we
                // should move to the next one.
                totalPoints += cell.NumberOfPoints;
                if (currentIndex < totalPoints)
                {
                    startCell = i;
                    currentIndex = Math.Max(0, startIndex - totalPoints);
                    break;
                }
            }

            // Start with the current candidate cell and read cells until there are no more to read.
            for (int i = startCell; i < m_storedCells.Count; i++)
            {
                // Test the cell against the filter.
                PointCloudCellStorage cell = m_storedCells[i];
                int filterResult = rFilter.TestCell(cell.LowerLeft, cell.UpperRight);

                // Filter result == -1 means the cell is entirely out of scope, skip it.
                if (filterResult == -1)
                    continue;

                // Filter result == 0 means some part of the cell is in scope.
                // Prepare for cell is called to process the cell's points.
                if (filterResult == 0)
                    rFilter.PrepareForCell(fullOutline.MinimumPoint, fullOutline.MaximumPoint, cell.NumberOfPoints);

                // Loop through all points in the cell.
                for (int j = currentIndex; j < cell.NumberOfPoints; j++)
                {
                    // If we need to test the point for acceptance, use the filter to do so.
                    // If filter result == 1 the entire cell was in scope, no need to test.
                    if (filterResult == 0)
                    {
                        if (!rFilter.TestPoint(cell.PointsBuffer[j]))
                            continue;
                    }

                    // Add the point to the buffer and increment the counter
                    *(cpBuffer + pointIndex) = cell.PointsBuffer[j];
                    pointIndex++;
                    
                    // Stop when the max number of points is reached
                    if (pointIndex >= nBufferSize)
                    {
                        break;
                    }
                }

                // Stop when the max number of points is reached
                if (pointIndex >= nBufferSize)
                {
                    break;
                }
                currentIndex = 0;
            }

            return pointIndex;
        }

        /// <summary>
        /// Sets up a point cloud from an XML root element.
        /// </summary>
        /// <param name="rootElement">The root element.</param>
        protected void SetupFrom(XElement rootElement)
        {  
            // Read scale, if it exists.
            foreach (XElement scaleElement in rootElement.Elements("Scale"))
            {
                double scale = XmlUtils.GetDouble(scaleElement);
                if (scale < 0.0)
                {
                    TaskDialog.Show("Scale error", "The value of scale is not a valid number greater than zero.");
                }
                else
                {
                    m_scale = scale;
                }
            }

            // Read cells.
            m_storedCells = new List<PointCloudCellStorage>();
            foreach (XElement cellElement in rootElement.Elements("Cell"))
            {
                PointCloudCellStorage cell = new PointCloudCellStorage(cellElement);
                m_storedCells.Add(cell);
                AddCellToOutline(cell);
                cell.GeneratePoints();
            }
        }
        #endregion

        /// <summary>
        /// The implementation for an IPointSetIterator for a file-based or predefined point cloud.
        /// </summary>
        protected class PointCloudAccessBaseIterator : IPointSetIterator
        {
            #region  Class Member Variables
            private PointCloudFilter m_filter;
            private int m_currentIndex;
            private PointCloudAccessBase m_access;
            private bool m_done = false;
            #endregion

            #region Class Methods
            /// <summary>
            /// Constructs a new instance of the point cloud iterator.
            /// </summary>
            /// <param name="access">The access.</param>
            /// <param name="filter">The filter used for this iteration.</param>
            public PointCloudAccessBaseIterator(PointCloudAccessBase access, PointCloudFilter filter)
            {
                m_access = access;
                m_filter = filter;
                m_currentIndex = 0;
            }
            #endregion

            #region IPointSetIterator Members

            /// <summary>
            /// Implementation of IPointSetIterator.ReadPoints()
            /// </summary>
            /// <param name="buffer">The point buffer.</param>
            /// <param name="nBufferSize">The buffer size.</param>
            /// <returns>The number of points read.</returns>
            public int ReadPoints(IntPtr buffer, int nBufferSize)
            {
                if (m_done)
                {
                    return 0;
                }

                int found = m_access.ReadSomePoints(m_filter, buffer, nBufferSize, m_currentIndex);
                m_currentIndex += found;

                if (found > nBufferSize)
                {
                    m_done = true;
                }

                return found;
            }

            /// <summary>
            /// Implementation of IPointSetIterator.Free()
            /// </summary>
            public void Free()
            {
                m_done = true;
            }

            #endregion
        }
    }
}

PointCloudCellStorage.cs

//
// (C) Copyright 2003-2019 by Autodesk, Inc.
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
//
// Use, duplication, or disclosure by the U.S. Government is subject to
// restrictions set forth in FAR 52.227-19 (Commercial Computer
// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
// (Rights in Technical Data and Computer Software), as applicable.
//

using System;
using System.Xml.Linq;

using Autodesk.Revit.DB;
using Autodesk.Revit.DB.PointClouds;
using Autodesk.Revit.UI;

namespace Revit.SDK.Samples.CS.PointCloudEngine
{
    /// <summary>
    /// This class is used to calculate and store points for a given cell.
    /// </summary>
    public class PointCloudCellStorage
    {
        #region  Class Member Variables
        [Flags]
        private enum PointDirections
        {
            PlusX = 1,
            MinusX = 2,
            PlusY = 4,
            MinusY = 8,
            PlusZ = 16,
            MinusZ = 32
        }

        private CloudPoint[] m_pointsBuffer;
        private int m_numberOfPoints;
        private XYZ m_lowerLeft;
        private XYZ m_upperRight;
        private int m_color;
        private bool m_randomize;
        private const int s_maxNumberOfPoints = 1000000;
        private const float s_delta = 0.1f;
        private Random m_random = new Random();
        #endregion

        #region Class Property
        /// <summary>
        /// The number of points in the cell.
        /// </summary>
        public int NumberOfPoints
        {
            get { return m_numberOfPoints; }
        }

        /// <summary>
        /// The lower left point of the cell.
        /// </summary>
        public XYZ LowerLeft
        {
            get { return m_lowerLeft; }
        }

        /// <summary>
        /// The upper right point of the cell.
        /// </summary>
        public XYZ UpperRight
        {
            get { return m_upperRight; }
        }

        /// <summary>
        /// The points in the cell.
        /// </summary>
        public CloudPoint[] PointsBuffer
        {
            get { return m_pointsBuffer; }
        }
        #endregion

        #region Class Methods
        /// <summary>
        /// Creates a new instance of a rectangular cell.
        /// </summary>
        /// <param name="lowerLeft">The lower left point of the cell.</param>
        /// <param name="upperRight">The upper right point of the cell.</param>
        /// <param name="color">The color used for points in the cell.</param>
        /// <param name="randomize">True to apply randomization to the number and location of points, false for a regular arrangement of points.</param>
        public PointCloudCellStorage(XYZ lowerLeft, XYZ upperRight, int color, bool randomize)
        {
            m_lowerLeft = lowerLeft;
            m_upperRight = upperRight;
            m_color = color;
            m_randomize = randomize;

            m_pointsBuffer = new CloudPoint[s_maxNumberOfPoints];
            m_numberOfPoints = 0;
        }

        /// <summary>
        /// Invokes the calculation for all points in the cell.
        /// </summary>
        public void GeneratePoints()
        {
            // X direction lines
            float xDistance = (float)(m_upperRight.X - m_lowerLeft.X);
            AddLine(m_lowerLeft, XYZ.BasisX, PointDirections.PlusY | PointDirections.PlusZ, xDistance);
            AddLine(new XYZ(m_lowerLeft.X, m_lowerLeft.Y, m_upperRight.Z), XYZ.BasisX, PointDirections.PlusY | PointDirections.MinusZ, xDistance);
            AddLine(new XYZ(m_lowerLeft.X, m_upperRight.Y, m_lowerLeft.Z), XYZ.BasisX, PointDirections.MinusY | PointDirections.PlusZ, xDistance);
            AddLine(new XYZ(m_lowerLeft.X, m_upperRight.Y, m_upperRight.Z), XYZ.BasisX, PointDirections.MinusY | PointDirections.MinusZ, xDistance);

            // Y direction lines
            float yDistance = (float)(m_upperRight.Y - m_lowerLeft.Y);
            AddLine(m_lowerLeft, XYZ.BasisY, PointDirections.PlusX | PointDirections.PlusZ, yDistance);
            AddLine(new XYZ(m_lowerLeft.X, m_lowerLeft.Y, m_upperRight.Z), XYZ.BasisY, PointDirections.PlusX | PointDirections.MinusZ, yDistance);
            AddLine(new XYZ(m_upperRight.X, m_lowerLeft.Y, m_lowerLeft.Z), XYZ.BasisY, PointDirections.MinusX | PointDirections.PlusZ, yDistance);
            AddLine(new XYZ(m_upperRight.X, m_lowerLeft.Y, m_upperRight.Z), XYZ.BasisY, PointDirections.MinusX | PointDirections.MinusZ, yDistance);

            // Z direction lines
            float zDistance = (float)(m_upperRight.Z - m_lowerLeft.Z);
            AddLine(m_lowerLeft, XYZ.BasisZ, PointDirections.PlusX | PointDirections.PlusY, zDistance);
            AddLine(new XYZ(m_lowerLeft.X, m_upperRight.Y, m_lowerLeft.Z), XYZ.BasisZ, PointDirections.PlusX | PointDirections.MinusY, zDistance);
            AddLine(new XYZ(m_upperRight.X, m_lowerLeft.Y, m_lowerLeft.Z), XYZ.BasisZ, PointDirections.MinusX | PointDirections.PlusY, zDistance);
            AddLine(new XYZ(m_upperRight.X, m_upperRight.Y, m_lowerLeft.Z), XYZ.BasisZ, PointDirections.MinusX | PointDirections.MinusY, zDistance);
        }

        private int AddLine(XYZ startPoint, XYZ direction, PointDirections directions, float distance)
        {
            float deltaX = 0.0f;
            int totalRead = 0;

            while (deltaX < distance)
            {
                AddPoints(startPoint + direction * deltaX, directions);
                deltaX += s_delta;
            }

            return totalRead;
        }

        private void AddModifiedPoint(XYZ point, XYZ modification, double transverseDelta, int pointNumber)
        {
            XYZ cloudPointXYZ = point + modification * Math.Pow(transverseDelta * pointNumber, 4.0);
            CloudPoint cp = new CloudPoint((float)cloudPointXYZ.X, (float)cloudPointXYZ.Y, (float)cloudPointXYZ.Z, m_color);
            m_pointsBuffer[m_numberOfPoints] = cp;
            m_numberOfPoints++;
            if (m_numberOfPoints == s_maxNumberOfPoints)
            {
                TaskDialog.Show("Point  cloud engine", "A single cell is requiring more than the maximum hardcoded number of points for one cell: " + s_maxNumberOfPoints);
                throw new Exception("Reached maximum number of points.");
            }
        }

        private void AddPoints(XYZ point, PointDirections directions)
        {
            // Two random items: number of points, and delta
            int numberOfPoints = 5;
            double transverseDelta = 0.1;
            if (m_randomize)
            {
                numberOfPoints = 5 + m_random.Next(10);
                transverseDelta = m_random.NextDouble() * 0.1;
            }

            for (int i = 1; i < numberOfPoints; i++)
            {
                if ((directions & PointDirections.PlusX) == PointDirections.PlusX)
                {
                    AddModifiedPoint(point, XYZ.BasisX, transverseDelta, i);                  
                }

                if ((directions & PointDirections.MinusX) == PointDirections.MinusX)
                {
                    AddModifiedPoint(point, -XYZ.BasisX, transverseDelta, i); 
                }

                if ((directions & PointDirections.PlusY) == PointDirections.PlusY)
                {
                    AddModifiedPoint(point, XYZ.BasisY, transverseDelta, i); 
                }

                if ((directions & PointDirections.MinusY) == PointDirections.MinusY)
                {
                    AddModifiedPoint(point, -XYZ.BasisY, transverseDelta, i); 
                }

                if ((directions & PointDirections.PlusZ) == PointDirections.PlusZ)
                {
                    AddModifiedPoint(point, XYZ.BasisZ, transverseDelta, i); 
                }

                if ((directions & PointDirections.MinusZ) == PointDirections.MinusZ)
                {
                    AddModifiedPoint(point, -XYZ.BasisZ, transverseDelta, i); 
                }
            }
        }

        /// <summary>
        /// Serializes the properties of the cell to an XML element.
        /// </summary>
        /// <param name="rootElement">The element to which the properties are added as subelements.</param>
        public void SerializeObjectData(XElement rootElement)
        {
            rootElement.Add(XmlUtils.GetXElement(m_lowerLeft, "LowerLeft"));
            rootElement.Add(XmlUtils.GetXElement(m_upperRight, "UpperRight"));
            rootElement.Add(XmlUtils.GetColorXElement(m_color, "Color"));
            rootElement.Add(XmlUtils.GetXElement(m_randomize, "Randomize"));
        }

        /// <summary>
        /// Constructs a new instance of a rectangular cell from an XML element.
        /// </summary>
        /// <param name="rootElement">The XML element representing the cell.</param>
        public PointCloudCellStorage(XElement rootElement)
        {
            m_lowerLeft = XmlUtils.GetXYZ(rootElement.Element("LowerLeft"));
            m_upperRight = XmlUtils.GetXYZ(rootElement.Element("UpperRight"));
            m_color = XmlUtils.GetColor(rootElement.Element("Color"));
            m_randomize = XmlUtils.GetBoolean(rootElement.Element("Randomize"));

            m_pointsBuffer = new CloudPoint[s_maxNumberOfPoints];
            m_numberOfPoints = 0;
        }
        #endregion
    }
}

PointCloudEngineSample.cs

//
// (C) Copyright 2003-2019 by Autodesk, Inc.
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
//
// Use, duplication, or disclosure by the U.S. Government is subject to
// restrictions set forth in FAR 52.227-19 (Commercial Computer
// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
// (Rights in Technical Data and Computer Software), as applicable.
//

using System;
using System.IO;
using System.Xml;
using System.Xml.Linq;

using Autodesk.Revit.DB;
using Autodesk.Revit.DB.PointClouds;
using Autodesk.Revit.UI;

namespace Revit.SDK.Samples.CS.PointCloudEngine
{
   /// <summary>
   /// ExternalApplication used to register the point cloud engines managed by this sample.
   /// </summary>
   [Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)]
   public class PointCloudTestApplication : IExternalApplication
   {
      #region IExternalApplication Members

      /// <summary>
      /// The implementation of IExternalApplication.OnStartup()
      /// </summary>
      /// <param name="application">The Revit application.</param>
      /// <returns>Result.Succeeded</returns>
      public Result OnStartup(UIControlledApplication application)
      {
         try
         {
            // Register point cloud engines for the sample.

            // Predefined engine (non-randomized)
            IPointCloudEngine engine = new BasicPointCloudEngine(PointCloudEngineType.Predefined);
            PointCloudEngineRegistry.RegisterPointCloudEngine("apipc", engine, false);

            // Predefined engine with randomized points at the cell borders
            engine = new BasicPointCloudEngine(PointCloudEngineType.RandomizedPoints);
            PointCloudEngineRegistry.RegisterPointCloudEngine("apipcr", engine, false);

            // XML-based point cloud definition
            engine = new BasicPointCloudEngine(PointCloudEngineType.FileBased);
            PointCloudEngineRegistry.RegisterPointCloudEngine("xml", engine, true);

            // Create user interface for accessing predefined point clouds
            RibbonPanel panel = application.CreateRibbonPanel("Point cloud testing");

            System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();

            panel.AddItem(new PushButtonData("AddPredefinedInstance",
                                              "Add predefined instance",
                                              assembly.Location,
                                              "Revit.SDK.Samples.CS.PointCloudEngine.AddPredefinedInstanceCommand"));
            panel.AddSeparator();

            panel.AddItem(new PushButtonData("AddRandomizedInstance",
                                              "Add randomized instance",
                                              assembly.Location,
                                              "Revit.SDK.Samples.CS.PointCloudEngine.AddRandomizedInstanceCommand"));
            panel.AddSeparator();

            panel.AddItem(new PushButtonData("AddTransformedInstance",
                                              "Add randomized instance\nat transform",
                                              assembly.Location,
                                              "Revit.SDK.Samples.CS.PointCloudEngine.AddTransformedInstanceCommand"));
            panel.AddSeparator();

            panel.AddItem(new PushButtonData("SerializePointCloud",
                                              "Serialize point cloud (utility)",
                                              assembly.Location,
                                              "Revit.SDK.Samples.CS.PointCloudEngine.SerializePredefinedPointCloud"));
         }
         catch (Exception e)
         {
            TaskDialog.Show("Exception from OnStartup", e.ToString());
         }

         return Result.Succeeded;
      }

      /// <summary>
      /// The implementation of IExternalApplication.OnShutdown()
      /// </summary>
      /// <param name="application">The Revit application.</param>
      /// <returns>Result.Succeeded.</returns>
      public Result OnShutdown(UIControlledApplication application)
      {
         return Result.Succeeded;
      }

      #endregion
   }

   /// <summary>
   /// ExternalCommand to add a predefined point cloud.
   /// </summary>
   [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
   public class AddPredefinedInstanceCommand : AddInstanceCommandBase, IExternalCommand
   {
      #region IExternalCommand Members
      /// <summary>
      /// The implementation for IExternalCommand.Execute()
      /// </summary>
      /// <param name="commandData">The Revit command data.</param>
      /// <param name="message">The error message (ignored).</param>
      /// <param name="elements">The elements to display in the failure dialog (ignored).</param>
      /// <returns>Result.Succeeded</returns>
      public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
      {
         Document doc = commandData.View.Document;

         AddInstance(doc, "apipc", "", Transform.Identity);

         return Result.Succeeded;
      }

      #endregion
   }

   /// <summary>
   /// ExternalCommand to a predefined point cloud with randomized points.
   /// </summary>
   [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
   public class AddRandomizedInstanceCommand : AddInstanceCommandBase, IExternalCommand
   {
      #region IExternalCommand Members
      /// <summary>
      /// The implementation for IExternalCommand.Execute()
      /// </summary>
      /// <param name="commandData">The Revit command data.</param>
      /// <param name="message">The error message (ignored).</param>
      /// <param name="elements">The elements to display in the failure dialog (ignored).</param>
      /// <returns>Result.Succeeded</returns>
      public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
      {
         Document doc = commandData.View.Document;

         AddInstance(doc, "apipcr", "", Transform.Identity);

         return Result.Succeeded;
      }

      #endregion
   }

   /// <summary>
   /// ExternalCommand to add a predefined point cloud at a non-default transform.
   /// </summary>
   [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
   public class AddTransformedInstanceCommand : AddInstanceCommandBase, IExternalCommand
   {
      #region IExternalCommand Members
      /// <summary>
      /// The implementation for IExternalCommand.Execute()
      /// </summary>
      /// <param name="commandData">The Revit command data.</param>
      /// <param name="message">The error message (ignored).</param>
      /// <param name="elements">The elements to display in the failure dialog (ignored).</param>
      /// <returns>Result.Succeeded</returns>
      public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
      {
         Document doc = commandData.View.Document;

         Transform trf = Transform.CreateRotationAtPoint(XYZ.BasisZ, Math.PI / 6.0, new XYZ(10, 5, 0));
         AddInstance(doc, "apipcr", "", trf);

         return Result.Succeeded;
      }

      #endregion
   }

   /// <summary>
   /// Base class for ExternalCommands used to add point cloud instances programmatically.
   /// </summary>
   public class AddInstanceCommandBase
   {
      /// <summary>
      /// Adds a point cloud instance programmatically.
      /// </summary>
      /// <param name="doc">The document.</param>
      /// <param name="engineType">The engine identifier string.</param>
      /// <param name="identifier">The identifier for the particular point cloud.</param>
      /// <param name="trf">The transform to apply to the new point cloud instance.</param>
      public void AddInstance(Document doc, String engineType, String identifier, Transform trf)
      {
         Transaction t = new Transaction(doc, "Create PC instance");
         t.Start();
         PointCloudType type = PointCloudType.Create(doc, engineType, identifier);
         PointCloudInstance.Create(doc, type.Id, trf);
         t.Commit();
      }
   }

   /// <summary>
   /// Utility ExternalCommand to take a predefined point cloud and write the corresponding XML for it to disk.
   /// </summary>
   [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.ReadOnly)]
   public class SerializePredefinedPointCloud : AddInstanceCommandBase, IExternalCommand
   {
      #region IExternalCommand Members
      /// <summary>
      /// The implementation for IExternalCommand.Execute()
      /// </summary>
      /// <param name="commandData">The Revit command data.</param>
      /// <param name="message">The error message (ignored).</param>
      /// <param name="elements">The elements to display in the failure dialog (ignored).</param>
      /// <returns>Result.Succeeded</returns>
      public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
      {
         PredefinedPointCloud cloud = new PredefinedPointCloud("dummy");

         XDocument doc = new XDocument();
         XElement root = new XElement("PointCloud");
         cloud.SerializeObjectData(root);
         doc.Add(root);

         TextWriter writer = new StreamWriter(@"c:\serializedPC.xml");
         doc.WriteTo(new XmlTextWriter(writer));

         writer.Close();

         return Result.Succeeded;
      }

      #endregion
   }


}

PredefinedPointCloud.cs

//
// (C) Copyright 2003-2019 by Autodesk, Inc.
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
//
// Use, duplication, or disclosure by the U.S. Government is subject to
// restrictions set forth in FAR 52.227-19 (Commercial Computer
// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
// (Rights in Technical Data and Computer Software), as applicable.
//

using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;

using Autodesk.Revit.DB;
using Autodesk.Revit.DB.PointClouds;

namespace Revit.SDK.Samples.CS.PointCloudEngine
{

    /// <summary>
    /// An implementation for a non file-based point cloud.  In this implementaiton, the location of the cells, including their colors and options, 
    /// are hardcoded.
    /// </summary>
    public class PredefinedPointCloud : PointCloudAccessBase, IPointCloudAccess
    {
        #region  Class Member Variables
        String m_identifier;
        #endregion

        #region Class Methods
        /// <summary>
        /// Constructs a new predefined point cloud access instance.
        /// </summary>
        /// <param name="identifier">The identifier of the point cloud.</param>
        public PredefinedPointCloud(String identifier)
        {
            m_identifier = identifier;

            Setup(false);
        }

        /// <summary>
        /// Constructs a new predefined point cloud access instance.
        /// </summary>
        /// <param name="identifier">The identifier of the point cloud.</param>
        /// <param name="randomizedPoints">True to use randomization for the point location and number, false otherwise.</param>
        public PredefinedPointCloud(String identifier, bool randomizedPoints)
        {
            m_identifier = identifier;

            Setup(randomizedPoints);
        }

        /// <summary>
        /// Sets up the predefined point cloud.
        /// </summary>
        /// <param name="randomizedPoints">True to use randomization for the point location and number, false otherwise.</param>
        private void Setup(bool randomizedPoints)
        {
            AddCell(new XYZ(0, 0, 0), new XYZ(0.5, 100, 10), 0x00CCCC, randomizedPoints);
            AddCell(new XYZ(0, 0, 0), new XYZ(50, 0.5, 10), 0x00CCCC, randomizedPoints);
            AddCell(new XYZ(49.5, 0, 0), new XYZ(50, 100, 10), 0x00CCCC, randomizedPoints);
            AddCell(new XYZ(0, 99.5, 0), new XYZ(50, 100, 10), 0x00CCCC, randomizedPoints);
            AddCell(new XYZ(10, 0, 0), new XYZ(14, 0.5, 7), 0xCC99CC, randomizedPoints);
            AddCell(new XYZ(30, 0, 3), new XYZ(33, 0.5, 8), 0xA0A0A0, randomizedPoints);
            AddCell(new XYZ(33, 0, 3), new XYZ(36, 0.5, 8), 0xA0A0A0, randomizedPoints);
            AddCell(new XYZ(0, 24, 3), new XYZ(0.5, 27, 8), 0xA0A0A0, randomizedPoints);
            AddCell(new XYZ(0, 27, 3), new XYZ(0.5, 30, 8), 0xA0A0A0, randomizedPoints);
            AddCell(new XYZ(0, 46, 0), new XYZ(0.5, 50, 7), 0xCC99CC, randomizedPoints);
            AddCell(new XYZ(0, 50, 0), new XYZ(0.5, 54, 7), 0xCC99CC, randomizedPoints);
            AddCell(new XYZ(0, 70, 3), new XYZ(0.5, 73, 8), 0xA0A0A0, randomizedPoints);
            AddCell(new XYZ(0, 73, 3), new XYZ(0.5, 76, 8), 0xA0A0A0, randomizedPoints);
        }
        #endregion
        
        #region IPointCloudAccess Members

        /// <summary>
        /// The implementation of IPointCloudAccess.GetName().
        /// </summary>
        /// <returns>The name (the file name).</returns>
        public String GetName()
        {
            return "apipc: " + m_identifier;
        }

        /// <summary>
        /// The implementation of IPointCloudAccess.GetColorEncoding()
        /// </summary>
        /// <returns>The color encoding.</returns>
        public PointCloudColorEncoding GetColorEncoding()
        {
            return PointCloudColorEncoding.ABGR;
        }

        /// <summary>
        /// The implementation of IPointCloudAccess.CreatePointSetIterator().
        /// </summary>
        /// <param name="rFilter">The filter.</param>
        /// <param name="viewId">The view id (unused).</param>
        /// <returns>The new iterator.</returns>
        public IPointSetIterator CreatePointSetIterator(PointCloudFilter rFilter, ElementId viewId)
        {
            return new PointCloudAccessBase.PointCloudAccessBaseIterator(this, rFilter);
        }

        /// <summary>
        /// The implementation of IPointCloudAccess.CreatePointSetIterator().
        /// </summary>
        /// <param name="rFilter">The filter.</param>
        /// <param name="density">The density.</param>
        /// <param name="viewId">The view id (unused).</param>
        /// <returns>The new iterator.</returns>
        public IPointSetIterator CreatePointSetIterator(PointCloudFilter rFilter, double density, ElementId viewId)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// The implementation of IPointCloudAccess.GetExtent().
        /// </summary>
        /// <returns>The extents of the point cloud.</returns>
        public Outline GetExtent()
        {
            return GetOutline();
        }

        /// <summary>
        /// The implementation of IPointCloudAccess.GetOffset().
        /// </summary>
        /// <remarks>This method is not used by Revit and will be removed in a later pre-release build.</remarks>
        /// <returns>Zero.</returns>
        public XYZ GetOffset()
        {
            return XYZ.Zero;
        }

        /// <summary>
        /// The implementation of IPointCloudAccess.GetUnitsToFeetConversionFactor().
        /// </summary>
        /// <returns>The scale.</returns>
        public double GetUnitsToFeetConversionFactor()
        {
            return GetScale();
        }

        /// <summary>
        /// The implementation of IPointCloudAccess.ReadPoints().
        /// </summary>
        /// <param name="rFilter">The filter.</param>
        /// <param name="viewId">The view id (unused).</param>
        /// <param name="buffer">The point cloud buffer.</param>
        /// <param name="nBufferSize">The maximum number of points.</param>
        /// <returns>The number of points read.</returns>
        public int ReadPoints(PointCloudFilter rFilter, ElementId viewId, IntPtr buffer, int nBufferSize)
        {
            int read = ReadSomePoints(rFilter, buffer, nBufferSize, 0);

            return read;
        }

        /// <summary>
        /// The implementation of IPointCloudAccess.Free().
        /// </summary>
        public void Free()
        {
            throw new NotImplementedException();
        }
        #endregion
    }
}

PredefinedPointCloudEngine.cs

//
// (C) Copyright 2003-2019 by Autodesk, Inc.
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
//
// Use, duplication, or disclosure by the U.S. Government is subject to
// restrictions set forth in FAR 52.227-19 (Commercial Computer
// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
// (Rights in Technical Data and Computer Software), as applicable.
//

using System;

using Autodesk.Revit.DB;
using Autodesk.Revit.DB.PointClouds;

namespace Revit.SDK.Samples.CS.PointCloudEngine
{
    /// <summary>
    /// The type of engine.
    /// </summary>
    /// <remarks>Because the same engine implementation is used for all types of engines in this sample, a member of this enumerated type
    /// is used to determine the logic necessary to create the IPointCloudAccess instance.</remarks>
    public enum PointCloudEngineType
    {
        /// <summary>
        /// A predefined point cloud engine (non-randomized).
        /// </summary>
        Predefined,
        /// <summary>
        /// A predefined point cloud engine (randomized).
        /// </summary>
        RandomizedPoints,
        /// <summary>
        /// A file based point cloud engine.
        /// </summary>
        FileBased
    }

    /// <summary>
    /// An implementation of IPointCloudEngine used by all the custom engines in this sample.
    /// </summary>
    public class BasicPointCloudEngine : IPointCloudEngine
    {
        #region  Class Member Variables
        private PointCloudEngineType m_type;
        #endregion

        #region Class Methods
        /// <summary>
        /// Constructs a new instance of the engine.
        /// </summary>
        /// <param name="type">The type of point cloud served by this engine instance.</param>
        public BasicPointCloudEngine(PointCloudEngineType type)
        {
            m_type = type;
        }
        #endregion

        #region IPointCloudEngine Members

        /// <summary>
        /// Implementation of IPointCloudEngine.CreatePointCloudAccess().
        /// </summary>
        /// <param name="identifier">The identifier (or file name) for the desired point cloud.</param>
        /// <returns>The IPointCloudAccess implementation serving this point cloud.</returns>
        public IPointCloudAccess CreatePointCloudAccess(string identifier)
        {
            switch (m_type)
            {
                case PointCloudEngineType.RandomizedPoints:
                    return new PredefinedPointCloud(identifier, true);
                case PointCloudEngineType.FileBased:
                    return new FileBasedPointCloud(identifier);
                case PointCloudEngineType.Predefined:
                default:
                    return new PredefinedPointCloud(identifier);
            }
        }

        /// <summary>
        /// Implementation of IPointCloudEngine.Free().
        /// </summary>
        public void Free()
        {
            //Nothing to do
        }

        #endregion
    }
}

XmlUtils.cs

//
// (C) Copyright 2003-2019 by Autodesk, Inc.
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
//
// Use, duplication, or disclosure by the U.S. Government is subject to
// restrictions set forth in FAR 52.227-19 (Commercial Computer
// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
// (Rights in Technical Data and Computer Software), as applicable.
//

using System;
using System.Xml.Linq;
using System.Text;
using Autodesk.Revit.DB;

namespace Revit.SDK.Samples.CS.PointCloudEngine
{
    /// <summary>
    /// Utilities used by the sample to process XML entries in file-based point clouds.
    /// </summary>
    public static class XmlUtils
    {
        /// <summary>
        /// Gets an XYZ point from an XML element.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns>The XYZ.</returns>
        public static XYZ GetXYZ(XElement element)
        {
            XAttribute x = element.Attribute("X");
            XAttribute y = element.Attribute("Y");
            XAttribute z = element.Attribute("Z");

            return new XYZ(Double.Parse(x.Value), Double.Parse(y.Value), Double.Parse(z.Value));
        }

        /// <summary>
        /// Gets a boolean value from an XML element.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns>The value.</returns>
        public static bool GetBoolean(XElement element)
        {
            return Boolean.Parse(element.Attribute("value").Value);
        }

        /// <summary>
        /// Gets a double value from an XML element.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns>The value.</returns>
        public static double GetDouble(XElement element)
        {
            return Double.Parse(element.Attribute("value").Value);
        }

        /// <summary>
        /// Gets an integer value from an XML element.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns>The value.</returns>
        public static int GetInteger(XElement element)
        {
            return Int32.Parse(element.Attribute("value").Value);
        }

        /// <summary>
        /// Gets a color value (in the form needed for inclusion in a CloudPoint) from an XML element.
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns>The value.</returns>
        public static int GetColor(XElement element)
        {
            return System.Drawing.ColorTranslator.ToWin32(System.Drawing.ColorTranslator.FromHtml(element.Attribute("value").Value));
        }

        /// <summary>
        /// Gets the XML element representing a point.
        /// </summary>
        /// <param name="point">The point.</param>
        /// <param name="name">The name of the XML element.</param>
        /// <returns>The element.</returns>
        public static XElement GetXElement(XYZ point, String name)
        {
            XElement ret = new XElement(name);
            ret.Add(new XAttribute("X", point.X));
            ret.Add(new XAttribute("Y", point.Y));
            ret.Add(new XAttribute("Z", point.Z));

            return ret;
        }

        /// <summary>
        /// Gets the XML element representing a CloudPoint color.
        /// </summary>
        /// <param name="color">The color.</param>
        /// <param name="name">The name.</param>
        /// <returns>The element.</returns>
        public static XElement GetColorXElement(int color, String name)
        {
            XElement ret = new XElement(name);
            string htmlRep = System.Drawing.ColorTranslator.ToHtml(System.Drawing.ColorTranslator.FromWin32(color));
            ret.Add(new XAttribute("value", htmlRep));

            return ret;
        }

        /// <summary>
        /// Gets the XML element representing an object.
        /// </summary>
        /// <param name="obj">The object.</param>
        /// <param name="name">The name.</param>
        /// <returns>The element.</returns>
        public static XElement GetXElement(object obj, String name)
        {
            XElement ret = new XElement(name);
            ret.Add(new XAttribute("value", obj.ToString()));

            return ret;
        }
    }

}