ソースを参照

mxg:提交模型检查

mengxiangge 5 年 前
コミット
8a2ed071ff
100 ファイル変更22399 行追加0 行削除
  1. BIN
      FWindSoft/Dlls/Newtonsoft.Json.dll
  2. 10912 0
      FWindSoft/Dlls/Newtonsoft.Json.xml
  3. BIN
      FWindSoft/Dlls/PinYinConverterCore.dll
  4. 160 0
      FWindSoft/Dlls/PinYinConverterCore.xml
  5. BIN
      FWindSoft/Dlls/RevitDll/2017/AdWindows.dll
  6. BIN
      FWindSoft/Dlls/RevitDll/2017/RevitAPI.dll
  7. BIN
      FWindSoft/Dlls/RevitDll/2017/RevitAPIIFC.dll
  8. BIN
      FWindSoft/Dlls/RevitDll/2017/RevitAPILink.dll
  9. BIN
      FWindSoft/Dlls/RevitDll/2017/RevitAPIUI.dll
  10. BIN
      FWindSoft/Dlls/RevitDll/2017/RevitAPIUILink.dll
  11. BIN
      FWindSoft/Dlls/RevitDll/2017/RevitAddInUtility.dll
  12. BIN
      FWindSoft/Dlls/RevitDll/2017/UIFramework.dll
  13. BIN
      FWindSoft/Dlls/RevitDll/2018/RevitAPI.dll
  14. BIN
      FWindSoft/Dlls/RevitDll/2018/RevitAPIUI.dll
  15. BIN
      FWindSoft/Dlls/RevitDll/2018/RevitAddInUtility.dll
  16. BIN
      FWindSoft/Dlls/RevitDll/Current/AdWindows.dll
  17. BIN
      FWindSoft/Dlls/RevitDll/Current/RevitAPI.dll
  18. BIN
      FWindSoft/Dlls/RevitDll/Current/RevitAPIIFC.dll
  19. BIN
      FWindSoft/Dlls/RevitDll/Current/RevitAPILink.dll
  20. BIN
      FWindSoft/Dlls/RevitDll/Current/RevitAPIUI.dll
  21. BIN
      FWindSoft/Dlls/RevitDll/Current/RevitAPIUILink.dll
  22. BIN
      FWindSoft/Dlls/RevitDll/Current/RevitAddInUtility.dll
  23. BIN
      FWindSoft/Dlls/RevitDll/Current/RevitVersion.dll
  24. BIN
      FWindSoft/Dlls/RevitDll/Current/UIFramework.dll
  25. BIN
      FWindSoft/Dlls/SAGA.DotNetUtils.dll
  26. BIN
      FWindSoft/Dlls/SAGA.RevitUtils.dll
  27. BIN
      FWindSoft/Dlls/System.Net.Http.Formatting.dll
  28. 4025 0
      FWindSoft/Dlls/System.Net.Http.Formatting.xml
  29. BIN
      FWindSoft/Dlls/System.Windows.Interactivity.dll
  30. 148 0
      FWindSoft/FWindSoft.Revit/Application/ExternalApplication.cs
  31. 152 0
      FWindSoft/FWindSoft.Revit/Application/RevitRegisterManager.cs
  32. 24 0
      FWindSoft/FWindSoft.Revit/Common/ElementEqualityComparer.cs
  33. 13 0
      FWindSoft/FWindSoft.Revit/Common/RevitSetting.cs
  34. 88 0
      FWindSoft/FWindSoft.Revit/Common/RevitTools.cs
  35. 121 0
      FWindSoft/FWindSoft.Revit/Common/SelectionFilter.cs
  36. 120 0
      FWindSoft/FWindSoft.Revit/DockablePane/DockableWindow.cs
  37. 78 0
      FWindSoft/FWindSoft.Revit/DockablePane/RevitCustomDockablePanels.cs
  38. 55 0
      FWindSoft/FWindSoft.Revit/ExtensibleStorage/EnumStorageExtension.cs
  39. 24 0
      FWindSoft/FWindSoft.Revit/ExtensibleStorage/ExtensibleAttribute.cs
  40. 329 0
      FWindSoft/FWindSoft.Revit/ExtensibleStorage/ExtensibleStorageExtension.cs
  41. 173 0
      FWindSoft/FWindSoft.Revit/ExtensibleStorage/ExtensibleStorageUtil.cs
  42. 21 0
      FWindSoft/FWindSoft.Revit/ExtensibleStorage/ICoustomStorage.cs
  43. 45 0
      FWindSoft/FWindSoft.Revit/ExtensibleStorage/InEnumUtil.cs
  44. 63 0
      FWindSoft/FWindSoft.Revit/Extension/ApplicationExtension.cs
  45. 91 0
      FWindSoft/FWindSoft.Revit/Extension/CableTrayExtension.cs
  46. 99 0
      FWindSoft/FWindSoft.Revit/Extension/ConduitExtension.cs
  47. 268 0
      FWindSoft/FWindSoft.Revit/Extension/ConnectorJoin/ConnectorExtension.cs
  48. 40 0
      FWindSoft/FWindSoft.Revit/Extension/ConnectorJoin/ConnectorSearchOptions.cs
  49. 399 0
      FWindSoft/FWindSoft.Revit/Extension/ConnectorJoin/ConnectorSearchUtils.cs
  50. 52 0
      FWindSoft/FWindSoft.Revit/Extension/ConnectorJoin/ElementPath.cs
  51. 48 0
      FWindSoft/FWindSoft.Revit/Extension/CurveElementExtension.cs
  52. 33 0
      FWindSoft/FWindSoft.Revit/Extension/DetailCurveExtension.cs
  53. 45 0
      FWindSoft/FWindSoft.Revit/Extension/DocumentExtension.cs
  54. 21 0
      FWindSoft/FWindSoft.Revit/Extension/DoubleExtension.cs
  55. 279 0
      FWindSoft/FWindSoft.Revit/Extension/DuctExtension.cs
  56. 186 0
      FWindSoft/FWindSoft.Revit/Extension/ElementExtension.cs
  57. 30 0
      FWindSoft/FWindSoft.Revit/Extension/ElementTypeExtension.cs
  58. 41 0
      FWindSoft/FWindSoft.Revit/Extension/FamilyInstanceExtension.cs
  59. 102 0
      FWindSoft/FWindSoft.Revit/Extension/Graphic/CurveExtension.cs
  60. 203 0
      FWindSoft/FWindSoft.Revit/Extension/Graphic/GeometryElementExtension.cs
  61. 117 0
      FWindSoft/FWindSoft.Revit/Extension/Graphic/LineExtension.cs
  62. 217 0
      FWindSoft/FWindSoft.Revit/Extension/Graphic/XYZExtension.cs
  63. 175 0
      FWindSoft/FWindSoft.Revit/Extension/InsulationExtension.cs
  64. 53 0
      FWindSoft/FWindSoft.Revit/Extension/LocationExtension.cs
  65. 153 0
      FWindSoft/FWindSoft.Revit/Extension/MepCurveExtension.cs
  66. 150 0
      FWindSoft/FWindSoft.Revit/Extension/MepCurveTypeExtension.cs
  67. 127 0
      FWindSoft/FWindSoft.Revit/Extension/MepSystemTypeExtension.cs
  68. 12 0
      FWindSoft/FWindSoft.Revit/Extension/ModelCurveExtension.cs
  69. 386 0
      FWindSoft/FWindSoft.Revit/Extension/PipeExtension.cs
  70. 203 0
      FWindSoft/FWindSoft.Revit/Extension/SelectionExtension.cs
  71. 134 0
      FWindSoft/FWindSoft.Revit/Extension/TextNodeExtension.cs
  72. 38 0
      FWindSoft/FWindSoft.Revit/Extension/TransactionExtension.cs
  73. 58 0
      FWindSoft/FWindSoft.Revit/Extension/UIDocumentExtension.cs
  74. 28 0
      FWindSoft/FWindSoft.Revit/ExternalCommand.cs
  75. 43 0
      FWindSoft/FWindSoft.Revit/ExternalCommand/ExternalCommand.cs
  76. 116 0
      FWindSoft/FWindSoft.Revit/ExternalEvent/ExternalEventCommand.cs
  77. 206 0
      FWindSoft/FWindSoft.Revit/FWindSoft.Revit.csproj
  78. 125 0
      FWindSoft/FWindSoft.Revit/FamilyManager/FamilyExtension.cs
  79. 26 0
      FWindSoft/FWindSoft.Revit/FamilyManager/FamilyLoadOptions.cs
  80. 95 0
      FWindSoft/FWindSoft.Revit/FamilyManager/FamilyManagerExtension.cs
  81. 54 0
      FWindSoft/FWindSoft.Revit/FamilyManager/FamilySymbolExtension.cs
  82. 81 0
      FWindSoft/FWindSoft.Revit/IdlingEvent/GuardianIdlingCommand.cs
  83. 40 0
      FWindSoft/FWindSoft.Revit/IdlingEvent/IdlingCommand.cs
  84. 70 0
      FWindSoft/FWindSoft.Revit/IdlingEvent/IdlingCommands.cs
  85. 80 0
      FWindSoft/FWindSoft.Revit/IdlingEvent/IdlingEventCommand.cs
  86. 41 0
      FWindSoft/FWindSoft.Revit/IdlingEvent/SelectedChangedCommand.cs
  87. 64 0
      FWindSoft/FWindSoft.Revit/IdlingEvent/SingleIdingCommand.cs
  88. 3 0
      FWindSoft/FWindSoft.Revit/IdlingEvent/说明.txt
  89. 54 0
      FWindSoft/FWindSoft.Revit/Interfaces/IRevitEventHandler.cs
  90. 22 0
      FWindSoft/FWindSoft.Revit/Interfaces/IRevitRegister.cs
  91. 24 0
      FWindSoft/FWindSoft.Revit/Menu/AutoParseButtonAttribute.cs
  92. 182 0
      FWindSoft/FWindSoft.Revit/Menu/ButtonAssemblyManager.cs
  93. 159 0
      FWindSoft/FWindSoft.Revit/Menu/ButtonAttribute.cs
  94. 113 0
      FWindSoft/FWindSoft.Revit/Menu/GroupButtons.cs
  95. 180 0
      FWindSoft/FWindSoft.Revit/Menu/MenuConfig.cs
  96. 125 0
      FWindSoft/FWindSoft.Revit/Menu/MenuConfigParser.cs
  97. 53 0
      FWindSoft/FWindSoft.Revit/Menu/RevitButton.cs
  98. 23 0
      FWindSoft/FWindSoft.Revit/Menu/RevitButtonStyle.cs
  99. 81 0
      FWindSoft/FWindSoft.Revit/Menu/RevitMenuComponment.cs
  100. 0 0
      FWindSoft/FWindSoft.Revit/Menu/RevitPanel.cs

BIN
FWindSoft/Dlls/Newtonsoft.Json.dll


ファイルの差分が大きいため隠しています
+ 10912 - 0
FWindSoft/Dlls/Newtonsoft.Json.xml


BIN
FWindSoft/Dlls/PinYinConverterCore.dll


+ 160 - 0
FWindSoft/Dlls/PinYinConverterCore.xml

@@ -0,0 +1,160 @@
+<?xml version="1.0"?>
+<doc>
+    <assembly>
+        <name>PinYinConverterCore</name>
+    </assembly>
+    <members>
+        <member name="T:Microsoft.International.Converters.PinYinConverter.AssemblyResource">
+            <summary>
+              一个强类型的资源类,用于查找本地化的字符串等。
+            </summary>
+        </member>
+        <member name="P:Microsoft.International.Converters.PinYinConverter.AssemblyResource.ResourceManager">
+            <summary>
+              返回此类使用的缓存的 ResourceManager 实例。
+            </summary>
+        </member>
+        <member name="P:Microsoft.International.Converters.PinYinConverter.AssemblyResource.Culture">
+            <summary>
+              使用此强类型资源类,为所有资源查找
+              重写当前线程的 CurrentUICulture 属性。
+            </summary>
+        </member>
+        <member name="P:Microsoft.International.Converters.PinYinConverter.AssemblyResource.CHARACTER_NOT_SUPPORTED">
+            <summary>
+              查找类似 The character is not in extended character set of Simplified Chinese. 的本地化字符串。
+            </summary>
+        </member>
+        <member name="P:Microsoft.International.Converters.PinYinConverter.AssemblyResource.EXCEED_BORDER_EXCEPTION">
+            <summary>
+              查找类似 The number of strokes cannot be a negative value or greater than the maximum number of strokes  in the Chinese character. 的本地化字符串。
+            </summary>
+        </member>
+        <member name="P:Microsoft.International.Converters.PinYinConverter.AssemblyResource.INDEX_OUT_OF_RANGE">
+            <summary>
+              查找类似 The index is out of range. 的本地化字符串。
+            </summary>
+        </member>
+        <member name="T:Microsoft.International.Converters.PinYinConverter.ChineseChar">
+            <summary>
+            封装了简体中文的读音和笔画等基本信息。
+            </summary>
+        </member>
+        <member name="P:Microsoft.International.Converters.PinYinConverter.ChineseChar.PinyinCount">
+            <summary>
+            获取这个字符的拼音个数。
+            </summary>
+        </member>
+        <member name="P:Microsoft.International.Converters.PinYinConverter.ChineseChar.StrokeNumber">
+            <summary>
+            获取这个字符的笔画数。
+            </summary>
+        </member>
+        <member name="P:Microsoft.International.Converters.PinYinConverter.ChineseChar.IsPolyphone">
+            <summary>
+            获取这个字符是否是多音字。
+            </summary>
+        </member>
+        <member name="P:Microsoft.International.Converters.PinYinConverter.ChineseChar.Pinyins">
+            <summary>
+            获取这个字符的拼音。该集合长度不能表示实际拼音个数,实际拼音个数请使用PinyinCount字段
+            </summary>
+        </member>
+        <member name="P:Microsoft.International.Converters.PinYinConverter.ChineseChar.ChineseCharacter">
+            <summary>
+            获取这个汉字字符。
+            </summary>
+        </member>
+        <member name="M:Microsoft.International.Converters.PinYinConverter.ChineseChar.#ctor(System.Char)">
+            <summary>
+            ChineseChar类的构造函数。
+            </summary>
+            <param name="ch">指定的汉字字符。</param>
+        </member>
+        <member name="M:Microsoft.International.Converters.PinYinConverter.ChineseChar.HasSound(System.String)">
+            <summary>
+            识别字符是否有指定的读音。
+            </summary>
+            <param name="pinyin">指定的需要被识别的拼音</param>
+            <returns>如果指定的拼音字符串在实例字符的拼音集合中则返回ture,否则返回false。 </returns>
+        </member>
+        <member name="M:Microsoft.International.Converters.PinYinConverter.ChineseChar.IsHomophone(System.Char)">
+            <summary>
+            识别给出的字符是否是实例字符的同音字。 
+            </summary>
+            <param name="ch">指出需要识别的字符。</param>
+            <returns>如果给出的实例字符是同音字则返回ture,否则返回false。</returns>
+        </member>
+        <member name="M:Microsoft.International.Converters.PinYinConverter.ChineseChar.IsHomophone(System.Char,System.Char)">
+            <summary>
+            识别给出的两个字符是否是同音字。
+            </summary>
+            <param name="ch1">指出第一个字符</param>
+            <param name="ch2">指出第二个字符</param>
+            <returns>如果给出的字符是同音字返回ture,否则返回false。</returns>
+        </member>
+        <member name="M:Microsoft.International.Converters.PinYinConverter.ChineseChar.CompareStrokeNumber(System.Char)">
+            <summary>
+            将给出的字符和实例字符的笔画数进行比较。
+            </summary>
+            <param name="ch">显示给出的字符</param>
+            <returns>说明比较操作的结果。 如果给出字符和实例字符的笔画数相同,返回值为 0。 如果实例字符比给出字符的笔画多,返回值为> 0。 如果实例字符比给出字符的笔画少,返回值为 &lt; 0。 </returns>
+        </member>
+        <member name="M:Microsoft.International.Converters.PinYinConverter.ChineseChar.GetChars(System.String)">
+            <summary>
+            获取给定拼音的所有同音字。
+            </summary>
+            <param name="pinyin">指出读音。</param>
+            <returns>返回具有相同的指定拼音的字符串列表。 如果拼音不是有效值则返回空。 </returns>
+        </member>
+        <member name="M:Microsoft.International.Converters.PinYinConverter.ChineseChar.IsValidPinyin(System.String)">
+            <summary>
+            识别给出的拼音是否是一个有效的拼音字符串。
+            </summary>
+            <param name="pinyin">指出需要识别的字符串。</param>
+            <returns>如果指定的字符串是一个有效的拼音字符串则返回ture,否则返回false。</returns>
+        </member>
+        <member name="M:Microsoft.International.Converters.PinYinConverter.ChineseChar.IsValidChar(System.Char)">
+            <summary>
+            识别给出的字符串是否是一个有效的汉字字符。
+            </summary>
+            <param name="ch">指出需要识别的字符。</param>
+            <returns>如果指定的字符是一个有效的汉字字符则返回ture,否则返回false。</returns>
+        </member>
+        <member name="M:Microsoft.International.Converters.PinYinConverter.ChineseChar.IsValidStrokeNumber(System.Int16)">
+            <summary>
+            识别给出的笔画数是否是一个有效的笔画数。
+            </summary>
+            <param name="strokeNumber">指出需要识别的笔画数。</param>
+            <returns>如果指定的笔画数是一个有效的笔画数则返回ture,否则返回false。</returns>
+        </member>
+        <member name="M:Microsoft.International.Converters.PinYinConverter.ChineseChar.GetHomophoneCount(System.String)">
+            <summary>
+            检索具有指定拼音的字符数。
+            </summary>
+            <param name="pinyin">显示需要被识别的拼音字符串。</param>
+            <returns>返回具有指定拼音的字符数。 如果拼音不是有效值则返回-1。</returns>
+        </member>
+        <member name="M:Microsoft.International.Converters.PinYinConverter.ChineseChar.GetStrokeNumber(System.Char)">
+            <summary>
+            检索指定字符的笔画数。 
+            </summary>
+            <param name="ch">指出需要识别的字符。</param>
+            <returns>返回指定字符的笔画数。 如果字符不是有效值则返回-1。 </returns>
+        </member>
+        <member name="M:Microsoft.International.Converters.PinYinConverter.ChineseChar.GetChars(System.Int16)">
+            <summary>
+            检索具有指定笔画数的所有字符串。
+            </summary>
+            <param name="strokeNumber">指出需要被识别的笔画数。</param>
+            <returns>返回具有指定笔画数的字符列表。 如果笔画数是无效值返回空。</returns>
+        </member>
+        <member name="M:Microsoft.International.Converters.PinYinConverter.ChineseChar.GetCharCount(System.Int16)">
+            <summary>
+            检索具有指定笔画数的字符个数。
+            </summary>
+            <param name="strokeNumber">显示需要被识别的笔画数。</param>
+            <returns>返回具有指定笔画数的字符数。 如果笔画数是无效值返回-1。</returns>
+        </member>
+    </members>
+</doc>

BIN
FWindSoft/Dlls/RevitDll/2017/AdWindows.dll


BIN
FWindSoft/Dlls/RevitDll/2017/RevitAPI.dll


BIN
FWindSoft/Dlls/RevitDll/2017/RevitAPIIFC.dll


BIN
FWindSoft/Dlls/RevitDll/2017/RevitAPILink.dll


BIN
FWindSoft/Dlls/RevitDll/2017/RevitAPIUI.dll


BIN
FWindSoft/Dlls/RevitDll/2017/RevitAPIUILink.dll


BIN
FWindSoft/Dlls/RevitDll/2017/RevitAddInUtility.dll


BIN
FWindSoft/Dlls/RevitDll/2017/UIFramework.dll


BIN
FWindSoft/Dlls/RevitDll/2018/RevitAPI.dll


BIN
FWindSoft/Dlls/RevitDll/2018/RevitAPIUI.dll


BIN
FWindSoft/Dlls/RevitDll/2018/RevitAddInUtility.dll


BIN
FWindSoft/Dlls/RevitDll/Current/AdWindows.dll


BIN
FWindSoft/Dlls/RevitDll/Current/RevitAPI.dll


BIN
FWindSoft/Dlls/RevitDll/Current/RevitAPIIFC.dll


BIN
FWindSoft/Dlls/RevitDll/Current/RevitAPILink.dll


BIN
FWindSoft/Dlls/RevitDll/Current/RevitAPIUI.dll


BIN
FWindSoft/Dlls/RevitDll/Current/RevitAPIUILink.dll


BIN
FWindSoft/Dlls/RevitDll/Current/RevitAddInUtility.dll


BIN
FWindSoft/Dlls/RevitDll/Current/RevitVersion.dll


BIN
FWindSoft/Dlls/RevitDll/Current/UIFramework.dll


BIN
FWindSoft/Dlls/SAGA.DotNetUtils.dll


BIN
FWindSoft/Dlls/SAGA.RevitUtils.dll


BIN
FWindSoft/Dlls/System.Net.Http.Formatting.dll


ファイルの差分が大きいため隠しています
+ 4025 - 0
FWindSoft/Dlls/System.Net.Http.Formatting.xml


BIN
FWindSoft/Dlls/System.Windows.Interactivity.dll


+ 148 - 0
FWindSoft/FWindSoft.Revit/Application/ExternalApplication.cs

@@ -0,0 +1,148 @@
+using System;
+using System.Text;
+using Autodesk.Revit.DB.Events;
+using Autodesk.Revit.UI;
+using Autodesk.Revit.UI.Events;
+using FWindSoft.Events;
+
+namespace FWindSoft.Revit
+{
+    [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
+    [Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)]
+    [Autodesk.Revit.Attributes.Journaling(Autodesk.Revit.Attributes.JournalingMode.NoCommandData)]
+    public class ExternalApplication : IExternalApplication
+    {
+        #region 构造函数
+        public ExternalApplication()
+        {
+            Events = new EventsWrapper();
+            Registers = new RevitRegisterManager(true);
+        } 
+        #endregion
+
+        #region 私有相关
+        /// <summary>
+        /// 事件包装器(不是每一个事件都进行了包装)
+        /// </summary>
+        public EventsWrapper Events { get;private set; }
+        private RevitRegisterManager Registers { get; set; }
+        #endregion
+        public static ExternalApplication CurrentApp{ get;private set; }
+        public virtual Result OnStartup(UIControlledApplication application)
+        {
+            RevitVersion.AddInManager.CheckCancelAddin();
+            CurrentApp = this;
+            UIControlApp = application;
+            #region 核心区,与ShutDown顺序相反相反
+            #region 事件绑定
+            Events.AddBindings(application);
+            Events.AddBindings(application.ControlledApplication);
+            #endregion
+            Registers.AddEvents(this);
+            AttachExecute(application);
+            #endregion
+            //加载application
+            Idling += ExternalApplication_Idling;
+            return Result.Succeeded;
+        }
+
+        /*此类由revit初始化
+         */
+        public virtual Result OnShutdown(UIControlledApplication application)
+        {
+            CurrentApp = null;
+            UIControlApp = application;
+
+            ShutExecute(application);
+            Registers.RemoveEvents(this);
+            #region 事件绑定
+            Events.RemoveBindings(application);
+            Events.RemoveBindings(application.ControlledApplication);
+            #endregion      
+         
+            return Result.Succeeded;
+        }
+
+        private static void ExternalApplication_Idling(object sender, IdlingEventArgs e)
+        {
+            RevitCore.InitCore((UIApplication) sender);
+            if (CurrentApp != null)
+            {
+                CurrentApp.Idling -= ExternalApplication_Idling;
+            }
+        }
+
+        #region 属性相关
+        /// <summary>
+        /// 关联UIControlApp
+        /// </summary>
+        public UIControlledApplication UIControlApp { get; private set; }
+        #endregion
+        #region 事件相关扩展    
+        public event EventHandler<IdlingEventArgs> Idling
+        {
+            add { Events["Idling"]?.AddEventHandler(value); }
+            remove { Events["Idling"]?.RemoveEventHandler(value); }
+        }
+        public event EventHandler<DocumentOpenedEventArgs> DocumentOpened
+        {
+            add { Events["DocumentOpened"]?.AddEventHandler(value); }
+            remove { Events["DocumentOpened"]?.RemoveEventHandler(value); }
+        }
+        #endregion
+
+        #region 自定义扩展
+        /// <summary>
+        /// 附加启动时的初始化设置
+        /// </summary>
+        protected virtual void AttachExecute(UIControlledApplication application)
+        {
+            //读一个初始化的配置文件,然后顺序执行配置文件中的各项操作
+            //1、定义一个命令度配置文件
+            //2、根据配置文件中的相关设置,再进行执行
+            DockableWindow win = new DockableWindow();
+            win.RegisterDockableWindow(CurrentApp.UIControlApp, RevitCustomDockablePanels.Default);
+        }
+
+        /// <summary>
+        /// 附加启动时的初始化设置
+        /// </summary>
+        protected virtual void ShutExecute(UIControlledApplication application)
+        {
+           
+        }
+        #endregion
+
+        #region 未处理异常捕获
+        /// <summary>
+        /// 不会未处理异常
+        /// </summary>
+        protected void CatchUnhandledException()
+        {
+            AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
+        }
+        /// <summary>
+        /// 去掉捕获未处理异常
+        /// </summary>
+        protected void NoCatchUnhandledException()
+        {
+            AppDomain.CurrentDomain.UnhandledException -= CurrentDomain_UnhandledException;
+        }
+        private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
+        {
+            StringBuilder builder = new StringBuilder();
+            var exception = e.ExceptionObject as Exception;
+            if (exception != null)
+            {
+                builder.AppendLine("Messsage:" + exception.Message);
+                builder.AppendLine("Trace:" + exception.StackTrace);
+            }
+            else
+            {
+                builder.Append("未处理异常");
+            }
+            TaskDialog.Show("捕获异常", builder.ToString());
+        }
+        #endregion
+    }
+}

+ 152 - 0
FWindSoft/FWindSoft.Revit/Application/RevitRegisterManager.cs

@@ -0,0 +1,152 @@
+/*-------------------------------------------------------------------------
+ * 功能描述:RevitEventsBinding
+ * 作者:xulisong
+ * 创建时间: 2019/1/4 9:17:42
+ * 版本号:v1.0
+ *  -------------------------------------------------------------------------*/
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Xml;
+using Autodesk.Revit.UI;
+using FWindSoft.Common;
+
+namespace FWindSoft.Revit
+{
+    /*
+     * 该策略未实用维护;
+     * 2016后,事件不能随意的在程序中绑定,所以后续使用通过代理来完成
+     */
+    /// <summary>
+    /// 事件绑定
+    /// </summary>
+    public class RevitRegisterManager
+    {
+        private const string DefaultConfig = "RevitRegister";
+        public RevitRegisterManager()
+        {
+            Registers = new List<IRevitRegister>();
+           
+        }
+        public RevitRegisterManager(bool loadDefault):this()
+        {
+            if (loadDefault)
+            {
+                LoadDefaultConfig();
+            }
+        }
+        /// <summary>
+        /// 存放注册配置文件的位置
+        /// </summary>
+        public static List<string> ConfigFiles { get; private set; } = new List<string>();
+        #region 属性相关
+        /// <summary>
+        /// 关联引用程序
+        /// </summary>
+        public UIControlledApplication CurrentApp { get; protected set; }
+        public List<IRevitRegister> Registers { get;private set; }
+        #endregion
+        public virtual void AddEvents(ExternalApplication application)
+        {
+            //必须解绑,才能释放实例
+            CurrentApp = application.UIControlApp;
+            if (Registers != null)
+            {
+                Registers.ForEach(r => r.Register(application));
+            }
+        }
+        /// <summary>
+        /// 移除绑定事件
+        /// </summary>
+        /// <param name="application"></param>
+        public virtual void RemoveEvents(ExternalApplication application)
+        {
+            if (Registers != null)
+            {
+                Registers.ForEach(r => r.Unregister(application));
+            }
+            //必须解绑,才能释放实例
+            CurrentApp = application.UIControlApp;
+        }
+
+        /// <summary>
+        /// 加载指定目录下的接口信息
+        /// </summary>
+        /// <param name="filePath"></param>
+        public void LoadConfig(string filePath)
+        {
+            if (!File.Exists(filePath)||Path.GetExtension(filePath)!=".xml")
+            {
+                return;
+            }
+            List<object> objects = new List<object>();
+            var document = new XmlDocument();
+            document.Load(filePath);
+            var nodes = document.SelectNodes(string.Format($"//RevitRegister"));
+            if (nodes == null)
+            {
+                return;
+            }
+            foreach (XmlNode node in nodes)
+            {
+                try
+                {
+                    string dllName = node.SelectSingleNode("DllName")?.InnerText.Trim();
+                    string className = node.SelectSingleNode("ClassName")?.InnerText.Trim();
+                    if (string.IsNullOrWhiteSpace(dllName) || string.IsNullOrWhiteSpace(className))
+                    {
+                        continue;
+                    }
+                    string path = Path.Combine(App.AppRunPath, dllName);
+                    if (File.Exists(path))
+                    {
+                        Assembly tempAsembly = Assembly.LoadFrom(path);
+                        objects.Add(tempAsembly.CreateInstance(className));
+                    }
+                }
+                catch (Exception e)
+                {
+                }
+            }
+
+            Registers.AddRange(objects.OfType<IRevitRegister>());
+        }
+
+        public void LoadDefaultConfig()
+        {
+            List<string> files = new List<string>();
+            var fileName = Path.Combine(App.DllRunPath, DefaultConfig + ".xml");
+
+            #region 路径获取
+
+            if (!File.Exists(fileName))
+            {
+                var directory = Path.Combine(App.DllRunPath, DefaultConfig);
+                var tempDirectors = new List<string>() {directory};
+                for (int i = 0; i < tempDirectors.Count; i++)
+                {
+                    var currentPath = tempDirectors[i];
+                    if (!Directory.Exists(currentPath))
+                    {
+                        continue;
+                    }
+                    files.AddRange(Directory.GetFiles(currentPath));
+                    tempDirectors.AddRange(Directory.GetDirectories(currentPath));
+                }
+
+            }
+            else
+            {
+                files.Add(fileName);
+            }
+            #endregion
+
+            files.AddRange(ConfigFiles);
+            files.ForEach(s => LoadConfig(s));
+
+        }
+    }
+}

+ 24 - 0
FWindSoft/FWindSoft.Revit/Common/ElementEqualityComparer.cs

@@ -0,0 +1,24 @@
+using Autodesk.Revit.DB;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit.Common
+{
+    public class ElementEqualityComparer: IEqualityComparer<Element>
+    {
+        public bool Equals(Element x, Element y)
+        {
+            bool flag = false;
+            return x.Id==y.Id;
+        }
+
+        public int GetHashCode(Element obj)
+        {
+            return 0;
+        }
+    }
+}

+ 13 - 0
FWindSoft/FWindSoft.Revit/Common/RevitSetting.cs

@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit.Common
+{
+    public static class RevitSetting
+    {
+        public readonly static List<string> RvtForbiddenChars = new List<string>() { "\\", ":", "{", "}", "[", "]", "|", ";", "<", ">", "?", "`", "~" };
+    }
+}

+ 88 - 0
FWindSoft/FWindSoft.Revit/Common/RevitTools.cs

