应用程序:PathReinforcement

Revit平台:所有

Revit版本:2011.0

首次发布版本:2008.0

编程语言:C#

技能水平:中等

类别:结构

类型:ExternalCommand

主题:显示PathReinforcement信息。

概要:

此示例演示了如何检索路径加强对象的曲线、剖面和属性。

类:

Autodesk.Revit.UI.IExternalCommand

Autodesk.Revit.DB.Structure.PathReinforcement

Autodesk.Revit.DB.Structure.RebarBarType

Autodesk.Revit.DB.ModelCurve

项目文件:

Command.cs

此文件定义了一个从IExternalCommand继承并实现Execute方法的Command类。类的主要功能是显示主要对话框。

 

PathReinforcementForm.cs

此文件定义了一个从Form继承的PathReinforcementForm类。该类是包含一个图片框和一个属性网格的主要对话框。图片框用于显示路径加强的曲线,而属性网格用于显示路径加强的属性。

Profile.cs

此文件定义了一个Profile类,用于存储路径加强的几何信息。该类包含一个公共方法Draw,用于绘制路径加强的曲线和剖面。

 

PathReinProperties.cs

此文件定义了一个PathReinProperties类,其中包含路径加强属性。路径加强的属性将显示在PathReinforcementForm的属性网格中。

 

BarTypeConverter.cs

此文件定义了一个BarTypeConverter类,用于在ElementId和String之间转换类型。

 

MathTools.cs

此文件定义了一个Vector4和一个Matrix4类,用于在2D和3D之间转换几何数据。

描述:

此示例将从活动文档中获取路径加强,并在对话框中显示其属性。路径加强的曲线将显示在图片

中,其他数据将显示在属性网格中。可以通过路径加强的曲线属性获取几何数据,并可以通过

属性获取其他属性。

说明:

1. 打开或新建一个Revit项目,并确保已放置一些路径加强。样例项目文件PathReinforcement.rvt可在示例文件夹中找到。

2. 选择一个路径加强,运行命令,一个窗体将弹出。

3. 所选路径加强的路径和剖面将显示在图片框中:路径以蓝色显示,剖面以红色显示。

4. 路径加强的属性将显示在属性网格中;用户可以通过属性网格更改路径加强的某些参数。

5. 单击“确定”按钮后,路径的更改参数将被更新。

源代码

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

PathReinforcementForm.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.
//


namespace Revit.SDK.Samples.PathReinforcement.CS
{
    partial class PathReinforcementForm
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.pictureBox = new System.Windows.Forms.PictureBox();
            this.propertyGrid = new System.Windows.Forms.PropertyGrid();
            this.okButton = new System.Windows.Forms.Button();
            this.cancelButton = new System.Windows.Forms.Button();
            ((System.ComponentModel.ISupportInitialize)(this.pictureBox)).BeginInit();
            this.SuspendLayout();
            // 
            // pictureBox
            // 
            this.pictureBox.BackColor = System.Drawing.SystemColors.Window;
            this.pictureBox.Enabled = false;
            this.pictureBox.Location = new System.Drawing.Point(12, 12);
            this.pictureBox.Name = "pictureBox";
            this.pictureBox.Size = new System.Drawing.Size(295, 281);
            this.pictureBox.TabIndex = 0;
            this.pictureBox.TabStop = false;
            this.pictureBox.Paint += new System.Windows.Forms.PaintEventHandler(this.pictureBox_Paint);
            // 
            // propertyGrid
            // 
            this.propertyGrid.Location = new System.Drawing.Point(313, 12);
            this.propertyGrid.Name = "propertyGrid";
            this.propertyGrid.Size = new System.Drawing.Size(302, 281);
            this.propertyGrid.TabIndex = 1;
            // 
            // okButton
            // 
            this.okButton.Location = new System.Drawing.Point(431, 311);
            this.okButton.Name = "okButton";
            this.okButton.Size = new System.Drawing.Size(75, 23);
            this.okButton.TabIndex = 2;
            this.okButton.Text = "&OK";
            this.okButton.UseVisualStyleBackColor = true;
            this.okButton.Click += new System.EventHandler(this.okButton1_Click);
            // 
            // cancelButton
            // 
            this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
            this.cancelButton.Location = new System.Drawing.Point(536, 311);
            this.cancelButton.Name = "cancelButton";
            this.cancelButton.Size = new System.Drawing.Size(75, 23);
            this.cancelButton.TabIndex = 3;
            this.cancelButton.Text = "&Cancel";
            this.cancelButton.UseVisualStyleBackColor = true;
            this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click);
            // 
            // PathReinforcementForm
            // 
            this.AcceptButton = this.okButton;
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.CancelButton = this.cancelButton;
            this.ClientSize = new System.Drawing.Size(623, 343);
            this.Controls.Add(this.cancelButton);
            this.Controls.Add(this.okButton);
            this.Controls.Add(this.propertyGrid);
            this.Controls.Add(this.pictureBox);
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
            this.MaximizeBox = false;
            this.MinimizeBox = false;
            this.Name = "PathReinforcementForm";
            this.ShowInTaskbar = false;
            this.Text = "Path Reinforcement";
            ((System.ComponentModel.ISupportInitialize)(this.pictureBox)).EndInit();
            this.ResumeLayout(false);

        }

        #endregion

        private System.Windows.Forms.PictureBox pictureBox;
        private System.Windows.Forms.PropertyGrid propertyGrid;
        private System.Windows.Forms.Button okButton;
        private System.Windows.Forms.Button cancelButton;
    }
}

