private static void CalculateTubeEdges(
            XYZ[] points_on_tube_surface,
            XYZ center_of_torus,
            XYZ axis_of_torus,
            out XYZ tube_begin,
            out XYZ tube_end)
        {
            // make vectors pointing from the center to the points on the surface.
            List <XYZ> vectors = points_on_tube_surface.ToList().ConvertAll(x => x - center_of_torus);

            // project all points on the tube surface to the plane perpendicular to the axis of the torus.
            List <XYZ> projected_vectors =
                vectors.ConvertAll(
                    x => axis_of_torus.CrossProduct(x).CrossProduct(axis_of_torus)
                    );

            // calculate barycentric coordinates of the projected points.
            XYZ barycentric = projected_vectors.Aggregate((p0, p1) => p0 + p1) / projected_vectors.Count;

            // tube_middle is a vector pointing from the center of the torus to the center of mass.
            XYZ tube_middle = barycentric.Normalize();

            // find the elements to which a vector pointing from the center of torus has min/max angles to the tube_middle.
            FindSurfaceRevitPluginUtils.MinMaxElement(projected_vectors, x => FindSurfaceRevitPluginUtils.GetAngleBetween(tube_middle, x.Normalize(), axis_of_torus), out tube_begin, out tube_end);
        }
        private static void DrawTorusAndInliers(Document doc, FS_FEATURE_RESULT?result)
        {
            // fetch parameters of the torus found by FindSurface.
            XYZ    center, axis;
            double mean_radius, tube_radius;

            FetchParametersOfTorus(result, out center, out axis, out mean_radius, out tube_radius);

            // create the inlier point cloud corresponding to the torus.
            string name = "Torus" + DirectShapeEngine.DirectTorusInstanceCount;

            ExtractInlierPointCloud(doc, name, S_TORUS_INLIER_COLOR);

            // find two edges of the torus part.
            XYZ tube_begin, tube_end;

            string last_pointcloud_name = InlierPointCloudEngine.GetPointCloudNames().Last();

            XYZ[] inlier_points = InlierPointCloudEngine.GetCloudPoints(last_pointcloud_name).ToList().ConvertAll(x => (XYZ)x).ToArray();

            CalculateTubeEdges(inlier_points, center, axis, out tube_begin, out tube_end);
            double positive_angle = FindSurfaceRevitPluginUtils.GetPositiveAngleBetween(tube_begin, tube_end, tube_begin.CrossProduct(tube_end));

            // draw the torus on the Revit document.
            DirectShapeEngine.DrawTorus(doc, center, axis, mean_radius, tube_radius, tube_begin, positive_angle);
        }
        /// <summary>
        /// creates a DirectShape instance of which shape is a part of a torus (like elbow joint pipe).
        /// Torus is defined by center, axis, tube radius, and mean radius (the distance between center and tube center).
        /// The tube_begin and tube_end defines the angle between the two edges of the piece.
        /// </summary>
        /// <param name="document">The Revit document where the instance to be drawn</param>
        /// <param name="name">The name of this instance</param>
        /// <param name="center">Position of center of the torus' hole</param>
        /// <param name="axis">Vector passing through the center</param>
        /// <param name="mean_radius">The distance between torus center and its tube center</param>
        /// <param name="tube_radius">Radius of tube</param>
        /// <param name="tube_begin">The vector pointing to one of the torus' edge from its center</param>
        /// <param name="torus_angle">The angle between the tube begin and end</param>
        /// <param name="line_color">Outline color of the torus</param>
        /// <param name="surface_transparency">Surface transparency; ranged from 0 (transparent) to 100 (opaque)</param>
        public DirectTorus(Document document, string name, XYZ center, XYZ axis, double mean_radius, double tube_radius, XYZ tube_begin, double torus_angle, Color line_color, int surface_transparency) : base(document, name)
        {
            m_shape_type = ShapeTypes.Torus;
            Center       = center;
            Axis         = axis;
            MeanRadius   = mean_radius;
            TubeRadius   = tube_radius;
            HasAnElbow   = true;
            TubeBegin    = tube_begin;
            TubeAngle    = torus_angle;

            XYZ    tilting_axis  = XYZ.BasisZ.CrossProduct(axis);
            double tilting_angle = FindSurfaceRevitPluginUtils.GetPositiveAngleBetween(XYZ.BasisZ, axis, tilting_axis);

            bool      no_need_to_tilt = tilting_axis.IsAlmostEqualTo(XYZ.Zero);
            Transform tilting_torus   = no_need_to_tilt ? Transform.Identity : Transform.CreateRotation(tilting_axis, tilting_angle);
            XYZ       tilted_basis_x  = tilting_torus.OfVector(XYZ.BasisX);

            // model space coordinates
            Frame frame = new Frame(XYZ.Zero, XYZ.BasisX, XYZ.BasisY, XYZ.BasisZ);

            XYZ model_tube_center = XYZ.BasisX * mean_radius;
            XYZ model_tube_top    = model_tube_center + tube_radius * XYZ.BasisZ;
            XYZ model_tube_bottom = model_tube_center - tube_radius * XYZ.BasisZ;
            XYZ model_tube_outer  = model_tube_center + tube_radius * XYZ.BasisX;
            XYZ model_tube_inner  = model_tube_center - tube_radius * XYZ.BasisX;

            List <Curve> tube_circle = new List <Curve>();

            tube_circle.Add(Arc.Create(model_tube_top, model_tube_bottom, model_tube_inner));
            tube_circle.Add(Arc.Create(model_tube_bottom, model_tube_top, model_tube_outer));

            CurveLoop    curve_loop = CurveLoop.Create(tube_circle);
            SolidOptions options    = new SolidOptions(ElementId.InvalidElementId, ElementId.InvalidElementId);

            if (Frame.CanDefineRevitGeometry(frame))
            {
                Solid torus = GeometryCreationUtilities.CreateRevolvedGeometry(frame, new CurveLoop[] { curve_loop }, 0, torus_angle, options);
                using (Transaction t = new Transaction(document, "Create torus direct shape."))
                {
                    t.Start();
                    DirectShape shape = DirectShape.CreateElement(document, new ElementId(BuiltInCategory.OST_GenericModel));
                    shape.SetShape(new GeometryObject[] { torus });
                    shape.SetName(name);
                    m_element_id = shape.Id;

                    if (no_need_to_tilt == false)
                    {
                        shape.Location.Rotate(Line.CreateUnbound(XYZ.Zero, tilting_axis), tilting_angle);
                    }
                    shape.Location.Rotate(Line.CreateUnbound(XYZ.Zero, axis), FindSurfaceRevitPluginUtils.GetPositiveAngleBetween(tilted_basis_x, tube_begin, axis));
                    shape.Location.Move(center);

                    document.ActiveView.SetElementOverrides(shape.Id, new OverrideGraphicSettings().SetProjectionLineColor(line_color).SetSurfaceTransparency(surface_transparency));
                    t.Commit();
                }
            }
        }