@@ -0,0 +1,88 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using Autodesk.Revit.DB;
+using Autodesk.Revit.UI.Selection;
+
+namespace FWindSoft.Revit.Common
+{
+    public static class RevitTools
+    {
+        /// <summary>
+        /// 移除非法字符串
+        /// </summary>
+        /// <param name="strValue"></param>
+        /// <returns></returns>
+        public static string RemoveForbiddenChars(this string strValue)
+        {
+            if (string.IsNullOrWhiteSpace(strValue))
+            {
+                return strValue;
+            }
+            foreach (var item in RevitSetting.RvtForbiddenChars)
+            {
+                strValue=strValue.Replace(item, "");
+            }
+            return strValue;
+        }
+
+        public static int RevitLeftPoint
+        {
+            get
+            {
+                var mainRec = RevitCore.UIApp.DrawingAreaExtents;
+                return mainRec.Left;
+            }
+        }
+        public static int RevitRightPoint
+        {
+            get
+            {
+                var mainRec = RevitCore.UIApp.DrawingAreaExtents;
+                return mainRec.Right;
+            }
+        }
+        public static int RevitTopPoint
+        {
+            get
+            {
+                var mainRec = RevitCore.UIApp.MainWindowExtents;              
+                return mainRec.Top;
+            }
+        }
+        public static int RevitBottomPoint
+        {
+            get
+            {              
+                var mainRec = RevitCore.UIApp.DrawingAreaExtents;
+                return mainRec.Bottom;
+            }
+        }
+
+        /// <summary>
+        /// 整数转rgb
+        /// </summary>
+        /// <param name="intColor"></param>
+        /// <returns></returns>
+        public static Color GetColor(int intColor)
+        {
+            byte b = (byte)(intColor / (256 * 256));
+            byte g = (byte)((intColor - b * 256 * 256) / 256);
+            byte r = (byte)(intColor - b * 256 * 256 - g * 256);
+            return new Color(r, g, b);
+        }
+
+        /// <summary>
+        /// rgb转整数(Revit参数使用)
+        /// </summary>
+        /// <param name="color"></param>
+        /// <returns></returns>
+        public static int GetColor(Color color)
+        {
+            return color.Red + color.Green * 256 + color.Blue * 256 * 256;
+        }
+    }
+}

+ 121 - 0
FWindSoft/FWindSoft.Revit/Common/SelectionFilter.cs

@@ -0,0 +1,121 @@
+/*-------------------------------------------------------------------------
+ * 功能描述:SelectionFilter
+ * 作者:xulisong
+ * 创建时间: 2019/5/23 14:14:35
+ * 版本号:v1.0
+ *  -------------------------------------------------------------------------*/
+
+using Autodesk.Revit.DB;
+using Autodesk.Revit.UI.Selection;
+using FWindSoft.Revit.Extension;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit.Common
+{
+    public class SelectionFilter : ISelectionFilter
+    {
+        private Predicate<Element> m_AllowElement;
+        private Func<Reference,XYZ,bool> m_AllowReference;
+        public SelectionFilter(Predicate<Element> allowElement, Func<Reference, XYZ, bool> allowReference)
+        {
+            m_AllowElement = allowElement;
+            m_AllowReference = allowReference;
+        }
+        public bool AllowElement(Element elem)
+        {
+            if (m_AllowElement != null)
+            {
+                return m_AllowElement.Invoke(elem);
+            }
+            return true;
+        }
+
+        public bool AllowReference(Reference reference, XYZ position)
+        {
+            if (m_AllowReference != null)
+            {
+                return m_AllowReference.Invoke(reference,position);
+            }
+            return true;
+        }    
+    }
+
+    /// <summary>
+    /// 类型选择过滤器
+    /// </summary>
+    public class TypeSelectionFilter : ISelectionFilter
+    {
+        private Type m_Type;
+
+        public TypeSelectionFilter(Type type)
+        {
+            m_Type = type;
+        }
+        public bool AllowElement(Element elem)
+        {
+            return elem.GetType() == m_Type;
+        }
+        public bool AllowReference(Reference reference, XYZ position)
+        {
+            return true;
+        }
+    }
+
+    /// <summary>
+    /// 类别过滤器
+    /// </summary>
+    public class CategorySelectionFilter : ISelectionFilter
+    {
+        private BuiltInCategory m_BuiltInCategory;
+
+        public CategorySelectionFilter(BuiltInCategory builtInCategory)
+        {
+            m_BuiltInCategory= builtInCategory;
+        }
+        public bool AllowElement(Element elem)
+        {
+            var bit = elem.GetCategory();
+            return bit== m_BuiltInCategory;
+        }
+
+        public bool AllowReference(Reference reference, XYZ position)
+        {
+            return true;
+        }
+    }
+    /// <summary>
+    /// 多类别过滤器
+    /// </summary>
+    public class CategoriesSelectionFilter : ISelectionFilter
+    {
+        private readonly List<BuiltInCategory> m_Categories = new List<BuiltInCategory>();
+
+        public CategoriesSelectionFilter(BuiltInCategory bic)
+        {
+            m_Categories.Add(bic);
+        }
+        public CategoriesSelectionFilter(List<BuiltInCategory> categories)
+        {
+            m_Categories.AddRange(categories??new List<BuiltInCategory>());
+        }
+        public bool AllowElement(Element elem)
+        {
+            if (!m_Categories.Any())
+            {
+                return false;
+            }
+
+            var useCategory = elem.GetCategory();
+            return m_Categories.Any(p => p == useCategory);
+        }
+
+        public bool AllowReference(Reference reference, XYZ position)
+        {
+            return true;
+        }
+    }
+}

+ 120 - 0
FWindSoft/FWindSoft.Revit/DockablePane/DockableWindow.cs

@@ -0,0 +1,120 @@
+/*-------------------------------------------------------------------------
+ * 功能描述:DockableWindow
+ * 作者:xulisong
+ * 创建时间: 2019/5/31 17:13:16
+ * 版本号:v1.0
+ *  -------------------------------------------------------------------------*/
+
+using Autodesk.Revit.UI;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Media;
+
+namespace FWindSoft.Revit
+{
+    public  class DockableWindow : Page, IDockablePaneProvider
+    {
+        public DockableWindow()
+        {
+            Background = Brushes.White;
+        }
+        #region 属性相关,注册时使用
+        /// <summary>
+        /// 关联PaneId
+        /// </summary>
+        public DockablePaneId PaneId { get; private set; }
+        /// <summary>
+        /// 关联UIControlledApplication
+        /// </summary>
+        public UIControlledApplication UIControlledApplication { get; private set; }
+        /// <summary>
+        /// 关联UIApplication
+        /// </summary>
+        public UIApplication UIApplication { get; private set; }
+        #endregion
+        public virtual void SetupDockablePane(DockablePaneProviderData data)
+        {
+            data.FrameworkElement = this as FrameworkElement;
+            data.InitialState = new DockablePaneState();
+            data.InitialState.DockPosition = DockPosition.Right;
+            if (data.InitialState.DockPosition == DockPosition.Floating)
+            {
+                data.InitialState.SetFloatingRectangle(new Autodesk.Revit.DB.Rectangle(100, 100, 100, 100));
+            }
+        }
+        /// <summary>
+        /// 注册窗体到app
+        /// </summary>
+        /// <param name="application"></param>
+        /// <param name="mainGuid"></param>
+        public DockableWindow RegisterDockableWindow(UIControlledApplication application, DockablePaneId mainGuid)
+        {
+            string title = string.IsNullOrWhiteSpace(this.Title) ? this.GetType().ToString() : this.Title;
+            UIControlledApplication = application;
+            PaneId = mainGuid;
+            return RevitCustomDockablePanels.RegisterDockablePane(application, PaneId, title, this);
+        }
+        public DockableWindow RegisterDockableWindow(UIApplication application, DockablePaneId mainGuid)
+        {
+            string title = string.IsNullOrWhiteSpace(this.Title) ? this.GetType().ToString() : this.Title;
+            UIApplication = application;
+            PaneId = mainGuid;
+            return RevitCustomDockablePanels.RegisterDockablePane(application, PaneId, title, this);
+        }
+        public new void Show()
+        {
+            try
+            {
+                DockablePane dockPane = null;
+                if (UIControlledApplication != null)
+                {
+                    dockPane = RevitCustomDockablePanels.GetDockablePane(UIControlledApplication, PaneId);
+                }
+                else if (UIApplication != null)
+                {
+                    dockPane = RevitCustomDockablePanels.GetDockablePane(UIControlledApplication, PaneId);
+                }
+
+                if (dockPane != null)
+                {
+                    dockPane.Show();
+                }
+            }
+            catch (Exception ex)
+            {
+
+                throw;
+            }
+        }
+        public new void Close()
+        {
+            try
+            {
+                DockablePane dockPane = null;
+                if (UIControlledApplication != null)
+                {
+                    dockPane = RevitCustomDockablePanels.GetDockablePane(UIControlledApplication, PaneId);
+                }
+                else if (UIApplication != null)
+                {
+                    dockPane = RevitCustomDockablePanels.GetDockablePane(UIControlledApplication, PaneId);
+                }
+
+                if (dockPane != null)
+                {
+                    dockPane.Hide();
+                }
+            }
+            catch (Exception ex)
+            {
+
+                throw;
+            }
+        }
+    }
+}

+ 78 - 0
FWindSoft/FWindSoft.Revit/DockablePane/RevitCustomDockablePanels.cs

@@ -0,0 +1,78 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using Autodesk.Revit.UI;
+
+namespace FWindSoft.Revit
+{
+    /*
+     * 可以使用attribute的形式控制是否自动检索Dockable,并自动注册。读指定的程序集名称
+     */ 
+    public class RevitCustomDockablePanels
+    {
+        #region 静态方法相关
+        private static List<DockableWindow> m_DockWindows;
+        static RevitCustomDockablePanels()
+        {
+            m_DockWindows = new List<DockableWindow>();
+            DockWindows = new ReadOnlyCollection<DockableWindow>(m_DockWindows);
+        }
+
+        public static ReadOnlyCollection<DockableWindow> DockWindows { get; private set; }
+        /// <summary>
+        /// 尝试获取指定Id的Window
+        /// </summary>
+        /// <param name="paneId"></param>
+        /// <param name="window"></param>
+        /// <returns></returns>
+        public static bool TryGetCoustomDockWindow(DockablePaneId paneId, out DockableWindow window)
+        {
+            window = DockWindows.FirstOrDefault(c => c.PaneId == paneId);
+            return window != null;
+        }
+        public static DockableWindow AddDockWindow(DockableWindow window)
+        {
+            DockableWindow defaultWin;
+            if (TryGetCoustomDockWindow(window.PaneId, out defaultWin))
+            {
+                return defaultWin;
+            }
+            else
+            {
+                m_DockWindows.Add(window);
+            }
+            return window;
+        }
+
+        public static DockablePane GetDockablePane(UIControlledApplication application, DockablePaneId paneId)
+        {
+            return application.GetDockablePane(paneId);
+        }
+        public static DockablePane GetDockablePane(UIApplication application, DockablePaneId paneId)
+        {
+            return application.GetDockablePane(paneId);
+        }
+        public static DockableWindow RegisterDockablePane(UIControlledApplication application, DockablePaneId paneId, string title, DockableWindow provider)
+        {
+            if (DockablePane.PaneExists(paneId))
+            {
+                throw new Exception("paneId已经注册过");
+            }
+            application.RegisterDockablePane(paneId, title, provider);
+            return AddDockWindow(provider);
+        }
+        public static DockableWindow RegisterDockablePane(UIApplication application, DockablePaneId paneId, string title, DockableWindow provider)
+        {
+            if (DockablePane.PaneExists(paneId))
+            {
+                throw new Exception("paneId已经注册过");
+            }
+            application.RegisterDockablePane(paneId, title, provider);
+            return AddDockWindow(provider);
+        }
+        #endregion
+
+        public static readonly DockablePaneId Default =new DockablePaneId(new Guid("{3BAFCF52-AC5C-4CF8-B1CB-D0B1D0E90237}"));
+    }
+}

+ 55 - 0
FWindSoft/FWindSoft.Revit/ExtensibleStorage/EnumStorageExtension.cs

@@ -0,0 +1,55 @@
+using Autodesk.Revit.DB;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit.ExtensibleStorage
+{
+    public static class EnumStorageExtension
+    {
+        #region 基础扩展数据操作
+        public static void SetExtendData<T>(this Element element,Enum en, T value)
+        {
+            element.SetExtendData<T>(InEnumUtil.CreateSchemaItem(en), value);
+        }
+
+        public static void SetExtendData<T>(this Element element, Enum en, IList<T> values)
+        {
+            element.SetExtendData<T>(InEnumUtil.CreateSchemaItem(en), values);
+        }
+
+        public static void SetExtendData<T, V>(this Element element,  Enum en, IDictionary<T, V> dict)
+        {
+            element.SetExtendData<T, V>(InEnumUtil.CreateSchemaItem(en), dict);
+        }
+
+
+        public static T GetExtendData<T>(this Element element, Enum en)
+        {
+            return element.GetExtendData<T>(InEnumUtil.CreateSchemaItem(en));         
+        }
+
+        public static List<T> GetExtendDatas<T>(this Element element, Enum en)
+        {
+            return element.GetExtendDatas<T>(InEnumUtil.CreateSchemaItem(en));
+        }
+
+        public static Dictionary<T, V> GetExtendData<T,V>(this Element element, Enum en)
+        {
+            return element.GetExtendData<T,V>(InEnumUtil.CreateSchemaItem(en));
+        }
+        #endregion
+
+        /// <summary>
+        /// 删除扩展数据
+        /// </summary>
+        /// <param name="element"></param>
+        /// <param name="dataEnum"></param>
+        public static void DeleteStorageData(this Element element, Enum dataEnum)
+        {
+            element.DeleteStorageData(InEnumUtil.CreateSchemaItem(dataEnum).SchemaGuid);
+        }
+    }
+}

+ 24 - 0
FWindSoft/FWindSoft.Revit/ExtensibleStorage/ExtensibleAttribute.cs

@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit.ExtensibleStorage
+{
+    [AttributeUsage(AttributeTargets.Enum)]
+    public class StorageFileNameAttribute:Attribute
+    {
+        public string Name { get; set; }
+    }
+    [AttributeUsage(AttributeTargets.Enum)]
+    public class StorageSchemeNameAttribute : Attribute
+    {
+        public string Name { get; set; }
+    }
+    [AttributeUsage(AttributeTargets.Enum)]
+    public class StorageSchemeGuidAttribute : Attribute
+    {
+        public string Guid { get; set; }
+    }
+}

+ 329 - 0
FWindSoft/FWindSoft.Revit/ExtensibleStorage/ExtensibleStorageExtension.cs

@@ -0,0 +1,329 @@
+using Autodesk.Revit.DB;
+using Autodesk.Revit.DB.ExtensibleStorage;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit.ExtensibleStorage
+{
+    /*
+     * 可能只能存储,几个kb的值
+     * 1、Schema需要一次创建,创建完成之后不能再进行修改
+     * 2、api可用性很高,暂时简单封装
+     */
+    public static class ExtensibleStorageExtension
+    {
+        #region 基础扩展数据操作
+        public static void SetExtendData<T>(this Element element, SchemaItem schemaItem, T value)
+        {
+            var guid = schemaItem.SchemaGuid;
+            var schemaName = schemaItem.SchemaName;
+            var fileName = schemaItem.FileName;
+            Schema schema = Schema.Lookup(guid);
+            if (schema == null)
+            {
+                SchemaBuilder schemaBuilder = new SchemaBuilder(guid);
+                schemaBuilder.SetReadAccessLevel(AccessLevel.Public);
+                schemaBuilder.SetWriteAccessLevel(AccessLevel.Public);
+                //这个应该和上面重复吧
+                schemaBuilder.SetSchemaName(schemaName);
+                FieldBuilder fieldBuilder = schemaBuilder.AddSimpleField(fileName, typeof(T));
+                schema = schemaBuilder.Finish();
+            }
+            Entity entity = new Entity(schema);
+            Field field = schema.GetField(fileName);
+            entity.Set<T>(field, value);
+            element.SetEntity(entity);
+        }
+
+        public static void SetExtendData<T>(this Element element, SchemaItem schemaItem, IList<T> values)
+        {
+            var guid = schemaItem.SchemaGuid;
+            var schemaName = schemaItem.SchemaName;
+            var fileName = schemaItem.FileName;
+            Schema schema = Schema.Lookup(guid);
+            if (schema == null)
+            {
+                SchemaBuilder schemaBuilder = new SchemaBuilder(guid);
+                schemaBuilder.SetReadAccessLevel(AccessLevel.Public);
+                schemaBuilder.SetWriteAccessLevel(AccessLevel.Public);
+                schemaBuilder.SetSchemaName(schemaName);
+                FieldBuilder fieldBuilder = schemaBuilder.AddArrayField(fileName, typeof(T));
+                schema = schemaBuilder.Finish();
+            }
+            Entity entity = new Entity(schema);
+            Field field = schema.GetField(fileName);
+            entity.Set<IList<T>>(field, values);
+            element.SetEntity(entity);
+        }
+
+        public static void SetExtendData<T, V>(this Element element, SchemaItem schemaItem, IDictionary<T, V> dict)
+        {
+            var guid = schemaItem.SchemaGuid;
+            var schemaName = schemaItem.SchemaName;
+            var fileName = schemaItem.FileName;
+            Schema schema = Schema.Lookup(guid);
+            if (schema == null)
+            {
+                SchemaBuilder schemaBuilder = new SchemaBuilder(guid);
+                schemaBuilder.SetReadAccessLevel(AccessLevel.Public);
+                schemaBuilder.SetWriteAccessLevel(AccessLevel.Public);
+                schemaBuilder.SetSchemaName(schemaName);
+                FieldBuilder fieldBuilder = schemaBuilder.AddMapField(fileName, typeof(T), typeof(V));
+                schema = schemaBuilder.Finish();
+            }
+            Entity entity = new Entity(schema);
+            Field field = schema.GetField(fileName);
+            entity.Set<IDictionary<T, V>>(field, dict);
+            element.SetEntity(entity);
+        }
+
+
+        public static T GetExtendData<T>(this Element element, SchemaItem schemaItem)
+        {
+            var guid = schemaItem.SchemaGuid;
+            var schemaName = schemaItem.SchemaName;
+            var fileName = schemaItem.FileName;
+            Schema schema = Schema.Lookup(guid);
+            if (schema != null)
+            {
+                Entity entity = element.GetEntity(schema);
+                if (entity.Schema == null)
+                {
+                    return default(T);
+                }
+                Field field = schema.GetField(fileName);
+                if (!entity.RecognizedField(field))
+                {
+                    return default(T);
+                }
+                return entity.Get<T>(field);
+            }
+            return default(T);
+        }
+
+        public static List<T> GetExtendDatas<T>(this Element element, SchemaItem schemaItem)
+        {
+            var guid = schemaItem.SchemaGuid;
+            var fileName = schemaItem.FileName;
+            Schema schema = Schema.Lookup(guid);
+            if (schema != null)
+            {
+                Entity entity = element.GetEntity(schema);
+                Field field = schema.GetField(fileName);
+                return entity.Get<IList<T>>(field).ToList();
+            }
+            return null;
+        }
+
+        public static Dictionary<T, TU> GetExtendData<T, TU>(this Element element, SchemaItem schemaItem)
+        {
+            var guid = schemaItem.SchemaGuid;
+            var schemaName = schemaItem.SchemaName;
+            var fileName = schemaItem.FileName;
+            Schema schema = Schema.Lookup(guid);
+            if (schema != null)
+            {
+                Entity entity = element.GetEntity(schema);
+                Field field = schema.GetField(fileName);
+                return entity.Get<IDictionary<T, TU>>(field) as Dictionary<T, TU>;
+            }
+            return null;
+        }
+        #endregion
+
+        /// <summary>
+        /// 删除扩展数据
+        /// </summary>
+        /// <param name="element"></param>
+        /// <param name="guid"></param>
+        public static void DeleteStorageData(this Element element, Guid guid)
+        {
+            Schema schema = Schema.Lookup(guid);
+            if (schema != null)
+            {
+                element.DeleteEntity(schema);
+            }
+        }
+
+        /// <summary>
+        /// 存储简单对象数据
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="element"></param>
+        /// <param name="value"></param>
+        public static void SetSimpleClass<T>(this Element element, T value)
+        {
+            var useType = typeof(T);
+            Guid guid = useType.GUID;
+            Schema schema = Schema.Lookup(guid);
+
+            #region 初始化属性集合
+
+            List<Tuple<string, Type, object>> useProperties = new List<Tuple<string, Type, object>>();
+            if (ExtensibleStorageUtil.IsCoustomStorage(useType))
+            {
+                var useValue = ((ICoustomStorage)value).GetStorage();
+                var propertyType = useValue.GetType();
+                useProperties.Add(new Tuple<string, Type, object>(useType.Name, propertyType, useValue));
+            }
+            else
+            {
+                var properties = useType.GetProperties();
+                foreach (var propertyInfo in properties)
+                {
+                    var propertyType = propertyInfo.PropertyType;
+                    var useValue = propertyInfo.GetValue(value);
+                    useProperties.Add(new Tuple<string, Type, object>(propertyInfo.Name, propertyType, useValue));
+                }
+            }
+
+            #endregion
+
+            #region 创建结构
+            if (schema == null)
+            {
+                #region 创建Schema
+
+                SchemaBuilder schemaBuilder = new SchemaBuilder(guid);
+                schemaBuilder.SetReadAccessLevel(AccessLevel.Public);
+                schemaBuilder.SetWriteAccessLevel(AccessLevel.Public);
+                schemaBuilder.SetSchemaName(useType.Name);
+
+                #endregion
+
+                foreach (var item in useProperties)
+                {
+                    var propertyType = item.Item2;
+                    if (ExtensibleStorageUtil.IsEffectiveContent(propertyType))
+                    {
+                        FieldBuilder fieldBuilder = schemaBuilder.AddSimpleField(item.Item1, propertyType);
+                    }
+                    else if (ExtensibleStorageUtil.IsEffectiveArray(propertyType, out Type arryContentType))
+                    {
+                        FieldBuilder fieldBuilder = schemaBuilder.AddArrayField(item.Item1, arryContentType);
+                    }
+                    else if (ExtensibleStorageUtil.IsEffectiveMap(propertyType, out Type keyType, out Type valueType))
+                    {
+                        FieldBuilder fieldBuilder = schemaBuilder.AddMapField(item.Item1, keyType, valueType);
+                    }
+                }
+
+                schema = schemaBuilder.Finish();
+            }
+            #endregion
+
+            #region 创建对象
+            Entity entity = new Entity(schema);
+            var method = ExtensibleStorageUtil.GetEntitySetMethod();
+            foreach (var item in useProperties)
+            {
+                var field = schema.GetField(item.Item1);
+                if (field == null)
+                    continue;
+                var fieldType = ExtensibleStorageUtil.GetFileType(field);
+                MethodInfo mi = method.MakeGenericMethod(fieldType);
+                var useValue = item.Item3;
+                if (useValue != null)
+                {
+                    mi.Invoke(entity, new object[] { item.Item1, useValue });
+                }
+            }
+            #endregion
+            element.SetEntity(entity);
+        }
+
+        /// <summary>
+        /// 获取简单对象数据
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="element"></param>
+        public static T GetSimpleClass<T>(this Element element)
+        {
+            var useType = typeof(T);
+            Guid guid = useType.GUID;
+            Schema schema = Schema.Lookup(guid);
+            if (schema == null)
+            {
+                return default(T);
+            }
+            Entity entity = element.GetEntity(schema);
+            if (entity?.Schema == null)
+            {
+                return default(T);
+            }
+            var fields = schema.ListFields();
+            #region 创建实体对象
+            T result = default(T);
+            if (fields.Any())
+            {
+                var cons = useType.GetConstructor(Type.EmptyTypes);
+                if (cons != null)
+                {
+                    result = (T)cons.Invoke(null);
+                }
+            }
+
+            if (result == null)
+            {
+                return default(T);
+            }
+            #endregion
+
+            var getMethod = typeof(Entity).GetMethod("Get", new Type[] { typeof(string) });
+            if (ExtensibleStorageUtil.IsCoustomStorage(useType))
+            {
+                var field = fields.FirstOrDefault(f => f.FieldName == useType.Name);
+                if (field != null)
+                {
+                    var useValueType = field.ValueType;
+                    if (field.ContainerType == ContainerType.Array)
+                    {
+                        useValueType = typeof(IList<>).MakeGenericType(field.ValueType);
+                    }
+                    else if (field.ContainerType == ContainerType.Map)
+                    {
+                        useValueType = typeof(IDictionary<,>).MakeGenericType(field.KeyType, field.ValueType);
+                    }
+                    MethodInfo mi = getMethod.MakeGenericMethod(useValueType);
+                    var useValue = mi.Invoke(entity, new object[] { field.FieldName });
+                    ((ICoustomStorage)result).SetStorage(useValue);
+                }
+            }
+            else
+            {
+                foreach (var field in fields)
+                {
+                    try
+                    {
+                        var property = useType.GetProperty(field.FieldName);
+
+                        if (property != null)
+                        {
+                            MethodInfo mi = getMethod.MakeGenericMethod(property.PropertyType);
+                            var useValue = mi.Invoke(entity, new object[] { field.FieldName });
+                            property.SetValue(result, useValue);
+                        }
+                    }
+                    catch (Exception)
+                    {
+
+
+                    }
+                }
+
+            }
+
+            return result;
+        }
+    }
+    public class SchemaItem
+    {
+        public Guid SchemaGuid { get; set; }
+        public string SchemaName { get; set; }
+        public string FileName { get; set; }
+    }
+}

+ 173 - 0
FWindSoft/FWindSoft.Revit/ExtensibleStorage/ExtensibleStorageUtil.cs

@@ -0,0 +1,173 @@
+/*-------------------------------------------------------------------------
+ * 功能描述:ExtensibleStorageUtil
+ * 作者:xulisong
+ * 创建时间: 2019/7/1 9:39:17
+ * 版本号:v1.0
+ *  -------------------------------------------------------------------------*/
+
+using Autodesk.Revit.DB;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+using Autodesk.Revit.DB.ExtensibleStorage;
+
+namespace FWindSoft.Revit.ExtensibleStorage
+{
+    /// <summary>
+    /// 扩展存储工具类
+    /// </summary>
+    public class ExtensibleStorageUtil
+    {
+        /// <summary>
+        /// 扩展数据内容兼容类型
+        /// </summary>
+        private static HashSet<Type> ContentTypes { get; set; } = new HashSet<Type>();
+        /// <summary>
+        /// 扩展数据键值兼容类型
+        /// </summary>
+        private static HashSet<Type> KeyTypes { get; set; } = new HashSet<Type>();
+
+        static ExtensibleStorageUtil()
+        {
+            InitData();
+        }
+
+        private static void InitData()
+        {
+            #region 内容类型
+            ContentTypes.Add(typeof(bool));
+            ContentTypes.Add(typeof(byte));
+            ContentTypes.Add(typeof(Int16));
+            ContentTypes.Add(typeof(Int32));
+            ContentTypes.Add(typeof(float));
+            ContentTypes.Add(typeof(double));
+            ContentTypes.Add(typeof(ElementId));
+            ContentTypes.Add(typeof(Guid));
+            ContentTypes.Add(typeof(string));
+            ContentTypes.Add(typeof(XYZ));
+            ContentTypes.Add(typeof(UV));
+            ContentTypes.Add(typeof(Entity));
+            #endregion
+
+            #region 键值类型
+            KeyTypes.Add(typeof(bool));
+            KeyTypes.Add(typeof(byte));
+            KeyTypes.Add(typeof(Int16));
+            KeyTypes.Add(typeof(Int32));
+            KeyTypes.Add(typeof(ElementId));
+            KeyTypes.Add(typeof(Guid));
+            KeyTypes.Add(typeof(string));
+            #endregion
+           
+        }
+        /// <summary>
+        /// 判定是否是有效的content类型
+        /// </summary>
+        /// <param name="type"></param>
+        /// <returns></returns>
+        public static bool IsEffectiveContent(Type type)
+        {
+            return ContentTypes.Contains(type);
+        }
+        /// <summary>
+        /// 判定是否是有效的key类型
+        /// </summary>
+        /// <param name="type"></param>
+        /// <returns></returns>
+        public static bool IsEffectiveKey(Type type)
+        {
+            return KeyTypes.Contains(type);
+        }
+
+        public static bool IsEffectiveArray(Type type,out Type contentType)
+        {
+            contentType = null;
+            var baseType = type.GetInterface(typeof(IList<>).FullName);
+            if (baseType == null)
+            {
+                return false;
+            }
+
+            var firstType = baseType.GetGenericArguments()?.FirstOrDefault();
+            var flag= firstType != null && IsEffectiveContent(firstType);
+            if (flag)
+            {
+                contentType = firstType;
+            }
+
+            return flag;
+        }
+        public static bool IsEffectiveMap(Type type,out Type outKeyType,out Type outValueTYpe)
+        {
+            outKeyType = null;
+            outValueTYpe = null;
+            var baseType = type.GetInterface(typeof(IDictionary<,>).FullName);
+            if (baseType == null)
+            {
+                return false;
+            }
+
+            var keyType = baseType.GetGenericArguments()?.FirstOrDefault();
+            var valueType = baseType.GetGenericArguments()?.FirstOrDefault();
+
+            var flag= keyType != null && valueType != null && IsEffectiveKey(keyType) && IsEffectiveContent(valueType);
+            if (flag)
+            {
+                outKeyType = keyType;
+                outValueTYpe = valueType;
+            }
+            return flag;
+        }
+
+        /// <summary>
+        /// 是否为自定义解析存储
+        /// </summary>
+        /// <param name="type"></param>
+        /// <returns></returns>
+        public static bool IsCoustomStorage(Type type)
+        {
+            var baseType = type.GetInterface(typeof(ICoustomStorage).FullName);
+            return baseType != null;
+        }
+        /// <summary>
+        /// 获取可用set方法
+        /// </summary>
+        /// <returns></returns>
+        public static MethodInfo GetEntitySetMethod()
+        {
+            var methods= typeof(Entity).GetMethods(BindingFlags.Public | BindingFlags.Instance);
+            foreach (var methodInfo in methods)
+            {
+                if (methodInfo.Name != "Set")
+                {
+                    continue;
+                }
+
+                var parameters = methodInfo.GetParameters();
+                if (parameters.Length == 2 && parameters[0].ParameterType == typeof(string))
+                {
+                    return methodInfo;
+                }
+            }
+            return null;
+        }
+
+        public static Type GetFileType(Field field)
+        {
+            var useType = field.ValueType;
+            if (field.ContainerType == ContainerType.Array)
+            {
+                useType = typeof(IList<>).MakeGenericType(field.ValueType);
+            }
+            else if (field.ContainerType == ContainerType.Map)
+            {
+                useType = typeof(IDictionary<,>).MakeGenericType(field.KeyType, field.ValueType);
+            }
+            return useType;
+        }
+    }
+}

+ 21 - 0
FWindSoft/FWindSoft.Revit/ExtensibleStorage/ICoustomStorage.cs