Profile.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.Text;
using System.Drawing;
using Autodesk.Revit;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using System.Drawing.Drawing2D;

namespace Revit.SDK.Samples.PathReinforcement.CS
{
   /// <summary>
   /// This class stores the geometry information of path reinforcement.
   /// </summary>
   class Profile
   {
      /// <summary>
      /// field used to store path reinforcement.
      /// </summary>
      private Autodesk.Revit.DB.Structure.PathReinforcement m_pathRein;

      /// <summary>
      /// field used to store external command data.
      /// </summary>
      private Autodesk.Revit.UI.ExternalCommandData m_commandData;

      /// <summary>
      /// field used to store the geometry curves of path reinforcement.
      /// 3d data.
      /// </summary>
      private List<List<XYZ>> m_curves = new List<List<XYZ>>();

      /// <summary>
      /// store path 3D.
      /// </summary>
      private List<List<XYZ>> m_path = new List<List<XYZ>>();

      /// <summary>
      /// field used to store the bound of the curves of path reinforcement.
      /// 2d data.
      /// </summary>
      private BoundingBoxUV m_box = new BoundingBoxUV();

      /// <summary>
      /// field used to store the geometry data of curves of path reinforcement.
      /// 2d data.
      /// </summary>
      private List<List<UV>> m_point2d = new List<List<UV>>();

      /// <summary>
      /// store path 2D.
      /// </summary>
      private List<List<UV>> m_path2d = new List<List<UV>>();

      /// <summary>
      /// Constructor
      /// </summary>
      /// <param name="pathRein">selected path reinforcement element.</param>
      /// <param name="commandData">External command data</param>
      public Profile(Autodesk.Revit.DB.Structure.PathReinforcement pathRein, ExternalCommandData commandData)
      {
         m_pathRein = pathRein;
         m_commandData = commandData;
         Tessellate();
         ComputeBound();
         ComputePathTo2D();
      }

      /// <summary>
      /// Draw the curves of path reinforcement.
      /// </summary>
      /// <param name="graphics">Gdi object, used to draw curves of path reinforcement.</param>
      /// <param name="size">Bound to limit the size of the whole picture</param>
      /// <param name="pen">Gdi object,determine the color of the line.</param>
      public void Draw(Graphics graphics, Size size, Pen pen)
      {
         Autodesk.Revit.DB.UV delta = m_box.Max - m_box.Min;
         float scaleX = size.Width / (float)delta.U;
         float scaleY = size.Width / (float)delta.V;
         float scale = scaleY > scaleX ? scaleX : scaleY;
         scale *= 0.90f;

         GraphicsContainer contain = graphics.BeginContainer();
         {
            //set graphics coordinate system to picture center
            //and  flip the yAxis.
            graphics.Transform = new Matrix(1, 0, 0, -1, size.Width / 2, size.Height / 2);

            //construct a matrix to transform the origin point to Bound center.
            Autodesk.Revit.DB.UV center = (m_box.Min + m_box.Max) / 2;
            Matrix toCenter = new Matrix(1, 0, 0, 1, -(float)center.U, -(float)center.V);

            bool isDrawFinished = false;
            List<List<UV>> point2d = m_point2d;
            Pen tmpPen = pen;

            while (!isDrawFinished)
            {
               foreach (List<UV> arr in point2d)
               {
                  for (int i = 0; i < arr.Count - 1; i++)
                  {
                     //get the two connection points to draw a line between them.
                     Autodesk.Revit.DB.UV uv1 = arr[i];
                     Autodesk.Revit.DB.UV uv2 = arr[i + 1];
                     PointF[] points = new PointF[] { 
                            new PointF((float)uv1.U, (float)uv1.V), 
                            new PointF((float)uv2.U, (float)uv2.V) };

                     //transform points to bound center.
                     toCenter.TransformPoints(points);

                     //Zoom(Scale) the points to fit the picture box.
                     PointF pf1 = new PointF(points[0].X * scale, points[0].Y * scale);
                     PointF pf2 = new PointF(points[1].X * scale, points[1].Y * scale);

                     //draw a line between pf1 and pf2.
                     graphics.DrawLine(tmpPen, pf1, pf2);
                  }
               }
               if (point2d == m_path2d)
               {
                  isDrawFinished = true;
               }
               point2d = m_path2d;
               tmpPen = Pens.Blue;
            }
         }
         graphics.EndContainer(contain);
      }

      /// <summary>
      /// Transform 3d path to 2d path.
      /// </summary>
      /// <returns></returns>
      private void ComputePathTo2D()
      {
         Matrix4 transform = GetActiveViewMatrix().Inverse();
         foreach (List<XYZ> arr in m_path)
         {
            List<UV> uvarr = new List<UV>();
            foreach (Autodesk.Revit.DB.XYZ xyz in arr)
            {
               Vector4 tmpVector = transform.Transform(new Vector4(xyz));
               Autodesk.Revit.DB.UV tmpUv = new Autodesk.Revit.DB.UV(
                   tmpVector.X,
                   tmpVector.Y);
               uvarr.Add(tmpUv);
            }
            m_path2d.Add(uvarr);
         }
      }

