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(); } } }
/// <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); }
/// <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); }
/// <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)); }