@@ -0,0 +1,21 @@
+/*-------------------------------------------------------------------------
+ * 功能描述:ICoustomParseStorage
+ * 作者:xulisong
+ * 创建时间: 2019/7/1 11:12:47
+ * 版本号:v1.0
+ *  -------------------------------------------------------------------------*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit.ExtensibleStorage
+{
+    public interface ICoustomStorage
+    {
+        void SetStorage(object value);
+        object GetStorage();
+    }
+}

+ 45 - 0
FWindSoft/FWindSoft.Revit/ExtensibleStorage/InEnumUtil.cs

@@ -0,0 +1,45 @@
+using FWindSoft.SystemExtensions;
+using System;
+using System.Linq;
+using System.Reflection;
+namespace FWindSoft.Revit.ExtensibleStorage
+{
+    /// <summary>
+    /// 内部应用
+    /// </summary>
+    internal class InEnumUtil
+    {
+        /// <summary>
+        /// 获取枚举的guid
+        /// </summary>
+        /// <param name="en"></param>
+        /// <returns></returns>
+        public static Guid GetGuid(Enum en)
+        {
+            var type = en.GetType();
+            string allPath = type.FullName + en.ToString();
+            return allPath.ToGuid();
+        }
+
+        internal static SchemaItem CreateSchemaItem(Enum en)
+        {
+            SchemaItem item = new SchemaItem();
+            FieldInfo fieldInfo = en.GetType().GetField(en.ToString());
+            var  fileNameAttribute = fieldInfo.GetCustomAttribute<StorageFileNameAttribute>();
+            item.FileName = fileNameAttribute?.Name?? en.ToString();
+            var schemeNameAttribute = fieldInfo.GetCustomAttribute<StorageSchemeNameAttribute>();
+            item.SchemaName = schemeNameAttribute?.Name ?? en.ToString();
+            var schemeGuidAttribute = fieldInfo.GetCustomAttribute<StorageSchemeGuidAttribute>();
+            if (schemeGuidAttribute?.Guid == null)
+            {
+                item.SchemaGuid = GetGuid(en);
+            }
+            else
+            {
+                item.SchemaGuid = new Guid(schemeGuidAttribute?.Guid);
+            }
+
+            return item;
+        }
+    }
+}

+ 63 - 0
FWindSoft/FWindSoft.Revit/Extension/ApplicationExtension.cs

@@ -0,0 +1,63 @@
+/*-------------------------------------------------------------------------
+ * 功能描述:ApplicationExtension
+ * 作者:xulisong
+ * 创建时间: 2019/3/12 11:30:00
+ * 版本号:v1.0
+ *  -------------------------------------------------------------------------*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Autodesk.Revit.DB;
+using Autodesk.Revit.UI;
+using Autodesk.Revit.UI.Selection;
+
+namespace FWindSoft.Revit
+{
+    public static class ApplicationExtension
+    {
+        public static Selection GetSelection(this UIApplication app)
+        {
+            UIDocument doc = app.ActiveUIDocument;
+            if (doc != null)
+                return doc.Selection;
+            return null;
+        }
+        public static void AddSelectElements(this UIApplication uiApp, List<Element> elements)
+        {
+            if (elements == null || elements.Count == 0)
+                return;
+            Selection selection = uiApp.GetSelection();
+            if (selection == null) return;
+            List<ElementId> idList = selection.GetElementIds().ToList();
+            elements.ForEach(p => idList.Add(p.Id));
+            selection.SetElementIds(idList);
+        }
+        public static void ClearSelectElements(this UIApplication uiApp)
+        {
+            Selection selection = uiApp.GetSelection();
+            if (selection == null) return;
+            selection.SetElementIds(new List<ElementId>());
+        }
+        public static void SelectElements(this UIApplication uiApp, List<Element> elements)
+        {
+            Selection selection = uiApp.GetSelection();
+            if (selection == null) return;
+            List<ElementId> idList = new List<ElementId>();
+            elements.ForEach(p => idList.Add(p.Id));
+            selection.SetElementIds(idList);
+        }
+        public static void SetShowElements(this UIApplication uiApp, List<Element> elements)
+        {
+            if (elements == null|| elements.Count==0)
+                return;
+            ElementSet set = new ElementSet();
+            elements.ForEach(e => set.Insert(e));
+            uiApp.ActiveUIDocument.ShowElements(set);
+            uiApp.SelectElements(elements);
+        }
+
+    }
+}

+ 91 - 0
FWindSoft/FWindSoft.Revit/Extension/CableTrayExtension.cs

@@ -0,0 +1,91 @@
+
+using Autodesk.Revit.DB;
+using Autodesk.Revit.DB.Electrical;
+using FWindSoft.SystemExtensions;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit
+{
+    public static class CableTrayExtension
+    {
+        /// <summary>
+        /// 获取项目中所有桥架类型
+        /// </summary>
+        /// <param name="doc"></param>
+        /// <returns></returns>
+        public static List<CableTrayType> GetCableTrays(this Document doc)
+        {
+            List<CableTrayType> list = doc.GetElements<CableTrayType>();
+            return list;
+        }
+        /// <summary>
+        /// 桥架线槽方向旋转
+        /// </summary>
+        /// <param name="cableTray"></param>
+        /// <param name="angle"></param>
+        public static void RotateNormal(this CableTray cableTray, double angle)
+        {
+            Line line = cableTray.GetLocationLine();
+            XYZ bottom = line.StartPoint();
+            XYZ top = line.EndPoint();
+            XYZ axis = bottom.NewLine(top).Direction;
+            XYZ direction = cableTray.CurveNormal;
+            cableTray.CurveNormal = direction.RotateVector(axis, angle);
+        }
+
+        /// <summary>
+        /// 判断桥架截面是否相同
+        /// </summary>
+        /// <param name="cableTray"></param>
+        /// <param name="cableTraySecond"></param>
+        /// <returns></returns>
+        public static bool IsSectionSameSize(this CableTray first, CableTray second)
+        {
+            return first.Height.IsEqual(second.Height) && first.Width.IsEqual(second.Width);
+        }
+
+        /// <summary>
+        /// 取桥架的系统类型名称,顺序优先
+        /// </summary>
+        /// <param name="cableTrays"></param>
+        /// <returns></returns>
+        public static string GetSystemName(this List<CableTray> cableTrays)
+        {
+            var reuslt = string.Empty;
+            if (cableTrays == null)
+                return reuslt;
+            foreach (var cableTray in cableTrays)
+            {
+                string str = cableTray.GetParameterString("系统类型");
+                if (!string.IsNullOrWhiteSpace(str))
+                    return str;
+            }
+            return reuslt;
+        }
+        /// <summary>
+        /// 获取垂直桥架角度
+        /// </summary>
+        /// <param name="cableTray"></param>
+        /// <returns>如果桥架垂直返回正确角度,如果桥架竖直,返回π/2</returns>
+        public static double GetVerAngle(this CableTray cableTray)
+        {
+            if (cableTray == null)
+                return 0;
+            double defalut = Math.PI / 2;
+            var line = cableTray.GetLocationLine();
+            XYZ start = line.StartPoint();
+            XYZ end = line.EndPoint();
+            if (!start.IsEqual2(end))
+            {
+                return defalut;
+            }
+            XYZ normal = cableTray.CurveNormal;
+            //此方法有漏洞,桥架垂直时使用
+            return XYZ.BasisX.AngleOnPlaneTo(normal, XYZ.BasisZ);
+        }
+    }
+}

+ 99 - 0
FWindSoft/FWindSoft.Revit/Extension/ConduitExtension.cs

@@ -0,0 +1,99 @@
+using Autodesk.Revit.DB;
+using Autodesk.Revit.DB.Electrical;
+using FWindSoft.SystemExtensions;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit
+{
+    /// <summary>
+    /// 线管相关类型扩展
+    /// </summary>
+    public static class ConduitExtension
+    {
+        /// <summary>
+        /// 获取项目中所有线管类型
+        /// </summary>
+        /// <param name="doc"></param>
+        /// <returns></returns>
+        public static List<ConduitType> GetConduitTypes(this Document doc)
+        {
+            List<ConduitType> list = doc.GetElements<ConduitType>();
+            return list;
+
+        }
+
+        /// <summary>
+        /// 获取线管类型
+        /// </summary>
+        /// <param name="typeName"></param>
+        /// <returns></returns>
+        public static ConduitType GetConduitType(this Document doc, string typeName)
+        {
+            var list = doc.GetConduitTypes();
+            if (list == null)
+                return default(ConduitType);
+            ConduitType wireTye = list.FirstOrDefault(t => t.Name.Equals(typeName));
+            return wireTye ?? list[0].DuplicateT<ConduitType>(typeName);
+        }
+        /// <summary>
+        /// 获取较较大直径的线管
+        /// </summary>
+        /// <param name="first"></param>
+        /// <param name="second"></param>
+        /// <returns></returns>
+        public static Conduit GetLargerDiameter(this Conduit first, Conduit second)
+        {
+            return first.Diameter.MoreEqual(second.Diameter)
+                ? first
+                : second;
+        }
+
+        /// <summary>
+        /// 获取较较小直径的线管
+        /// </summary>
+        /// <param name="first"></param>
+        /// <param name="second"></param>
+        /// <returns></returns>
+        public static Conduit GetSmallerDiameter(this Conduit first, Conduit second)
+        {
+            return first.Diameter.LessEqual(second.Diameter)
+                ? first
+                : second;
+        }
+        /// <summary>
+        /// 获取线管类型可使用的直径尺寸
+        /// </summary>
+        /// <param name="conduitType">线管类型</param>
+        /// <returns></returns>
+        public static List<ConduitSize> GetConduitSizes(this ConduitType conduitType)
+        {
+            var document = conduitType.Document;
+            var standard = document.GetElement(conduitType.GetParameterElementId(BuiltInParameter.CONDUIT_STANDARD_TYPE_PARAM));
+            var standardName = standard.Name.Trim();
+            ConduitSizeSettings sizeSettings = ConduitSizeSettings.GetConduitSizeSettings(document);
+            ConduitSizes useConduitSizes = null;
+            foreach (var sizeItem in sizeSettings)
+            {
+                if (sizeItem.Key.Trim() == standardName)
+                {
+                    useConduitSizes = sizeItem.Value;
+                    break;
+                }
+            }
+            List<ConduitSize> conduitSizes = new List<ConduitSize>();
+            if (useConduitSizes == null)
+            {
+                return conduitSizes;
+            }
+            foreach (var size in useConduitSizes)
+            {
+                conduitSizes.Add(size);
+            }
+            return conduitSizes;
+        }
+    }
+}

+ 268 - 0
FWindSoft/FWindSoft.Revit/Extension/ConnectorJoin/ConnectorExtension.cs

@@ -0,0 +1,268 @@
+using Autodesk.Revit.DB;
+using FWindSoft.SystemExtensions;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit
+{
+    public static class ConnectorExtension
+    {
+        static ConnectorExtension()
+        {
+            InitMepComponment();
+        }
+        #region 缓存设置
+        private static List<int> m_MepComponment;             
+        private static void InitMepComponment()
+        {
+            m_MepComponment= new List<int>() { (int)BuiltInCategory.OST_PipeCurves, (int)BuiltInCategory.OST_PipeFitting, (int)BuiltInCategory.OST_DuctCurves, (int)BuiltInCategory.OST_DuctFitting };
+        }
+        #endregion
+
+        #region 节点获取相关
+        /// <summary>
+        /// 获取ConnectorSet
+        /// </summary>
+        /// <param name="element"></param>
+        /// <returns></returns>
+        private static ConnectorSet GetConnectorSet(this Element element)
+        {
+            if (element != null)
+            {
+                FamilyInstance instance = element as FamilyInstance;
+                if (instance!=null && instance.MEPModel?.ConnectorManager != null)
+                {
+                    return instance.MEPModel.ConnectorManager.Connectors;
+                }
+                MEPSystem system = element as MEPSystem;
+                if (system != null)
+                {
+                    return system.ConnectorManager.Connectors;
+                }
+                MEPCurve curve = element as MEPCurve;
+                if (curve!=null)
+                {
+                    return curve.ConnectorManager.Connectors;
+                }
+            }
+            return null;
+        }
+        /// <summary>
+        /// 获取EndConnector
+        /// </summary>
+        /// <param name="connectorSet"></param>
+        /// <returns></returns>
+        public static List<Connector> ToList(this ConnectorSet connectorSet)
+        {
+            List<Connector> result = new List<Connector>();
+            try
+            {
+                if (connectorSet != null)
+                {
+                    ConnectorSetIterator iterator = connectorSet.ForwardIterator();
+                    while (iterator.MoveNext())
+                    {
+                        Connector current = iterator.Current as Connector;
+                        if (current.IsPhysical())
+                        {
+                            result.Add(current);
+                        }
+                    }
+                }
+                return result;
+            }
+            catch
+            {
+            }
+            return result;
+        }
+        /// <summary>
+        /// 获取第一个满足条件的Connector,条件可以为空
+        /// </summary>
+        /// <param name="element"></param>
+        /// <param name="predicate"></param>
+        /// <returns></returns>
+        public static Connector GetFirstConnector(this Element element,Predicate<Connector> predicate)
+        {
+            var set = element.GetConnectorSet();
+            Connector result = null;
+            try
+            {
+                if (set != null)
+                {
+                    ConnectorSetIterator iterator = set.ForwardIterator();
+                    while (iterator.MoveNext())
+                    {
+                        Connector current = iterator.Current as Connector;
+                        if (current.IsPhysical()&& (predicate==null|| predicate(current)))
+                        {
+                            return current;
+                        }
+                    }
+                }
+                return result;
+            }
+            catch
+            {
+            }
+            return result;
+        }
+        /// <summary>
+        /// 获取指定类型的Connector
+        /// </summary>
+        /// <param name="element"></param>
+        /// <param name="domain"></param>
+        /// <returns></returns>
+        public static List<Connector> GetConnectors(this Element element, Domain domain)
+        {
+            return element.GetConnectorSet().ToList().Where(c=>c.Domain==domain).ToList();
+        }
+        /// <summary>
+        /// 获取指定类型的所有可用Connector
+        /// </summary>
+        /// <param name="element"></param>
+        /// <returns></returns>
+        public static List<Connector> GetAllConnectors(this Element element)
+        {
+            return element.GetConnectorSet().ToList();
+        }
+
+
+        #endregion
+
+        #region  逻辑相关处理
+        /// <summary>
+        /// 标志connector是否是可被检索的
+        /// </summary>
+        /// <param name="connector"></param>
+        /// <returns></returns>
+        public static bool Searchable(this Connector connector)
+        {
+            return connector.IsPhysical() &&connector.IsConnected && connector.AllRefs != null;
+        }    
+        #endregion
+        /// <summary>
+        /// 是否是物理节点
+        /// </summary>
+        /// <param name="connector"></param>
+        /// <returns></returns>
+        public static bool IsPhysical(this Connector connector)
+        {
+            return ConnectorType.Physical.HasFlag(connector.ConnectorType);
+        }
+
+        /// <summary>
+        /// 获取相连的第一个Connector
+        /// </summary>
+        /// <param name="connector"></param>
+        /// <returns></returns>
+        public static Connector GetJoinConnector(this Connector connector)
+        {
+            return connector.GetJoinConnectors().FirstOrDefault();
+        }
+        /// <summary>
+        /// 获取相连的Connector;
+        /// </summary>
+        /// <param name="connector"></param>
+        /// <returns></returns>
+        public static List<Connector> GetJoinConnectors(this Connector connector)
+        {
+           return GetJoinConnectors(connector, false);
+        }
+        /// <summary>
+        /// 获取相连的Connector;
+        /// </summary>
+        /// <param name="connector"></param>
+        /// <returns></returns>
+        public static List<Connector> GetJoinConnectors(this Connector connector,bool containInputOwner)
+        {
+            List<Connector> list = new List<Connector>();
+            if (connector.AllRefs != null)
+            {
+                var cons = connector.AllRefs.ToList();
+                if(!containInputOwner)
+                {
+                    return cons.Where(t =>t.Owner.Id!=(connector.Owner.Id)).ToList();
+                }              
+            }
+            return list;
+        }
+
+        /// <summary>
+        ///根据点获取Connector
+        /// </summary>
+        /// <param name="element"></param>
+        /// <param name="origin"></param>
+        /// <returns></returns>
+        public static Connector GetConnectorByOrigin(this Element element, XYZ origin)
+        {
+            var connectors = element.GetAllConnectors();
+            return connectors.FirstOrDefault(c => c.ConnectorType == ConnectorType.End && c.Origin.IsEqual(origin));
+        }
+        /// <summary>
+        /// 根据方向获取Connector
+        /// </summary>
+        /// <param name="element"></param>
+        /// <param name="direction"></param>
+        /// <returns></returns>
+        public static Connector GetConnectorByDirection(this Element element, XYZ direction)
+        {
+            var connectors = element.GetAllConnectors();
+            return connectors.FirstOrDefault(c => c.ConnectorType == ConnectorType.End && c.CoordinateSystem.BasisZ.IsSameDirection(direction));
+        }
+        /// <summary>
+        /// 获取与给定方向,夹角最小的点
+        /// </summary>
+        /// <param name="element"></param>
+        /// <param name="direction"></param>
+        /// <returns></returns>
+        public static Connector GetConnectorByMinAngle(this Element element, XYZ direction)
+        {
+            var connectors = element.GetAllConnectors();
+            Connector useConnector = null;
+            double angle = double.MinValue;
+            foreach (Connector connector in connectors)
+            {
+                var tempDirection = connector.CoordinateSystem.BasisZ;
+                var tempAngle = direction.DotProduct(tempDirection);
+                //点乘值越大,角度越小
+                if (tempAngle.More(angle))
+                {
+                    useConnector = connector;
+                    angle = tempAngle;
+                }
+            }
+            return useConnector;
+        }
+        /// <summary>
+        /// 获取给点附近的Connector
+        /// </summary>
+        /// <param name="element"></param>
+        /// <param name="position"></param>
+        /// <returns></returns>
+        public static Connector GetNearConnector(this Element element, XYZ position)
+        {
+            var connectors = element.GetAllConnectors();
+            Connector resultConnector = null;
+            double minDistance = double.MaxValue;
+            foreach (var connector in connectors)
+            {
+                if (connector.ConnectorType != ConnectorType.End)
+                {
+                    //只计算端点
+                    continue;
+                }
+                var tempLength = connector.Origin.DistanceTo(position);
+                if (tempLength < minDistance)
+                {
+                    resultConnector = connector;
+                    minDistance = tempLength;
+                }
+            }
+            return resultConnector;
+        }
+    }
+}

+ 40 - 0
FWindSoft/FWindSoft.Revit/Extension/ConnectorJoin/ConnectorSearchOptions.cs

@@ -0,0 +1,40 @@
+using Autodesk.Revit.DB;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit
+{
+    public class ConnectorSearchOptions
+    {
+        /// <summary>
+        /// 允许元素限定
+        /// </summary>
+        public Predicate<Element> AllowElement { get; set; }
+        /// <summary>
+        /// 允许连接件限定
+        /// </summary>
+        public Predicate<Connector> AllowConnector { get; set; }
+
+        /// <summary>
+        /// Connector可用判定
+        /// </summary>
+        /// <param name="connector"></param>
+        /// <returns></returns>
+        public bool ConnectorUsable(Connector connector)
+        {
+            return AllowConnector == null || AllowConnector(connector);
+        }
+        /// <summary>
+        /// 元素可用判定
+        /// </summary>
+        /// <param name="connector"></param>
+        /// <returns></returns>
+        public bool ElementUsable(Element element)
+        {
+            return AllowElement == null || AllowElement(element);
+        }
+    }
+}

+ 399 - 0
FWindSoft/FWindSoft.Revit/Extension/ConnectorJoin/ConnectorSearchUtils.cs

@@ -0,0 +1,399 @@
+using Autodesk.Revit.DB;
+using FWindSoft.Revit.Common;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit
+{
+    public static class ConnectorSearchUtils
+    {
+        #region 获取直接相连接的元素
+        /// <summary>
+        /// 获取与connector相连接的元素,不包括自身
+        /// </summary>
+        /// <param name="connector"></param>
+        /// <param name="allowConnector"></param>
+        /// <returns></returns>
+        public static List<Element> GetJoinElements(Connector connector,Predicate<Connector> allowConnector)
+        {
+            List<Element> joinElements = new List<Element>();
+            Element element = connector.Owner;
+            ConnectorSearchOptions options = new ConnectorSearchOptions() { AllowConnector = allowConnector };
+            if (connector.Searchable())
+            {
+                ConnectorSet conSet = connector.AllRefs;
+                foreach (var con in conSet.ToList())
+                {
+                    if (con.Owner.Id == element.Id)
+                        continue;
+                    if(options.ConnectorUsable(con))
+                    {
+                        joinElements.Add(con.Owner);
+                    }
+                }
+            }
+            return joinElements;
+        }
+        /// <summary>
+        /// 获取与connector相连接的元素,不包括自身
+        /// </summary>
+        /// <param name="connector"></param>
+        /// <returns></returns>
+        public static List<Element> GetJoinElements(Connector connector)
+        {
+            return GetJoinElements(connector,null);
+        }
+        /// <summary>
+        /// 获取关联元素
+        /// </summary>
+        /// <param name="sourceElement"></param>
+        /// <param name="allowConnector"></param>
+        /// <returns></returns>
+        public static List<Element> GetJoinElements(Element sourceElement, Predicate<Connector> allowConnector)
+        {
+            IEnumerable<Element> joinElements = new List<Element>();
+            Element element = sourceElement;
+            ConnectorSearchOptions options = new ConnectorSearchOptions() { AllowConnector = allowConnector };
+            var connectors = sourceElement.GetAllConnectors();
+            foreach (var baseConnector in connectors)
+            {
+                if (!options.ConnectorUsable(baseConnector))
+                {
+                    continue;
+                }
+                var childJoinElements = GetJoinElements(baseConnector, allowConnector);
+                joinElements=joinElements.Intersect(childJoinElements, new ElementEqualityComparer());
+            }
+            return joinElements.ToList();
+        }
+        /// <summary>
+        /// 获取关联元素
+        /// </summary>
+        /// <param name="sourceElement"></param>
+        public static List<Element> GetJoinElements(Element sourceElement)
+        {
+            return GetJoinElements(sourceElement, null);
+        }
+        #endregion
+        #region 通过连接关系,找到满足条件的元素
+        /// <summary>
+        /// 根据连接关系,获取满足条件的元素
+        /// </summary>
+        /// <param name="inputElement"></param>
+        /// <param name="inputConnector"></param>
+        /// <param name="allowConnector"></param>
+        /// <param name="endPredicate"></param>
+        /// <returns></returns>
+        public static List<Element> GetFirstMatchElements(Element inputElement, Connector inputConnector, Predicate<Connector> allowConnector, Predicate<Element> endPredicate)
+        {
+            var startElement = inputElement;
+            ConnectorSearchOptions options = new ConnectorSearchOptions() { AllowConnector = allowConnector, AllowElement = endPredicate };
+            List<Element> result = new List<Element>();
+            List<Element> reference = new List<Element>();
+            reference.Add(startElement);
+            for (int i = 0; i < reference.Count; i++)
+            {
+                var currrentElement = reference[i];
+                #region 获取可用连接件
+                List<Connector> connectors = currrentElement.GetAllConnectors().ToList();
+                if (inputConnector != null && i == 0)
+                {
+                    connectors = new List<Connector> { inputConnector };
+                }
+                else
+                {
+                    connectors = currrentElement.GetAllConnectors().ToList();
+                }
+                #endregion
+                foreach (var con in connectors)
+                {
+                    if (!con.Searchable() || !options.ConnectorUsable(con))
+                    {
+                        continue;
+                    }
+                    List<Element> elements = GetJoinElements(con, allowConnector);
+                    foreach (var element in elements)
+                    {
+                        if (options.ElementUsable(element))
+                        {
+                            if (result.All(e => e.Id != element.Id))
+                            {
+                                result.Add(element);
+                            }
+                        }
+                        else
+                        {
+                            if (reference.All(e => e.Id != element.Id))
+                            {
+                                reference.Add(element);
+                            }
+                        }
+                    }
+                }
+            }
+            result.RemoveAll(r => r.Id.IntegerValue == startElement.Id.IntegerValue);
+            return result;
+        }
+        /// <summary>
+        /// 根据连接关系,获取满足条件的元素
+        /// </summary>
+        /// <param name="connector"></param>
+        /// <param name="allowConnector"></param>
+        /// <param name="endPredicate"></param>
+        /// <returns></returns>
+        public static List<Element> GetFirstMatchElements(Connector connector, Predicate<Connector> allowConnector, Predicate<Element> endPredicate)
+        {
+            return GetFirstMatchElements(connector.Owner, connector, allowConnector, endPredicate);
+        }
+        /// <summary>
+        /// 根据连接关系,获取满足条件的元素
+        /// </summary>
+        /// <param name="inputElement"></param>
+        /// <param name="allowConnector"></param>
+        /// <param name="endPredicate"></param>
+        /// <returns></returns>
+        public static List<Element> GetFirstMatchElements(Element inputElement, Predicate<Connector> allowConnector, Predicate<Element> endPredicate)
+        {
+            return GetFirstMatchElements(inputElement,null, allowConnector, endPredicate);
+        }
+
+        /// <summary>
+        /// 根据连接关系,获取指定类型的元素
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="startElement"></param>
+        /// <param name="startConnector"></param>
+        /// <returns></returns>
+        public static List<T> GetFirstMatchElements<T>(this Element startElement,Connector startConnector = null) where T : Element
+        {
+            return GetFirstMatchElements(startElement, startConnector, null, e => e is T).OfType<T>().ToList();
+        }
+
+        #endregion
+
+        #region 获取所有连接元素
+        /// <summary>
+        /// 获取与指定元素关联的所有元素
+        /// </summary>
+        /// <param name="element"></param>
+        /// <returns></returns>
+        public static List<Element> GetAllJoinElements(this Element element)
+        {
+            List<Element> elements = new List<Element>();
+            element.GetAllJoinElements(ref elements, null);
+            return elements;
+        }
+        public static List<Element> GetAllJoinElements(this Element element, Predicate<Element> ignoredElement)
+        {
+            List<Element> elements = new List<Element>();
+            element.GetAllJoinElements(ref elements, ignoredElement);
+            return elements;
+        }
+        /// <summary>
+        /// 获取与元素通过connector相连接的元素
+        /// </summary>
+        /// <param name="sourceElement"></param>
+        /// <param name="reference"></param>
+        /// <param name="ignoredElement"></param>
+        private static void GetAllJoinElements(this Element sourceElement, ref List<Element> reference, Predicate<Element> ignoredElement)
+        {
+            //就这样使用引用类型传入,不使用返回值形式,是避免数据转来转去拖慢算法速度
+            reference.Add(sourceElement);
+            var elements = GetJoinElements(sourceElement);
+            foreach (var element in elements)
+            {
+                if (reference.Contains(element, new ElementEqualityComparer()))
+                    continue;
+                if (ignoredElement != null && ignoredElement(element))
+                    continue;
+                element.GetAllJoinElements(ref reference, ignoredElement);
+            }
+        }
+        #endregion
+
+        //以上为最终完善代码
+
+
+        /// <summary>
+        /// 获取单线Path
+        /// </summary>
+        /// <param name="startElement">起始元素</param>
+        /// <param name="startConnector">指定元素上一点</param>
+        /// <param name="breakCondition">断开约束条件</param>
+        /// <returns></returns>
+        public static List<Element> GetPathElements(this Element startElement, Connector startConnector, Predicate<Element> breakCondition)
+        {
+            /*
+             * 获取元素以指定Connector开始的Path,单点相连情况,不分叉
+             */
+            return GetPathElements(startElement, startConnector, null, breakCondition);
+        }
+        /// <summary>
+        /// 获取单线Path
+        /// </summary>
+        /// <param name="startElement">起始元素</param>
+        /// <param name="startConnector">指定元素上一点</param>
+        /// <param name="ignoredElement">忽略点位</param>
+        /// <param name="breakCondition">断开约束条件</param>
+        /// <returns></returns>
+        public static List<Element> GetPathElements(this Element startElement, Connector startConnector, Predicate<Element> ignoredElement, Predicate<Element> breakCondition)
+        {
+            List<Element> useElements = new List<Element>() { startElement };
+            Connector useConnector = startConnector;
+            while (useConnector != null)
+            {
+                var joinElements = GetJoinElements(useConnector);
+                if (joinElements.Count != 1)
+                {
+                    break;
+                }
+                var nextElement = joinElements[0];
+                if (ignoredElement != null && ignoredElement(nextElement))
+                {
+                    break;
+                }
+                useElements.Add(nextElement);
+                //如果原始集合中存在,如环路情况。则收尾元素相等;【理论上是只可能和第一个元素相等】
+                if (startElement.Id == nextElement.Id)
+                {
+                    break;
+                }
+                if (breakCondition != null && breakCondition(nextElement))
+                {
+                    break;
+                }
+                var connectors = nextElement.GetAllConnectors();
+                if (connectors.Count != 2)
+                {
+                    break;
+                }
+                var preElement = useConnector.Owner;
+                useConnector = null;
+                for (int i = 0; i < connectors.Count; i++)
+                {
+                    var element = connectors[i].GetJoinConnector()?.Owner;
+                    if (element != null && element.Id != preElement.Id)
+                    {
+                        useConnector = connectors[i];
+                        break;
+                    }
+                }
+            }
+            return useElements;
+        }
+
+
+
+        #region 元素之间路由相关
+        /// <summary>
+        /// 获取到指定条件的全部路径
+        /// </summary>
+        /// <param name="element"></param>
+        /// <param name="endPedicate"></param>
+        /// <returns></returns>
+        public static List<ElementPath> GetRouteElements(this Element element, Predicate<Element> endPedicate)
+        {
+            List<Element> temp = new List<Element>();
+            List<ElementPath> routed = new List<ElementPath>();
+            routed = element.GetRouteElements(null, endPedicate, routed, ref temp);
+            return routed;
+        }
+        /// <summary>
+        /// 获取与指定connector连接的所有分支信息
+        /// </summary>
+        /// <param name="element"></param>
+        /// <param name="connectorSpecify"></param>
+        /// <returns></returns>
+        public static List<ElementPath> GetRouteElements(this Element element, Connector connectorSpecify, Predicate<Element> endPedicate)
+        {
+            List<Element> temp = new List<Element>();
+            List<ElementPath> routed = new List<ElementPath>();
+            routed = element.GetRouteElements(null, endPedicate, routed, ref temp);
+            return routed;
+        }
+        private static List<ElementPath> AppendElementPath(List<ElementPath> source, List<Element> elements)
+        {
+            ElementPath elementPath = new ElementPath();
+            elementPath.AddRange(elements);
+            if (source == null)
+            {
+                source = new List<ElementPath>();
+            }
+            if (!source.Any(rp => rp.Count == elementPath.Count && rp.IsMatch(elementPath)))
+            {
+                source.Add(elementPath);
+            }
+            return source;
+        }
+
+        private static List<ElementPath> GetRouteElements(this Element element, Connector connectorSpecify, Predicate<Element> endPedicate,
+            List<ElementPath> oldElementRoutes, ref List<Element> result)
+        {
+            #region 描述
+
+            /*
+             * 遍历结束条件:1、指定的条件
+             *                             2、最后端头点
+             *                             3、遍历找回到自身
+             *
+             *返回新的路径值
+            */
+
+            #endregion
+            var isEnd = result.Contains(element, new ElementEqualityComparer());
+            result.Add(element);
+            if (isEnd ||
+                (result.Count > 1 && endPedicate != null && endPedicate.Invoke(element)))
+            {
+                //结束;如果result中只有一个元素,则为开始元素。开始元素满足限定的条件时,不退出遍历
+                oldElementRoutes = AppendElementPath(oldElementRoutes, result);
+            }
+            else
+            {
+                //如果没有向下,递归项,则同样判定为路由寻址结束
+                bool hasNext = false;
+                Element preElement = null;
+                if (result.Count > 1)
+                {
+                    preElement = result[result.Count - 2];//.LastOrDefault();
+                }
+                #region 连接点处理
+                List<Connector> useConnectors = new List<Connector>();
+                if (connectorSpecify != null)
+                {
+                    useConnectors.Add(connectorSpecify);
+                }
+                else
+                {
+                    useConnectors.AddRange(element.GetAllConnectors());
+                }
+                #endregion
+                foreach (var connector in useConnectors)
+                {
+                    var elements = GetJoinElements(connector);
+                    foreach (var joinElement in elements)
+                    {
+                        if (joinElement.Id == element.Id || (preElement != null && joinElement.Id == preElement.Id))
+                            continue;
+                        if (!hasNext)
+                        {
+                            hasNext = true;
+                        }
+
+                        joinElement.GetRouteElements(null, endPedicate, oldElementRoutes, ref result);
+                        result.RemoveRange(result.Count - 1, 1);
+                    }
+                }
+                if (!hasNext)
+                {
+                    oldElementRoutes = AppendElementPath(oldElementRoutes, result);
+                }
+            }
+            return oldElementRoutes;
+        }
+        #endregion
+    }
+}