Пример #4
0
        /// <summary>
        /// Resets the plugin to the state of when users imported a point cloud file.
        /// </summary>
        /// <returns>false if any point cloud file has been opened or true otherwise</returns>
        public static bool OnResetCommand(Document document)
        {
            OnCleanUpCommand();

            CloudPoint[] points;
            if (s_xyz == null || s_xyz.Length == 0)
            {
                return(false);
            }
            FindSurfaceRevitPluginUtils.Pack(s_xyz, s_color, out points);
            OutlierPointCloudEngine.CreatePointCloud(document, s_file_full_name, points, Transform.Identity, s_subdivision);

            FindSurface.CleanUp();
            FindSurface.SetPointCloud(s_xyz);
            return(true);
        }
Пример #5
0
        /// <summary>
        /// Creates a point cloud and send the data to FindSurface when users imported a point cloud file using Open button in FindSurface tab.
        /// </summary>
        /// <param name="doc">The active document that Revit uses</param>
        /// <param name="file_full_name">The name of imported file</param>
        /// <param name="xyz_array">Imported xyz data</param>
        /// <param name="color_array">Imported color data</param>
        /// <param name="subdivision">Subdivision number</param>
        /// <param name="unit">The base unit of when the inspector displays information</param>
        public static void OnOpenCommand(Document doc, string file_full_name, float[] xyz_array, int[] color_array, int subdivision, Units unit)
        {
            s_file_full_name  = file_full_name;
            s_xyz             = xyz_array;
            s_color           = color_array;
            s_subdivision     = subdivision;
            s_measurementUnit = unit;

            CloudPoint[] points;
            FindSurfaceRevitPluginUtils.Pack(xyz_array, color_array, out points);
            s_temporary_outlier_deletion = true;
            OutlierPointCloudEngine.CreatePointCloud(doc, file_full_name, points, Transform.Identity, subdivision);

            FindSurface.CleanUp();
            FindSurface.SetPointCloud(xyz_array);
        }
        private static void ExtractInlierPointCloud(Document doc, string inlier_identifier, int highlight_color)
        {
            CloudPoint[] original_points = OutlierPointCloudEngine.GetCloudPoint();

            List <CloudPoint> inlier_point_list  = new List <CloudPoint>();
            List <CloudPoint> outlier_point_list = new List <CloudPoint>();
            List <float>      outlier_xyz        = new List <float>();

            // this is a flag array of which each element is set when the point of its corresponding location is in outlier.
            bool[] outlier_flags = FindSurface.GetInOutlierFlags();
            for (int k = 0; k < outlier_flags.Length; k++)
            {
                float x     = original_points[k].X;
                float y     = original_points[k].Y;
                float z     = original_points[k].Z;
                int   color = original_points[k].Color;

                if (outlier_flags[k])                  // outlier
                {
                    outlier_point_list.Add(new CloudPoint(x, y, z, color));
                    outlier_xyz.AddRange(new float[] { x, y, z });
                }
                else                 // inlier
                {
                    color = FindSurfaceRevitPluginUtils.MixARGB(color, highlight_color);
                    inlier_point_list.Add(new CloudPoint(x, y, z, color));
                }
            }

            Transform outlier_transform = OutlierPointCloudEngine.GetPointCloudTransform();

            // replace outlier (or original one) to new outlier points.
            s_temporary_outlier_deletion = true;
            OutlierPointCloudEngine.CreatePointCloud(doc, "Outlier", outlier_point_list.ToArray(), outlier_transform, s_subdivision);

            // give new outlier points to FindSurface.
            FindSurface.CleanUp();
            FindSurface.SetPointCloud(outlier_xyz.ToArray());

            // create inlier point cloud.
            InlierPointCloudEngine.CreatePointCloud(doc, inlier_identifier, inlier_point_list.ToArray(), outlier_transform);
        }