      /// <summary>
      /// Compute the bound of the curves of path reinforcement.
      /// </summary>
      private void ComputeBound()
      {
         //make the bound
         Autodesk.Revit.DB.UV min = m_box.get_Bounds(0);
         Autodesk.Revit.DB.UV max = m_box.get_Bounds(1);

         Matrix4 transform = GetActiveViewMatrix().Inverse();

         bool isFirst = true;
         foreach (List<XYZ> arr in m_curves)
         {
            List<UV> uvarr = new List<UV>();
            foreach (Autodesk.Revit.DB.XYZ xyz in arr)
            {
               Vector4 tmpVector = transform.Transform(new Vector4(xyz));
               Autodesk.Revit.DB.UV tmpUv = new Autodesk.Revit.DB.UV(
                   tmpVector.X,
                   tmpVector.Y);
               uvarr.Add(tmpUv);

               if (isFirst)
               {
                  isFirst = false;
                  min = new UV(tmpUv.U, tmpUv.V);
                  max = new UV(tmpUv.U, tmpUv.V);
               }
               if (tmpUv.U < min.U)
               {
                  min = new UV(tmpUv.U, min.V);
               }
               else if (tmpUv.U > max.U)
               {
                  max = new UV(tmpUv.U, max.V);
               }
               if (tmpUv.V < min.V)
               {
                  min = new UV(min.U, tmpUv.V);
               }
               else if (tmpUv.V > max.V)
               {
                  max = new UV(max.U, tmpUv.V);
               }
            }
            m_point2d.Add(uvarr);
         }
         m_box.Min = min;
         m_box.Max = max;
      }

      /// <summary>
      /// Tessellate the curves of path reinforcement.
      /// </summary>
      private void Tessellate()
      {
         Options option = new Options();
         option.DetailLevel = ViewDetailLevel.Fine;
         Autodesk.Revit.DB.GeometryElement geoElem = m_pathRein.get_Geometry(option);
         //GeometryObjectArray geoArray = geoElem.Objects;
         IEnumerator<GeometryObject> Objects = geoElem.GetEnumerator();
         //foreach (GeometryObject geo in geoArray)
         while (Objects.MoveNext())
         {
            GeometryObject geo = Objects.Current;

            if (geo is Curve)
            {
               Curve curve = geo as Curve;
               m_curves.Add(curve.Tessellate() as List<XYZ>);
            }
         }

         IList<ElementId> curveIds = m_pathRein.GetCurveElementIds();

         foreach (ElementId id in curveIds)
         {
            ModelCurve modelCurve = m_commandData.Application.ActiveUIDocument.Document.GetElement(id) as ModelCurve;
            m_path.Add(modelCurve.GeometryCurve.Tessellate() as List<XYZ>);
         }
      }

      /// <summary>
      /// Get view matrix from active view.
      /// </summary>
      /// <returns>view matrix</returns>
      private Matrix4 GetActiveViewMatrix()
      {
         View activeView = m_commandData.Application.ActiveUIDocument.Document.ActiveView;
         Autodesk.Revit.DB.XYZ vZAxis = activeView.ViewDirection;
         Autodesk.Revit.DB.XYZ vXAxis = activeView.RightDirection;
         Autodesk.Revit.DB.XYZ vYAxis = activeView.UpDirection;

         return new Matrix4(new Vector4(vXAxis), new Vector4(vYAxis), new Vector4(vZAxis));
      }
   }
}

PathReinProperties.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.Text;
using System.Reflection;
using System.ComponentModel;

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

namespace Revit.SDK.Samples.PathReinforcement.CS
{
    /// <summary>
    /// path reinforcement layout rules parameters.
    /// </summary>
    public enum LayoutRule
    {
        /// <summary>
        /// fixed number layout rule.
        /// </summary>
        Fixed_Number = 2,

        /// <summary>
        /// maximum spacing layout rule.
        /// </summary>
        Maximum_Spacing = 3
    };

    /// <summary>
    /// path reinforcement face parameters.
    /// </summary>
    public enum Face
    {
        /// <summary>
        /// floor top or wall exterior.
        /// </summary>
        Top = 0,

        /// <summary>
        /// floor bottom or wall interior.
        /// </summary>
        Bottom
    };

    /// <summary>
    /// This class used as PropertyGrid.SelectedObject.
    /// It stores parameters of path reinforcement.
    /// </summary>
    [DefaultPropertyAttribute("NumberOfBars")]
    public class PathReinProperties
    {
        /// <summary>
        /// cache path reinforcement object.
        /// </summary>
        protected Autodesk.Revit.DB.Structure.PathReinforcement m_pathRein;

        /// <summary>
        /// layout rule 
        /// </summary>
        private LayoutRule m_layoutRule;

        /// <summary>
        /// face parameter
        /// </summary>
        private Face m_face;

        /// <summary>
        /// number of bars
        /// </summary>
        private int m_numberOfBars;

        /// <summary>
        /// bar spacing
        /// </summary>
        private String m_barSpacing;

        /// <summary>
        /// primary bar type
        /// </summary>
        private Autodesk.Revit.DB.ElementId m_primaryBarType;