+ 52 - 0
FWindSoft/FWindSoft.Revit/Extension/ConnectorJoin/ElementPath.cs

@@ -0,0 +1,52 @@
+using Autodesk.Revit.DB;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit
+{
+    /// <summary>
+    /// 元素集合相关
+    /// </summary>
+    public class ElementPath:List<Element>
+    {
+        public bool FirstIsType<T>()
+        {
+            return FirstIsMath(e => e is T);
+        }
+        public bool FirstIsMath(Predicate<Element> predicate)
+        {
+            var useElement = this.FirstOrDefault();
+            if (useElement == null)
+                return false;
+            return predicate(useElement);
+        }
+
+        public bool LastIsType<T>()
+        {
+            return LastIsMatch(e => e is T);
+        }
+        public bool LastIsMatch(Predicate<Element> predicate)
+        {
+            var useElement = this.LastOrDefault();
+            if (useElement == null)
+                return false;
+            return predicate(useElement);
+        }
+
+        public bool IsMatch(ElementPath path)    
+        {
+          return  this.Select(e => e.Id.IntegerValue)
+                               .Intersect(path.Select(e => e.Id.IntegerValue))
+                               .Count() == path.Count();
+        }
+        #region 重写方法
+        public override string ToString()
+        {
+            return string.Join(",", this.Select(e => e.Id.ToString()));
+        }
+        #endregion
+    }
+}

+ 48 - 0
FWindSoft/FWindSoft.Revit/Extension/CurveElementExtension.cs

@@ -0,0 +1,48 @@
+using Autodesk.Revit.DB;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit
+{
+    public static class CurveElementExtension
+    {
+        public static GraphicsStyle GetGraphicStyle(this CurveElement curveElement,string styleName)
+        {
+            var ids = curveElement.GetLineStyleIds();
+            var document = curveElement.Document;
+            foreach (var id in ids)
+            {
+                var style=document.GetElement(id) as GraphicsStyle;
+                if(style!=null&&styleName== style.Name)
+                {
+                    return style;
+                }
+            }
+            return null;
+        }
+        public static GraphicsStyle SetLineStyle(this CurveElement curveElement, Color color, int lineWeight,
+            string styleName)
+        {
+            if (string.IsNullOrWhiteSpace(styleName))
+            {
+                styleName =string.Format(color.ToString()+"-"+ lineWeight);
+            }
+            var useStyle = curveElement.GetGraphicStyle(styleName);
+            if (useStyle == null)
+            {
+                var subCategory = curveElement.Document.Settings.Categories.NewSubcategory(curveElement.Category, styleName);
+                useStyle = subCategory.GetGraphicsStyle(GraphicsStyleType.Projection);
+            }
+            useStyle.GraphicsStyleCategory.LineColor = color;
+            if (lineWeight > 0)
+            {
+                useStyle.GraphicsStyleCategory.SetLineWeight(lineWeight, GraphicsStyleType.Projection);
+            }
+            curveElement.LineStyle = useStyle;
+            return useStyle;
+        }
+    }
+}

+ 33 - 0
FWindSoft/FWindSoft.Revit/Extension/DetailCurveExtension.cs

@@ -0,0 +1,33 @@
+using Autodesk.Revit.DB;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit
+{
+    public static class DetailCurveExtension
+    {
+        public static DetailCurve NewDetailCurve(this View view ,Curve curve, Color color ,
+            int lineWeight)
+        {
+            DetailCurve result = view.Document.Create.NewDetailCurve(view, curve);
+            result.SetLineStyle(color, lineWeight,null);
+            return result;
+        }
+        public static List<DetailCurve> NewDetailCurve(this View view,CurveArray curves,
+           Color color ,int lineWeight)
+        {
+            var listLines =  view.Document.Create.NewDetailCurveArray(view, curves).OfType<DetailCurve>().ToList();
+            foreach (var detailCurve in listLines)
+            {
+                if (detailCurve == null)
+                    continue;
+
+                detailCurve.SetLineStyle(color, lineWeight,null);
+            }
+            return listLines;
+        }
+    }
+}

+ 45 - 0
FWindSoft/FWindSoft.Revit/Extension/DocumentExtension.cs

@@ -0,0 +1,45 @@
+using Autodesk.Revit.DB;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit
+{
+    public static class DocumentExtension
+    {
+        #region 过滤
+        public static List<Element> GetElements(this Document doc, ElementFilter filter)
+        {
+            var collector = new FilteredElementCollector(doc);
+
+            return collector.WherePasses(filter).ToList<Element>();
+        }
+
+        public static List<T> GetElements<T>(this Document doc) where T : Element
+        {
+            var collector = new FilteredElementCollector(doc);
+            collector.OfClass(typeof(T));
+            return collector.OfType<T>().ToList<T>();
+        }
+        public static List<T> GetElementTypes<T>(this Document doc, ElementFilter filter) where T : ElementType
+        {
+            var collector = new FilteredElementCollector(doc);
+            collector.WherePasses(filter);
+            collector.WhereElementIsElementType();
+            collector.OfClass(typeof(T));
+            return collector.OfType<T>().ToList<T>();
+        }
+        #endregion
+
+        public static ElementType GetElementType(this Document doc, string typeName)
+        {
+            var types = doc.GetElements<ElementType>();
+            return types.FirstOrDefault(type => type != null && type.Name == typeName);
+        }
+
+
+    }
+}

+ 21 - 0
FWindSoft/FWindSoft.Revit/Extension/DoubleExtension.cs

@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit
+{
+    public  static class DoubleExtension
+    {
+        public const double Coff = 304.8;
+        public static double MmToFt(this double input)
+        {
+            return input / Coff;
+        }
+        public static double MmFromFt(this double input)
+        {
+            return input* Coff;
+        }
+    }
+}

+ 279 - 0
FWindSoft/FWindSoft.Revit/Extension/DuctExtension.cs

@@ -0,0 +1,279 @@
+using Autodesk.Revit.DB;
+using Autodesk.Revit.DB.Mechanical;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit
+{
+    public static class DuctExtension
+    {
+        /// <summary>
+        /// 获取风管系统类型(非枚举)
+        /// </summary>
+        /// <param name="duct">风管</param>
+        /// <returns></returns>
+        public static MechanicalSystemType GetMechanicalSystemType(this Duct duct)
+        {
+            var id = duct.GetParameterElementId(BuiltInParameter.RBS_DUCT_SYSTEM_TYPE_PARAM);
+            return duct.Document.GetElement(id) as MechanicalSystemType;
+        }
+        /// <summary>
+        /// 获取风管系统分类
+        /// </summary>
+        /// <param name="duct"></param>
+        /// <returns></returns>
+        public static DuctSystemType GetDuctSystemType(this Duct duct)
+        {
+            var ductSystem = duct.MEPSystem as MechanicalSystem;
+            if (ductSystem != null)
+                return ductSystem.SystemType;
+            return DuctSystemType.UndefinedSystemType;
+        }
+        /// <summary>
+        /// 获取风管的朝向
+        /// </summary>
+        /// <param name="duct"></param>
+        /// <returns></returns>
+        public static XYZ GetCurveNormal(this Duct duct)
+        {
+            //通过connector basizY的方向去确定朝向
+            Connector connector = duct.GetFirstConnector(c=>c.ConnectorType==ConnectorType.End);
+            return connector.CoordinateSystem.BasisY.Negate();
+        }
+
+        /// <summary>
+        /// 设置风管的朝向
+        /// </summary>
+        /// <param name="duct"></param>
+        /// <param name="normal"></param>
+        public static void SetCurveNormal(this Duct duct, XYZ normal)
+        {
+            XYZ sorce = duct.GetCurveNormal();
+            Line axis = duct.GetLocationLine();
+            double angle = sorce.AngleOnPlaneTo(normal, axis.Direction.Normalize());
+            duct.Rotate(axis, angle);
+        }
+
+        /// <summary>
+        /// 获取风管的最长尺寸
+        /// </summary>
+        /// <param name="duct"></param>
+        /// <returns></returns>
+        public static double GetLongestSize(this Duct duct)
+        {
+            double tempDia = duct.GetParameterDouble(BuiltInParameter.RBS_CURVE_DIAMETER_PARAM).MmFromFt();
+            double tempWidth = duct.GetParameterDouble(BuiltInParameter.RBS_CURVE_WIDTH_PARAM).MmFromFt();
+            double tempHeight = duct.GetParameterDouble(BuiltInParameter.RBS_CURVE_HEIGHT_PARAM).MmFromFt();
+            double length = tempHeight > tempWidth ? tempHeight : tempWidth;
+            length = tempDia > length ? tempDia : length;
+            return length;
+        }
+
+        /// <summary>
+        /// 判断给定的风管集合的垂直对齐方式
+        /// </summary>
+        /// <param name="ducts">风管集合</param>
+        /// <returns>返回垂直对齐的标识(-1,底对齐;0,一般处理;1,顶对齐。)</returns>
+        public static int GetVerAlignType(this List<Duct> ducts)
+        {
+            int flag = 0;
+            //List<Connector> connectors = ducts.Select(d => d.GetConnectors()[0]).ToList();
+            //List<Tuple<XYZ, XYZ, double>> listTuple = new List<Tuple<XYZ, XYZ, double>>();
+            //foreach (var connector in connectors)
+            //{
+            //    double length = connector.Shape == ConnectorProfileType.Round ? connector.Radius * 2 : connector.Height;
+            //    listTuple.Add(new Tuple<XYZ, XYZ, double>(connector.Origin, connector.CoordinateSystem.BasisY, length));
+            //}
+            //if (listTuple.Count == 0)
+            //    return flag;
+            //Tuple<XYZ, XYZ, double> baseTuple = listTuple[0];
+            //if (listTuple.Any(t => !t.Item2.IsParallel(baseTuple.Item2)))
+            //    return 0;
+            //Line baseLine = baseTuple.Item1.NewLine(baseTuple.Item1.OffsetPoint(baseTuple.Item2, 1000));
+            //XYZ baseOrigion = baseLine.GetProjectPt(baseTuple.Item1, true);
+            //if (listTuple.All(t => baseLine.GetProjectPt(t.Item1, true).IsEqual(baseOrigion, 0.001)))
+            //{
+            //    return 0;
+            //}
+            //XYZ bottom = baseTuple.Item1.OffsetPoint(baseTuple.Item2, baseTuple.Item3 / 2);
+            //XYZ bottomProject = baseLine.GetProjectPt(bottom, true);
+            //if (
+            //    listTuple.All(
+            //        t =>
+            //            baseLine.GetProjectPt(t.Item1.OffsetPoint(t.Item2, t.Item3 / 2), true)
+            //                .IsEqual(bottomProject, 0.001)))
+            //{
+            //    return -1;
+            //}
+            //XYZ top = baseTuple.Item1.OffsetPoint(baseTuple.Item2.Negate(), baseTuple.Item3 / 2);
+            //XYZ topProject = baseLine.GetProjectPt(top, true);
+            //if (
+            //    listTuple.All(
+            //        t =>
+            //            baseLine.GetProjectPt(t.Item1.OffsetPoint(t.Item2.Negate(), t.Item3 / 2), true)
+            //                .IsEqual(topProject, 0.001)))
+            //{
+            //    return 1;
+            //}
+            return flag;
+        }
+
+        /// <summary>
+        /// 获取风管实例截面类型
+        /// </summary>
+        /// <param name="duct">指定风管</param>
+        /// <returns>风管截面形状</returns>
+        public static DuctShape GetDuctShape(this Duct duct)
+        {
+            DuctShape shape = DuctShape.Rectangular;
+            var connector = duct.GetFirstConnector(c=>c.ConnectorType==ConnectorType.End);
+            switch (connector.Shape)
+            {
+                case ConnectorProfileType.Oval:
+                    {
+                        shape = DuctShape.Oval;
+                        break;
+                    }
+                case ConnectorProfileType.Round:
+                    {
+                        shape = DuctShape.Round;
+                        break;
+                    }
+                case ConnectorProfileType.Rectangular:
+                    {
+                        shape = DuctShape.Rectangular;
+                        break;
+                    }
+            }
+            return shape;
+        }
+
+        /// <summary>
+        /// 获取垂直风管角度
+        /// </summary>
+        /// <param name="duct"></param>
+        /// <returns>如果风管垂直返回正确角度,如果风管竖直,返回π/2</returns>
+        public static double GetVerAngle(this Duct duct)
+        {
+            if (duct == null)
+                return 0;
+            double defalut = Math.PI / 2;
+            var line = duct.GetLocationLine();
+            XYZ start = line.StartPoint();
+            XYZ end = line.EndPoint();
+            if (!start.IsEqual2(end))
+            {
+                return defalut;
+            }
+            XYZ normal = duct.GetCurveNormal();
+            //不封装,是为了保证使用的严谨性,时刻记住是三维
+            return XYZ.BasisX.AngleOnPlaneTo(normal, XYZ.BasisZ);
+        }
+        /// <summary>
+        /// 根据界面类型获取所需要的尺寸
+        /// </summary>
+        /// <param name="doc"></param>
+        /// <param name="shape"></param>
+        /// <returns></returns>
+        public static List<double> GetDuctSizes(this Document doc, DuctShape shape)
+        {
+
+            List<double> sizes = new List<double>();
+            DuctSizeSettings setting = DuctSizeSettings.GetDuctSizeSettings(doc);
+
+            if (setting != null)
+            {
+                sizes = setting[shape].Select(size => size.NominalDiameter.MmFromFt()).ToList();
+            }
+            return sizes;
+        }
+
+        /// <summary>
+        /// 获取项目中设置的空气密度
+        /// </summary>
+        /// <param name="doc"></param>
+        /// <returns></returns>
+        public static double GetAirDensity(this Document doc)
+        {
+            double airDensity = 1;
+            List<double> sizes = new List<double>();
+            DuctSettings setting = DuctSettings.GetDuctSettings(doc);
+            if (setting != null)
+            {
+                airDensity = setting.AirDensity;
+            }
+            //单位转换的问题
+            return 0;//airDensity.FromApi(DisplayUnitType.DUT_KILOGRAMS_PER_CUBIC_METER);
+        }
+
+
+     
+
+        /// <summary>
+        /// 获取制定风管类型的截面类型
+        /// </summary>
+        /// <param name="ductType">风管类型</param>
+        /// <returns></returns>
+        public static DuctShape GetDuctShape(this DuctType ductType)
+        {
+            string strShape = ductType.GetParameterString(BuiltInParameter.ALL_MODEL_FAMILY_NAME);
+            do
+            {
+                if ("矩形风管".Equals(strShape))
+                {
+                    return DuctShape.Rectangular;
+                }
+                if ("圆形风管".Equals(strShape))
+                {
+                    return DuctShape.Round;
+                }
+                if ("椭圆形风管".Equals(strShape))
+                {
+                    return DuctShape.Oval;
+                }
+            } while (false);
+            throw new Exception("获取风管类型截面出错");
+        }
+
+
+
+        /// <summary>
+        /// 获取项目中所有风管类型
+        /// </summary>
+        /// <param name="doc"></param>
+        /// <returns></returns>
+        public static List<DuctType> GetDuctTypes(this Document doc)
+        {
+            List<DuctType> list = doc.GetElements<DuctType>();
+            return list;
+
+        }
+
+        /// <summary>
+        /// 获取项目中所有风管类型
+        /// </summary>
+        /// <param name="doc"></param>
+        /// <param name="shape"></param>
+        /// <returns></returns>
+        public static List<DuctType> GetDuctTypes(this Document doc, DuctShape shape)
+        {
+            List<DuctType> list = doc.GetDuctTypes();
+            return list.Where(type => type.GetDuctShape() == shape).ToList();
+
+        }
+
+        /// <summary>
+        /// 获取所有的软管类型
+        /// </summary>
+        /// <param name="doc"></param>
+        /// <returns></returns>
+        public static List<FlexDuctType> GetFlexDuctTypes(this Document doc)
+        {
+            List<FlexDuctType> list = doc.GetElements<FlexDuctType>();
+            return list;
+        }
+    }
+}

+ 186 - 0
FWindSoft/FWindSoft.Revit/Extension/ElementExtension.cs

@@ -0,0 +1,186 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Autodesk.Revit.DB;
+using Autodesk.Revit.DB.Mechanical;
+using Autodesk.Revit.DB.Plumbing;
+
+namespace FWindSoft.Revit
+{
+    public static class ElementExtension
+    {
+        /// <summary>
+        /// 获取定位线
+        /// </summary>
+        /// <param name="element"></param>
+        /// <returns></returns>
+        public static Curve GetLocationCurve(this Element element)
+        {
+            return element.Location?.ConvertToCurve();
+        }
+        /// <summary>
+        /// 获取定位线
+        /// </summary>
+        /// <param name="element"></param>
+        /// <returns></returns>
+        public static Line GetLocationLine(this Element element)
+        {
+            return element.Location?.ConvertToLine();
+        }
+        /// <summary>
+        /// 获取元素定位点
+        /// </summary>
+        /// <param name="element"></param>
+        /// <returns></returns>
+        public static XYZ GetLocationPoint(this Element element)
+        {
+            return element.Location?.ConvertToPoint();
+        }
+        /// <summary>
+        /// 获取元素开始点
+        /// </summary>
+        /// <param name="element"></param>
+        /// <returns></returns>
+        public static XYZ StartPoint(this Element element)
+        {
+            return element.GetLocationCurve()?.StartPoint();
+        }
+        /// <summary>
+        /// 获取元素结束点
+        /// </summary>
+        /// <param name="element"></param>
+        /// <returns></returns>
+        public static XYZ EndPoint(this Element element)
+        {
+            return element.GetLocationCurve()?.EndPoint();
+        }
+
+        public static BuiltInCategory GetCategory(this Element elem)
+        {
+            var bic = BuiltInCategory.INVALID;
+            if (elem.Category != null)
+            {
+                bic = (BuiltInCategory)elem.Category.Id.IntegerValue;
+            }
+            return bic;
+        }
+        /// <summary>
+        /// 元素旋转信息
+        /// </summary>
+        /// <param name="element"></param>
+        /// <param name="axis"></param>
+        /// <param name="angle"></param>
+        public static void Rotate(this Element element, Line axis, double angle)
+        {
+            ElementTransformUtils.RotateElement(element.Document, element.Id, axis, angle);
+        }
+        /// <summary>
+        /// 获取元素的内置分类
+        /// </summary>
+        /// <param name="elem"></param>
+        /// <returns></returns>
+        public static BuiltInCategory GetBuiltInCategory(this Element elem)
+        {
+            var bic = BuiltInCategory.INVALID;
+            if (!elem.IsValidObject)
+                return BuiltInCategory.INVALID;
+            if (elem.Category != null && elem.Category.Id != null)
+            {
+                bic = (BuiltInCategory)elem.Category.Id.IntegerValue;
+            }
+            return bic;
+        }
+
+        public static bool IsWaterComponment(this Element element)
+        {
+            return element is Pipe || element is FlexPipe || (element is FamilyInstance && element.GetBuiltInCategory() == BuiltInCategory.OST_PipeFitting);
+        }
+        public static bool IsHavcComponment(this Element element)
+        {
+            return element is Duct|| element is FlexDuct || (element is FamilyInstance && element.GetBuiltInCategory() == BuiltInCategory.OST_DuctFitting);
+        }
+
+        /// <summary>
+        /// 获取图元类型
+        /// </summary>
+        /// <param name="element"></param>
+        /// <returns></returns>
+        public static ElementType GetElementType(this Element element)
+        {
+            ElementId id = element.GetTypeId();
+            if (id != null && id != ElementId.InvalidElementId)
+            {
+                Element elementType = element.Document.GetElement(id);
+                return elementType as ElementType;
+            }
+            return null;
+        }
+        /// <summary>
+        /// 获取图元类型
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="element"></param>
+        /// <returns></returns>
+        public static T GetElementType<T>(this Element element) where T : ElementType
+        {
+            ElementId id = element.GetTypeId();
+            if (id != null && id != ElementId.InvalidElementId)
+            {
+                Element elementType = element.Document.GetElement(id);
+                return elementType as T;
+            }
+            return null;
+        }
+
+        /// <summary>
+        /// 获取参照标高
+        /// </summary>
+        /// <param name="element"></param>
+        /// <returns></returns>
+        public static Level GetLevel(this Element element)
+        {
+            Level level = null;
+            ElementId eId = element.GetLevelId();
+            if (eId != ElementId.InvalidElementId)
+            {
+                level = element.Document.GetElement(eId) as Level;
+            }
+            return level;
+        }
+
+        /// <summary>
+        /// 获取参照标高Id
+        /// </summary>
+        /// <param name="element"></param>
+        /// <returns></returns>
+        public static ElementId GetLevelId(this Element element)
+        {
+            return element.GetParameterElementId(BuiltInParameter.INSTANCE_REFERENCE_LEVEL_PARAM);
+        }
+
+        /// <summary>
+        /// 参照标高
+        /// </summary>
+        /// <param name="element"></param>
+        /// <param name="level"></param>
+        public static void SetLevel(this Element element, Level level)
+        {
+            if (level != null)
+            {
+                element.SetLevel(level.Id);
+            }
+        }
+
+        /// <summary>
+        /// 设置参照标高参照标高
+        /// </summary>
+        /// <param name="element"></param>
+        /// <param name="levelId"></param>
+        public static void SetLevel(this Element element, ElementId levelId)
+        {
+            element.SetParameter(BuiltInParameter.INSTANCE_REFERENCE_LEVEL_PARAM, levelId);
+        }
+    }
+}

+ 30 - 0
FWindSoft/FWindSoft.Revit/Extension/ElementTypeExtension.cs

@@ -0,0 +1,30 @@
+using Autodesk.Revit.DB;
+using FWindSoft.Revit.Common;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit
+{
+    public static class ElementTypeExtension
+    {
+        /// <summary>
+        /// 复制增加图元类型
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="elementType"></param>
+        /// <param name="strName"></param>
+        /// <returns></returns>
+        public static T DuplicateT<T>(this ElementType elementType, string strName) where T : ElementType
+        {
+            if (strName.Length > 128)
+            {
+                strName = strName.Substring(0, 127);
+            }
+            strName = RevitTools.RemoveForbiddenChars(strName);
+            return elementType.Duplicate(strName) as T;
+        }
+    }
+}

+ 41 - 0
FWindSoft/FWindSoft.Revit/Extension/FamilyInstanceExtension.cs

@@ -0,0 +1,41 @@
+using Autodesk.Revit.DB;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit
+{
+    public static class FamilyInstanceExtension
+    {
+        /// <summary>
+        /// 获取FamilyInstance的FamilySymbol
+        /// </summary>
+        /// <param name="familyInstance"></param>
+        /// <returns></returns>
+        public static FamilySymbol GetFamilySymbol(this FamilyInstance familyInstance)
+        {
+            FamilyInstance finst = familyInstance;
+            if (familyInstance != null)
+            {
+                return finst.Symbol;
+            }
+            return null;
+        }
+        /// <summary>
+        /// 获取FamilyInstance的Family
+        /// </summary>
+        /// <param name="familyInstance"></param>
+        /// <returns></returns>
+        public static Family GetFamily(this FamilyInstance familyInstance)
+        {
+            FamilyInstance finst = familyInstance;
+            if (familyInstance != null)
+            {
+                return finst.Symbol?.Family;
+            }
+            return null;
+        }
+    }
+}

+ 102 - 0
FWindSoft/FWindSoft.Revit/Extension/Graphic/CurveExtension.cs

@@ -0,0 +1,102 @@
+using Autodesk.Revit.DB;
+using FWindSoft.SystemExtensions;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit
+{
+    public static class CurveExtension
+    {
+        public static XYZ StartPoint(this Curve curve)
+        {
+            return curve.GetEndPoint(0);
+        }
+
+        public static XYZ EndPoint(this Curve curve)
+        {
+            return curve.GetEndPoint(1);
+        }
+        public static Line NewLine(this XYZ start,XYZ end)
+        {
+            return Line.CreateBound(start, end);
+        }
+        public static Line NewUnBoundLine(this XYZ start, XYZ direction)
+        {
+            return Line.CreateUnbound(start, direction);
+        }
+        /// <summary>
+        /// 将线克隆成无边界模式
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="curve"></param>
+        /// <returns></returns>
+        public static T CloneUnbound<T>(this T curve) where T : Curve
+        {
+            var clone = curve.Clone();
+            if (clone.IsBound)
+            {
+                clone.MakeUnbound();
+            }
+            return clone as T;
+        }
+
+        /// <summary>
+        /// 获取曲线相交点
+        /// </summary>
+        public static List<XYZ> GetIntersections(this Curve curve1, Curve curve2)
+        {
+            List<XYZ> result = new List<XYZ>();
+            if(curve1 == null || curve2 == null)
+            {
+                return result;
+            }
+            var setResult = curve1.Intersect(curve2, out IntersectionResultArray interResult);
+            if (null != interResult)
+            {
+                foreach (IntersectionResult iResult in interResult)
+                {
+                    result.Add(iResult.XYZPoint);
+                }
+            }
+            return result;
+        }
+        /// <summary>
+        /// 求交点都用些方法,有问题请讨论
+        /// </summary>
+        /// <param name="curve1"></param>
+        /// <param name="curve2"></param>
+        /// <returns></returns>
+        public static XYZ GetIntersection(this Curve curve1, Curve curve2)
+        {
+            List<XYZ> intersections = curve1.GetIntersections(curve2);
+            if (intersections != null && intersections.Count > 0)
+            {
+                return intersections[0];
+            }
+            return null;
+        }
+        /// <summary>
+        /// 判断点是否在Curve上
+        /// </summary>
+        public static bool InCurve(this Curve curve, XYZ input, double tolerance = 0)
+        {
+            //当Curve上的,存在多个到input点距离相等,且同时为最短距离是,Distance函数可能出现异常
+            try
+            {
+                if (curve is Arc arc && arc.Center.IsEqual(input, tolerance))
+                {
+                    return false;
+                }
+            }
+            catch (Exception)
+            {
+
+                return false;
+            }
+            return curve.Distance(input).IsEqual(0, tolerance);
+        }
+    }
+}

+ 203 - 0
FWindSoft/FWindSoft.Revit/Extension/Graphic/GeometryElementExtension.cs

@@ -0,0 +1,203 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Autodesk.Revit.DB;
+
+namespace FWindSoft.Revit
+{
+    public static class GeometryElementExtension
+    {
+        /// <summary>
+        /// 查找原始的几何对象
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="geoElement"></param>
+        /// <returns></returns>
+        public static List<T> GetGeometryOriginalObjects<T>(this GeometryElement geoElement) where T : GeometryObject
+        {
+            List<T> listRtn = new List<T>();
+            List<GeometryElement> useElements = new List<GeometryElement>() { geoElement };
+            for (int i = 0; i < useElements.Count; i++)
+            {
+                var useGeoElement = useElements[i];
+                foreach (var geoObject in useGeoElement)
+                {
+                    //系统族、相交切割后的外部族
+                    if (geoObject is T)
+                    {
+                        listRtn.Add(geoObject as T);
+                    }
+                    else if (geoObject is GeometryInstance)
+                    {
+                        var childElment = (geoObject as GeometryInstance).GetInstanceGeometry();
+                        if (childElment != null)
+                        {
+                            useElements.Add(childElment);
+                        }
+                    }
+                    else if (geoObject is GeometryElement)
+                    {
+                        useElements.Add(geoObject as GeometryElement);
+                    }
+                }
+            }
+            return listRtn;
+        }
+        public static List<T> GetGeometryObjects<T>(this GeometryElement geoElement) where T : GeometryObject
+        {
+            List<T> listRtn = geoElement.GetGeometryOriginalObjects<T>();
+            if (listRtn.Count==0)
+            {
+                //计算为几何信息复制,可能引用相关有问题
+                var geoElementNew = geoElement.GetTransformed(Transform.Identity);
+                listRtn = geoElementNew.GetGeometryOriginalObjects<T>();
+            }
+            return listRtn;
+        }
+
+        /// <summary>
+        /// 获取指定元素的几何描述
+        /// </summary>
+        /// <param name="element"></param>
+        /// <param name="visibleObj"></param>
+        /// <param name="view"></param>
+        /// <returns></returns>
+        public static GeometryElement GetGeometryElement(this Element element, bool visibleObj = false, View view = null)
+        {
+            var options = new Options();
+            options.ComputeReferences = true;
+            options.IncludeNonVisibleObjects = visibleObj;
+            if (view == null)
+            {
+                options.DetailLevel = ViewDetailLevel.Fine;
+            }
+            else
+            {
+                options.View = view;
+            }
+
+            return element.get_Geometry(options);
+        }
+
+        /// <summary>
+        /// 获取几何Solid
+        /// </summary>
+        /// <param name="elem"></param>
+        /// <param name="view"></param>
+        /// <param name="visibleObj"></param>
+        /// <returns></returns>
+        public static List<Solid> GetSolids(this Element elem, View view = null, bool visibleObj = false)
+        {
+            var geoElement = elem.GetGeometryElement(visibleObj, view);
+            return geoElement.GetGeometryObjects<Solid>();
+        }
+
+        /// <summary>
+        /// 获取几何Solid;最大的默认第一个
+        /// </summary>
+        /// <param name="elem"></param>
+        /// <returns></returns>
+        public static Solid GetSolid(this Element elem)
+        {
+            Solid solid = null;
+            List<Solid> listRtn = elem.GetSolids();
+            if (listRtn != null && listRtn.Count > 0)
+            {
+                solid = listRtn[0];
+            }
+            return solid;
+        }
+        #region 当前集合信息
+        /// <summary>
+        /// 获取元素当前的面信息
+        /// </summary>
+        /// <param name="elem"></param>
+        /// <param name="view"></param>
+        /// <returns></returns>
+        public static List<Face> GetFaces(this Element elem, View view = null)
+        {
+            var listRtn = new List<Face>();
+            List<Solid> listSoild = elem.GetSolids(view);
+            foreach (var solid in listSoild)
+            {
+                listRtn.AddRange(solid.Faces.OfType<Face>());
+            }
+            return listRtn;
+        }
+        #endregion
+
+
+        #region 原始为切割几何信息
+        /// <summary>
+        /// 未切割的Edge
+        /// </summary>
+        /// <param name="instance"></param>
+        /// <returns></returns>
+        public static List<Edge> GetOriginalEdges(this FamilyInstance instance)
+        {
+            var listRtn = new List<Edge>();
+            List<Solid> listSoild = instance.GetOriginalSolids();
+            foreach (var solid in listSoild)
+            {
+                listRtn.AddRange(solid.Edges.OfType<Edge>());
+            }
+            return listRtn;
+        }
+
+       
+
+        /// <summary>
+        /// 法向相等的某一面 ljy
+        /// </summary>
+        /// <param name="instance"></param>
+        /// <param name="normal"></param>
+        /// <returns></returns>
+        public static List<Face> GetOriginalFaces(this FamilyInstance instance, XYZ normal)
+        {
+            var faces = instance.GetOriginalFaces();
+            return faces.Where(p => p is PlanarFace&& (p as PlanarFace).FaceNormal.IsSameDirection(normal)).ToList();
+        }
+
+        /// <summary>
+        /// 未切割的Face
+        /// </summary>
+        /// <param name="instance"></param>
+        /// <returns></returns>
+        public static List<Face> GetOriginalFaces(this FamilyInstance instance)
+        {
+            var listRtn = new List<Face>();
+            List<Solid> listSoild = instance.GetOriginalSolids();
+            foreach (var solid in listSoild)
+            {
+                listRtn.AddRange(solid.Faces.OfType<Face>());
+            }
+            return listRtn;
+        } /// <summary>
+        /// 未切割的Solid
+        /// </summary>
+        /// <param name="instance"></param>
+        /// <returns></returns>
+        public static List<Solid> GetOriginalSolids(this FamilyInstance instance)
+        {
+            var options = new Options();
+            //不能计算reference
+            options.ComputeReferences = false;
+            var geoElement = instance.GetOriginalGeometry(options);
+            if (geoElement == null)
+            {
+                return null;
+            }
+            var transform = instance.GetTransform();
+            geoElement = geoElement.GetTransformed(transform);
+            var listSoild = geoElement.GetGeometryObjects<Solid>();
+            if (listSoild.Count == 0)
+            {
+                listSoild = new List<Solid>();
+            }
+            return listSoild;
+        }
+        #endregion
+    }
+}

