// // (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 { /// /// This class is used to calculate and store points for a given cell. /// 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 /// /// The number of points in the cell. /// public int NumberOfPoints { get { return m_numberOfPoints; } } /// /// The lower left point of the cell. /// public XYZ LowerLeft { get { return m_lowerLeft; } } /// /// The upper right point of the cell. /// public XYZ UpperRight { get { return m_upperRight; } } /// /// The points in the cell. /// public CloudPoint[] PointsBuffer { get { return m_pointsBuffer; } } #endregion #region Class Methods /// /// Creates a new instance of a rectangular cell. /// /// The lower left point of the cell. /// The upper right point of the cell. /// The color used for points in the cell. /// True to apply randomization to the number and location of points, false for a regular arrangement of points. 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; } /// /// Invokes the calculation for all points in the cell. /// 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); } } } /// /// Serializes the properties of the cell to an XML element. /// /// The element to which the properties are added as subelements. 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")); } /// /// Constructs a new instance of a rectangular cell from an XML element. /// /// The XML element representing the cell. 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 } }