        /// <summary>
        /// primary bar length
        /// </summary>
        private String m_primaryBarLength;

        #region EnventHanlder for updating selected object of PropertyGrid
        /// <summary>
        /// update selected object of Property grid after enable / disable some properties.
        /// </summary>
        public delegate void UpdateSelectObjEventHandler();

        /// <summary>
        /// my event object of updating event
        /// </summary>
        public event UpdateSelectObjEventHandler UpdateSelectObjEvent;
        #endregion

        /// <summary>
        /// constructor of class
        /// </summary>
        /// <param name="pathRein"></param>
        public PathReinProperties(Autodesk.Revit.DB.Structure.PathReinforcement pathRein)
        {
            m_pathRein = pathRein;
            m_layoutRule = (LayoutRule)GetParameter("Layout Rule").AsInteger();
            m_face = (Face)GetParameter("Face").AsInteger();
            m_numberOfBars = m_pathRein.get_Parameter(
                    BuiltInParameter.PATH_REIN_NUMBER_OF_BARS).AsInteger();
            m_barSpacing = m_pathRein.get_Parameter(
                    BuiltInParameter.PATH_REIN_SPACING).AsValueString();
            m_primaryBarLength = m_pathRein.get_Parameter(
                    BuiltInParameter.PATH_REIN_LENGTH_1).AsValueString();
            m_primaryBarType = GetParameter("Primary Bar - Type").AsElementId();
        }

        /// <summary>
        /// update the parameters of path reinforcement.
        /// </summary>
        public void Update()
        {
            try
            {
                GetParameter("Layout Rule").Set((int)m_layoutRule);
                GetParameter("Face").Set((int)m_face);
                GetParameter("Primary Bar - Type").Set(m_primaryBarType);
                m_pathRein.get_Parameter(
                    BuiltInParameter.PATH_REIN_LENGTH_1).SetValueString(m_primaryBarLength);                

                // if layout rule is maximum spacing, number of bar will be read only.
                // In order to update previously modified number of bar, we should change the layout rule
                // to fixed number, and then set the layout rule back.
                if(m_layoutRule == LayoutRule.Maximum_Spacing)
                {
                    m_pathRein.get_Parameter(
                                    BuiltInParameter.PATH_REIN_SPACING).SetValueString(m_barSpacing);
                    GetParameter("Layout Rule").Set((int)LayoutRule.Fixed_Number);
                    m_pathRein.get_Parameter(
                            BuiltInParameter.PATH_REIN_NUMBER_OF_BARS).Set(m_numberOfBars);
                    GetParameter("Layout Rule").Set((int)m_layoutRule);                    
                }
                // if layout rule is fixed number, bar spacing will be read only.
                // In order to update previously modified bar spacing, we should change the layout rule 
                // to maximum spacing, and then set the layout rule back.
                else if (m_layoutRule == LayoutRule.Fixed_Number)
                {
                    m_pathRein.get_Parameter(
                            BuiltInParameter.PATH_REIN_NUMBER_OF_BARS).Set(m_numberOfBars);
                    GetParameter("Layout Rule").Set((int)LayoutRule.Maximum_Spacing);
                    m_pathRein.get_Parameter(
                            BuiltInParameter.PATH_REIN_SPACING).SetValueString(m_barSpacing);
                    GetParameter("Layout Rule").Set((int)m_layoutRule);
                }
            }
            catch (Exception e)
            {
                Autodesk.Revit.UI.TaskDialog.Show("Exception", e.ToString());
            }
        }

        /// <summary>
        /// Bar numbers of path reinforcement,read only property.
        /// the property is read-only by default
        /// </summary>
        [Category("Layers"), DisplayName("Number of Bars"), ReadOnlyAttribute(true)]
        public int NumberOfBars
        {
            get
            {
                return m_numberOfBars;
            }
            set
            {
                m_numberOfBars = value;
            }
        }

        /// <summary>
        /// Layout rule of path reinforcement,get/set property.
        /// </summary>
        [Category("Construction"), DisplayName("Layout Rule"), ReadOnlyAttribute(false)]
        public LayoutRule LayoutRule
        {
            get
            {
                return m_layoutRule;
            }
            set
            {
                if(m_layoutRule == value)
                {
                    return;
                }
                m_layoutRule = value;

                // set BarSpacing and NumberOfBars readonly dynamically when:
                // When set LayoutRule to "Fixed Number", BarSpacing should be read only
                // When set to "Maximum Spacing", Number Of Bars should be read only
                if (m_layoutRule == LayoutRule.Fixed_Number)
                {
                    SetPropertyReadOnly("BarSpacing", true);
                    SetPropertyReadOnly("NumberOfBars", false);
                }
                else if (m_layoutRule == LayoutRule.Maximum_Spacing)
                {
                    SetPropertyReadOnly("BarSpacing", false);
                    SetPropertyReadOnly("NumberOfBars", true);
                }

                // update the selected object is necessary
                if (null != UpdateSelectObjEvent)
                {
                    UpdateSelectObjEvent();
                }
            }
        }

        /// <summary>
        /// Bar spacing of path reinforcement,get/set property.
        /// </summary>
        [Category("Layers"), DisplayName("Bar Spacing"), ReadOnlyAttribute(false)]
        public String BarSpacing
        {
            get
            {
                return m_barSpacing;
            }
            set
            {
                if (!ValidateInch(value))
                {
                    throw new Exception("Invalid value.");
                }
                m_barSpacing = value;
            }
        }