+ 117 - 0
FWindSoft/FWindSoft.Revit/Extension/Graphic/LineExtension.cs

@@ -0,0 +1,117 @@
+using Autodesk.Revit.DB;
+using FWindSoft.SystemExtensions;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit
+{
+    public static class LineExtension
+    {
+        /// <summary>
+        /// 两直线平行
+        /// </summary>
+        /// <param name="line1"></param>
+        /// <param name="line2"></param>
+        /// <returns></returns>
+        public static bool IsParallel(this Line line1, Line line2)
+        {
+            return line1.Direction.IsParallel(line2.Direction);
+        }
+        /// <summary>
+        /// 获取线的端点与指定点 最远的点    
+        /// </summary>
+        /// <param name="line"></param>
+        /// <param name="point"></param>
+        /// <returns></returns>
+        public static XYZ GetFarnessPoint(this Line line, XYZ point)
+        {
+            XYZ start = line.StartPoint();
+            XYZ end = line.EndPoint();
+            return start.DistanceTo(point).Less(end.DistanceTo(point)) ? end : start;
+        }
+
+        /// <summary>
+        /// 获取线的端点与指定点 最近的点        
+        /// </summary>
+        /// <param name="line"></param>
+        /// <param name="point"></param>
+        /// <returns></returns>
+        public static XYZ GetNearnessPoint(this Line line, XYZ point)
+        {
+            XYZ start = line.StartPoint();
+            XYZ end = line.EndPoint();
+            return start.DistanceTo(point).Less(end.DistanceTo(point)) ? start : end;
+        }
+
+        /// <summary>
+        /// 获取空间直线的垂足点
+        /// </summary>
+        /// <param name="baseLine"></param>
+        /// <param name="line2"></param>
+        /// <returns></returns>
+        public static XYZ GetSpatialIntersection(this Line baseLine, Line line2)
+        {
+            //两条法向量构建,和baseLine上一点构建平面,line2中的点在平面内的投影线。求投影线和baseLine1两条直线的夹角
+            XYZ basePoint = null;
+            do
+            {
+                if (baseLine.IsParallel(line2))
+                {
+                    break;
+                }
+                var normal = baseLine.Direction.CrossProduct(line2.Direction);
+                var origin = baseLine.Origin;
+                var start = line2.Origin;
+                var end = start + 10 * line2.Direction;
+                if (line2.IsBound)
+                {
+                    start = line2.StartPoint();
+                    end = line2.EndPoint();
+                }
+                //取投影点
+                XYZ point1 = start.GetPlaneProject(normal, origin);
+                XYZ point2 = end.GetPlaneProject(normal, origin);
+                if (point1.IsEqual(point2))
+                {
+                    basePoint = point1;
+                }
+                else
+                {
+                    var unBoundLine1 = baseLine.CloneUnbound();
+                    var unboundLine2 = point1.NewLine(point2).CloneUnbound();
+                    basePoint = unBoundLine1.GetIntersection(unboundLine2);
+                }
+
+            } while (false);
+            return basePoint;
+        }
+
+        /// <summary>
+        /// 是否共线
+        /// </summary>
+        /// <param name="baseLine"></param>
+        /// <param name="line2"></param>
+        /// <returns></returns>
+        public static bool IsCollinear(this Line baseLine,Line line2)
+        {
+            return baseLine.IsParallel(line2) && baseLine.Direction.IsParallel(line2.Origin - baseLine.Origin);
+        }
+        /// <summary>
+        /// 获取输入点在直线上的投影点
+        /// </summary>
+        /// <param name="line"></param>
+        /// <param name="input"></param>
+        /// <returns></returns>
+        public static XYZ GetProject(this  Line line, XYZ input)
+        {
+            var origin = line.Origin;
+            var direction = line.Direction;
+            var useVector = input - origin;
+            var project = useVector.DotProduct(direction) * direction + origin;
+            return project;
+        }
+    }
+}

+ 217 - 0
FWindSoft/FWindSoft.Revit/Extension/Graphic/XYZExtension.cs

@@ -0,0 +1,217 @@
+using Autodesk.Revit.DB;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using FWindSoft.SystemExtensions;
+
+namespace FWindSoft.Revit
+{
+    /// <summary>
+    /// 点的扩展相关
+    /// </summary>
+    public static class XYZExtension
+    {
+        /// <summary>
+        /// 向量是否平行
+        /// </summary>
+        /// <param name="baseDirection"></param>
+        /// <param name="direction"></param>
+        /// <returns></returns>
+        public static bool IsParallel(this XYZ baseDirection, XYZ direction)
+        {
+            return baseDirection.CrossProduct(direction).GetLength().IsZero();
+        }
+        /// <summary>
+        /// 向量是否垂直
+        /// </summary>
+        /// <param name="baseDirection"></param>
+        /// <param name="direction"></param>
+        /// <returns></returns>
+        public static bool IsVertical(this XYZ baseDirection, XYZ direction)
+        {
+            return baseDirection.DotProduct(direction).IsZero();
+        }
+        /// <summary>
+        /// 判断向量是否同向
+        /// </summary>
+        /// <param name="firstDirection"></param>
+        /// <param name="secondDirection"></param>
+        /// <returns></returns>
+        public static bool IsSameDirection(this XYZ firstDirection, XYZ secondDirection)
+        {
+            if(firstDirection.IsParallel(secondDirection))
+            {
+                return firstDirection.DotProduct(secondDirection).MoreEqual(0);
+            }
+            return false;
+        }
+        /// <summary>
+        /// 向量方向相反 
+        /// </summary>
+        /// <param name="firstDirection"></param>
+        /// <param name="secondDirection"></param>
+        /// <returns></returns>
+        public static bool IsOppositeDirection(this XYZ firstDirection, XYZ secondDirection)
+        {
+            if (firstDirection.IsParallel(secondDirection))
+            {
+                return secondDirection.DotProduct(secondDirection).LessEqual(0);
+            }
+            return false;
+        }
+       
+        /// <summary>
+        /// 偏移指定向量
+        /// </summary>
+        /// <param name="origin"></param>
+        /// <param name="vector"></param>
+        /// <returns></returns>
+        public static XYZ Offset(this XYZ origin,XYZ vector)
+        {
+            return origin + vector;
+        }
+        /// <summary>
+        /// 判断两个点是否重合
+        /// </summary>
+        /// <param name="first"></param>
+        /// <param name="second"></param>
+        /// <param name="tolerance"></param>
+        /// <returns></returns>
+        public static bool IsEqual(this XYZ first, XYZ second, double tolerance)
+        {
+
+            return first.X.IsEqual(second.X, tolerance)
+                   && first.Y.IsEqual(second.Y, tolerance)
+                   && first.Z.IsEqual(second.Z, tolerance);
+        }
+        /// <summary>
+        /// 判断两个点是否重合
+        /// </summary>
+        /// <param name="first"></param>
+        /// <param name="second"></param>
+        /// <returns></returns>
+        public static bool IsEqual(this XYZ first, XYZ second)
+        {
+
+            return first.X.IsEqual(second.X, DoubleExtensions.Precision)
+                   && first.Y.IsEqual(second.Y, DoubleExtensions.Precision)
+                   && first.Z.IsEqual(second.Z, DoubleExtensions.Precision);
+        }
+        /// <summary>
+        /// 判断两个点是否重合
+        /// </summary>
+        /// <param name="first"></param>
+        /// <param name="second"></param>
+        /// <returns></returns>
+        public static bool IsEqual2(this XYZ first, XYZ second)
+        {
+
+            return first.X.IsEqual(second.X, DoubleExtensions.Precision)
+                   && first.Y.IsEqual(second.Y, DoubleExtensions.Precision);
+        }
+        /// <summary>
+        /// 按指定方向的轴,在原点位置旋转向量
+        /// </summary>
+        /// <param name="vec"></param>
+        /// <param name="axis"></param>
+        /// <param name="angle"></param>
+        /// <returns></returns>
+        public static XYZ RotateVector(this XYZ vec, XYZ axis, double angle)
+        {
+            var transform = Transform.CreateRotationAtPoint(axis, angle, XYZ.Zero);
+            return transform.OfVector(vec);
+        }
+        /// <summary>
+        /// 计算点到指定平面的投影
+        /// </summary>
+        /// <param name="input"></param>
+        /// <param name="normal"></param>
+        /// <param name="origin"></param>
+        /// <returns></returns>
+        public static XYZ GetPlaneProject(this XYZ input, XYZ normal, XYZ origin)
+        {
+            if (!normal.IsUnitLength())
+            {
+                normal = normal.Normalize();
+            }
+            return input + normal * origin.Subtract(input).DotProduct(normal);
+        }
+        /// <summary>
+        /// 计算点到指定直线的投影
+        /// </summary>
+        /// <param name="input"></param>
+        /// <param name="direction"></param>
+        /// <param name="origin"></param>
+        /// <returns></returns>
+        public static XYZ GetLineProject(this XYZ input, XYZ direction, XYZ origin)
+        {
+            if (!direction.IsUnitLength())
+            {
+                direction = direction.Normalize();
+            }
+            return origin + direction * input.Subtract(origin).DotProduct(direction);
+        }
+        /// <summary>
+        /// 获取任意一个与input垂直的向量
+        /// </summary>
+        /// <param name="input"></param>
+        /// <returns></returns>
+        public static XYZ GetAnyVerticalVector(this XYZ input)
+        {
+            if (!XYZ.BasisX.IsParallel(input))
+            {
+                return input.CrossProduct(XYZ.BasisX).Normalize();
+            }
+            else
+            {
+                return input.CrossProduct(XYZ.BasisY).Normalize();
+            }
+        }
+        /// <summary>
+        /// 判断点的投影是否在直线段内
+        /// </summary>
+        /// <param name="input"></param>
+        /// <param name="line"></param>
+        /// <returns></returns>
+        public static bool IsProjectInLine(this XYZ input, Line line)
+        {
+            if (!line.IsBound)
+            {
+                return true;
+            }
+            var project =line.GetProject(input);
+           return line.InCurve(project);
+        }
+        /// <summary>
+        /// 使用Input在line上的投影点分割指定直线
+        /// </summary>
+        /// <param name="input"></param>
+        /// <param name="line"></param>
+        /// <returns>如果点在线外侧,则返回一个较大的向量,另一个去掉。如果在线上,则返回两个向量</returns>
+        public static List<XYZ> SplitVector(this XYZ input, Line line)
+        {
+            if (!line.IsBound)
+            {
+                return new List<XYZ>() { line.Direction * Double.MaxValue, line.Direction * Double.MaxValue, };
+            }
+            var project = line.GetProject(input);
+            var startVector = line.StartPoint() - project;
+            var endVector = line.EndPoint() - project;
+            if (startVector.DotProduct(endVector).MoreEqual(0))
+            {
+                //两个向量同向,去较大的返回
+                if (startVector.GetLength().More(endVector.GetLength()))
+                {
+                    return new List<XYZ>() { startVector };
+                }
+                else
+                {
+                    return new List<XYZ>() { endVector };
+                }
+            }
+            return new List<XYZ>() { startVector, endVector };
+        }
+    }
+}

+ 175 - 0
FWindSoft/FWindSoft.Revit/Extension/InsulationExtension.cs

@@ -0,0 +1,175 @@
+using Autodesk.Revit.DB;
+using Autodesk.Revit.DB.Mechanical;
+using Autodesk.Revit.DB.Plumbing;
+using FWindSoft.SystemExtensions;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit.Extension
+{
+    public static class InsulationExtension
+    {  /// <summary>
+       /// 获取水管和风管保温层
+       /// </summary>
+       /// <param name="doc"></param>
+       /// <returns></returns>
+        public static List<ElementType> GetInsulationTypes(this Document doc)
+        {
+            ElementFilter pipe = new ElementCategoryFilter(BuiltInCategory.OST_PipeInsulations);
+            ElementFilter duct = new ElementCategoryFilter(BuiltInCategory.OST_DuctInsulations);
+            LogicalOrFilter filter = new LogicalOrFilter(pipe, duct);
+            List<ElementType> types = doc.GetElementTypes<ElementType>(filter);
+            return types;
+
+        }
+
+        /// <summary>
+        /// 获取水管的保温层
+        /// </summary>
+        /// <param name="doc"></param>
+        /// <returns></returns>
+        public static List<ElementType> GetPipeInsulationTypes(this Document doc)
+        {
+            List<ElementType> types = doc.GetElementTypes<ElementType>(new ElementCategoryFilter(BuiltInCategory.OST_PipeInsulations));
+            return types;
+        }
+
+        /// <summary>
+        /// 获取风管的保温层
+        /// </summary>
+        /// <param name="doc"></param>
+        /// <returns></returns>
+        public static List<ElementType> GetDuctInsulationTypes(this Document doc)
+        {
+            List<ElementType> types = doc.GetElementTypes<ElementType>(new ElementCategoryFilter(BuiltInCategory.OST_DuctInsulations));
+            return types;
+        }
+
+        /// <summary>
+        /// 获取管道和管道连接件的保温层
+        /// </summary>
+        /// <param name="doc"></param>
+        /// <returns></returns>
+        public static List<InsulationLiningBase> GetPipeInsulations(this Document doc)
+        {
+
+            List<InsulationLiningBase> elements =
+                doc.GetElements<InsulationLiningBase>().Where(
+                    el =>
+                        el.GetBuiltInCategory() == BuiltInCategory.OST_PipeInsulations ||
+                        el.GetBuiltInCategory() == BuiltInCategory.OST_PipeFittingInsulation).ToList();
+            return elements.Where(e => e.IsValidObject).ToList();
+        }
+
+        /// <summary>
+        /// 创建保温层   
+        /// </summary>
+        /// <param name="element"></param>
+        /// <param name="info"></param>
+        public static void CreateInsulation(this Element element, InsulationItem info)
+        {
+
+            if (!element.IsValidObject) return;
+            if (info == null || info.InsulationType == null) return;
+            Document doc = element.Document;
+
+            if (element.IsWaterComponment())
+            {
+                var ids = InsulationLiningBase.GetInsulationIds(doc, element.Id);
+                doc.Delete(ids);
+                PipeInsulation.Create(doc, element.Id, info.InsulationType.Id, info.Thickness);
+            }
+            else if (element.IsHavcComponment())
+            {
+                var ids = InsulationLiningBase.GetInsulationIds(doc, element.Id);
+                doc.Delete(ids);
+                DuctInsulation.Create(doc, element.Id, info.InsulationType.Id, info.Thickness);
+            }
+        }
+
+        /// <summary>
+        /// 删除保温层
+        /// </summary>
+        /// <param name="elements"></param>
+        public static void DeleteInsulations(this List<Element> elements)
+        {
+            var list = elements;
+            if (list == null || list.Count == 0) return;
+            Document doc = elements[0].Document;
+            for (int i = 0; i < list.Count; i++)
+            {
+                Element temp = list[i];
+                if (!temp.IsValidObject) continue;
+                bool isValid = temp.IsWaterComponment() || temp.IsHavcComponment();
+                if (!isValid) continue;
+                var ids = InsulationLiningBase.GetInsulationIds(doc, temp.Id);
+                doc.Delete(ids);
+            }
+        }
+
+        /// <summary>
+        /// 获取指定管道集合中的第一个保温层信息
+        /// </summary>
+        /// <param name="elements">elements尽可能只包含水系统或者风系统</param>
+        /// <returns></returns>
+        public static InsulationItem GetInsulationItem(this List<Element> elements)
+        {
+            InsulationItem info = null;
+            List<ElementType> pipeInsulation = null;
+            List<ElementType> ductInsulation = null;
+            do
+            {
+                if (elements == null || elements.Count == 0)
+                {
+                    break;
+                }
+                Document doc = elements[0].Document;
+                foreach (var element in elements)
+                {
+                    if (element == null) continue;
+                    string name = element.GetParameterString(BuiltInParameter.RBS_REFERENCE_INSULATION_TYPE);
+                    double thick = element.GetParameterDouble(BuiltInParameter.RBS_REFERENCE_INSULATION_THICKNESS);
+                    if (!string.IsNullOrWhiteSpace(name) && thick.More(0))
+                    {
+                        ElementType tempType = null;
+                        if (element.IsWaterComponment())
+                        {
+                            if (pipeInsulation == null)
+                            {
+                                pipeInsulation = doc.GetPipeInsulationTypes();
+                            }
+                            tempType = pipeInsulation.FirstOrDefault(t => t.Name.Equals(name));
+                        }
+                        else if (element.IsHavcComponment())
+                        {
+                            if (ductInsulation == null)
+                            {
+                                ductInsulation = doc.GetDuctInsulationTypes();
+                            }
+                            tempType = ductInsulation.FirstOrDefault(t => t.Name.Equals(name));
+                        }
+
+                        if (null != tempType)
+                        {
+                            info = new InsulationItem { InsulationType = tempType, Thickness = thick };
+                            break;
+                        }
+
+                    }
+                }
+            } while (false);
+            return info;
+        }
+    }
+    /// <summary>
+    /// 保温层包装类
+    /// </summary>
+    public class InsulationItem
+    {
+        public ElementType InsulationType { get; set; }
+        public double Thickness { get; set; }
+    }
+}

+ 53 - 0
FWindSoft/FWindSoft.Revit/Extension/LocationExtension.cs

@@ -0,0 +1,53 @@
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Autodesk.Revit.DB;
+
+namespace FWindSoft.Revit
+{
+   public static  class LocationExtension
+    {    
+        /// <summary>
+        /// 转换成线
+        /// </summary>
+        /// <param name="loc"></param>
+        /// <returns></returns>
+        public static Curve ConvertToCurve(this Location loc)
+        {
+            if (loc is LocationCurve lc)
+            {
+                return lc.Curve;
+            }
+            return null;
+        }
+        /// <summary>
+        /// 转换成点
+        /// </summary>
+        /// <param name="loc"></param>
+        /// <returns></returns>
+        public static XYZ ConvertToPoint(this Location loc)
+        {
+            if (loc is LocationPoint lp)
+            {
+                return lp.Point;
+            }
+            return null;
+        }
+        /// <summary>
+        /// 转换成直线线
+        /// </summary>
+        /// <param name="loc"></param>
+        /// <returns></returns>
+        public static Line ConvertToLine(this Location loc)
+        {
+            if (loc is LocationCurve lc)
+            {
+                return lc.Curve as Line;
+            }
+            return null;
+        }
+    }
+}

+ 153 - 0
FWindSoft/FWindSoft.Revit/Extension/MepCurveExtension.cs

@@ -0,0 +1,153 @@
+using Autodesk.Revit.DB;
+using Autodesk.Revit.DB.Electrical;
+using Autodesk.Revit.DB.Mechanical;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit
+{
+    public static class MepCurveExtension
+    {
+        /// <summary>
+        /// 是否是水平的
+        /// </summary>
+        /// <param name="mepCurve"></param>
+        /// <returns></returns>
+        public static bool IsHorizontal(this MEPCurve mepCurve)
+        {
+            var line = mepCurve.GetLocationCurve() as Line;
+            if (line == null)
+                return false;
+            return line.Direction.IsVertical(XYZ.BasisZ);
+        }
+        /// <summary>
+        /// 是否垂直的
+        /// </summary>
+        /// <param name="mepCurve"></param>
+        /// <returns></returns>
+        public static bool IsVertical(this MEPCurve mepCurve)
+        {
+            var line = mepCurve.GetLocationCurve() as Line;
+            if (line == null)
+                return false;
+            return line.Direction.IsParallel(XYZ.BasisZ);
+        }
+        /// <summary>
+        /// 复制指定的mepCurve
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="mepCurve"></param>
+        /// <param name="start"></param>
+        /// <param name="end"></param>
+        /// <returns></returns>
+        public static T Copy<T>(this T mepCurve, XYZ start, XYZ end) where T : MEPCurve
+        {
+            var doc = mepCurve.Document;
+            var ids = ElementTransformUtils.CopyElement(doc, mepCurve.Id, XYZ.Zero);
+            T copy = null;
+            if (ids.Count > 0)
+            {
+                copy = doc.GetElement(ids.FirstOrDefault()) as T;
+            }
+            copy.UpdateLocation(start, end);
+            return copy;
+        }
+
+        /// <summary>
+        /// 更新指定mepCurve的迹线
+        /// </summary>
+        /// 2015-09-15 xls
+        /// <param name="mepCurve"></param>
+        /// <param name="start"></param>
+        /// <param name="end"></param>
+        public static void UpdateLocation(this MEPCurve mepCurve, XYZ start, XYZ end)
+        {
+            if (start.IsEqual(end))
+                return;
+            var locationCurve = mepCurve.Location as LocationCurve;
+            Line newLine =start.NewLine(end);
+            locationCurve.Curve = newLine;
+            //mepCurve.Rotate(newLine, Math.PI * 2);
+        }
+
+        /// <summary>
+        /// 刷新mepCurve,mepCurve绕迹线旋转360度
+        /// </summary>
+        /// <param name="mepCurve"></param>
+        public static void Refresh(this MEPCurve mepCurve)
+        {
+            var locationCurve = mepCurve.Location as LocationCurve;
+            mepCurve.Rotate(mepCurve.GetLocationLine(), Math.PI * 2);
+        }
+        /// <summary>
+        /// 替换mepCurve指定点位新的坐标
+        /// </summary>
+        /// <param name="mepCurve">要修改的MepCurve</param>
+        /// <param name="oldPoint">将要被替换的点的位置</param>
+        /// <param name="newPoint">新的点的位置</param>
+        public static void ReplaceLocation(this MEPCurve mepCurve, XYZ oldPoint, XYZ newPoint)
+        {
+            //按最接近的点,找到需要替换的点的位置
+            var oldLine = mepCurve.GetLocationLine();
+            oldPoint = oldLine.GetNearnessPoint(oldPoint);
+            if (oldPoint.IsEqual(newPoint))
+                return;
+            Line newLine = null;
+            if (oldLine.StartPoint().IsEqual(oldPoint))
+            {
+                newLine = newPoint.NewLine(oldLine.EndPoint());
+            }
+            else
+            {
+                newLine = oldLine.StartPoint().NewLine(newPoint);
+            }
+            if (newLine != null)
+            {
+                var locationCurve = mepCurve.Location as LocationCurve;
+                locationCurve.Curve = newLine;
+                //mepCurve.Rotate(newLine, Math.PI * 2);
+            }
+        }
+        /// <summary>
+        /// 获取距离给定点最近的点connector
+        /// </summary>
+        /// <param name="element"></param>
+        /// <param name="point"></param>
+        /// <returns></returns>
+        public static Connector GetNearnessConnector(this MEPCurve element, XYZ point)
+        {
+            var line = element.GetLocationCurve() as Line;
+            return element.GetConnectorByOrigin(line.GetNearnessPoint(point));
+        }
+        /// <summary>
+        /// 获取距离给定点最远的点connector
+        /// </summary>
+        /// <param name="element"></param>
+        /// <param name="point"></param>
+        /// <returns></returns>
+        public static Connector GetFarnessConnector(this MEPCurve element, XYZ point)
+        {
+            var line = element.GetLocationCurve() as Line;
+            return element.GetConnectorByOrigin(line.GetFarnessPoint(point));
+        }
+        /// <summary>
+        /// 设置mepCurve的朝向(有效构件为方向风管或者桥架)
+        /// </summary>
+        /// <param name="mepCurve"></param>
+        /// <param name="normal"></param>
+        public static void SetCurveNormal(this MEPCurve mepCurve, XYZ normal)
+        {
+            if (mepCurve is CableTray cableTray)
+            {
+                cableTray.CurveNormal = normal;
+            }
+            else if (mepCurve is Duct duct)
+            {
+                duct.SetCurveNormal(normal);
+            }
+        }
+    }
+}

+ 150 - 0
FWindSoft/FWindSoft.Revit/Extension/MepCurveTypeExtension.cs

@@ -0,0 +1,150 @@
+using Autodesk.Revit.DB;
+using Autodesk.Revit.DB.Electrical;
+using Autodesk.Revit.DB.Mechanical;
+using Autodesk.Revit.DB.Plumbing;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit
+{
+    public static class MepCurveTypeExtension
+    {
+        #region 水管风管类型布线规则维护
+        /// <summary>
+        /// 增加MepCurve优先规则
+        /// </summary>
+        /// <param name="pipeDuctType">MepCurve类型</param>
+        /// <param name="groupType">规则分组</param>
+        /// <param name="elementId">规则使用的element</param>
+        /// <param name="index">规则在分组中的位置</param>
+        /// <returns>-1操作类型不符</returns>
+        public static int AddRoutingRule(this MEPCurveType pipeDuctType, RoutingPreferenceRuleGroupType groupType,
+            ElementId elementId, int index = 0)
+        {
+            if (pipeDuctType is PipeType || pipeDuctType is DuctType)
+            {
+                RoutingPreferenceManager manager = pipeDuctType.RoutingPreferenceManager;
+                if (null != manager)
+                {
+                    RoutingPreferenceRule rule = new RoutingPreferenceRule(elementId, "");
+                    rule.AddCriterion(PrimarySizeCriterion.All());
+                    manager.AddRule(groupType, rule, 0);
+                }
+                return index;
+            }
+            else
+            {
+                return -1;
+            }
+        }
+
+        /// <summary>
+        /// 移除MepCurve规则分组中制定位置的规则
+        /// </summary>
+        /// <param name="pipeDuctType">MepCurve类型</param>
+        /// <param name="groupType">规则分组</param>
+        /// <param name="index">规则在该分组中的位置</param>
+        /// <returns>-1操作类型不符</returns>
+        public static int RemoveRoutingRule(this MEPCurveType pipeDuctType, RoutingPreferenceRuleGroupType groupType,
+            int index = 0)
+        {
+            if (pipeDuctType is PipeType || pipeDuctType is DuctType)
+            {
+                RoutingPreferenceManager manager = pipeDuctType.RoutingPreferenceManager;
+                if (null != manager)
+                {
+                    manager.RemoveRule(groupType, index);
+                }
+            }
+            else
+            {
+                index = -1;
+            }
+            return index;
+        }
+
+        /// <summary>
+        /// 获取MepCurve优先规则分组中指定位置的规则
+        /// </summary>
+        /// <param name="pipeDuctType"></param>
+        /// <param name="groupType"></param>
+        /// <param name="index"></param>
+        /// <returns></returns>
+        public static RoutingPreferenceRule GetRoutingRule(this MEPCurveType pipeDuctType,
+            RoutingPreferenceRuleGroupType groupType, int index = 0)
+        {
+            RoutingPreferenceManager manager = pipeDuctType.RoutingPreferenceManager;
+            RoutingPreferenceRule rule = null;
+            if (pipeDuctType is PipeType || pipeDuctType is DuctType)
+            {
+                if (null != manager)
+                {
+                    rule = manager.GetRule(groupType, index);
+                }
+            }
+            return rule;
+        }
+
+        #endregion
+
+        #region 线管桥架连接件类型维护
+        /// <summary>
+        /// 修改桥架线管指定连接件的参数
+        /// </summary>
+        /// <param name="cableTrayConduitType">桥架线管</param>
+        /// <param name="parameter">连接件类型参数</param>
+        /// <param name="elementId">规则使用的element</param>
+        /// <returns></returns>
+        public static void AddFitting(this MEPCurveType cableTrayConduitType, BuiltInParameter parameter,ElementId elementId)
+        {
+            if(cableTrayConduitType is ConduitType|| cableTrayConduitType is CableTrayType)
+            {
+                if (null != cableTrayConduitType)
+                {
+                    cableTrayConduitType.SetParameter(parameter, elementId);
+                }
+
+            }
+        }
+
+        /// <summary>
+        /// 移除桥架线管指定连接件的参数
+        /// </summary>
+        /// <param name="cableTrayConduitType">桥架线管</param>
+        /// <param name="parameter">连接件类型参数</param>
+        /// <returns></returns>
+        public static void RemoveFitting(this MEPCurveType cableTrayConduitType, BuiltInParameter parameter)
+        {
+            if (cableTrayConduitType is ConduitType || cableTrayConduitType is CableTrayType)
+            {
+                if (null != cableTrayConduitType)
+                {
+                    cableTrayConduitType.SetParameter(parameter, ElementId.InvalidElementId);
+                }
+            }          
+        }
+        /// <summary>
+        /// 获取桥架线管指定连接件的参数
+        /// </summary>
+        /// <param name="cableTrayConduitType"></param>
+        /// <param name="parameter"></param>
+        /// <returns></returns>
+        public static ElementId GetFitting(this MEPCurveType cableTrayConduitType, BuiltInParameter parameter)
+        {
+            ElementId elmentId = null;
+            if (cableTrayConduitType is ConduitType || cableTrayConduitType is CableTrayType)
+            {
+                if (null != cableTrayConduitType)
+                {
+                    elmentId = cableTrayConduitType.GetParameterElementId(parameter);
+                }
+            }
+
+            return elmentId;
+        }
+        #endregion
+    }
+}

+ 127 - 0
FWindSoft/FWindSoft.Revit/Extension/MepSystemTypeExtension.cs