Пример #7
0
        /// <summary>
        /// Performs ray casting to the point cloud with a given ray.
        /// The ray sweeps the points and collects the points
        /// of which distance to the ray is less than the ray radius.
        /// Among the points, the one that is nearest to the ray origin will be picked.
        /// </summary>
        /// <param name="ray_origin">The ray origin</param>
        /// <param name="ray_direction">The ray direction</param>
        /// <param name="ray_radius">The radius of ray sweeping</param>
        /// <param name="idx">The index of the point that is picked</param>
        /// <returns>true if there is a point picked, false otherwise</returns>
        public bool Cast(XYZ ray_origin, XYZ ray_direction, float ray_radius, out uint idx)
        {
            Transform t = this.Transform.Inverse;

            ray_origin    = t.OfPoint(ray_origin);
            ray_direction = t.OfVector(ray_direction);

            idx = 0;
            Func <XYZ, XYZ, XYZ, double> Distance = (o, d, p) =>
            {
                XYZ AB = p - o;
                return(((d.DotProduct(AB) / d.DotProduct(d)) * d - AB).GetLength());
            };

            List <uint> indices_of_the_points_swept_by_the_ray = new List <uint>();

            // collect indices of the points of which distance
            // to the ray is less than ray_radius.
            for (int k = 0; k < m_points.Length; k++)
            {
                CloudPoint cp   = m_points[k];
                XYZ        cpos = new XYZ(cp.X, cp.Y, cp.Z);

                if (Distance(ray_origin, ray_direction, cpos) < ray_radius)
                {
                    indices_of_the_points_swept_by_the_ray.Add((uint)k);
                }
            }

            if (indices_of_the_points_swept_by_the_ray.Any() == false)
            {
                return(false);
            }

            // find index of the point having minimum distance to viewer (ray_origin).
            return(FindSurfaceRevitPluginUtils.MinElement(indices_of_the_points_swept_by_the_ray, i => ray_origin.DistanceTo(new XYZ(m_points[(int)i].X, m_points[(int)i].Y, m_points[(int)i].Z)), out idx));
        }