        /// <summary>
        /// Primary bar type of path reinforcement,get/set property.
        /// </summary>
        [Category("Layers"), TypeConverter(typeof(BartypeConverter)), DisplayName("Primary Bar - Type")]
        public Autodesk.Revit.DB.ElementId PrimaryBarType
        {
            get
            {
                return m_primaryBarType;
            }
            set
            {
                m_primaryBarType = value;
            }
        }

        /// <summary>
        /// Primary bar length of path reinforcement,get/set property.
        /// </summary>
        [Category("Layers"), DisplayName("Primary Bar - Length")]
        public String PrimaryBarLength
        {
            get
            {
                return m_primaryBarLength;

            }
            set
            {
                if (!ValidateInch(value))
                {
                    throw new Exception("Invalid value.");
                }
                m_primaryBarLength = value;
            }
        }

        /// <summary>
        /// Face of path reinforcement, get/set property.
        /// </summary>
        [Category("Layers"), DisplayName("Face")]
        public Face Face
        {
            get
            {
                return m_face;
            }
            set
            {
                m_face = value;
            }
        }

        /// <summary>
        /// Get parameter by given name.
        /// </summary>
        /// <param name="name">name of parameter</param>
        /// <returns>parameter whose definition name is the given name.</returns>
        protected Parameter GetParameter(String name)
        {
            foreach (Parameter para in m_pathRein.Parameters)
            {
                if (para.Definition.Name.Equals(name))
                {
                    return para;
                }
            }
            return null;
        }

        /// <summary>
        /// set some properties to read only or not
        /// </summary>
        /// <param name="propertyName">name of property</param>
        /// <param name="readOnly">read only or not</param>
        void SetPropertyReadOnly(string propertyName, bool readOnly)
        {
            string strEx = string.Empty;
            try
            {
                Type type = typeof(System.ComponentModel.ReadOnlyAttribute);
                PropertyDescriptorCollection props = TypeDescriptor.GetProperties(this);
                AttributeCollection attrs = props[propertyName].Attributes;
                FieldInfo fld = type.GetField("isReadOnly",
                    BindingFlags.Instance | BindingFlags.NonPublic);
                fld.SetValue(attrs[type], readOnly);
            }
            catch (System.ArgumentException ex)
            {
                strEx = ex.ToString();
            }
            catch (FieldAccessException ex)
            {
                strEx = ex.ToString();
            }
            catch (System.Reflection.TargetException ex)
            {
                strEx = ex.ToString();
            }
            catch (Exception ex)
            {
                strEx = ex.ToString();
            }

            // exception occurs?
            if (strEx != string.Empty)
            {
                throw new Exception(strEx);
            }
        }

        /// <summary>
        /// validate inch like this 124'- 9".
        /// </summary>
        /// <param name="input">input string</param>
        /// <returns>true if input string is a valid inch.</returns>
        private Boolean ValidateInch(String input)
        {
            // check whether the input string is a valid double value.
            // if it's true, return directly, otherwise parse the string.
            try
            {
                Double.Parse(input);
                return true;
            }
            catch (Exception) 
            { 
                // reasonable exception.
                // continue to parse the string in below lines if exception occurs.
            }

            String inputTrim = input.Trim();
            int number = 0;     // number [0, 9].
            int sQuotation = 0; // single quotation mark.
            int dQuotation = 0; // double quotation mark.
            int hLine = 0;      // char '-' mark

            foreach (Char ch in inputTrim)
            {
                if (dQuotation > 0)
                {
                    return false;
                }

                if ('0' <= ch && ch <= '9')
                {
                    number++;
                }
                else if (ch.Equals('\''))
                {
                    if (sQuotation > 0 || number == 0)
                    {
                        return false;
                    }
                    sQuotation++;
                    number = 0;
                }
                else if (ch.Equals('\"'))
                {
                    if (dQuotation > 0 || number == 0)
                    {
                        return false;
                    }
                    dQuotation++;
                    number = 0;
                }
                else if (ch.Equals('-'))
                {
                    if (hLine != 0 || sQuotation == 0 || (sQuotation != 0 && number != 0))
                    {
                        return false;
                    }
                    hLine++;
                    number = 0;
                }
                else if (ch.Equals(' '))
                {
                    // skip the white space
                }
                else
                {
                    return false;
                }
            }

            //check whether the parsed string is valid.
            int length = inputTrim.Length;
            Char last = inputTrim[length - 1];
            if (dQuotation > 0 && !last.Equals('\"'))
            {
                return false;
            }

            if (sQuotation > 0 && dQuotation == 0 && !last.Equals('\''))
            {
                return false;
            }
            return true;
        }
    };
}

BarTypeConverter.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;
using System.ComponentModel;
using System.Globalization;

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

namespace Revit.SDK.Samples.PathReinforcement.CS
{
    /// <summary>
    /// Converter between Autodesk.Revit.DB.ElementId and Element's name
    /// </summary>
    public class BartypeConverter : TypeConverter
    {
        /// <summary>
        /// hash table 
        /// </summary>
        protected Hashtable m_hash = null;
        