@@ -0,0 +1,127 @@
+using Autodesk.Revit.DB;
+using Autodesk.Revit.DB.Mechanical;
+using Autodesk.Revit.DB.Plumbing;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit
+{
+    public static class MepSystemTypeExtension
+    {
+        public static readonly ReadOnlyCollection<string> DuctClassifications =new ReadOnlyCollection<string>( new List<string> { "SupplyAir", "ReturnAir", "ExhaustAir" });
+        public static readonly ReadOnlyCollection<string> PipeClassifications = new ReadOnlyCollection<string>(new List<string> { "Sanitary",
+                "Vent",
+                "DomesticHotWater",
+                "DomesticColdWater",
+                "OtherPipe",
+                "FireProtectWet",
+                "FireProtectDry",
+                "FireProtectPreaction",
+                "FireProtectOther",
+                "SupplyHydronic",
+                "ReturnHydronic"});
+        /// <summary>
+        /// 根据系统分类创建系统类型
+        /// </summary>
+        /// <param name="doc">创建系统的指定项目</param>
+        /// <param name="classification">系统分类</param>
+        /// <param name="name">系统名称</param>
+        /// <returns></returns>
+        public static MEPSystemType MEPSystemTypeCreate(this Document doc, MEPSystemClassification classification,string name)
+        {
+           
+            if (DuctClassifications.Contains(classification.ToString()))
+                return MechanicalSystemType.Create(doc, classification, name);
+            if (PipeClassifications.Contains(classification.ToString()))
+                return PipingSystemType.Create(doc, classification, name);
+            return null;
+        }
+        /// <summary>
+        /// 或取全部管道系统(可指定相应的系统分类)
+        /// </summary>
+        /// <param name="doc"></param>
+        /// <param name="classification"></param>
+        /// <returns></returns>
+        public static List<PipingSystemType> GetPipingSystemTypes(this Document doc,
+            MEPSystemClassification classification = MEPSystemClassification.UndefinedSystemClassification)
+        {
+            ElementCategoryFilter pipeSystemFilter = new ElementCategoryFilter(BuiltInCategory.OST_PipingSystem);
+            List<PipingSystemType> list = doc.GetElements<PipingSystemType>();
+            if (classification != MEPSystemClassification.UndefinedSystemClassification)
+            {
+
+                list = list.Where(s => s.SystemClassification == classification).ToList();
+            }
+
+            return list;
+
+        }
+        /// <summary>
+        /// 或取项目已经使用的管道系统(可指定相应的系统分类)
+        /// </summary>
+        /// <param name="doc"></param>
+        /// <param name="classification"></param>
+        /// <returns></returns>
+        public static List<PipingSystemType> GetUsedPipingSystemTypes(this Document doc,
+            MEPSystemClassification classification = MEPSystemClassification.UndefinedSystemClassification)
+        {
+            ElementCategoryFilter pipeSystemFilter = new ElementCategoryFilter(BuiltInCategory.OST_PipingSystem);
+            var listIds = doc.GetElements<PipingSystem>().Select(p => p.GetTypeId()).Distinct();
+            List<Element> list = listIds.Select(id => doc.GetElement(id)).ToList();
+            List<PipingSystemType> tempSystemType = list.OfType<PipingSystemType>().ToList();
+            if (classification != MEPSystemClassification.UndefinedSystemClassification)
+            {
+
+                tempSystemType = tempSystemType.Where(s => s.SystemClassification == classification).ToList();
+            }
+            return tempSystemType;
+
+        }
+
+        /// <summary>
+        /// 或取全部风管系统类型(可指定相应的系统分类)
+        /// </summary>
+        /// <param name="doc"></param>
+        /// <param name="classification"></param>
+        /// <returns></returns>
+        public static List<MechanicalSystemType> GetMechanicalSystemTypes(this Document doc,
+            MEPSystemClassification classification = MEPSystemClassification.UndefinedSystemClassification)
+        {
+
+            ElementCategoryFilter ductSystemFilter = new ElementCategoryFilter(BuiltInCategory.OST_DuctSystem);
+            List<MechanicalSystemType> list = doc.GetElements(ductSystemFilter).OfType<MechanicalSystemType>().ToList();
+            if (classification != MEPSystemClassification.UndefinedSystemClassification)
+            {
+                list = list.Where(s => s.SystemClassification == classification).ToList();
+            }
+            return list;
+        }
+
+        /// <summary>
+        /// 或取项目已经使用的风管系统系统(可指定相应的系统分类)
+        /// </summary>
+        /// <param name="doc"></param>
+        /// <param name="classification"></param>
+        /// <returns></returns>
+        public static List<MechanicalSystemType> GetUsedMechanicalSystemTypes(this Document doc,
+            MEPSystemClassification classification = MEPSystemClassification.UndefinedSystemClassification)
+        {
+            ElementCategoryFilter ductSystemFilter = new ElementCategoryFilter(BuiltInCategory.OST_DuctSystem);
+            var listIds = doc.GetElements(ductSystemFilter).OfType<MechanicalSystemType>()
+                    .Select(p => p.GetTypeId())
+                    .Distinct();
+            List<Element> list = listIds.Select(id => doc.GetElement(id)).ToList();
+            List<MechanicalSystemType> tempSystemType = list.OfType<MechanicalSystemType>().ToList();
+            if (classification != MEPSystemClassification.UndefinedSystemClassification)
+            {
+                tempSystemType = tempSystemType.Where(s => s.SystemClassification == classification).ToList();
+            }
+            return tempSystemType;
+
+        }
+    }
+}

+ 12 - 0
FWindSoft/FWindSoft.Revit/Extension/ModelCurveExtension.cs

@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit
+{
+    class ModelCurveExtension
+    {
+    }
+}

+ 386 - 0
FWindSoft/FWindSoft.Revit/Extension/PipeExtension.cs

@@ -0,0 +1,386 @@
+using Autodesk.Revit.DB;
+using Autodesk.Revit.DB.Mechanical;
+using Autodesk.Revit.DB.Plumbing;
+using FWindSoft.SystemExtensions;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit
+{
+    public static class PipeExtension
+    {
+        /// <summary>
+        /// 获取较较大直径的管道
+        /// </summary>
+        /// <param name="first"></param>
+        /// <param name="second"></param>
+        /// <returns></returns>
+        public static Pipe GetLargerDiameter(this Pipe first, Pipe second)
+        {
+            return first.Diameter.MoreEqual(second.Diameter)
+                ? first
+                : second;
+        }
+
+        /// <summary>
+        /// 获取较较小直径的管道
+        /// </summary>
+        /// <param name="first"></param>
+        /// <param name="second"></param>
+        /// <returns></returns>
+        public static Pipe GetSmallerDiameter(this Pipe first, Pipe second)
+        {
+            return first.Diameter.LessEqual(second.Diameter)
+                ? first
+                : second;
+        }
+
+        /// <summary>
+        /// 获取管道系统分类
+        /// </summary>
+        /// <param name="pipe"></param>
+        /// <returns></returns>
+        public static PipeSystemType GetPipeSystemType(this Pipe pipe)
+        {
+            var pipingSystem = pipe.MEPSystem as PipingSystem;
+            if (pipingSystem != null)
+                return pipingSystem.SystemType;
+            return PipeSystemType.UndefinedSystemType;
+        }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="pipe"></param>
+        /// <returns></returns>Horizontal
+        public static PipingSystemType GetPipingSystemType(this Pipe pipe)
+        {
+            var elementId = pipe.GetParameterElementId(BuiltInParameter.RBS_PIPING_SYSTEM_TYPE_PARAM);
+            return pipe.Document.GetElement(elementId) as PipingSystemType;
+
+        }
+
+      
+
+        public static List<XYZ> GetPoints(this Pipe pipe)
+        {
+            return new List<XYZ> { pipe.GetLocationLine().StartPoint(), pipe.GetLocationLine().EndPoint() };
+        }
+
+     
+
+        /// <summary>
+        /// 获取指定管道的管道系统
+        /// </summary>
+        /// <param name="pipe"></param>
+        /// <returns></returns>
+        public static PipingSystemType GePipingSystemType(this Pipe pipe)
+        {
+            return pipe.Document.GetElement(pipe.MEPSystem.GetTypeId()) as PipingSystemType;
+        }
+
+        /// <summary>
+        /// 获取横向管道系统,处于同一直线的一系列管道
+        /// </summary>
+        /// <param name="pipe">指定管道</param>
+        /// <returns></returns>
+        public static List<Pipe> GetSystemPipe(this Pipe pipe)
+        {
+            List<Pipe> pipes = new List<Pipe>();
+            do
+            {
+                //if (pipe == null)
+                //{
+                //    break;
+                //}
+                //Line baseLine = pipe.GetLocationLine();
+                //pipes.Add(pipe);
+                //for (int i = 0; i < pipes.Count; i++)
+                //{
+                //    Pipe tempPipe = pipes[i];
+                //    List<Element> verPipes = tempPipe.GetFirstSameTypeElements();
+                //    foreach (var element in verPipes)
+                //    {
+                //        Pipe tempVerPipe = element as Pipe;
+                //        if (tempVerPipe != null && tempVerPipe.GetCurveExt().IsParallel(baseLine, 0.001) &&
+                //            pipes.All(e => e.Id.IntegerValue != tempVerPipe.Id.IntegerValue))
+                //        {
+                //            pipes.Add(tempVerPipe);
+                //        }
+                //    }
+                //}
+            } while (false);
+            return pipes;
+        }
+
+        /// <summary>
+        /// 判断管道系统是否为坡度管
+        /// </summary>
+        /// <param name="pipes"></param>
+        /// <returns></returns>
+        public static bool IsSlopPipe(this List<Pipe> pipes)
+        {
+            if (pipes == null || pipes.Count == 0)
+                return false;
+
+            double baseZ = pipes[0].GetPoints()[0].Z;
+            foreach (var pipe in pipes)
+            {
+                List<XYZ> ends = pipe.GetPoints();
+                if (ends.Any(xyz => !xyz.Z.IsEqual(baseZ)))
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        /// <summary>
+        /// 设置管道直径
+        /// </summary>
+        /// <param name="pipe"></param>
+        /// <param name="dia">直径</param>
+        public static void SetDiameter(this Pipe pipe, double dia)
+        {
+            pipe.SetParameter(BuiltInParameter.RBS_PIPE_DIAMETER_PARAM, dia); //直径
+        }
+       
+        /// <summary>
+        /// 获取管道的管材
+        /// </summary>
+        /// <param name="pipe"></param>
+        public static string GetMaterial(this Pipe pipe)
+        {
+            string material = pipe.GetParameterString(BuiltInParameter.RBS_PIPE_MATERIAL_PARAM);
+            return material;
+        }
+        /// <summary>
+        /// 是否是相同的系统
+        /// </summary>
+        /// <param name="pipe"></param>
+        /// <param name="element"></param>
+        /// <returns></returns>
+        public static bool IsSameSystem(this Pipe pipe, Element element)
+        {
+            var elementId = pipe.GetParameterElementId(BuiltInParameter.RBS_PIPING_SYSTEM_TYPE_PARAM);
+            if (elementId == null)
+                return false;
+            var refElementId = element.GetParameterElementId(BuiltInParameter.RBS_PIPING_SYSTEM_TYPE_PARAM);
+            if (refElementId == null)
+                return false;
+            if (elementId.IntegerValue == -1 || refElementId.IntegerValue == -1)
+                return false;
+            return elementId == refElementId;
+        }
+        /// <summary>
+        /// 获取坡度设置
+        /// </summary>
+        /// <param name="doc"></param>
+        /// <returns></returns>
+        public static List<double> GetSlopes(this Document doc)
+        {
+            List<double> slopes = new List<double>();
+            PipeSettings setting = PipeSettings.GetPipeSettings(doc);
+            if (setting != null)
+            {
+                slopes = setting.GetPipeSlopes().ToList();
+            }
+            return slopes;
+        }
+        /// <summary>
+        /// 获取项目中所有管道类型
+        /// </summary>
+        /// <param name="doc"></param>
+        /// <returns></returns>
+        public static List<PipeType> GetPipeTypes(this Document doc)
+        {
+            List<PipeType> list = doc.GetElements<PipeType>();
+            return list;
+        }
+
+        /// <summary>
+        /// 获取管道类型的 管段 信息
+        /// </summary>
+
+        /// <param name="pipeType">管道类型</param>
+        /// <param name="doc">所在项目</param>
+        /// <returns></returns>
+        public static PipeSegment GetPipeSegment(this PipeType pipeType, Document doc)
+        {
+            PipeSegment pipeSegment = null;
+            RoutingPreferenceRule rule =
+                pipeType.RoutingPreferenceManager.GetRule(RoutingPreferenceRuleGroupType.Segments, 0);
+            if (rule == null)
+                return pipeSegment;
+            pipeSegment = doc.GetElement(rule.MEPPartId) as PipeSegment;
+            return pipeSegment;
+        }
+
+        /// <summary>
+        /// 增加管道的管段信息
+        /// </summary>
+        /// <param name="pipeType">管道类型</param>
+        /// <param name="segmentId">管段Id</param>
+        /// <returns></returns>
+        public static int AddPipeSegment(this PipeType pipeType, ElementId segmentId)
+        {
+            return pipeType.AddRoutingRule(RoutingPreferenceRuleGroupType.Segments, segmentId, 0);
+        }
+
+        /// <summary>
+        /// 移除管段类型
+        /// </summary>
+        /// <param name="pipeType"></param>
+        /// <param name="index"></param>
+        /// <returns></returns>
+        public static int RemovePipeSegment(this PipeType pipeType, int index)
+        {
+            return pipeType.RemoveRoutingRule(RoutingPreferenceRuleGroupType.Segments, index);
+        }
+
+        /// <summary>
+        /// 获取管道类型的可用直径信息
+        /// </summary>
+        /// <param name="pipeType">管道类型</param>
+        /// <param name="doc">所在项目</param>
+        /// <returns></returns>
+        public static List<double> GetAvailableDias(this PipeType pipeType, Document doc)
+        {
+            PipeSegment pipeSegment = pipeType.GetPipeSegment(doc);
+            List<double> dias = new List<double>();
+            if (pipeSegment != null)
+            {
+                dias = pipeSegment.GetSizes().Select(mepSize => mepSize.NominalDiameter.MmFromFt()).ToList();
+            }
+            return dias;
+        }
+
+        #region 管道类型规则操作基础
+
+        /// <summary>
+        /// 增加管道优先规则
+        /// </summary>
+        /// <param name="pipeType">管道类型</param>
+        /// <param name="groupType">规则分组</param>
+        /// <param name="elementId">规则使用的element</param>
+        /// <param name="index">规则在分组中的位置</param>
+        /// <returns></returns>
+        public static int AddRoutingRule(this PipeType pipeType, RoutingPreferenceRuleGroupType groupType,
+            ElementId elementId, int index = 0)
+        {
+            RoutingPreferenceManager manager = pipeType.RoutingPreferenceManager;
+            RoutingPreferenceRule rule = new RoutingPreferenceRule(elementId, "");
+            rule.AddCriterion(PrimarySizeCriterion.All());
+            manager.AddRule(groupType, rule, 0);
+            return index;
+        }
+
+        /// <summary>
+        /// 移除管道规则分组中制定位置的规则
+        /// </summary>
+        /// <param name="pipeType">管道类型</param>
+        /// <param name="groupType">规则分组</param>
+        /// <param name="index">规则在该分组中的位置</param>
+        /// <returns></returns>
+        public static int RemoveRoutingRule(this PipeType pipeType, RoutingPreferenceRuleGroupType groupType,
+            int index = 0)
+        {
+            RoutingPreferenceManager manager = pipeType.RoutingPreferenceManager;
+            manager.RemoveRule(groupType, index);
+            return index;
+        }
+
+        /// <summary>
+        /// 获取管道优先规则分组中指定位置的规则
+        /// </summary>
+        /// <param name="pipeType"></param>
+        /// <param name="groupType"></param>
+        /// <param name="index"></param>
+        /// <returns></returns>
+        public static RoutingPreferenceRule GetRoutingRule(this PipeType pipeType,
+            RoutingPreferenceRuleGroupType groupType, int index = 0)
+        {
+            RoutingPreferenceRule rule = pipeType.RoutingPreferenceManager.GetRule(groupType, index);
+            return rule;
+        }
+
+        public static ElementId GetRoutingRule(this PipeType pipeType, RoutingPreferenceRuleGroupType groupType,
+            double nd)
+        {
+            RoutingConditions conditions = new RoutingConditions(RoutingPreferenceErrorLevel.None);
+            conditions.AppendCondition(new RoutingCondition(nd));
+            ElementId id = pipeType.RoutingPreferenceManager.GetMEPPartId(groupType,
+                conditions);
+            return id;
+        }
+
+        #endregion
+
+        #region 动态修改连接件辅助使用方法
+
+        /// <summary>
+        /// 在三通规则分组第一个位置添加制定类型三通
+        /// </summary>
+        /// <param name="pipeType"></param>
+        /// <param name="id"></param>
+        /// <returns></returns>
+        public static int AddFirstTee(this PipeType pipeType, ElementId id)
+        {
+            return pipeType.AddRoutingRule(RoutingPreferenceRuleGroupType.Junctions, id, 0);
+        }
+
+        /// <summary>
+        /// 移除三通规则分组第一个位置的三通
+        /// </summary>
+        /// <param name="pipeType"></param>
+        public static void RemoveFirstTee(this PipeType pipeType)
+        {
+            pipeType.RemoveRoutingRule(RoutingPreferenceRuleGroupType.Junctions);
+        }
+
+        /// <summary>
+        /// 获取第一个三通
+        /// </summary>
+        /// <param name="pipeType"></param>
+        /// <returns></returns>
+        public static FamilySymbol GetFirstTee(this PipeType pipeType)
+        {
+            Document doc = pipeType.Document;
+            FamilySymbol fitting = null;
+            RoutingPreferenceRule rule = pipeType.GetRoutingRule(RoutingPreferenceRuleGroupType.Junctions);
+            if (rule == null)
+                return fitting;
+            fitting = doc.GetElement(rule.MEPPartId) as FamilySymbol;
+            return fitting;
+        }
+
+        /// <summary>
+        /// 通过直径获取指定规则的三通,如果指定直径不存在对应三通,则默认去第一个设定的三通
+        /// </summary>
+        /// <param name="pipeType">管道类型</param>
+        /// <param name="nd">直径</param>
+        /// <returns></returns>
+        public static FamilySymbol GetFirstTeeByNd(this PipeType pipeType, double nd)
+        {
+            Document doc = pipeType.Document;
+            FamilySymbol fitting = null;
+            ElementId elementId = pipeType.GetRoutingRule(RoutingPreferenceRuleGroupType.Junctions, nd);
+            if (elementId == null)
+            {
+                RoutingPreferenceRule rule = pipeType.GetRoutingRule(RoutingPreferenceRuleGroupType.Junctions);
+                if (rule == null)
+                    return fitting;
+                elementId = rule.MEPPartId;
+            }
+            fitting = doc.GetElement(elementId) as FamilySymbol;
+            return fitting;
+        }
+
+        #endregion
+
+        
+    }
+}

+ 203 - 0
FWindSoft/FWindSoft.Revit/Extension/SelectionExtension.cs

@@ -0,0 +1,203 @@
+/*-------------------------------------------------------------------------
+ * 功能描述:SelectionExtension
+ * 作者:xulisong
+ * 创建时间: 2019/5/23 11:31:45
+ * 版本号:v1.0
+ *  -------------------------------------------------------------------------*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Autodesk.Revit.DB;
+using Autodesk.Revit.UI.Selection;
+
+namespace FWindSoft.Revit
+{
+    /// <summary>
+    /// 选择项相关扩展
+    /// </summary>
+    public static class SelectionExtension
+    {
+        static SelectionExtension()
+        {
+            AllSnapTypes = GetAllSnapTypes();
+        }
+        /// <summary>
+        /// 全部可选信息
+        /// </summary>
+        public static ObjectSnapTypes AllSnapTypes { get; private set; }
+        #region 私有方法
+        /// <summary>
+        /// 获取全局选择配置
+        /// </summary>
+        /// <returns></returns>
+        private static ObjectSnapTypes GetAllSnapTypes()
+        {
+            ObjectSnapTypes snapSettings =
+                ObjectSnapTypes.Centers | ObjectSnapTypes.Endpoints |
+                ObjectSnapTypes.Intersections | ObjectSnapTypes.Midpoints |
+                ObjectSnapTypes.Nearest | ObjectSnapTypes.WorkPlaneGrid |
+                ObjectSnapTypes.Perpendicular | ObjectSnapTypes.Points |
+                ObjectSnapTypes.Quadrants | ObjectSnapTypes.Tangents;
+            return snapSettings;
+        }
+        #endregion
+        #region 选取点信息
+        /// <summary>
+        /// 选择点信息
+        /// </summary>
+        /// <param name="selection"></param>
+        /// <param name="snapSettings">选择项</param>
+        /// <param name="strMessage">提示消息</param>
+        /// <returns></returns>
+        public static XYZ PickPointT(this Selection selection, ObjectSnapTypes snapSettings, string strMessage)
+        {
+            try
+            {
+                return selection.PickPoint(snapSettings, strMessage);
+            }
+            catch (OperationCanceledException)
+            {
+                return null;
+            }
+        }
+        /// <summary>
+        /// 选取点
+        /// </summary>
+        /// <param name="selection"></param>
+        /// <param name="strMessage"></param>
+        /// <returns></returns>
+        public static XYZ PickPointT(this Selection selection, string strMessage)
+        {
+            return PickPointT(selection, AllSnapTypes, strMessage);
+        }
+        #endregion
+
+        #region 选取reference
+        /// <summary>
+        /// 选取指定的reference
+        /// </summary>
+        /// <param name="selection"></param>
+        /// <param name="strMessage"></param>
+        /// <param name="filter"></param>
+        /// <param name="objType"></param>
+        /// <returns></returns>
+        public static Reference PickReferenceT(this Selection selection, string strMessage,
+            ISelectionFilter filter, ObjectType objType)
+        {
+            strMessage = strMessage ?? string.Empty;
+            Reference reference = null;
+            try
+            {
+                if (filter == null)
+                {
+                    reference = selection.PickObject(objType, strMessage);
+                }
+                else
+                {
+                    reference = selection.PickObject(objType, filter, strMessage);
+                }
+            }
+            #region 异常处理
+            catch (OperationCanceledException)
+            {
+                return null;
+            }
+            catch (InvalidOperationException)
+            {
+                return null;
+            } 
+            #endregion
+            return reference;
+        }
+
+        public static IList<Reference> PickReferencesT(this Selection selection, string strMessage,
+            ISelectionFilter filter, ObjectType objType)
+        {
+            strMessage = strMessage ?? string.Empty;
+            IList<Reference> references = null;
+            try
+            {
+                if (filter == null)
+                {
+                    references = selection.PickObjects(objType, strMessage);
+                }
+                else
+                {
+                    references = selection.PickObjects(objType, filter, strMessage);
+                }
+            }
+            #region 异常处理
+            catch (OperationCanceledException)
+            {
+                return null;
+            } 
+            #endregion
+            return references;
+        }
+        /// <summary>
+        /// 获取选中元素elementId
+        /// </summary>
+        /// <param name="selection"></param>
+        /// <param name="strMessage"></param>
+        /// <param name="filter"></param>
+        /// <returns></returns>
+        public static ElementId PickElementId(this Selection selection, string strMessage, ISelectionFilter filter)
+        {
+            ElementId selectedElementId = null;
+            strMessage = strMessage ?? string.Empty;
+            try
+            {
+                Reference reference = null;
+                reference = selection.PickReferenceT(strMessage, filter, ObjectType.Element);
+                if (reference != null)
+                {
+                    selectedElementId = reference.ElementId;
+                }
+            }
+            catch (OperationCanceledException)
+            {
+                return null;
+            }
+            return selectedElementId;
+        }
+        #endregion
+
+        #region 框选
+        /// <summary>
+        /// 框选相关元素信息
+        /// </summary>
+        /// <param name="selection"></param>
+        /// <param name="strMessage"></param>
+        /// <param name="filter">过滤器</param>
+        /// <returns></returns>
+        public static List<Element> PickElementsByRectangleT(this Selection selection, string strMessage, ISelectionFilter filter)
+        {
+            strMessage = strMessage ?? string.Empty;
+            try
+            {
+                var listSelected = filter != null
+                    ? selection.PickElementsByRectangle(filter, strMessage).ToList()
+                    : selection.PickElementsByRectangle(strMessage).ToList();
+                if (listSelected.Count == 0)
+                {
+                    return PickElementsByRectangleT(selection,strMessage, filter);
+                }
+                return listSelected;
+            }
+            #region 异常处理
+            catch (OperationCanceledException)
+            {
+                return null;
+            }
+            catch (InvalidOperationException)
+            {
+                return null;
+            } 
+            #endregion
+        }
+        #endregion
+    }
+}

+ 134 - 0
FWindSoft/FWindSoft.Revit/Extension/TextNodeExtension.cs

@@ -0,0 +1,134 @@
+using Autodesk.Revit.DB;
+using FWindSoft.Revit.Common;
+using FWindSoft.SystemExtensions;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit
+{
+    public static class TextNodeExtension
+    {
+        /*
+         * 操作TextNode时,要注意考虑缩放系数
+         */
+        /// <summary>
+        /// 视图中的文字
+        /// </summary>
+        /// <param name="view"></param>
+        /// <returns></returns>
+        public static List<TextNote> GetTextNotes(this View view)
+        {
+            return null;// view.GetViewElements(ElementFilters.TextNote).ToListExt<TextNote>();
+        }
+
+        /// <summary>
+        /// 项目中的文字 
+        /// </summary>
+        /// <param name="doc"></param>
+        /// <returns></returns>
+        public static List<TextNote> GetTextNotes(this Document doc)
+        {
+            return doc.GetElements<TextNote>();
+        }
+        /// <summary>
+        /// 获取项目中NoteType全集
+        /// </summary>
+        /// <param name="doc"></param>
+        /// <returns></returns>
+        public static List<TextNoteType> GetTextNoteTypes(this Document doc)
+        {
+            return doc.GetElements<TextNoteType>();
+        }
+        /// <summary>
+        /// 获取系统默认使用NodtType
+        /// </summary>
+        /// <param name="doc"></param>
+        /// <returns></returns>
+        public static TextNoteType GetDefaultNodeType(this Document doc)
+        {
+            return doc.GetTextNodeType("仿宋", 3, 0.7);
+        }
+        /// <summary>
+        /// 获取TextNodeType
+        /// </summary>
+        /// <param name="doc"></param>
+        /// <param name="font"></param>
+        /// <param name="fontHeight"></param>
+        /// <param name="widthRatio"></param>
+        /// <returns></returns>
+        public static TextNoteType GetTextNodeType(this Document doc, string font, double fontHeight,
+            double widthRatio)
+        {
+            List<TextNoteType> types = doc.GetTextNoteTypes();
+            TextNoteType useType = null;
+            var typeName = string.Format("{0} {1}*{2}", font, fontHeight, widthRatio );
+            if (types.Count > 0)
+            {
+                typeName = RevitTools.RemoveForbiddenChars(typeName);
+                useType = types.FirstOrDefault(t => t.Name == typeName);
+                if (useType == null)
+                {
+                    useType = types[0].DuplicateT<TextNoteType>(typeName);
+                    useType.SetParameter(BuiltInParameter.TEXT_WIDTH_SCALE, widthRatio);
+                    useType.SetParameter(BuiltInParameter.TEXT_SIZE, fontHeight.MmToFt());
+                    useType.SetParameter(BuiltInParameter.TEXT_FONT, font);
+                    useType.SetParameter(BuiltInParameter.TEXT_BACKGROUND, 1);
+                    useType.SetParameter(BuiltInParameter.LEADER_OFFSET_SHEET, 0.0);
+                }
+            }
+            return useType;
+        }
+  
+     /// <summary>
+     /// 试图创建新的TextNode
+     /// </summary>
+     /// <param name="view"></param>
+     /// <param name="typeId"></param>
+     /// <param name="position"></param>
+     /// <param name="text"></param>
+     /// <param name="angle"></param>
+     /// <returns></returns>
+        public static TextNote NewTextNote(this View view, ElementId typeId, XYZ position, string text, 
+            double angle = 0)
+        {
+            TextNoteOptions options = new TextNoteOptions
+            {
+                TypeId = typeId,
+                Rotation = angle
+            };
+            return TextNote.Create(view.Document, view.Id, position, text, options);
+        }
+        /// <summary>
+        /// 试图创建新的TextNode
+        /// </summary>
+        /// <param name="view"></param>
+        /// <param name="typeId"></param>
+        /// <param name="position"></param>
+        /// <param name="text"></param>
+        /// <param name="angle"></param>
+        /// <returns></returns>
+        public static TextNote NewTextNote(this View view, ElementId typeId, XYZ position, string text, double width,
+            TextAlignFlags textAlign,double angle = 0)
+        {
+            TextNoteOptions options = new TextNoteOptions
+            {
+                TypeId = typeId,
+                Rotation = angle
+            };
+            TextNote note;
+            if (width.IsZero())
+            {
+                note = TextNote.Create(view.Document, view.Id, position, text, options);
+            }
+            else
+            {
+                note = TextNote.Create(view.Document, view.Id, position, width, text, options);
+            }
+            note?.SetParameter(BuiltInParameter.TEXT_ALIGN_HORZ, (int)textAlign);
+            return note;
+        }
+    }
+}

+ 38 - 0
FWindSoft/FWindSoft.Revit/Extension/TransactionExtension.cs

@@ -0,0 +1,38 @@
+using Autodesk.Revit.DB;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit
+{
+    /// <summary>
+    /// 事务扩展相关
+    /// </summary>
+    public static class TransactionExtension
+    {
+        /// <summary>
+        /// 开始事务并设定预处理
+        /// </summary>
+        /// <param name="tran"></param>
+        /// <param name="preprocessor"></param>
+        /// <returns></returns>
+        public static TransactionStatus StartWidthPreprocessor(this Transaction tran,IFailuresPreprocessor preprocessor)
+        {
+            FailureHandlingOptions failureOptions = tran.GetFailureHandlingOptions();
+            failureOptions.SetFailuresPreprocessor(preprocessor);
+            tran.SetFailureHandlingOptions(failureOptions);
+           return tran.Start();
+        }
+        /// <summary>
+        /// 以默认预处理开始事务
+        /// </summary>
+        /// <param name="tran"></param>
+        /// <returns></returns>
+        public static TransactionStatus StartWidthPreprocessor(this Transaction tran)
+        {
+            return StartWidthPreprocessor(tran, new ErrorWarningPreprocessor(false));
+        }
+    }
+}

+ 58 - 0
FWindSoft/FWindSoft.Revit/Extension/UIDocumentExtension.cs

@@ -0,0 +1,58 @@
+/*-------------------------------------------------------------------------
+ * 功能描述:UIDocumentExtension
+ * 作者:xulisong
+ * 创建时间: 2019/5/23 11:22:36
+ * 版本号:v1.0
+ *  -------------------------------------------------------------------------*/
+
+using Autodesk.Revit.DB;
+using Autodesk.Revit.UI;
+using Autodesk.Revit.UI.Selection;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit
+{
+    /// <summary>
+    /// UIDocument 相关扩展信息
+    /// </summary>
+    public static class UIDocumentExtension
+    {
+        /// <summary>
+        /// 获取当前选中元素
+        /// </summary>
+        /// <param name="uiDocument"></param>
+        /// <returns></returns>
+        public static Element GetSelectedElement(this UIDocument uiDocument)
+        {
+            Element selected = null;
+            UIDocument doc = uiDocument;
+            var useId = doc.Selection.GetElementIds().FirstOrDefault();
+            if (useId != null)
+            {
+                selected = doc.Document.GetElement(useId);
+            }   
+            return selected;
+        }
+        /// <summary>
+        /// 获取选中元素
+        /// </summary>
+        /// <param name="uiDocument"></param>
+        /// <returns></returns>
+        public static List<Element> GetSelectedElements(this UIDocument uiDocument)
+        {
+            List<Element> selectedElements = new List<Element>();
+            UIDocument uiDoc = uiDocument;
+            var useIds = uiDoc.Selection.GetElementIds();
+            if (useIds!=null)
+            {
+                var doc = uiDoc.Document;
+                selectedElements = useIds.Select(id=>doc.GetElement(id)).ToList();
+            }
+            return selectedElements;
+        }
+    }
+}

+ 28 - 0
FWindSoft/FWindSoft.Revit/ExternalCommand.cs

@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows;
+using Autodesk.Revit.UI;
+using FWindSoft.Revit;
+
+namespace RevitTest
+{
+
+
+    [Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
+    [Autodesk.Revit.Attributes.Regeneration(Autodesk.Revit.Attributes.RegenerationOption.Manual)]
+    [Autodesk.Revit.Attributes.Journaling(Autodesk.Revit.Attributes.JournalingMode.NoCommandData)]
+    public class ShowCommand : ExternalCommand
+    {
+        public override Result Execute(ExternalCommandData commandData, ref string message, Autodesk.Revit.DB.ElementSet elements)
+        {
+            //var pane = RevitCustomDockablePanels.GetDockablePane(commandData.Application, RevitCustomDockablePanels.Default);
+            //pane.Show();
+            MessageBox.Show("ss");
+            return Result.Succeeded;
+        }
+    }
+}

+ 43 - 0
FWindSoft/FWindSoft.Revit/ExternalCommand/ExternalCommand.cs

@@ -0,0 +1,43 @@
+/*-------------------------------------------------------------------------
+ * 功能描述:ExternalCommand
+ * 作者:xulisong
+ * 创建时间: 2019/3/7 14:50:24
+ * 版本号:v1.0
+ *  -------------------------------------------------------------------------*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Autodesk.Revit.DB;
+using Autodesk.Revit.UI;
+using Autodesk.Revit.Attributes;
+
+namespace FWindSoft.Revit
+{
+    [Transaction(TransactionMode.Manual)]
+    [Regeneration(RegenerationOption.Manual)]
+    //[Journaling(JournalingMode.NoCommandData)]
+    public class ExternalCommand : IExternalCommand, IExternalCommandAvailability
+    {
+        /// <summary>
+        /// 应用级别显示,不用打开项目自动显示
+        /// </summary>
+        public bool ApplicationShow { get; set; }
+        public virtual Result Execute(ExternalCommandData commandData, ref string message,ElementSet elements)
+        {
+            RevitCore.InitCore((UIApplication)commandData.Application);
+            return Result.Succeeded;
+        }
+
+        public virtual bool IsCommandAvailable(UIApplication applicationData, CategorySet selectedCategories)
+        {
+            if (ApplicationShow)
+            {
+                return true;
+            }
+            return applicationData.ActiveUIDocument != null;
+        }
+    }
+}

+ 116 - 0
FWindSoft/FWindSoft.Revit/ExternalEvent/ExternalEventCommand.cs

@@ -0,0 +1,116 @@
+using Autodesk.Revit.UI;
+
+namespace FWindSoft.Revit
+{
+    /*
+     * 验证是否是同步,不是同步的话,则需要提供回调函数
+     */
+    /// <summary>
+    /// 扩展事件
+    /// </summary>
+    public class ExternalEventCommand
+    {
+        public ExternalEventCommand(RevitHandler handler) : this(handler, true)
+        {
+        }
+
+        public ExternalEventCommand(RevitHandler handler, bool createRefCommand)
+        {
+            Handler = handler;
+            if (createRefCommand)
+            {
+                CreateEvent();
+            }
+        }
+
+        /// <summary>
+        /// 命令实际处理者
+        /// </summary>
+        public RevitHandler Handler { get; private set; }
+
+        /// <summary>
+        /// 生成Event
+        /// </summary>
+        /// <returns></returns>
+        public ExternalEvent CreateEvent()
+        {
+            if (Handler != null && Event == null)
+            {
+                Event = ExternalEvent.Create(Handler);
+            }
+
+            return Event;
+        }
+
+        #region 关联扩展事件
+
+        /// <summary>
+        /// 扩展事件的命令
+        /// </summary>
+        public ExternalEvent Event { get; private set; }
+
+        /// <summary>
+        /// 触发命令
+        /// </summary>
+        /// <returns></returns>
+        public ExternalEventRequest Raise()
+        {
+            #region 如果关联命令为空,创建一次
+
+            if (Event == null)
+            {
+                CreateEvent();
+            }
+
+            #endregion
+
+            if (Event == null)
+            {
+                return ExternalEventRequest.Pending;
+            }
+
+            return Event.Raise();
+        }
+
+        /// <summary>
+        /// 根据指定参数触发命令
+        /// </summary>
+        /// <param name="parameter">传入参数,在回调方法参数中可以找打使用</param>
+        /// <returns></returns>
+        public ExternalEventRequest Raise(object parameter)
+        {
+            if (Handler != null)
+            {
+                Handler.Parameter = parameter;
+            }
+
+            #region 如果关联命令为空,创建一次
+
+            if (Event == null)
+            {
+                CreateEvent();
+            }
+
+            #endregion
+
+            if (Event == null)
+            {
+                return ExternalEventRequest.Pending;
+            }
+
+            return Event.Raise();
+        }
+
+        #endregion
+
+        #region 析构处理
+
+        ~ExternalEventCommand()
+        {
+            if (Event != null)
+                Event.Dispose();
+        }
+
+        #endregion
+    }
+}

+ 206 - 0
FWindSoft/FWindSoft.Revit/FWindSoft.Revit.csproj

@@ -0,0 +1,206 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{E2F5ADD4-E414-4334-93BD-C7112E9AA151}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>FWindSoft.Revit</RootNamespace>
+    <AssemblyName>FWindSoft.Revit</AssemblyName>
+    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <TargetFrameworkProfile />
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\OutputDll\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="AdWindows">
+      <HintPath>..\Dlls\RevitDll\Current\AdWindows.dll</HintPath>
+    </Reference>
+    <Reference Include="PresentationCore" />
+    <Reference Include="PresentationFramework" />
+    <Reference Include="RevitAddInUtility, Version=18.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\Dlls\RevitDll\Current\RevitAddInUtility.dll</HintPath>
+    </Reference>
+    <Reference Include="RevitAPI, Version=17.0.0.0, Culture=neutral, processorArchitecture=AMD64">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\Dlls\RevitDll\Current\RevitAPI.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="RevitAPIUI, Version=17.0.0.0, Culture=neutral, processorArchitecture=AMD64">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\Dlls\RevitDll\Current\RevitAPIUI.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="RevitVersion, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\Dlls\RevitDll\Current\RevitVersion.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xaml" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Net.Http" />
+    <Reference Include="System.Xml" />
+    <Reference Include="WindowsBase" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Application\RevitRegisterManager.cs" />
+    <Compile Include="Common\ElementEqualityComparer.cs" />
+    <Compile Include="Common\RevitSetting.cs" />
+    <Compile Include="Common\RevitTools.cs" />
+    <Compile Include="Common\SelectionFilter.cs" />
+    <Compile Include="DockablePane\DockableWindow.cs" />
+    <Compile Include="ExtensibleStorage\EnumStorageExtension.cs" />
+    <Compile Include="ExtensibleStorage\ExtensibleAttribute.cs" />
+    <Compile Include="ExtensibleStorage\ExtensibleStorageExtension.cs" />
+    <Compile Include="ExtensibleStorage\ExtensibleStorageUtil.cs" />
+    <Compile Include="ExtensibleStorage\ICoustomStorage.cs" />
+    <Compile Include="ExtensibleStorage\InEnumUtil.cs" />
+    <Compile Include="Extension\ApplicationExtension.cs" />
+    <Compile Include="Extension\CableTrayExtension.cs" />
+    <Compile Include="Extension\ConduitExtension.cs" />
+    <Compile Include="Extension\ConnectorJoin\ConnectorExtension.cs" />
+    <Compile Include="Extension\ConnectorJoin\ConnectorSearchUtils.cs" />
+    <Compile Include="Extension\ConnectorJoin\ConnectorSearchOptions.cs" />
+    <Compile Include="Extension\ConnectorJoin\ElementPath.cs" />
+    <Compile Include="Extension\CurveElementExtension.cs" />
+    <Compile Include="Extension\DetailCurveExtension.cs" />
+    <Compile Include="Extension\DocumentExtension.cs" />
+    <Compile Include="Extension\DoubleExtension.cs" />
+    <Compile Include="Extension\DuctExtension.cs" />
+    <Compile Include="Extension\ElementExtension.cs" />
+    <Compile Include="Extension\ElementTypeExtension.cs" />
+    <Compile Include="Extension\FamilyInstanceExtension.cs" />
+    <Compile Include="Extension\Graphic\CurveExtension.cs" />
+    <Compile Include="Extension\Graphic\GeometryElementExtension.cs" />
+    <Compile Include="Extension\Graphic\LineExtension.cs" />
+    <Compile Include="Extension\Graphic\XYZExtension.cs" />
+    <Compile Include="Extension\InsulationExtension.cs" />
+    <Compile Include="Extension\LocationExtension.cs" />
+    <Compile Include="Extension\MepCurveExtension.cs" />
+    <Compile Include="Extension\MepCurveTypeExtension.cs" />
+    <Compile Include="Extension\MepSystemTypeExtension.cs" />
+    <Compile Include="Extension\ModelCurveExtension.cs" />
+    <Compile Include="Extension\PipeExtension.cs" />
+    <Compile Include="Extension\SelectionExtension.cs" />
+    <Compile Include="Extension\TextNodeExtension.cs" />
+    <Compile Include="Extension\TransactionExtension.cs" />
+    <Compile Include="Extension\UIDocumentExtension.cs" />
+    <Compile Include="ExternalCommand\ExternalCommand.cs" />
+    <Compile Include="FamilyManager\FamilyExtension.cs" />
+    <Compile Include="FamilyManager\FamilyLoadOptions.cs" />
+    <Compile Include="FamilyManager\FamilyManagerExtension.cs" />
+    <Compile Include="FamilyManager\FamilySymbolExtension.cs" />
+    <Compile Include="IdlingEvent\GuardianIdlingCommand.cs" />
+    <Compile Include="IdlingEvent\SingleIdingCommand.cs" />
+    <Compile Include="IdlingEvent\IdlingCommand.cs" />
+    <Compile Include="IdlingEvent\IdlingEventCommand.cs" />
+    <Compile Include="IdlingEvent\SelectedChangedCommand.cs" />
+    <Compile Include="Interfaces\IRevitEventHandler.cs" />
+    <Compile Include="Menu\AutoParseButtonAttribute.cs" />
+    <Compile Include="Menu\ButtonAssemblyManager.cs" />
+    <Compile Include="Menu\ButtonAttribute.cs" />
+    <Compile Include="Menu\GroupButtons.cs" />
+    <Compile Include="Menu\MenuConfigParser.cs" />
+    <Compile Include="Menu\MenuConfig.cs" />
+    <Compile Include="Menu\RevitButton.cs" />
+    <Compile Include="Menu\RevitButtonStyle.cs" />
+    <Compile Include="Menu\RevitMenuComponment.cs" />
+    <Compile Include="Menu\RevitTab.cs" />
+    <Compile Include="Menu\RevitPanel.cs" />
+    <Compile Include="Menu\RibbonItemUtil.cs" />
+    <Compile Include="Mep\MepJoin\ConduitJoin\ConduitFittingCreator.cs" />
+    <Compile Include="Mep\MepJoin\ConduitJoin\ConduitJoin.cs" />
+    <Compile Include="Mep\MepJoin\ConduitJoin\JoinConduits.cs" />
+    <Compile Include="Mep\MepJoin\ConduitJoin\JoinConduitUtils.cs" />
+    <Compile Include="Mep\MepJoin\ConnectorPatternUtils.cs" />
+    <Compile Include="Mep\MepJoin\FittingWrapper.cs" />
+    <Compile Include="Mep\MepJoin\IFittingCoordinate.cs" />
+    <Compile Include="Mep\MepJoin\IJoinCurve.cs" />
+    <Compile Include="Mep\MepJoin\IMepCurveJoin.cs" />
+    <Compile Include="Mep\MepJoin\IMepEquipmentJoin.cs" />
+    <Compile Include="Mep\MepJoin\JoinContext.cs" />
+    <Compile Include="Mep\MepJoin\JoinCreator.cs" />
+    <Compile Include="Mep\MepJoin\JoinElementWraper.cs" />
+    <Compile Include="Mep\MepJoin\RotationStrategy.cs" />
+    <Compile Include="Parameter\ParameterDefinition.cs" />
+    <Compile Include="Parameter\ParameterExtension.cs" />
+    <Compile Include="Parameter\ParameterUtil.cs" />
+    <Compile Include="Parameter\SharedParameterDefinition.cs" />
+    <Compile Include="Parameter\SharedParameterExtension.cs" />
+    <Compile Include="Parameter\SharedParameterUtil.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="RevitCore\RevitFileSwitch.cs" />
+    <Compile Include="RevitCore\RevitCore.cs" />
+    <Compile Include="RevitHandler\RevitEventArgs.cs" />
+    <Compile Include="RevitHandler\RevitHandler.cs" />
+    <Compile Include="RevitHandler\RevitHandlerFactory.cs" />
+    <Compile Include="Application\ExternalApplication.cs" />
+    <Compile Include="ExternalCommand.cs" />
+    <Compile Include="ExternalEvent\ExternalEventCommand.cs" />
+    <Compile Include="IdlingEvent\IdlingCommands.cs" />
+    <Compile Include="DockablePane\RevitCustomDockablePanels.cs" />
+    <Compile Include="Interfaces\IRevitRegister.cs" />
+    <Compile Include="RevitInterfaces\ErrorWarningPreprocessor.cs" />
+    <Compile Include="RevitTable\RevitTableDrawContext.cs" />
+    <Compile Include="Updater\RevitTrigger.cs" />
+    <Compile Include="Updater\RevitUpdater.cs" />
+    <Compile Include="Updater\UpdaterRegister.cs" />
+    <Compile Include="Utils\ConnectorUtils.cs" />
+    <Compile Include="Utils\ElectricalUtils.cs" />
+    <Compile Include="Utils\FittingUtils.cs" />
+    <Compile Include="Utils\SolidUtil.cs" />
+    <Compile Include="Window\RevitModelessWindow.cs" />
+    <Compile Include="Window\RevitWindow.cs" />
+    <Compile Include="Wrapper\ElementWrapper.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\FWindSoft.Wpf\FWindSoft.Wpf.csproj">
+      <Project>{28e63cc9-6cfb-47a1-8b40-4cf9e4309d51}</Project>
+      <Name>FWindSoft.Wpf</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\FWindSoft\FWindSoft.csproj">
+      <Project>{063ebafb-9f7b-4cd7-b960-70464bf3ea33}</Project>
+      <Name>FWindSoft</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="IdlingEvent\说明.txt" />
+    <Content Include="Mep\MepJoin\ConduitJoin\描述.txt" />
+    <Content Include="说明.txt" />
+  </ItemGroup>
+  <ItemGroup>
+    <Folder Include="Utils\TableManager\" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>

+ 125 - 0
FWindSoft/FWindSoft.Revit/FamilyManager/FamilyExtension.cs

@@ -0,0 +1,125 @@
+using Autodesk.Revit.DB;
+using FWindSoft.Revit.FamilyManager;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit
+{
+    public static class FamilyExtension
+    {
+        #region 查找族相关信息
+        /// <summary>
+        /// 查找family的所有族类型
+        /// </summary>
+        /// <param name="family"></param>
+        /// <returns></returns>
+        public static List<FamilySymbol> GetFamilySymbols(this Family family)
+        {
+            var fsIds = family.GetFamilySymbolIds();
+            var refDoc = family.Document;
+            return fsIds.Select(id => refDoc.GetElement(id)).OfType<FamilySymbol>().ToList();
+        }
+        /// <summary>
+        /// 查找family的第一个可用Symbol
+        /// </summary>
+        /// <param name="family"></param>
+        /// <returns></returns>
+        public static FamilySymbol GetFamilySymbol(this Family family)
+        {
+            return family.GetFamilySymbol(strTypeName: null);
+        }
+        /// <summary>
+        /// 查找指定名称familySymbol,没有找到则返回null
+        /// </summary>
+        /// <param name="family"></param>
+        /// <param name="strTypeName"></param>
+        /// <returns></returns>
+        public static FamilySymbol GetFamilySymbol(this Family family, string strTypeName)
+        {
+            FamilySymbol familySymbol = null;
+            var symbolList = family.GetFamilySymbols();
+            if (string.IsNullOrWhiteSpace(strTypeName))
+            {
+                familySymbol = symbolList.FirstOrDefault();
+            }
+            else
+            {
+                familySymbol = symbolList.FirstOrDefault(fs => fs.Name == strTypeName);
+            }
+
+            familySymbol.ActivateT();
+            return familySymbol;
+        }
+
+
+        /// <summary>
+        /// 查找指定条件的FamilySymbol,没有找到则返回Null
+        /// </summary>
+        /// <param name="family"></param>
+        /// <param name="parameterValues"></param>
+        /// <returns></returns>
+        public static FamilySymbol GetFamilySymbol(this Family family, Dictionary<string, string> parameterValues)
+        {
+            var symbols = family.GetFamilySymbols();
+            FamilySymbol fsResult = null;
+            foreach (var fs in symbols)
+            {
+                bool valueEqual = true;
+                foreach (var parameterValue in parameterValues)
+                {
+                    var parameter = fs.GetParameter(parameterValue.Key);
+                    if (parameter == null)
+                        continue;
+                    valueEqual = ParameterUtil.EqualValue(parameter, parameterValue.Value);
+                    if (!valueEqual)
+                    {
+                        break;
+                    }
+                }
+                if (valueEqual)
+                {
+                    fsResult = fs;
+                    break;
+                }
+            }
+            fsResult.ActivateT();
+            return fsResult;
+        } 
+        #endregion
+
+
+        /// <summary>
+        /// 获取指定类型参数的Symbol,如条件果没有条件指定的类型,则创建满足条件的类型
+        /// </summary>
+        /// <param name="family"></param>
+        /// <param name="parameterValues"></param>
+        /// <param name="symbolName"></param>
+        /// <returns></returns>
+        public static FamilySymbol GetAndCopySymbol(this Family family,
+            Dictionary<string, string> parameterValues, ref string symbolName)
+        {
+            var familySymbol = family.GetFamilySymbol(symbolName);
+            if (familySymbol == null)
+            {
+                familySymbol = family.GetFamilySymbol(parameterValues);
+                if (familySymbol == null)
+                {
+                    familySymbol = family.GetFamilySymbol()?.CopyFamilySymbol(symbolName, parameterValues);
+                }
+            }
+            if(familySymbol!=null)
+            {
+                symbolName = familySymbol.Name;
+            }
+            familySymbol.ActivateT();
+            return familySymbol;
+        }
+
+
+        
+    }
+}

+ 26 - 0
FWindSoft/FWindSoft.Revit/FamilyManager/FamilyLoadOptions.cs

@@ -0,0 +1,26 @@
+using Autodesk.Revit.DB;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit.FamilyManager
+{
+    public class FamilyLoadOptions : IFamilyLoadOptions
+    {
+        public bool OnFamilyFound(bool familyInUse, out bool overwriteParameterValues)
+        {
+            overwriteParameterValues = true;
+            return true;
+        }
+
+        public bool OnSharedFamilyFound(Family sharedFamily, bool familyInUse, out FamilySource source,
+            out bool overwriteParameterValues)
+        {
+            source = FamilySource.Family;
+            overwriteParameterValues = true;
+            return true;
+        }
+    }
+}

+ 95 - 0
FWindSoft/FWindSoft.Revit/FamilyManager/FamilyManagerExtension.cs

@@ -0,0 +1,95 @@
+using Autodesk.Revit.DB;
+using FWindSoft.Revit.Extension;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit.FamilyManager
+{
+    public static class FamilyManagerExtension
+    {
+        #region 族加载
+        /// <summary>
+        /// 获取项目中的族
+        /// </summary>
+        /// <param name="doc"></param>
+        /// <returns></returns>
+        public static List<Family> GetFamilys(this Document doc)
+        {
+            return doc.GetElements<Family>();
+        }
+
+        /// <summary>
+        /// 加载族文件ljy
+        /// </summary>
+        /// <param name="doc"></param>
+        /// <param name="familyFile"></param>
+        /// <returns></returns>
+        public static Family LoadFamilyT(this Document doc, string familyFile)
+        {
+            Family family = null;
+            doc.LoadFamily(familyFile, new FamilyLoadOptions(), out family);
+            return family;
+        }
+
+        /// <summary>
+        /// 加载族文件ljy
+        /// </summary>
+        /// <param name="doc"></param>
+        /// <param name="familyFile"></param>
+        /// <param name="bic"></param>
+        /// <returns></returns>
+        public static Family LoadFamilyT(this Document doc, string familyFile, string familyName)
+        {
+            var strFamilyName = string.IsNullOrWhiteSpace(familyName)?Path.GetFileNameWithoutExtension(familyFile):familyName;
+            Family family = doc.FindFamily(strFamilyName);
+            if (family == null)
+            {
+                family = doc.LoadFamilyT(familyFile);
+            }
+            return family;
+        }
+        /// <summary>
+        /// 加载制定文件的族,加载之前判断族名称是否存在
+        /// </summary>
+        /// <param name="doc"></param>
+        /// <param name="familyFile"></param>
+        /// <returns></returns>
+        public static Family LoadFamilyCheckName(this Document doc, string familyFile)
+        {
+            return doc.LoadFamilyT(familyFile, null);
+        }
+        public static Family FindFamily(this Document doc, string familyName)
+        {
+            Family family = null;
+            List<Family> listFamily = doc.GetFamilys();
+            foreach (var f in listFamily)
+            {
+                if (f.Name == familyName)
+                {
+                    family = f;
+                    break;
+                }
+            }
+            return family;
+        }
+        #endregion
+
+        /// <summary>
+        /// 获取指定文件的默认族类型
+        /// </summary>
+        /// <param name="doc"></param>
+        /// <param name="familyFile"></param>
+        /// <returns></returns>
+        public static FamilySymbol LoadSysmbol(this Document doc,string familyFile)
+        {
+            var family = doc.LoadFamilyCheckName(familyFile);
+            if (family == null)
+                return null;
+            return family.GetFamilySymbol();
+        }
+    }
+}

+ 54 - 0
FWindSoft/FWindSoft.Revit/FamilyManager/FamilySymbolExtension.cs

@@ -0,0 +1,54 @@
+using Autodesk.Revit.DB;
+using FWindSoft.Revit.Extension;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit
+{
+    public static class FamilySymbolExtension
+    {
+        /// <summary>
+        /// 激活封装
+        /// </summary>
+        /// <param name="fs"></param>
+        public static void ActivateT(this FamilySymbol fs)
+        {
+            if (fs != null && fs.IsActive)
+            {
+                fs.Activate();
+            }
+        }
+
+        /// <summary>
+        /// 复制FamilySymbol
+        /// </summary>
+        /// <param name="familySymbolSource"></param>
+        /// <param name="symbolName"></param>
+        /// <param name="parameterValues"></param>
+        /// <returns></returns>
+        public static FamilySymbol CopyFamilySymbol(this FamilySymbol familySymbolSource, string symbolName,
+            Dictionary<string, string> parameterValues)
+        {
+            var familySymbol = familySymbolSource.DuplicateT<FamilySymbol>(symbolName);
+            if (familySymbol == null) return null;
+            #region 参数处理
+            if (parameterValues != null && parameterValues.Count > 0)
+            {
+                foreach (var parameterValue in parameterValues)
+                {
+                    var parameter = familySymbol.GetParameter(parameterValue.Key);
+                    if (parameter == null)
+                        continue;
+                    ParameterUtil.SetValue(parameter, parameterValue.Value);                    
+                }
+            }
+            #endregion
+            familySymbol.Activate();
+
+            return familySymbol;
+        }
+    }
+}

+ 81 - 0
FWindSoft/FWindSoft.Revit/IdlingEvent/GuardianIdlingCommand.cs

@@ -0,0 +1,81 @@
+using Autodesk.Revit.UI;
+using Autodesk.Revit.UI.Events;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit
+{
+    /// <summary>
+    /// 守护命令【该命令队列,可控制是否移除】
+    /// </summary>
+    public class GuardianIdlingCommand : IRevitRegister
+    {
+        public  List<IdlingCommand> Commands { get; private set; }
+        public  GuardianIdlingCommand()
+        {
+            Commands = new List<IdlingCommand>();
+        }
+        #region 关联命令
+        /// <summary>
+        /// 对接事件绑定
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        public void ApplicaionIdling(object sender, IdlingEventArgs e)
+        {
+            var application = sender as UIApplication;
+            foreach (var command in Commands)
+            {
+                command.Raise(application);
+            }          
+            e.SetRaiseWithoutDelay();
+        }
+        #endregion
+
+        #region 操作命令
+        //添加,移除
+        public IdlingCommand AddExecute(Func<RevitEventArgs, HandlerResult> handler)
+        {
+            IdlingCommand command = new IdlingCommand(RevitHandlerFactory.CreateOnceHandler(handler));
+            Commands.Add(command);
+            return command;
+        }
+        public IdlingCommand AddExecute(IdlingCommand command)
+        {
+            if (command == null)
+                return null;
+            Commands.Add(command);
+            return command;
+        }
+
+        public void RemoveExecute(IdlingCommand command)
+        {
+            if (command == null)
+                return;
+            Commands.Remove(command);
+        }
+        public void RemoveExecute(string commandName)
+        {
+            if (string.IsNullOrWhiteSpace(commandName))
+                return;
+            Commands.RemoveAll(command=>command.Handler?.Name==commandName);
+        }
+        #endregion
+
+
+        #region 事件注册相关
+        public void Register(ExternalApplication application)
+        {
+            application.Idling += ApplicaionIdling;
+        }
+
+        public void Unregister(ExternalApplication application)
+        {
+            application.Idling -= ApplicaionIdling;
+        }
+        #endregion
+    }
+}

+ 40 - 0
FWindSoft/FWindSoft.Revit/IdlingEvent/IdlingCommand.cs

@@ -0,0 +1,40 @@
+using Autodesk.Revit.UI;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit
+{
+    /// <summary>
+    /// 空闲命令
+    /// </summary>
+    public class IdlingCommand
+    {
+        #region 构造函数
+        public IdlingCommand(RevitHandler handler)
+        {
+            this.Handler = handler;
+        }
+        #endregion
+        #region 实例相关方法
+        /// <summary>
+        /// 命令实际处理者
+        /// </summary>
+        public RevitHandler Handler { get; private set; }
+        /// <summary>
+        /// 触发命令【raise把命令发给接受者】
+        /// </summary>
+        /// <returns></returns>
+        public void Raise(UIApplication uiApplication)
+        {
+            if (Handler == null)
+            {
+                return;
+            }
+            Handler.Execute(uiApplication);
+        }
+        #endregion
+    }
+}

+ 70 - 0
FWindSoft/FWindSoft.Revit/IdlingEvent/IdlingCommands.cs

@@ -0,0 +1,70 @@
+/*-------------------------------------------------------------------------
+ * 功能描述:IdlingCommands
+ * 作者:xulisong
+ * 创建时间: 2019/1/3 17:22:01
+ * 版本号:v1.0
+ *  -------------------------------------------------------------------------*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Autodesk.Revit.UI;
+
+namespace FWindSoft.Revit
+{
+    /// <summary>
+    /// 空闲命令消费者队列
+    /// </summary>
+    public class IdlingCommands
+    {
+        internal IdlingCommands()
+        {
+            Commands = new Queue<IdlingCommand>();
+        }
+        #region 生产消费队列维护
+        /// <summary>
+        /// 命令队列
+        /// </summary>
+        private readonly Queue<IdlingCommand> Commands;
+
+        /// <summary>
+        /// 在队列中加入command
+        /// </summary>
+        /// <param name="command"></param>
+        public void Enqueue(IdlingCommand command)
+        {
+            lock (Commands)
+            {
+                Commands.Enqueue(command);
+            }
+        }
+        /// <summary>
+        /// 获取队列中的command
+        /// </summary>
+        /// <returns></returns>
+        public IdlingCommand Dequeue()
+        {
+            IdlingCommand command = null;
+            lock (Commands)
+            {
+                if (HasCommand)
+                {
+                    command = Commands.Dequeue(); ;
+                }
+            }
+
+            return command;
+        }
+        public bool HasCommand
+        {
+            get
+            {
+                return Commands.Count > 0;
+            }
+        }
+        #endregion
+    }
+   
+}

+ 80 - 0
FWindSoft/FWindSoft.Revit/IdlingEvent/IdlingEventCommand.cs

@@ -0,0 +1,80 @@
+using Autodesk.Revit.UI;
+using Autodesk.Revit.UI.Events;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit
+{
+    /// <summary>
+    /// 业务轮询命令
+    /// </summary>
+    public class IdlingEventCommand: IRevitRegister
+    {
+        #region 初始化
+        public IdlingEventCommand()
+        {
+            Commands = new IdlingCommands();
+        }
+        /// <summary>
+        /// 命令队列
+        /// </summary>
+        private readonly IdlingCommands Commands;
+        #endregion
+
+        #region 消费队列
+        /// <summary>
+        /// 对接事件绑定
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        protected void ApplicaionIdling(object sender, IdlingEventArgs e)
+        {
+            IdlingCommand currentCommand = Commands.Dequeue();
+            if (currentCommand != null)
+            {
+                currentCommand.Raise(sender as UIApplication);
+                e.SetRaiseWithoutDelay();
+            }
+        }
+        #endregion
+
+        #region 生产队列
+        public IdlingCommand OnceExecute(Func<RevitEventArgs, HandlerResult> handler, Action<RevitEventArgs> callBack)
+        {
+            IdlingCommand command = new IdlingCommand(RevitHandlerFactory.CreateOnceHandler(handler, callBack));
+            Commands.Enqueue(command);
+            return command;
+        }
+
+        public IdlingCommand WhileExecute(Func<RevitEventArgs, HandlerResult> handler, Action<RevitEventArgs> callBack)
+        {
+            IdlingCommand command = new IdlingCommand(RevitHandlerFactory.CreateWhileHandler(handler, callBack));
+            Commands.Enqueue(command);
+            return command;
+        }
+
+        public IdlingCommand Execute(IdlingCommand command)
+        {
+            if (command == null)
+                return null;
+            Commands.Enqueue(command);
+            return command;
+        }
+        #endregion
+
+        #region 事件注册相关
+        public void Register(ExternalApplication application)
+        {
+            application.Idling += ApplicaionIdling;
+        }
+
+        public void Unregister(ExternalApplication application)
+        {
+            application.Idling -= ApplicaionIdling;
+        } 
+        #endregion
+    }
+}

+ 41 - 0
FWindSoft/FWindSoft.Revit/IdlingEvent/SelectedChangedCommand.cs

@@ -0,0 +1,41 @@
+/*-------------------------------------------------------------------------
+ * 功能描述:SelectedChangedCommand
+ * 作者:xulisong
+ * 创建时间: 2019/5/31 16:03:04
+ * 版本号:v1.0
+ *  -------------------------------------------------------------------------*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Autodesk.Revit.UI.Events;
+using Autodesk.Revit.DB;
+using Autodesk.Revit.UI;
+
+namespace FWindSoft.Revit
+{
+    public class SelectedChangedCommand: SingleIdingCommand
+    {
+        private HashSet<ElementId> m_OldIds;
+        protected override void ApplicaionIdling(object sender, IdlingEventArgs e)
+        {
+            if (!Enable)
+            {
+                return;
+            }
+            var application = sender as UIApplication;
+            var ids = application.ActiveUIDocument.Selection.GetElementIds();
+            //if (ids.Count == 0)
+            //{
+            //    return;
+            //}
+            if (m_OldIds == null || ids.Count != m_OldIds.Count || ids.Any(id => !m_OldIds.Contains(id)))
+            {
+                base.ApplicaionIdling(sender, e);
+                m_OldIds = new HashSet<ElementId>(ids);
+            }
+        }
+    }
+}

+ 64 - 0
FWindSoft/FWindSoft.Revit/IdlingEvent/SingleIdingCommand.cs

@@ -0,0 +1,64 @@
+/*-------------------------------------------------------------------------
+ * 功能描述:IdingSingleCommand
+ * 作者:xulisong
+ * 创建时间: 2019/5/31 15:46:51
+ * 版本号:v1.0
+ *  -------------------------------------------------------------------------*/
+
+using Autodesk.Revit.UI;
+using Autodesk.Revit.UI.Events;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit
+{
+    public class SingleIdingCommand : IRevitRegister
+    {
+        #region 初始化
+        public SingleIdingCommand()
+        {
+            Enable = true;
+        }
+        public bool Enable { get; set; }
+        #endregion
+       
+        #region 消费队列
+        /// <summary>
+        /// 对接事件绑定
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        protected virtual void ApplicaionIdling(object sender, IdlingEventArgs e)
+        {
+            if (!Enable)
+            {
+                return;
+            }
+            var application = sender as UIApplication;
+            OnExecute(application);
+            e.SetRaiseWithoutDelay();
+        }
+        #endregion
+
+        protected virtual void OnExecute(UIApplication application)
+        {
+            Execute?.Invoke(this, application);
+        }
+
+        public event EventHandler<UIApplication> Execute;
+        #region 事件注册相关
+        public void Register(ExternalApplication application)
+        {
+            application.Idling += ApplicaionIdling;
+        }
+
+        public void Unregister(ExternalApplication application)
+        {
+            application.Idling -= ApplicaionIdling;
+        }
+        #endregion
+    }
+}