        /// <summary>
        /// initialize m_hash
        /// </summary>
        public BartypeConverter()
        {
            m_hash = new Hashtable();
            GetConvertHash();
        }

        /// <summary>
        /// fill hash table
        /// </summary>
        public void GetConvertHash()
        {
            m_hash = Command.BarTypes;
        }

        /// <summary>
        /// Get supported standard value 
        /// </summary>
        /// <param name="context"></param>
        /// <returns>always return true</returns>
        public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
        {
            return true;
        }

        /// <summary>
        /// provide Autodesk.Revit.DB.ElementId collection
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
        {
            BartypeConverter.StandardValuesCollection standardValues = null;

            Autodesk.Revit.DB.ElementId[] Ids = new Autodesk.Revit.DB.ElementId[m_hash.Values.Count];
            int i = 0;

            foreach (DictionaryEntry de in m_hash)
            {
                Ids[i++] = (Autodesk.Revit.DB.ElementId)(de.Value);
            }
            standardValues = new StandardValuesCollection(Ids);

            return standardValues;
        }

        /// <summary>
        /// whether conversion is allowed
        /// </summary>
        /// <param name="context"></param>
        /// <param name="sourceType"></param>
        /// <returns></returns>
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            if (sourceType == typeof(string))
            {
                return true;
            }
            return base.CanConvertFrom(context, sourceType);
        }

        /// <summary>
        /// convert from Name to ElementId
        /// </summary>
        /// <param name="context"></param>
        /// <param name="culture"></param>
        /// <param name="v">Name</param>
        /// <returns>ElementId</returns>
        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object v)
        {
            if (v is string)
            {
                foreach (DictionaryEntry de in m_hash)
                {
                    if (de.Key.Equals(v.ToString()))
                    {
                        return de.Value;
                    }
                }
            }
            return base.ConvertFrom(context, culture, v);
        }

        /// <summary>
        /// convert from Autodesk.Revit.DB.ElementId to Name
        /// </summary>
        /// <param name="context"></param>
        /// <param name="culture"></param>
        /// <param name="v">ElementId</param>
        /// <param name="destinationType">String</param>
        /// <returns>Name</returns>
        public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object v, Type destinationType)
        {
            if (destinationType == typeof(string))
            {
                foreach (DictionaryEntry de in m_hash)
                {
                    Autodesk.Revit.DB.ElementId tmpId = (Autodesk.Revit.DB.ElementId)de.Value;
                    Autodesk.Revit.DB.ElementId cmpId = (Autodesk.Revit.DB.ElementId)v;

                    if (tmpId.IntegerValue == cmpId.IntegerValue)
                    {
                        return de.Key.ToString();
                    }
                }
                return "";
            }
            return base.ConvertTo(context, culture, v, destinationType);
        }

        /// <summary>
        /// always return true so that user can't input unexpected text
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
        {
            return true;
        }
    }
}

MathTools.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.Text;
using Autodesk.Revit.DB;

namespace Revit.SDK.Samples.PathReinforcement.CS
{
    /// <summary>
    /// Vector4 class is used to store vector 
    /// and contain method to handle the vector
    /// </summary>
    public class Vector4
    {
        #region Class member variables and properties
        /// <summary>
        /// The coordinate x value
        /// </summary>
        private float    m_x; 
        
        /// <summary>
        /// The coordinate y value
        /// </summary>
        private float    m_y; 

        /// <summary>
        /// The coordinate z value
        /// </summary>
        private float    m_z; 

        /// <summary>
        /// The coordinate w value
        /// </summary>
        private float    m_w = 1.0f;

        /// <summary>
        /// The coordinate x value
        /// </summary>
        public float X 
        {
            get
            {
                return m_x;
            }
            set
            {
                m_x = value;
            }
        }

        /// <summary>
        ///The coordinate y value 
        /// </summary>
        public float Y
        {
            get
            {
                return m_y;
            }
            set
            {
                m_y = value;
            }
        }

        /// <summary>
        /// The coordinate z value
        /// </summary>
        public float Z
        {
            get
            {
                return m_z;
            }
            set
            {
                m_z = value;
            }
        }

        /// <summary>
        /// The coordinate w value
        /// </summary>
        public float W
        {
            get
            {
                return m_w;
            }
            set
            {
                m_w = value;
            }
        }
        #endregion

        /// <summary>
        /// constructor
        /// </summary>
        public Vector4(float x, float y, float z)
        {
            this.X = x; 
            this.Y = y; 
            this.Z = z;
        }

        /// <summary>
        /// constructor, transform Autodesk.Revit.DB.XYZ to vector
        /// </summary>
        public Vector4(Autodesk.Revit.DB.XYZ v)
        {
            this.X = (float)v.X; 
            this.Y = (float)v.Y; 
            this.Z = (float)v.Z;
        }

        /// <summary>
        /// add two vectors
        /// </summary>
        /// <param name="va">first vector</param>
        /// <param name="vb">second vector</param>
        /// <returns>add result of two vectors</returns>
        public static Vector4 operator+ (Vector4 va, Vector4 vb)
        {
            return new Vector4(va.X + vb.X, va.Y + vb.Y, va.Z + vb.Z);
        }

        /// <summary>
        /// subtraction of two vectors
        /// </summary>
        /// <param name="va">first vector</param>
        /// <param name="vb">second vector</param>
        /// <returns>subtraction of two vectors</returns>
        public static Vector4 operator- (Vector4 va, Vector4 vb)
        {
            return new Vector4(va.X - vb.X, va.Y - vb.Y, va.Z - vb.Z);
        }

        /// <summary>
        /// get vector multiplied by a floating type value
        /// </summary>
        /// <param name="v">vector</param>
        /// <param name="factor">multiplier of floating type</param>
        /// <returns> the result vector </returns>
        public static Vector4 operator* (Vector4 v,float factor)
        {
            return new Vector4(v.X * factor, v.Y * factor, v.Z * factor);
        }

        /// <summary>
        /// get vector divided by a floating type value
        /// </summary>
        /// <param name="v">vector</param>
        /// <param name="factor">floating type value</param>
        /// <returns> vector divided by a floating type value</returns>
        public static Vector4 operator /(Vector4 v, float factor)
        {
            return new Vector4(v.X / factor, v.Y / factor, v.Z / factor);
        }

        /// <summary>
        /// dot multiply this vector with another vector
        /// </summary>
        /// <param name="v">vector</param>
        /// <returns> dot multiply result of two vectors </returns>
        public float DotProduct(Vector4 v)
        {
            return (this.X * v.X + this.Y * v.Y + this.Z * v.Z);
        }

        /// <summary>
        /// cross multiply vector
        /// </summary>
        /// <param name="v">second vector</param>
        /// <returns> cross multiply result of two vectors</returns>
        public Vector4 CrossProduct(Vector4 v)
        {
            return new Vector4(this.Y * v.Z - this.Z * v.Y,this.Z * v.X
                - this.X * v.Z,this.X * v.Y - this.Y * v.X);
        }

        /// <summary>
        /// dot multiply two vectors
        /// </summary>
        /// <param name="va">first vector</param>
        /// <param name="vb">second vector</param>
        /// <returns> dot product result of two vectors</returns>
        public static float DotProduct(Vector4 va, Vector4 vb)
        {
            return (va.X * vb.X + va.Y * vb.Y + va.Z * vb.Z);
        }

        /// <summary>
        /// cross multiply two vectors
        /// </summary>
        /// <param name="va">first vector</param>
        /// <param name="vb">second vector</param>
        /// <returns> cross multiply result of two vectors</returns>
        public static Vector4 CrossProduct(Vector4 va, Vector4 vb)
        {
            return new Vector4(va.Y * vb.Z - va.Z * vb.Y, va.Z * vb.X
                - va.X * vb.Z, va.X * vb.Y - va.Y * vb.X);
        }

        /// <summary>
        /// get unit vector
        /// </summary>
        public void Normalize()
        {
            float length = Length();
            if(length == 0)
            {
                length = 1;
            }
            this.X /= length;
            this.Y /= length;
            this.Z /= length;            
        }

        /// <summary>
        /// calculate the length of vector
        /// </summary>
        /// <returns>length of this vector</returns>
        public float Length()
        {
            return (float)Math.Sqrt(this.X * this.X + this.Y * this.Y + this.Z * this.Z);
        }
    };

    /// <summary>
    /// Matrix used to transform between ucs coordinate and world coordinate.
    /// </summary>
    public class Matrix4
    {
        #region MatrixType
        /// <summary>
        /// matrix algorithm
        /// </summary>
        public enum MatrixType
        {
            /// <summary>
            /// rotation matrix
            /// </summary>
            Rotation,

            /// <summary>
            /// translation matrix
            /// </summary>
            Translation,

            /// <summary>
            /// scale matrix
            /// </summary>
            Scale,

            /// <summary>
            /// rotation and translation mix matrix
            /// </summary>
            RotationAndTranslation,

            /// <summary>
            /// identity matrix
            /// </summary>
            Normal
        };
        private float[,] m_matrix = new float[4,4];
        private MatrixType m_type;
        #endregion

        /// <summary>
        /// default constructor
        /// </summary>
        public Matrix4()
        {
            m_type = MatrixType.Normal;
            Identity();            
        }

        /// <summary>
        /// constructor,rotation matrix,origin is at (0,0,0)
        /// </summary>
        /// <param name="xAxis">identity of x axis</param>
        /// <param name="yAxis">identity of y axis</param>
        /// <param name="zAxis">identity of z axis</param>
        public Matrix4(Vector4 xAxis,Vector4 yAxis, Vector4 zAxis)
        {
            m_type = MatrixType.Rotation;
            Identity();
            m_matrix[0, 0] = xAxis.X; m_matrix[0, 1] = xAxis.Y; m_matrix[0, 2] = xAxis.Z;
            m_matrix[1, 0] = yAxis.X; m_matrix[1, 1] = yAxis.Y; m_matrix[1, 2] = yAxis.Z;
            m_matrix[2, 0] = zAxis.X; m_matrix[2, 1] = zAxis.Y; m_matrix[2, 2] = zAxis.Z;
        }

        /// <summary>
        /// Constructor,translation matrix.
        /// </summary>
        /// <param name="origin">origin of ucs in world coordinate</param>
        public Matrix4(Vector4 origin)
        {
            m_type = MatrixType.Translation;
            Identity();
            m_matrix[3, 0] = origin.X; m_matrix[3, 1] = origin.Y; m_matrix[3, 2] = origin.Z;
        }

        /// <summary>
        /// rotation and translation matrix constructor
        /// </summary>
        /// <param name="xAxis">x Axis</param>
        /// <param name="yAxis">y Axis</param>
        /// <param name="zAxis">z Axis</param>
        /// <param name="origin">origin</param>
        public Matrix4(Vector4 xAxis, Vector4 yAxis, Vector4 zAxis, Vector4 origin)
        {
            m_type = MatrixType.RotationAndTranslation;
            Identity();
            m_matrix[0, 0] = xAxis.X;  m_matrix[0, 1] = xAxis.Y;  m_matrix[0, 2] = xAxis.Z;
            m_matrix[1, 0] = yAxis.X;  m_matrix[1, 1] = yAxis.Y;  m_matrix[1, 2] = yAxis.Z;
            m_matrix[2, 0] = zAxis.X;  m_matrix[2, 1] = zAxis.Y;  m_matrix[2, 2] = zAxis.Z;
            m_matrix[3, 0] = origin.X; m_matrix[3, 1] = origin.Y; m_matrix[3, 2] = origin.Z;
        }

        /// <summary>
        /// scale matrix constructor
        /// </summary>
        /// <param name="scale">scale factor</param>
        public Matrix4(float scale)
        {
            m_type = MatrixType.Scale;
            Identity();
            m_matrix[0, 0] = m_matrix[1, 1] = m_matrix[2, 2] = scale;
        }

        /// <summary>
        /// indexer of matrix
        /// </summary>
        /// <param name="row">row number</param>
        /// <param name="column">column number</param>
        /// <returns></returns>
        public float this[int row, int column]
        {
            get
            {
                return this.m_matrix[row, column];
            }
            set
            {
                this.m_matrix[row, column] = value;
            }
        }

        /// <summary>
        /// Identity matrix
        /// </summary>
        public void Identity()
        {
            for (int i = 0; i < 4; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    this.m_matrix[i, j] = 0.0f;
                }
            }
            this.m_matrix[0, 0] = 1.0f;
            this.m_matrix[1, 1] = 1.0f;
            this.m_matrix[2, 2] = 1.0f;
            this.m_matrix[3, 3] = 1.0f;
        }

        /// <summary>
        ///  multiply matrix left and right
        /// </summary>
        /// <param name="left">left matrix</param>
        /// <param name="right">right matrix</param>
        /// <returns>multiply result of two matrixes </returns>
        public static Matrix4 Multiply(Matrix4 left, Matrix4 right)
        {
            Matrix4 result = new Matrix4();
            for (int i = 0; i < 4; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    result[i, j] = left[i, 0] * right[0, j] + left[i, 1] * right[1, j]
                        + left[i, 2] * right[2, j] + left[i, 3] * right[3, j];
                }
            }
            return result;
        }

        /// <summary>
        /// transform point use this matrix
        /// </summary>
        /// <param name="point">point needed to be transformed</param>
        /// <returns>transform result</returns>
        public Vector4 Transform(Vector4  point)
        {
            return new Vector4(point.X * this[0, 0] + point.Y * this[1, 0]
                + point.Z * this[2, 0]+ point.W * this[3, 0],
                point.X * this[0, 1] + point.Y * this[1, 1]
                + point.Z * this[2, 1]+ point.W * this[3, 1],
                point.X * this[0, 2] + point.Y * this[1, 2]
                + point.Z * this[2, 2]+ point.W * this[3, 2]);
        }

        /// <summary>
        /// if m_matrix is a rotation matrix,this method can get the rotation inverse matrix.
        /// </summary>
        /// <returns>inversed rotation matrix</returns>
        public Matrix4 RotationInverse()
        {
            return new Matrix4(new Vector4(this[0, 0], this[1, 0], this[2, 0]), 
                new Vector4(this[0, 1], this[1, 1], this[2, 1]), 
                new Vector4(this[0, 2], this[1, 2], this[2, 2]));
        }

        /// <summary>
        /// if this m_matrix is a translation matrix,
        /// this method can get the translation inverse matrix.
        /// </summary>
        /// <returns>inversed translation matrix</returns>
        public Matrix4 TranslationInverse()
        {
            return new Matrix4(new Vector4(-this[3, 0], -this[3, 1], -this[3, 2]));
        } 
       
        /// <summary>
        /// get inverse matrix
        /// </summary>
        /// <returns>inversed matrix</returns>
        public Matrix4 Inverse()
        {
            switch(m_type)
            {
                case MatrixType.Rotation:
                    return RotationInverse();

                case MatrixType.Translation:
                    return TranslationInverse();

                case MatrixType.RotationAndTranslation:
                    return Multiply(TranslationInverse(),RotationInverse());
                
                case MatrixType.Scale:
                    return ScaleInverse();
               
                case MatrixType.Normal:
                    return new Matrix4();

                default: return null;
            }
        }

        /// <summary>
        /// if m_matrix is a scale matrix,this method can get the scale inverse matrix.
        /// </summary>
        /// <returns> inversed scale matrix</returns>
        public Matrix4 ScaleInverse()
        {
            return new Matrix4(1 / m_matrix[0,0]);
        }
    };
}