+ 3 - 0
FWindSoft/FWindSoft.Revit/IdlingEvent/说明.txt

@@ -0,0 +1,3 @@
+1、idling和扩展事件是有区别的
+2、一般只执行一次,使用Idling。如果可执行多次,当成一个固定的事件,可使用扩展事件
+3、方法扩展成需要带参数执行的,放在handler里,通过args参数传递

+ 54 - 0
FWindSoft/FWindSoft.Revit/Interfaces/IRevitEventHandler.cs

@@ -0,0 +1,54 @@
+/*-------------------------------------------------------------------------
+ * 功能描述:IRevitEventHandler
+ * 作者:xulisong
+ * 创建时间: 2019/1/7 12:59:33
+ * 版本号:v1.0
+ *  -------------------------------------------------------------------------*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit
+{
+    /// <summary>
+    /// revit事件处理接口
+    /// </summary>
+    public interface IRevitEventHandler
+    {
+        void Execute(object sender, EventArgs args);
+    }
+    public class RevitEvent: IRevitEventHandler
+    {
+        /// <summary>
+        /// 事件名称
+        /// </summary>
+        public string Name { get; set; }
+        /// <summary>
+        /// 关联实际处理类型
+        /// </summary>
+        private List<IRevitEventHandler> Handlers { get; set; }
+
+        public void AddHandler(IRevitEventHandler handler)  
+        {
+            if (handler == null)
+                return;
+            if (Handlers == null)
+                Handlers = new List<IRevitEventHandler>();
+            Handlers.Add(handler);
+        }
+        public event EventHandler<EventArgs> Handler;
+        public void Execute(object sender, EventArgs args)
+        {
+            if (Handlers == null||!Handlers.Any())
+                return;
+            foreach (var revitEventHandler in Handlers)
+            {
+                revitEventHandler.Execute(sender, args);
+            }
+            Handler?.Invoke(sender, args);
+        }
+    }
+}

+ 22 - 0
FWindSoft/FWindSoft.Revit/Interfaces/IRevitRegister.cs

@@ -0,0 +1,22 @@
+/*-------------------------------------------------------------------------
+ * 功能描述:IUpdaterRegister
+ * 作者:xulisong
+ * 创建时间: 2018/12/28 10:23:36
+ * 版本号:v1.0
+ *  -------------------------------------------------------------------------*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Autodesk.Revit.UI;
+
+namespace FWindSoft.Revit
+{
+    public interface IRevitRegister
+    {
+        void Register(ExternalApplication application);
+        void Unregister(ExternalApplication application);
+    }
+}

+ 24 - 0
FWindSoft/FWindSoft.Revit/Menu/AutoParseButtonAttribute.cs

@@ -0,0 +1,24 @@
+/*-------------------------------------------------------------------------
+ * 功能描述:AutoParseButtonAttribute
+ * 作者:xulisong
+ * 创建时间: 2019/7/25 12:05:21
+ * 版本号:v1.0
+ *  -------------------------------------------------------------------------*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit.Menu
+{
+    [AttributeUsage(AttributeTargets.Assembly)]
+    public class AutoParseButtonAttribute : Attribute
+    {
+        /// <summary>
+        /// 是否自动解析相关类
+        /// </summary>
+        public bool Use { get; set; } = true;
+    }
+}

+ 182 - 0
FWindSoft/FWindSoft.Revit/Menu/ButtonAssemblyManager.cs

@@ -0,0 +1,182 @@
+/*-------------------------------------------------------------------------
+ * 功能描述:ButtonAssemblyManager
+ * 作者:xulisong
+ * 创建时间: 2019/7/25 13:06:54
+ * 版本号:v1.0
+ *  -------------------------------------------------------------------------*/
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+using Autodesk.Revit.UI;
+
+namespace FWindSoft.Revit.Menu
+{
+    public class ButtonAssemblyManager
+    {
+        public static MenuConfig GetMenuConfigIsolate(string path)
+        {
+           return DoaminProxy.NewDomainExecute(ButtonAssemblyManager.GetMenuConfig, path);
+        }
+        public static MenuConfig GetMenuConfig(string path)
+        {
+            var usePath = path;
+            MenuConfig config = new MenuConfig();
+            List<string> files = new List<string>();
+            #region 获取相关文件
+            List<string> tempFolders = new List<string>();
+            var flag = Tools.FileUtil.IsPathDirectory(path);
+            if (flag == 1)
+            {
+                tempFolders.Add(usePath);
+            }
+            else
+            {
+                files.Add(usePath);
+            }
+
+            for (int i = 0; i < tempFolders.Count; i++)
+            {
+                var tempPath = tempFolders[i];
+                files.AddRange(Directory.GetFiles(tempPath));
+                tempFolders.AddRange(Directory.GetDirectories(tempPath));
+            } 
+            #endregion
+            foreach (var file in files)
+            {
+                if (".dll"!= Path.GetExtension(file)?.ToLower())
+                {
+                    continue;
+                }
+
+                //if (!file.Contains("Tool"))
+                //{
+                //    continue;
+                //}
+                try
+                {
+                    Assembly tempAssembly=Assembly.ReflectionOnlyLoadFrom(file);
+                    var refAssemblies = tempAssembly.GetReferencedAssemblies();
+                    if (refAssemblies.All(s => s.Name != "FWindSoft.Revit"))
+                    {
+                        continue;
+                    }
+                    var assembly=Assembly.LoadFrom(file);
+                    var attribue = assembly.GetCustomAttribute<AutoParseButtonAttribute>();
+                    if (attribue == null || !attribue.Use)
+                    {
+                        continue;
+                    }
+                    var types = assembly.GetTypes();
+                    var interfaceName = typeof(IExternalCommand).FullName;
+                    foreach (var type in types)
+                    {
+                        if (type.GetInterface(interfaceName) != null)
+                        {
+                            if (type.IsAbstract || type.IsGenericTypeDefinition)
+                                continue;
+                            var buttonAttribute = type.GetCustomAttribute<ButtonAttribute>();
+                            if (buttonAttribute == null)
+                            {
+                                continue;
+                            }
+
+                            #region 增加命令信息
+                            var tab = buttonAttribute.GetTab();
+                            if (config.Tabs.All(t => t.Name != tab.Name))
+                            {
+                                config.Tabs.Add(tab);
+                            }
+                            var panel = buttonAttribute.GetPanel();
+                            if (config.Panels.All(t => t.Name != panel.Name))
+                            {
+                                config.Panels.Add(panel);
+                            }
+                            var button = buttonAttribute.GetButton();
+                            button.AssemblyName = assembly.Location;
+                            button.ClassName = type.FullName;
+                            button.Index = buttonAttribute.Index;
+                            config.Buttons.Add(button); 
+                            #endregion
+                        }
+                    }
+                }
+                catch (Exception ex)
+                {
+
+                    //非托管dll可能会报错
+                }
+            }
+            return config;
+        }
+        /// <summary>
+        /// 将assistantConfig数据合并到config中
+        /// </summary>
+        /// <param name="config"></param>
+        /// <param name="assistantConfig"></param>
+        /// <returns></returns>
+        public static MenuConfig GetMenuConfig(MenuConfig config, MenuConfig assistantConfig)
+        {
+            var tabs = assistantConfig.Tabs;
+            foreach (var tab in tabs)
+            {
+                if (config.Tabs.Any(t => t.Name == tab.Name))
+                {
+                    continue;
+                }
+                config.Tabs.Add(tab);
+            }
+            var panels = assistantConfig.Panels;
+            foreach (var panel in panels)
+            {
+                if (config.Panels.Any(t => t.Name == panel.Name))
+                {
+                    continue;
+                }
+                config.Panels.Add(panel);
+            }
+            var buttons = assistantConfig.Buttons;
+            foreach (var button in buttons)
+            {
+                if (config.Buttons.Any(t => t.Name == button.Name))
+                {
+                    continue;
+                }
+                config.Buttons.Add(button);
+            }
+            return config;
+        }
+    }
+
+    internal class DoaminProxy : MarshalByRefObject
+    {
+        public R Execute<T, R>(Func<T, R> func,T input)
+        {
+            if (func == null)
+            {
+                return default(R);
+            }
+            return func.Invoke(input);
+        }
+        public void Execute<T>(Action<T> action, T input)
+        {
+            if (action == null)
+            {
+                return ;
+            }
+            action(input);
+        }
+        internal static R NewDomainExecute<T, R>(Func<T, R> func, T input)
+        {
+            AppDomain tempAppDomain = AppDomain.CreateDomain(Guid.NewGuid().ToString());
+            DoaminProxy proxy = (DoaminProxy)tempAppDomain.CreateInstanceAndUnwrap(Assembly.GetAssembly(typeof(DoaminProxy)).GetName().Name, typeof(DoaminProxy).FullName);
+            var result = proxy.Execute<T,R>(func,input);
+            AppDomain.Unload(tempAppDomain);
+            return result;
+        }
+    }
+}

+ 159 - 0
FWindSoft/FWindSoft.Revit/Menu/ButtonAttribute.cs

@@ -0,0 +1,159 @@
+/*-------------------------------------------------------------------------
+ * 功能描述:ButtonAttribute
+ * 作者:xulisong
+ * 创建时间: 2019/7/25 11:30:56
+ * 版本号:v1.0
+ *  -------------------------------------------------------------------------*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit.Menu
+{
+    [AttributeUsage(AttributeTargets.Class)]
+    public class ButtonAttribute:Attribute
+    {
+        public ButtonAttribute()
+        {
+            //此处获取到的程序集为mscorlib,不太合适
+            //var assemblyName= Assembly.GetCallingAssembly().GetName().Name;
+            this.TabName = "自定义";
+            this.PanelName = "自定义";
+        }
+        /// <summary>
+        /// 菜单顺序
+        /// </summary>
+        public int Index { get; set; }
+        private string m_TabName;
+        private string m_TabText;
+        /// <summary>
+        /// tab名称
+        /// </summary>
+        public string TabName
+        {
+            get { return GetResult(m_TabName, m_TabText); }
+            set
+            {
+                m_TabName = value;
+            }
+        }    
+        /// <summary>
+        /// tab显示
+        /// </summary>
+        public string TabText
+        {
+            get { return GetResult(m_TabText, m_TabName); }
+            set
+            {
+                m_TabText = value;
+            }
+        }
+        private string m_PanelName;
+        private string m_PanelText;
+        /// <summary>
+        /// panel名称
+        /// </summary>
+        public string PanelName
+        {
+            get { return GetResult(m_PanelName, m_PanelText); }
+            set
+            {
+                m_PanelName = value;
+            }
+        }
+        /// <summary>
+        /// panel显示
+        /// </summary>
+        public string PanelText
+        {
+            get { return GetResult(m_PanelText, m_PanelName); }
+            set
+            {
+                m_PanelText = value;
+            }
+        }
+        private string m_ButtonName;
+        private string m_ButtonText;
+        /// <summary>
+        /// button名称
+        /// </summary>
+        public string ButtonName
+        {
+            get { return GetResult(m_ButtonName, m_ButtonText); }
+            set
+            {
+                m_ButtonName = value;
+            }
+        }
+        /// <summary>
+        /// button显示
+        /// </summary>
+        public string ButtonText
+        {
+            get { return GetResult(m_ButtonText, m_ButtonName); }
+            set
+            {
+                m_ButtonText = value;
+            }
+        }
+        public string ImageName { get; set; }
+        public string Description { get; set; }
+        public string LongDescription { get; set; }
+        public RevitButtonStyle ButtonStyle { get; set; }
+        public string GroupName { get; set; }
+        public bool IsStack { get; set; }
+
+        private T GetResult<T>(T useResult, T spareResult) where T : class
+        {
+            return useResult ?? spareResult;
+        }
+        /// <summary>
+        /// 生成tab
+        /// </summary>
+        /// <returns></returns>
+        public RevitTab GetTab()
+        {
+            RevitTab tab = new RevitTab();
+            tab.Text = this.TabText;
+            tab.Name = this.TabName;
+
+            return tab;
+        }
+        /// <summary>
+        /// 生成Panel
+        /// </summary>
+        /// <returns></returns>
+        public RevitPanel GetPanel()
+        {
+            RevitPanel panel = new RevitPanel();
+            panel.Text = this.PanelText;
+            panel.Name = this.PanelName;
+            panel.TabName = this.TabName;
+            return panel;
+        }
+        /// <summary>
+        /// 生成Button
+        /// </summary>
+        /// <returns></returns>
+        public RevitButton GetButton()
+        {
+            RevitButton button = new RevitButton();
+            button.Text = this.ButtonText;
+            button.Name = this.ButtonName;
+            button.PanelName = this.PanelName;
+
+            button.IsStack = this.IsStack;
+            button.GroupName = this.GroupName;
+            button.ButtonStyle = this.ButtonStyle;
+            button.Description = this.Description;
+            button.LongDescription = this.LongDescription;
+            button.ImageName = this.ImageName;
+            return button;
+        }
+        
+    }
+}

+ 113 - 0
FWindSoft/FWindSoft.Revit/Menu/GroupButtons.cs

@@ -0,0 +1,113 @@
+/*-------------------------------------------------------------------------
+ * 功能描述:GroupButtons
+ * 作者:xulisong
+ * 创建时间: 2019/3/8 9:23:22
+ * 版本号:v1.0
+ *  -------------------------------------------------------------------------*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Autodesk.Revit.UI;
+
+namespace FWindSoft.Revit.Menu
+{
+    public class GroupButtons : List<RevitButton>
+    {
+        public GroupButtons()
+        { }
+        public GroupButtons(IEnumerable<RevitButton> source) : base(source)
+        { }
+
+        private void Valid()
+        {
+            if (!IsValid)
+            {
+                throw new Exception("分组数量不能为零");
+            }
+        }
+        public bool IsValid
+        {
+            get
+            {
+                return this.Any();
+            }
+        }
+        public bool IsStack
+        {
+            get
+            {
+                return this.Any(r => r.IsStack);
+            }
+        }
+        /// <summary>
+        /// 分组的按钮样式
+        /// </summary>
+        public RevitButtonStyle GroupButtonStyle
+        {
+            get
+            {
+                Valid();
+                return this.FirstOrDefault().ButtonStyle;
+            }
+        }
+
+        /// <summary>
+        /// 创建按钮数据
+        /// </summary>
+        /// <returns></returns>
+        public List<PushButtonData> CreatePushButtons()
+        {
+            List<PushButtonData> result = new List<PushButtonData>();
+            foreach (RevitButton button in this)
+            {
+                PushButtonData data = new PushButtonData(button.Name, button.Text, button.AssemblyName, button.ClassName);
+                RibbonItemUtil.AppendButtonData(data, button);
+                result.Add(data);
+            }
+            return result;
+        }
+
+        /// <summary>
+        /// 获取创建按钮的数据
+        /// </summary>
+        /// <returns></returns>
+        public ButtonData GetButtonData()
+        {
+            Valid();
+            var firstButton = this.FirstOrDefault();
+            switch (GroupButtonStyle)
+            {
+                case RevitButtonStyle.Pulldown:
+                {
+                        string name = firstButton.Name;
+                        string text = firstButton.Text;
+                        var data= new PulldownButtonData(name, text);
+                        RibbonItemUtil.AppendButtonData(data, firstButton);
+                        return data;
+                    }
+                case RevitButtonStyle.Split:
+                    {
+                        return new SplitButtonData(firstButton.Name, firstButton.Text);
+                    }
+                case RevitButtonStyle.Push:
+                    {
+                        return CreatePushButtons().FirstOrDefault();
+                    }
+            }
+            return null;
+        }
+
+        /// <summary>
+        /// 将子按钮附着单button上
+        /// </summary>
+        /// <param name="button"></param>
+        public void AppendButton(RibbonItem button)
+        {
+            var buttonDatas = CreatePushButtons();
+            RibbonItemUtil.AppendButtons(button, buttonDatas);
+        }
+    }
+}

+ 180 - 0
FWindSoft/FWindSoft.Revit/Menu/MenuConfig.cs

@@ -0,0 +1,180 @@
+/*-------------------------------------------------------------------------
+ * 功能描述:MenuManagerConfig
+ * 作者:xulisong
+ * 创建时间: 2019/3/7 15:58:29
+ * 版本号:v1.0
+ *  -------------------------------------------------------------------------*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+using Autodesk.Revit.UI;
+
+namespace FWindSoft.Revit.Menu
+{
+    public class MenuConfig
+    {
+        public MenuConfig()
+        {
+            Tabs = new RevitComponmentCollection<RevitTab>(this);
+            Panels = new RevitComponmentCollection<RevitPanel>(this);
+            Buttons = new RevitComponmentCollection<RevitButton>(this);
+        }
+        public MenuConfig(string configFile) : this()
+        { }
+        public RevitComponmentCollection<RevitTab> Tabs { get; private set; }
+        public RevitComponmentCollection<RevitPanel> Panels { get; private set; }
+        public RevitComponmentCollection<RevitButton> Buttons { get; private set; }
+        /// <summary>
+        /// 加载配置字符串信息
+        /// </summary>
+        /// <param name="configData"></param>
+        public void Load(string configData)
+        {
+          
+      
+        }
+
+        public void CreateUIRibbion(UIControlledApplication app)
+        {
+            #region 限定tab个数
+            var tabs = Tabs.ToList();
+            if (tabs.Count > 20)
+            {
+                tabs = tabs.GetRange(0, 20);
+            }
+            #endregion
+            for (int i = 0; i < tabs.Count; i++)
+            {
+                var currentTab = tabs[i];
+                var panels = Panels.Where(p => p.TabName == currentTab.Name).ToList();
+                var buttons = Buttons.Where(b => panels.Any(p => p.Name == b.PanelName)).ToList();
+                if (buttons.Count == 0)
+                {
+                    continue;
+                }
+                buttons=buttons.OrderBy(b => b.Index).ToList();
+                #region tab相关操作处理
+                List<RibbonPanel> ribbonPanels = new List<RibbonPanel>();
+                try
+                {
+                    //测试创建同名的tab会不会发生问题
+                    ribbonPanels = app.GetRibbonPanels(currentTab.Text);
+                }
+                catch (Exception e)
+                {
+                    app.CreateRibbonTab(currentTab.Name);
+                }
+                #endregion
+                foreach (var panel in panels)
+                {
+                    var useButtons = buttons.Where(b => b.PanelName == panel.Name).ToList();
+                    if (!useButtons.Any())
+                    {
+                        continue;
+                    }
+                    #region 初始化panel
+                    var existPanel = ribbonPanels.FirstOrDefault(p => p.Name == panel.Text);
+                    if (existPanel == null)
+                    {
+                        existPanel = app.CreateRibbonPanel(currentTab.Text, panel.Text);
+                    }
+                    #endregion
+                    List<GroupButtons> groupButtons = new List<GroupButtons>();
+                    List<RevitButton> cacheButtons = new List<RevitButton>();
+                    #region 处理按钮分组
+                    for (int j = 0; j < useButtons.Count; j++)
+                    {
+                        var currentButton = useButtons[j];
+                        if (!cacheButtons.Any())
+                        {
+                            cacheButtons.Add(currentButton);
+                        }
+                        else
+                        {
+                            //缓存存在
+                            var lastButton = cacheButtons.LastOrDefault();
+                            if (lastButton.ButtonStyle != currentButton.ButtonStyle)
+                            {
+                                groupButtons.Add(new GroupButtons(cacheButtons));
+                                cacheButtons = new List<RevitButton>();
+                            }
+                            else
+                            {
+                                if (lastButton.ButtonStyle == RevitButtonStyle.Push || lastButton.ButtonStyle == RevitButtonStyle.Separator || lastButton.GroupName != currentButton.GroupName)
+                                {
+                                    groupButtons.Add(new GroupButtons(cacheButtons));
+                                    cacheButtons = new List<RevitButton>();
+                                }
+                            }
+                            cacheButtons.Add(currentButton);
+                        }
+                    }
+                    if (cacheButtons.Any())
+                    {
+                        groupButtons.Add(new GroupButtons(cacheButtons));
+                    }
+                 
+                    #endregion
+                    List<GroupButtons> cacheGroupButtons = new List<GroupButtons>();
+                    for (int j = 0; j < groupButtons.Count; j++)
+                    {
+                        var groupButton = groupButtons[j];
+                        if (j == 0 && groupButton.GroupButtonStyle == RevitButtonStyle.Separator)
+                        {
+                            continue;
+                        }
+                        #region 创建核心处理
+                        try
+                        {
+                            if (groupButton.GroupButtonStyle == RevitButtonStyle.Separator)
+                            {
+                                if (cacheGroupButtons.Any())
+                                {
+                                    //创建异常处理
+                                    RibbonItemUtil.AddStackButton(existPanel, cacheGroupButtons);
+
+                                }
+                                cacheGroupButtons = new List<GroupButtons>();
+                                existPanel.AddSeparator();
+                            }
+                            else
+                            {
+                                if (groupButton.IsStack)
+                                {
+                                    cacheGroupButtons.Add(groupButton);
+                                }
+                                else
+                                {
+                                    if (cacheGroupButtons.Any())
+                                    {
+                                        RibbonItemUtil.AddStackButton(existPanel, cacheGroupButtons);
+                                    }
+                                    cacheGroupButtons = new List<GroupButtons>();
+                                    var data = groupButton.GetButtonData();
+                                    var ribbonItem = existPanel.AddItem(data);
+                                    groupButton.AppendButton(ribbonItem);
+                                }
+                            }
+                        }
+                        catch (Exception)
+                        {
+                           #if DEBUG
+                            throw;
+                           #endif
+                        }
+                        #endregion
+                    }
+
+                    if (cacheGroupButtons.Any())
+                    {
+                        RibbonItemUtil.AddStackButton(existPanel, cacheGroupButtons);
+                    }
+                }
+            }
+        }
+    }   
+}

+ 125 - 0
FWindSoft/FWindSoft.Revit/Menu/MenuConfigParser.cs

@@ -0,0 +1,125 @@
+/*-------------------------------------------------------------------------
+ * 功能描述:MenuConfigParser
+ * 作者:xulisong
+ * 创建时间: 2019/3/12 14:43:05
+ * 版本号:v1.0
+ *  -------------------------------------------------------------------------*/
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+using System.Xml;
+using FWindSoft.Tools;
+
+namespace FWindSoft.Revit.Menu
+{
+   public  class MenuConfigParser
+    {
+        public static MenuConfig Load(string path)
+        {
+            XmlDocument xmlDoc = new XmlDocument();
+            xmlDoc.Load(path);
+            return Load(xmlDoc);
+        }
+        public static MenuConfig LoadContent(string xmlContent)
+        {
+            XmlDocument xmlDoc = new XmlDocument();
+            xmlDoc.LoadXml(xmlContent);
+            return Load(xmlDoc);
+        }
+        public static MenuConfig Load(Stream steam)
+        {
+            XmlDocument xmlDoc = new XmlDocument();
+            xmlDoc.Load(steam);
+            return Load(xmlDoc);
+        }
+        public static MenuConfig Load(XmlDocument xmlDocument)
+        {
+            MenuConfig config = new MenuConfig();
+            var root = xmlDocument.SelectSingleNode(@"Menu");
+            if (root == null)
+            {
+                return config;
+            }
+            Dictionary<string, string> map = new Dictionary<string, string>();
+            map["Tabs"] = @"Tabs/Tab";
+            map["Panels"] = @"Panels/Panel";
+            map["Buttons"] = @"Buttons/Button";
+            #region 解析tab
+
+            var configProperties = typeof(MenuConfig).GetProperties(BindingFlags.Instance | BindingFlags.Public);
+            foreach (var keyValue in map)
+            {
+                var property = configProperties.FirstOrDefault(p => p.Name == keyValue.Key);
+                if (property == null)
+                {
+                    continue;
+                }
+                var nodes = root.SelectNodes(keyValue.Value);
+                if (nodes != null)
+                {
+                    foreach (XmlNode node in nodes)
+                    {
+                        var revitObject = CreateObject(node,property.PropertyType.GenericTypeArguments[0]);
+                        ((IList) property.GetValue(config)).Add(revitObject);
+                    }
+                }
+            }
+          
+            #endregion
+            return config;
+        }
+
+        #region 解析节点通用方法
+        private static T CreateObject<T>(XmlNode xmlNode)
+        {
+            T t = Activator.CreateInstance<T>();
+            PropertyInfo[] properties = t.GetType().GetProperties();
+            for (int i = 0; i < properties.Length; i++)
+            {
+                PropertyInfo propertyInfo = properties[i];
+                try
+                {
+                    var currentNode = xmlNode.SelectSingleNode(string.Format("/{0}", propertyInfo.Name));
+                    if (currentNode != null)
+                    {
+                        propertyInfo.SetValue(t, TypeUtil.ChangeType(currentNode.InnerText, propertyInfo.PropertyType) ?? "", null);
+                    }
+                }
+                catch (Exception ex)
+                {
+                }
+            }
+            return t;
+
+        }
+        private static object CreateObject(XmlNode xmlNode,Type targetType)
+        {
+            object t = Activator.CreateInstance(targetType);
+            PropertyInfo[] properties = t.GetType().GetProperties();
+            for (int i = 0; i < properties.Length; i++)
+            {
+                PropertyInfo propertyInfo = properties[i];
+                try
+                {
+                    var currentNode = xmlNode.SelectSingleNode(string.Format("{0}", propertyInfo.Name));
+                    if (currentNode != null)
+                    {
+                        propertyInfo.SetValue(t, TypeUtil.ChangeType(currentNode.InnerText, propertyInfo.PropertyType) ?? "", null);
+                    }
+                }
+                catch (Exception ex)
+                {
+                }
+            }
+            return t;
+
+        }
+        #endregion
+    }
+}

+ 53 - 0
FWindSoft/FWindSoft.Revit/Menu/RevitButton.cs

@@ -0,0 +1,53 @@
+/*-------------------------------------------------------------------------
+ * 功能描述:RevitButton
+ * 作者:xulisong
+ * 创建时间: 2019/3/7 15:37:11
+ * 版本号:v1.0
+ *  -------------------------------------------------------------------------*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit.Menu
+{
+    public class RevitButton:RevitMenuComponment
+    {
+        /// <summary>
+        /// 命令顺序
+        /// </summary>
+        public int Index { get;internal set; } = 0;
+        #region 描述属性
+        public string AssemblyName { get; set; }
+        public string ClassName { get; set; }
+        public string ImageName { get; set; }
+        public string Description { get; set; }
+        public string LongDescription { get; set; }
+        public bool Visible { get; set; }
+
+        /// <summary>
+        /// 按钮类型
+        /// </summary>
+        public RevitButtonStyle ButtonStyle { get; set; }
+        public string GroupName { get; set; }
+        public bool IsStack { get; set; }
+        #endregion
+
+        #region 关联属性
+        public string PanelName { get; set; }
+        #endregion
+
+        #region 相关方法
+        public RevitPanel GetPanel()
+        {
+            return Config.Panels.FirstOrDefault(t => t.Name == PanelName);
+        }
+        public RevitTab GetTab()
+        {
+            return GetPanel()?.GetTab();
+        } 
+        #endregion
+    }
+}

+ 23 - 0
FWindSoft/FWindSoft.Revit/Menu/RevitButtonStyle.cs

@@ -0,0 +1,23 @@
+/*-------------------------------------------------------------------------
+ * 功能描述:RevitButtonStyle
+ * 作者:xulisong
+ * 创建时间: 2019/3/7 18:10:48
+ * 版本号:v1.0
+ *  -------------------------------------------------------------------------*/
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit.Menu
+{
+    public enum RevitButtonStyle
+    {
+        Push,
+        Separator,
+        Pulldown,     
+        Split
+    }
+}

+ 81 - 0
FWindSoft/FWindSoft.Revit/Menu/RevitMenuComponment.cs

@@ -0,0 +1,81 @@
+/*-------------------------------------------------------------------------
+ * 功能描述:RevitMenuComponment
+ * 作者:xulisong
+ * 创建时间: 2019/3/7 15:38:41
+ * 版本号:v1.0
+ *  -------------------------------------------------------------------------*/
+
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FWindSoft.Revit.Menu
+{
+    public class RevitMenuComponment
+    {
+        public MenuConfig Config { get; internal set; }
+        /// <summary>
+        /// 名称
+        /// </summary>
+        public string Name { get; set; }
+        /// <summary>
+        /// 显示
+        /// </summary>
+        public string Text { get; set; }
+    }
+
+    /// <summary>
+    /// 节点集合
+    /// </summary>
+    public class RevitComponmentCollection<T> : Collection<T> where T: RevitMenuComponment
+    {
+        private MenuConfig m_Config;
+        internal RevitComponmentCollection(MenuConfig config)
+        {
+            m_Config = config;
+        }
+
+        protected override void ClearItems()
+        {
+            foreach (var item in this)
+            {
+                if (item != null)
+                {
+                    item.Config = null;
+                }
+
+            }
+            base.ClearItems();
+        }
+        protected override void InsertItem(int index, T item)
+        {
+
+            base.InsertItem(index, item);
+            item.Config = m_Config ;
+        }
+        protected override void RemoveItem(int index)
+        {
+            if (this[index] != null)
+            {
+                this[index].Config = null;
+            }
+            base.RemoveItem(index);
+        }
+        protected override void SetItem(int index, T item)
+        {
+
+            base.SetItem(index, item);
+            item.Config = m_Config;
+        }
+        public void AddRange(IEnumerable<T> items)
+        {
+            foreach (var item in items)
+            {
+                this.Add(item);
+            }
+        }
+    }
+}

+ 0 - 0
FWindSoft/FWindSoft.Revit/Menu/RevitPanel.cs


この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません