├── .gitignore ├── AdnRme.sln ├── AdnRme ├── AboutBox.Designer.cs ├── AboutBox.cs ├── AboutBox.resx ├── AdnRme.addin ├── AdnRme.csproj ├── App.cs ├── Bip.cs ├── CmdAbout.cs ├── CmdAssignFlowToTerminals.cs ├── CmdChangeSize.cs ├── CmdElectricalConnectors.cs ├── CmdElectricalHierarchy2.cs ├── CmdElectricalSystemBrowser.cs ├── CmdInspectElectricalForm.Designer.cs ├── CmdInspectElectricalForm.cs ├── CmdInspectElectricalForm.resx ├── CmdInspectElectricallForm2.cs ├── CmdInspectElectricallForm2.designer.cs ├── CmdInspectElectricallForm2.resx ├── CmdPopulateCfmPerSf.cs ├── CmdResetDemo.cs ├── CmdUnhostedElements.cs ├── Command.cs ├── Const.cs ├── FamilySelector.Designer.cs ├── FamilySelector.cs ├── FamilySelector.resx ├── PanelTreeNodeHelper.cs ├── ParameterName.cs ├── ParameterValue.cs ├── ProgressForm.Designer.cs ├── ProgressForm.cs ├── ProgressForm.resx ├── Properties │ └── AssemblyInfo.cs ├── Util.cs └── WaitCursor.cs ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.sln.docstates 8 | 9 | # Build results 10 | [Dd]ebug/ 11 | [Dd]ebugPublic/ 12 | [Rr]elease/ 13 | x64/ 14 | build/ 15 | bld/ 16 | [Bb]in/ 17 | [Oo]bj/ 18 | 19 | # MSTest test Results 20 | [Tt]est[Rr]esult*/ 21 | [Bb]uild[Ll]og.* 22 | 23 | #NUNIT 24 | *.VisualState.xml 25 | TestResult.xml 26 | 27 | # Build Results of an ATL Project 28 | [Dd]ebugPS/ 29 | [Rr]eleasePS/ 30 | dlldata.c 31 | 32 | *_i.c 33 | *_p.c 34 | *_i.h 35 | *.ilk 36 | *.meta 37 | *.obj 38 | *.pch 39 | *.pdb 40 | *.pgc 41 | *.pgd 42 | *.rsp 43 | *.sbr 44 | *.tlb 45 | *.tli 46 | *.tlh 47 | *.tmp 48 | *.tmp_proj 49 | *.log 50 | *.vspscc 51 | *.vssscc 52 | .builds 53 | *.pidb 54 | *.svclog 55 | *.scc 56 | 57 | # Chutzpah Test files 58 | _Chutzpah* 59 | 60 | # Visual C++ cache files 61 | .vs/ 62 | ipch/ 63 | *.aps 64 | *.ncb 65 | *.opensdf 66 | *.sdf 67 | *.cachefile 68 | 69 | # Visual Studio profiler 70 | *.psess 71 | *.vsp 72 | *.vspx 73 | 74 | # TFS 2012 Local Workspace 75 | $tf/ 76 | 77 | # Guidance Automation Toolkit 78 | *.gpState 79 | 80 | # ReSharper is a .NET coding add-in 81 | _ReSharper*/ 82 | *.[Rr]e[Ss]harper 83 | *.DotSettings.user 84 | 85 | # JustCode is a .NET coding addin-in 86 | .JustCode 87 | 88 | # TeamCity is a build add-in 89 | _TeamCity* 90 | 91 | # DotCover is a Code Coverage Tool 92 | *.dotCover 93 | 94 | # NCrunch 95 | *.ncrunch* 96 | _NCrunch_* 97 | .*crunch*.local.xml 98 | 99 | # MightyMoose 100 | *.mm.* 101 | AutoTest.Net/ 102 | 103 | # Web workbench (sass) 104 | .sass-cache/ 105 | 106 | # Installshield output folder 107 | [Ee]xpress/ 108 | 109 | # DocProject is a documentation generator add-in 110 | DocProject/buildhelp/ 111 | DocProject/Help/*.HxT 112 | DocProject/Help/*.HxC 113 | DocProject/Help/*.hhc 114 | DocProject/Help/*.hhk 115 | DocProject/Help/*.hhp 116 | DocProject/Help/Html2 117 | DocProject/Help/html 118 | 119 | # Click-Once directory 120 | publish/ 121 | 122 | # Publish Web Output 123 | *.[Pp]ublish.xml 124 | *.azurePubxml 125 | 126 | # NuGet Packages Directory 127 | packages/ 128 | ## TODO: If the tool you use requires repositories.config uncomment the next line 129 | #!packages/repositories.config 130 | 131 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets 132 | # This line needs to be after the ignore of the build folder (and the packages folder if the line above has been uncommented) 133 | !packages/build/ 134 | 135 | # Windows Azure Build Output 136 | csx/ 137 | *.build.csdef 138 | 139 | # Windows Store app package directory 140 | AppPackages/ 141 | 142 | # Others 143 | sql/ 144 | *.Cache 145 | ClientBin/ 146 | [Ss]tyle[Cc]op.* 147 | ~$* 148 | *~ 149 | *.dbmdl 150 | *.dbproj.schemaview 151 | *.pfx 152 | *.publishsettings 153 | node_modules/ 154 | 155 | # RIA/Silverlight projects 156 | Generated_Code/ 157 | 158 | # Backup & report files from converting an old project file to a newer 159 | # Visual Studio version. Backup files are not needed, because we have git ;-) 160 | _UpgradeReport_Files/ 161 | Backup*/ 162 | UpgradeLog*.XML 163 | UpgradeLog*.htm 164 | 165 | # SQL Server files 166 | *.mdf 167 | *.ldf 168 | 169 | # Business Intelligence projects 170 | *.rdl.data 171 | *.bim.layout 172 | *.bim_*.settings 173 | 174 | # Microsoft Fakes 175 | FakesAssemblies/ 176 | -------------------------------------------------------------------------------- /AdnRme.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AdnRme", "AdnRme\AdnRme.csproj", "{DBAF92E6-72D5-4C38-ADC7-754F11E27E3A}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Any CPU = Debug|Any CPU 9 | Release|Any CPU = Release|Any CPU 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {DBAF92E6-72D5-4C38-ADC7-754F11E27E3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 13 | {DBAF92E6-72D5-4C38-ADC7-754F11E27E3A}.Debug|Any CPU.Build.0 = Debug|Any CPU 14 | {DBAF92E6-72D5-4C38-ADC7-754F11E27E3A}.Release|Any CPU.ActiveCfg = Release|Any CPU 15 | {DBAF92E6-72D5-4C38-ADC7-754F11E27E3A}.Release|Any CPU.Build.0 = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /AdnRme/AboutBox.Designer.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeremytammik/AdnRme/d2764222508f2dce275815bf95b755ae94754415/AdnRme/AboutBox.Designer.cs -------------------------------------------------------------------------------- /AdnRme/AboutBox.cs: -------------------------------------------------------------------------------- 1 | #region Header 2 | // Revit MEP API sample application 3 | // 4 | // Copyright (C) 2007-2021 by Jeremy Tammik, Autodesk, Inc. 5 | // 6 | // Permission to use, copy, modify, and distribute this software 7 | // for any purpose and without fee is hereby granted, provided 8 | // that the above copyright notice appears in all copies and 9 | // that both that copyright notice and the limited warranty and 10 | // restricted rights notice below appear in all supporting 11 | // documentation. 12 | // 13 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 14 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 15 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. 16 | // AUTODESK, INC. DOES NOT WARRANT THAT THE OPERATION OF THE 17 | // PROGRAM WILL BE UNINTERRUPTED OR ERROR FREE. 18 | // 19 | // Use, duplication, or disclosure by the U.S. Government is subject 20 | // to restrictions set forth in FAR 52.227-19 (Commercial Computer 21 | // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) 22 | // (Rights in Technical Data and Computer Software), as applicable. 23 | #endregion // Header 24 | 25 | #region Namespaces 26 | using System; 27 | using System.Windows.Forms; 28 | using System.Reflection; 29 | #endregion // Namespaces 30 | 31 | namespace AdnRme 32 | { 33 | partial class AboutBox : Form 34 | { 35 | public AboutBox() 36 | { 37 | InitializeComponent(); 38 | 39 | // Initialize the AboutBox to display the product 40 | // information from the assembly information. 41 | // Change assembly information settings for your 42 | // application through either Project > Properties 43 | // > Application > Assembly Information or 44 | // by editing AssemblyInfo.cs 45 | 46 | Text = "About " + AssemblyTitle; 47 | labelProductName.Text = AssemblyProduct; 48 | labelVersion.Text = "Version " + AssemblyVersion; 49 | labelCopyright.Text = AssemblyCopyright; 50 | labelCompanyName.Text = AssemblyCompany; 51 | textBoxDescription.Text = AssemblyDescription; 52 | } 53 | 54 | #region Assembly Attribute Accessors 55 | 56 | /// 57 | /// Short cut to get executing assembly 58 | /// 59 | Assembly ExecutingAssembly 60 | { 61 | get 62 | { 63 | return Assembly.GetExecutingAssembly(); 64 | } 65 | } 66 | 67 | object GetFirstCustomAttribute( Type t ) 68 | { 69 | Assembly a = ExecutingAssembly; 70 | object[] attributes 71 | = a.GetCustomAttributes( t, false ); 72 | return ( 0 < attributes.Length ) 73 | ? attributes[0] 74 | : null; 75 | } 76 | 77 | public string AssemblyTitle 78 | { 79 | get 80 | { 81 | // Get all Title attributes on this assembly 82 | //object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes( typeof( AssemblyTitleAttribute ), false ); 83 | //object[] attributes = GetCustomAttributes( typeof( AssemblyTitleAttribute ) ); 84 | object a = GetFirstCustomAttribute( typeof( AssemblyTitleAttribute ) ); 85 | // If there is at least one Title attribute 86 | if( null != a ) 87 | { 88 | // Select the first one 89 | AssemblyTitleAttribute titleAttribute = (AssemblyTitleAttribute) a; 90 | // If it is not an empty string, return it 91 | if( titleAttribute.Title != "" ) 92 | return titleAttribute.Title; 93 | } 94 | // If there was no Title attribute, or if the Title attribute was the empty string, return the .exe name 95 | return System.IO.Path.GetFileNameWithoutExtension( ExecutingAssembly.CodeBase ); 96 | } 97 | } 98 | 99 | public string AssemblyVersion 100 | { 101 | get 102 | { 103 | return ExecutingAssembly.GetName().Version.ToString(); 104 | } 105 | } 106 | 107 | public string AssemblyDescription 108 | { 109 | get 110 | { 111 | // Get all Description attributes on this assembly 112 | //object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes( typeof( AssemblyDescriptionAttribute ), false ); 113 | //object[] attributes = GetCustomAttributes( typeof( AssemblyDescriptionAttribute ) ); 114 | object a = GetFirstCustomAttribute( typeof( AssemblyDescriptionAttribute ) ); 115 | // If there aren't any Description attributes, return an empty string 116 | //if( attributes.Length == 0 ) 117 | // return ""; 118 | // If there is a Description attribute, return its value 119 | //return ( (AssemblyDescriptionAttribute) attributes[0] ).Description; 120 | return (null == a) 121 | ? string.Empty 122 | : ( (AssemblyDescriptionAttribute) a ).Description; 123 | } 124 | } 125 | 126 | public string AssemblyProduct 127 | { 128 | get 129 | { 130 | // Get all Product attributes on this assembly 131 | //object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes( typeof( AssemblyProductAttribute ), false ); 132 | //object[] attributes = GetCustomAttributes( typeof( AssemblyProductAttribute ) ); 133 | object a = GetFirstCustomAttribute( typeof( AssemblyProductAttribute ) ); 134 | // If there aren't any Product attributes, return an empty string 135 | //if( attributes.Length == 0 ) 136 | // return ""; 137 | // If there is a Product attribute, return its value 138 | //return ( (AssemblyProductAttribute) attributes[0] ).Product; 139 | return ( null == a ) 140 | ? string.Empty 141 | : ( ( AssemblyProductAttribute ) a ).Product; 142 | } 143 | } 144 | 145 | public string AssemblyCopyright 146 | { 147 | get 148 | { 149 | // Get all Copyright attributes on this assembly 150 | //object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes( typeof( AssemblyCopyrightAttribute ), false ); 151 | //object[] attributes = GetCustomAttributes( typeof( AssemblyCopyrightAttribute ) ); 152 | object a = GetFirstCustomAttribute( typeof( AssemblyCopyrightAttribute ) ); 153 | // If there aren't any Copyright attributes, return an empty string 154 | //if( attributes.Length == 0 ) 155 | // return ""; 156 | // If there is a Copyright attribute, return its value 157 | //return ( (AssemblyCopyrightAttribute) attributes[0] ).Copyright; 158 | return ( null == a ) 159 | ? string.Empty 160 | : ( ( AssemblyCopyrightAttribute ) a ).Copyright; 161 | } 162 | } 163 | 164 | public string AssemblyCompany 165 | { 166 | get 167 | { 168 | // Get all Company attributes on this assembly 169 | //object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes( typeof( AssemblyCompanyAttribute ), false ); 170 | //object[] attributes = GetCustomAttributes( typeof( AssemblyCompanyAttribute ) ); 171 | object a = GetFirstCustomAttribute( typeof( AssemblyCompanyAttribute ) ); 172 | // If there aren't any Company attributes, return an empty string 173 | //if( attributes.Length == 0 ) 174 | // return ""; 175 | // If there is a Company attribute, return its value 176 | //return ( (AssemblyCompanyAttribute) attributes[0] ).Company; 177 | return ( null == a ) 178 | ? string.Empty 179 | : ( ( AssemblyCompanyAttribute ) a ).Company; 180 | } 181 | } 182 | #endregion 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /AdnRme/AboutBox.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 122 | 123 | iVBORw0KGgoAAAANSUhEUgAAAHgAAAEGCAIAAAAhWcaAAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8 124 | YQUAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAD2JJREFUeF7tnU2S 125 | 5CgShWN2dZSq5Vxjlm02i57zzHJOUmZZu5ij1DLP0btskCtcHvw6wnGBoCwrLDIDIcnj4/FwkPSPH9+/ 126 | vj0efz32f6H3/zeff3t828r8y/zPlbflVhkI6BEHE+jcz8eP788f3+E1W3gVCEfggbH7Jwni+3sTX/j5 127 | iJc5al9lIKROHGygc6GBEEOsA1Uwvqr1NXwdRMdlYUmHgB4u6VBqo4toAVo5HmFptFL/sYhWJDrnJZa9 128 | E9DxRbQi0Y18tBmA5tqKkj4yxgoCzGKXiCdO99uQaLo/Tr98jzKQ4vDPpZWPfiWpOPXfimsMdGAInkPp 129 | zMjQD3RuL0pa2fowYifeykfT/eX6AEl9vHZfeNZ+/9REo+n+plJqP9BHD8nIvRX76GCgr2VNx//ECDPn 130 | 3oRoOKupWKbSH3UdOdZO5qOXj14+uq3DUfXRIB25tnIfv0H7AAi0ko9eGu0Y9lY+2vazK9dBuG7oOlqP 131 | wcaqn5OLKPbRDG9+q/wG53zFiHa8euzXsTDkHC3zxMU0Gvb3Ff8HBe7nQ5gnLkm0CXIs1vD3W44V8dSC 132 | jOGnYhqNIfZjTT/SyTlothvmiQsTDd+qL1v4R/TXSDe8gU2o+/YLYAqFK4uMckG/T48E60gcObLs7PDt 133 | 7/4YxutDWbkOCjJtTShhqNF4GsAdDbR/VujHUd+xjNNUY1oZ/DtWQv0+/Wr97wjHuj4BFC/UTycgrYgO 134 | cs0gjFUk2BmUBlrzCPfWmtNNlo9mEp3gguLsaIjDXQJSv0dKE01zMoAqbUP0aw+2Ldj8SqKDaoWNzldG 135 | KC/pW1lto6BXyGq0v8O2Gk3Rxq8a37T2A87e8ctrt19KtN9tHLAzIGLNgsP+/CjTWDOZZRxSNKEcC3RN 136 | neltmScu6aNjUaYSlusPanMgfqDbsUztZnZIzJFFLtEcVWxHFp42PWedNpQ9cavvUj6aUY/GfIq+RjPb 137 | qBjRrVFl1q+v0dwD88aBPncsH+3XY865tT769etrdPAY/PbdkGgFffRp6oHo4Ik31GgFD+vrYw8aTQON 138 | vC+i5dd4RInO9ZtLo8v8EgT65us65tJox8Breo9rNdo5ccp1E43298c0m/XFriWanrhzLmK5DsdH4y4Z 139 | Pr02v0H7mGt9NA20kkb7ga6nlVPDtURDzhr+BYjOaShrztDpZ+nOcvWX9elpj3StRmOgA+NkBias7F1w 140 | kMaoXNjGXk40xDoQDYaGnvTRvpdk7KtWr6/V6ETbbeI69EHGPfZAdPD0G+Y6FPjtM9cR5HoRLdxJxFpz 141 | Kx+dy5/UanGsfmesZH7V9DyzaDREWXnOkNkh3Uej/SjThcKXcx3VaL8N9v8Xf/0KEzeFYgGNdtAwvz5/ 142 | Pp+/nh8/P56/Pp8/P835bO+f8PfEkga1jxzFwJUkl3j5YP/hDcm9yyNsoPcom1j/NrF2woefqoU1uJKx 143 | Z5ztcJF+5zEuCL+fHxvRwX8X0h3sAy/X5bfYUnmKBTpNNA36VbGmRx5MNSiocHoXh3TEotx/H+gcIbk3 144 | MM07Xvw+FegXGjR79/vH908GHbK39LYx+uPfJiv2YfqLUV9RR+J5L8qCifInT/uOWPPKJ8aKNn34iq95 145 | M+Z7mvfy2iCc/AmiYUMpru03DfE1XA/6E5UO7FJe90IHri3RJXkMEa7t/di3QD9NlP/zp431cK/5QFcQ 146 | Da2hPj12F6Lxej8nHfPS1nMafaiHoEaPyDIcc2uiRZS6lmiOQ20t/flA12n0EegKrms1OjhEcJqvKdNU 147 | 9/OBrtPojoiOZQ7gazCvTaE+ch3SPpr64krvcfjocxqNoUxko25AdL33cDU6oblBKpEhf0N6cWuMaBHY 148 | 89JRrdG7eohoNObKEVIndqCzEBrb12/K6wQahAKrwuR1UKOD9Z9QcxNoy8s2xqV5ZzMSMx/RMSG8N7mO 149 | E77Yr6f4L9uA5ZgP5BiJdBnnOl/EllPzCTV/YK7Z7IDOm0DcydwKvv96/vp6/rSvH9sr432wnmOOZtuv 150 | oSydx7DHQ1t6MCJ8ov1Ac4jGtlLaWxwU+0RD3L3XPb4QZd5rsB6nZgh0LD+3Hye92jkYaGCN4gm/xjbM 151 | ajTu5QTFdBMzH7jHizZM+LZLmOVwnShj5h5tFjSmfb5oFKkkDbRjn2mgi+o8QbSlMkgHj1Y+14mShm5L 152 | dKLfp0dYChf2nGl7V1ptUXmjy/b8Yz0AQ38rWYbo7xrNJLqYpu30sgOWtkRnO1kVrlNEJ7SYyVT2HKEA 153 | s7ZzxVL3XkSlbs91SqN9GM1fmtJX2mI45fOB7oFof83GOawu3CofaBXvkdLoFkTrt4l8oG9JdGtF9ptO 154 | PtC8sV+l99DW6EV0YJI7KB2Vatsp0eycxmmul0bbTJPI2C+dFcn4aHHX0SnRd/LRzuBFzY/nO8ObEV2T 155 | M6npGPKBvpmPdgK9iD7sh7jrkEoxFwHOIvpOGg3zAMtHa/hohVzdyZHh8tGc/Fy6TF46buY6ioRVsHA+ 156 | 0LfMddQTWlpDPtCLaBGu84G+mY8uJVGqfH46bREtQ3R7j8xZ06Sdj5bilF/PsUpGhdxYDk87eycCaVEl 157 | exb0aq6189F8EqVKLqKVLlw81t6p+OWYXi+N5q4XrZyFWRpdtg56mDlDKeXl17M0emn065rvFiuV+CRK 158 | lVxEaxHdPtfMuc5l+ejlOoTuELJ8tNLdP5ZGL42+mevAhPTK3hVl40oLH5crORHXzedNkOtwhgPmV/b1 159 | sJX5DZqbniDXERx3qcwTUn89gY/2Aw2LkXW5noPoMNRKeTvgegKNBnKhJ6RXoC+iS31FuvwxZ+gvPFCc 160 | c5lAo5Fc334oOusJNLr/+3XcLR+9iJYVZae2N4127s6yNFrwCpdjHLiIbkv00mipWcHMiv/lOpqCjJUv 161 | jVafYVka3RTtAe57t3y0YIZvgpEhrusIzgBozbOsXMda1yG4rgPzdv7IUGsdk2o++pprwYP3y4RbC941 162 | e3fNteDB698U7+GYvzepuOvAU9YZE8JebK6DxppOstySaHqyTY2zm70zvgJUIrHuoL330NNoJ9CC+bmV 163 | 63hbXedIpRrUk+Y6TLjVWD40Gu/V7di7W2o0IGwCrcbyvsc589EzE308r8Ltr0OPKq/k8QKi+8h1WDeN 164 | vfbrgSz2aSH0uUCCT5iYlmi7WioI6fZkFvskHqf/GI/oPjT6jWjHD4DBN+vzBInWHBN25TqiRINDgBAj 165 | 1/oKW9mA7Fl0qNFBovfFxBvXpQobzOf4I5emzrqTdR0sopHrUqIhprEH3sA3V1pnKeOdzBnmNdrpDIvo 166 | gyjHYo2fFtVZqvLjEf0CsOCp9xhiP9b0o1JIi8oPptHAdUJzY88kjG2YdTK4r0reRyU6Fm4nlQHKS7FF 167 | oXCEO6bRfp9ZBPKxUmkUH+1oNMdIpMs4qo1OhlPzCboX0fs3yCT6tDm5p0ZDOGJPUabMLo1m3ePfZEE4 168 | itmF6xhUo19PS7ZPT80q5vLRb6v3YmwGze/Rm8efVEvKdDAy7CrX8Xh8hn5Mj/358fPTvD63101ksWT0 169 | 2ctIOsdIoOvItg9OG/LLdOI67DPCH4//PR6/twg6r6bH/r3Fen/dAneU4cj05WVkch1ZZHJr+PTWdZzj 170 | sX4rGaJ9GY2tl4zMrK/10bx7HOQDnalnrY/OrY/Oika2wMb4TvQ2Q2jnZN9f7ZzhVmZ/3eoMlvS37eYv 171 | CR+djZGTl0lk1mMfmRro/Tro/Dd5b8o8t3t67LHe9osRNG9GeB+8zhBDnJ2VSItGNvSWzEmIDvpozUBv 172 | 3/Su0RE2LdGgG8D1i+hBWLYN7plyHTrSQYmOLO1wp/vMgV3ui0sPoMpHi2t0en4km2mrd7vtaqj10bIa 173 | fWeiK3Md9YGmGr2Ijj7Vuz7QS6MPVUlcw1IfaE6X69jE1pm2Fkp9vUZvYxa70AtecV1A8D1+WtrpX16+ 174 | ds5QhGhYveisF00HulHWuAXL++xl5R1oRAI9BdGVc4Yygd7WiNLV5rRafxdLo7O5DbcA9IRTEH25j16u 175 | g3V3g3rpWD5ayUfPdf9ouMeBM9HHvHKW0/ZjZV6eZ80Z8uYMq58JsOYMc3OGTOpz91efgOhKH13N8jX3 176 | +Nd34rW5jkGJhj5DMwFSm+sQuse0qkZjz9wus9Hz2jtje+waXP8nOASvgZFaoJp6iratmjOUu9eS6to7 177 | Gmi1LOB0Gu04+iIqawpPrdGa3mM6ooFKZcth97h8tI73WESrP3PWTyoJeeQenwuuqc4yc4bjjgxrLMSJ 178 | bSfVaB1dpnuZVKNPIFm5yZt/96/wkRv7HdduhurM5Dr8eYPSER1ndqK0zqLy+6wKHMe5GZZcrjm6bo/o 179 | e9t8tH92/nR9a2f9Fmga620VwB6j9lynch0wvnAyQWU0Je+phPdYKaqzVOVT0iHkKGqJhkDTFWKlcomb 180 | +4lAvD1Kc6Ir13UIee2URvuBTgtuIBf8/j05m+PCyRjRUL6S9wFcB2YnnC4EAxRMyCGh+KlTHhUju0LV 181 | Ua3S9rQff/+5jn1k5fXVHCORKOMHuuhuCMUaXbmaVEjHU64DCXKUGiNVSjTVZSrfMVT9b+sE1APko9/G 182 | VwyMsQW87lKzbxOTGqZGgxadVuphNJoJEZXmWFOIdYbMXZwrNkCuo4YjR9/T9u40rZwjvBvRQdwgvsEo 183 | Uz05hypzq8E0msNO0EcztL3WKaePbQqimdA1LTaFRp9rB7JbLaLXnOGfDZ/YXZ+7KOV9UqJb5+p8uZ9U 184 | oxfRWoqpuzjaZnqHyEeLj9kW0c2JDqb6mjrowfLRpb18ojyNtXhbie13RtchMmNS2ghm1GgMtGArybaM 185 | GYm2HmD7V0plTfl5fXTljElpa5iX6Bo8T2w7o0Zn9bSUVk75SYk+gWTlJpNqNIdB2TKL6OZj0X1kOGeu 186 | Q5ZWTm2LaC2iu1l7tz/XnkPHiGU6IXp/ijJ9FkVlL9/b5p346MBTlPF+/yPy6x9zX0QHMYSI90Zo6fF0 187 | 4qNTzwUHOky4LxnRSbWnAYhGdobm2mq0c/EBrvsTuj6Fcy14nujRubZEx9YLC63m51yVtbsOjvANynVq 188 | laXidYZcosflejyi99TBaD5kMI2mHmAsHzKS63AUPHafPI7Q65cZxkcHxlqP/POTpVxwfT0DE21OfiAH 189 | 0m+ugzMOBPXglLy8zCJ6rnx0mY9GihfR3NEgvXvNprnBJ91/Jv8evkevvq9I77ETjbbPk308/vt4mJiW 190 | /ozhPTrRaNbdDXqDtOh4OvHRmXsqXe4Z6r3N31AGkrd5WtJ5AAAAAElFTkSuQmCC 191 | 192 | 193 | -------------------------------------------------------------------------------- /AdnRme/AdnRme.addin: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | AdnRme 5 | Y:\a\src\rvt\AdnRme\AdnRme\bin\Debug\AdnRme.dll 6 | 62e0c2bf-02f4-4a95-be8d-4de120048dbb 7 | AdnRme.App 8 | com.typepad.thebuildingcoder 9 | The Building Coder, http://thebuildingcoder.typepad.com 10 | NotVisibleInArchitecture 11 | NotVisibleInFamily 12 | NotVisibleInStructure 13 | NotVisibleWhenNoActiveDocument 14 | 15 | 16 | -------------------------------------------------------------------------------- /AdnRme/AdnRme.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | None 6 | 7 | 8 | 9 | Debug 10 | AnyCPU 11 | 9.0.30729 12 | 2.0 13 | {DBAF92E6-72D5-4C38-ADC7-754F11E27E3A} 14 | Library 15 | Properties 16 | AdnRme 17 | v4.8 18 | 512 19 | 20 | 21 | 3.5 22 | 23 | publish\ 24 | true 25 | Disk 26 | false 27 | Foreground 28 | 7 29 | Days 30 | false 31 | false 32 | true 33 | 0 34 | 1.0.0.%2a 35 | false 36 | false 37 | true 38 | 39 | 40 | 41 | true 42 | full 43 | false 44 | bin\Debug\ 45 | DEBUG;TRACE 46 | prompt 47 | 4 48 | Program 49 | $(ProgramFiles)\Autodesk\Revit Architecture 2011\Program\Revit.exe 50 | AllRules.ruleset 51 | false 52 | 53 | 54 | pdbonly 55 | true 56 | bin\Release\ 57 | TRACE 58 | prompt 59 | 4 60 | Program 61 | $(ProgramFiles)\Autodesk\Revit Architecture 2011\Program\Revit.exe 62 | AllRules.ruleset 63 | false 64 | 65 | 66 | 67 | C:\Program Files\Autodesk\Revit 2021\RevitAPI.dll 68 | False 69 | 70 | 71 | C:\Program Files\Autodesk\Revit 2021\RevitAPIUI.dll 72 | False 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | Form 82 | 83 | 84 | AboutBox.cs 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | Form 96 | 97 | 98 | CmdInspectElectricalForm.cs 99 | 100 | 101 | Form 102 | 103 | 104 | CmdInspectElectricallForm2.cs 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | Form 113 | 114 | 115 | 116 | 117 | 118 | 119 | Form 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | AboutBox.cs 132 | 133 | 134 | CmdInspectElectricalForm.cs 135 | 136 | 137 | CmdInspectElectricallForm2.cs 138 | 139 | 140 | 141 | 142 | 143 | 144 | False 145 | .NET Framework 3.5 SP1 Client Profile 146 | false 147 | 148 | 149 | False 150 | .NET Framework 3.5 SP1 151 | true 152 | 153 | 154 | False 155 | Windows Installer 3.1 156 | true 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | copy "$(ProjectDir)AdnRme.addin" "$(AppData)\Autodesk\REVIT\Addins\2021" 165 | 166 | -------------------------------------------------------------------------------- /AdnRme/App.cs: -------------------------------------------------------------------------------- 1 | #region Header 2 | // Revit MEP API sample application 3 | // 4 | // Copyright (C) 2007-2021 by Jeremy Tammik, Autodesk, Inc. 5 | // 6 | // Permission to use, copy, modify, and distribute this software 7 | // for any purpose and without fee is hereby granted, provided 8 | // that the above copyright notice appears in all copies and 9 | // that both that copyright notice and the limited warranty and 10 | // restricted rights notice below appear in all supporting 11 | // documentation. 12 | // 13 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 14 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 15 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. 16 | // AUTODESK, INC. DOES NOT WARRANT THAT THE OPERATION OF THE 17 | // PROGRAM WILL BE UNINTERRUPTED OR ERROR FREE. 18 | // 19 | // Use, duplication, or disclosure by the U.S. Government is subject 20 | // to restrictions set forth in FAR 52.227-19 (Commercial Computer 21 | // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) 22 | // (Rights in Technical Data and Computer Software), as applicable. 23 | #endregion // Header 24 | 25 | #region Namespaces 26 | using System.Collections.Generic; 27 | using System.Diagnostics; 28 | using System.Reflection; 29 | using Autodesk.Revit.Attributes; 30 | using Autodesk.Revit.UI; 31 | using Autodesk.Revit.ApplicationServices; 32 | #endregion // Namespaces 33 | 34 | namespace AdnRme 35 | { 36 | /// 37 | /// This MEP sample demonstrates use of the generic and the MEP 38 | /// specific parts of the Revit API for tasks in Revit MEP. 39 | /// 40 | /// The following HVAC tasks are adressed using the generic API: 41 | /// 42 | /// - determine air terminals for each space. 43 | /// - assign flow to the air terminals depending on the space's calculated supply air flow. 44 | /// - change size of diffuser, i.e. type, based on flow. 45 | /// - populate the value of the 'CFM per SF' variable on all spaces. 46 | /// - enter two element id's and create a 3D sectioned box view of their extents. 47 | /// - determine unhosted elements (cf. SPR 134098). 48 | /// - reset demo to original state. 49 | /// 50 | /// CFM = cubic feet per second, SF = square feet. 51 | /// Revit internal units are feet and seconds, so we need to multiply by 60 to get CFM. 52 | /// 53 | /// The electrical conection hierarchy is determined and displayed in a tree view 54 | /// using both the generic Revit API, based on parameters, and the MEP specific API, 55 | /// based on connectors. 56 | /// 57 | /// For Revit 2009, we implemented an external application demonstrating how to create 58 | /// an own add-in menu. In Revit 2010, this was migrated to the ribbon and a custom panel. 59 | /// One can also use RvtSamples from the Revit SDK Samples directory to load 60 | /// this MEP sample, with the following additional entries in RvtSamples.txt: 61 | /// 62 | /// ADN Rme 63 | /// About... 64 | /// About ADN RME API Samples 65 | /// LargeImage: 66 | /// Image: 67 | /// C:\a\j\adn\train\revit\2011\src\rme\mep\bin\Debug\mep.dll 68 | /// mep.CmdAbout 69 | /// 70 | /// ADN Rme 71 | /// Electrical System Browser 72 | /// Inspect electrical systems in model and reproduce system browser info using parameter data only 73 | /// LargeImage: 74 | /// Image: 75 | /// C:\a\j\adn\train\revit\2011\src\rme\mep\bin\Debug\mep.dll 76 | /// mep.CmdElectricalSystemBrowser 77 | /// 78 | /// #ADN Rme 79 | /// #Electrical Hierarchy 80 | /// #Inspect electrical systems in model and display full connection hierarchy tree structure 81 | /// #LargeImage: 82 | /// #Image: 83 | /// #C:\a\j\adn\train\revit\2011\src\rme\mep\bin\Debug\mep.dll 84 | /// #mep.CmdElectricalHierarchy 85 | /// # 86 | /// #ADN Rme 87 | /// #Electrical Hierarchy 2 88 | /// #Inspect electrical systems in model and display full connection hierarchy tree structure 89 | /// #LargeImage: 90 | /// #Image: 91 | /// #C:\a\j\adn\train\revit\2011\src\rme\mep\bin\Debug\mep.dll 92 | /// #mep.CmdElectricalHierarchy2 93 | /// 94 | /// ADN Rme 95 | /// Electrical Hierarchy Tree 96 | /// Inspect electrical systems and connectors in model and display full hierarchy tree structure 97 | /// LargeImage: 98 | /// Image: 99 | /// C:\a\j\adn\train\revit\2011\src\rme\mep\bin\Debug\mep.dll 100 | /// mep.CmdElectricalConnectors 101 | /// 102 | /// ADN Rme 103 | /// HVAC Assign flow to terminals 104 | /// Assign flow to terminals 105 | /// LargeImage: 106 | /// Image: 107 | /// C:\a\j\adn\train\revit\2011\src\rme\mep\bin\Debug\mep.dll 108 | /// mep.CmdAssignFlowToTerminals 109 | /// 110 | /// ADN Rme 111 | /// HVAC Change size 112 | /// Change terminal sizes 113 | /// LargeImage: 114 | /// Image: 115 | /// C:\a\j\adn\train\revit\2011\src\rme\mep\bin\Debug\mep.dll 116 | /// mep.CmdChangeSize 117 | /// 118 | /// ADN Rme 119 | /// HVAC Populate CFM per SF on rooms 120 | /// Populate CFM per SF variable on rooms 121 | /// LargeImage: 122 | /// Image: 123 | /// C:\a\j\adn\train\revit\2011\src\rme\mep\bin\Debug\mep.dll 124 | /// mep.CmdPopulateCfmPerSf 125 | /// 126 | /// ADN Rme 127 | /// HVAC Reset demo 128 | /// Reset ADN RME API Demo 129 | /// LargeImage: 130 | /// Image: 131 | /// C:\a\j\adn\train\revit\2011\src\rme\mep\bin\Debug\mep.dll 132 | /// mep.CmdResetDemo 133 | /// 134 | /// ADN Rme 135 | /// Unhosted elements 136 | /// List unhosted elementes 137 | /// LargeImage: 138 | /// Image: 139 | /// C:\a\j\adn\train\revit\2011\src\rme\mep\bin\Debug\mep.dll 140 | /// mep.CmdUnhostedElements 141 | /// 142 | class App : IExternalApplication 143 | { 144 | /// 145 | /// Create a ribbon panel for the MEP sample application. 146 | /// We present a column of three buttons: Electrical, HVAC and About. 147 | /// The first two include subitems, the third does not. 148 | /// 149 | static void AddRibbonPanel( 150 | UIControlledApplication a ) 151 | { 152 | const int nElectricalCommands = 3; 153 | 154 | const string m = "AdnRme.Cmd"; // namespace and command prefix 155 | 156 | string path = Assembly.GetExecutingAssembly().Location; 157 | 158 | string[] text = new string[] { 159 | "Electrical Connectors", 160 | "Electrical System Browser", 161 | //"Electrical Hierarchy", 162 | //"Electrical Hierarchy 2", 163 | "Unhosted elements", 164 | "Assign flow to terminals", 165 | "Change size", 166 | "Populate CFM per SF on spaces", 167 | "Reset demo", 168 | "About..." 169 | }; 170 | 171 | string[] classNameStem = new string[] { 172 | "ElectricalConnectors", 173 | "ElectricalSystemBrowser", 174 | //"ElectricalHierarchy", 175 | //"ElectricalHierarchy2", 176 | "UnhostedElements", 177 | "AssignFlowToTerminals", 178 | "ChangeSize", 179 | "PopulateCfmPerSf", 180 | "ResetDemo", 181 | "About" 182 | }; 183 | 184 | int n = classNameStem.Length; 185 | 186 | Debug.Assert( text.Length == n, 187 | "expected equal number of text and class name entries" ); 188 | 189 | // Create three stacked buttons for the HVAC, 190 | // electrical and about commands, respectively: 191 | 192 | RibbonPanel panel = a.CreateRibbonPanel( 193 | "MEP Sample" ); 194 | 195 | PulldownButtonData d1 = new PulldownButtonData( 196 | "Electrical", "Electrical" ); 197 | 198 | d1.ToolTip = "Electrical Commands"; 199 | 200 | PulldownButtonData d2 = new PulldownButtonData( 201 | "Hvac", "HVAC" ); 202 | 203 | d2.ToolTip = "HVAC Commands"; 204 | 205 | n = n - 1; 206 | 207 | PushButtonData d3 = new PushButtonData( 208 | classNameStem[n], text[n], path, m + classNameStem[n] ); 209 | 210 | d3.ToolTip = "About the HVAC and Electrical MEP Sample."; 211 | 212 | IList ribbonItems = panel.AddStackedItems( 213 | d1, d2, d3 ); 214 | 215 | // Add subitems to the HVAC and 216 | // electrical pulldown buttons: 217 | 218 | PulldownButton pulldown; 219 | PushButton pb; 220 | int i, j; 221 | 222 | for( i = 0; i < n; ++i ) 223 | { 224 | j = i < nElectricalCommands ? 0 : 1; 225 | pulldown = ribbonItems[j] as PulldownButton; 226 | 227 | PushButtonData pbd = new PushButtonData( 228 | text[i], text[i], path, m + classNameStem[i] ); 229 | 230 | pb = pulldown.AddPushButton( pbd ); 231 | 232 | pb.ToolTip = text[i]; 233 | } 234 | } 235 | 236 | public Result OnStartup( UIControlledApplication a ) 237 | { 238 | // only create a new ribbon panel in Revit MEP: 239 | 240 | ProductType pt = a.ControlledApplication.Product; 241 | 242 | //if( ProductType.MEP == pt ) // 2012 243 | 244 | if( ProductType.MEP == pt 245 | || ProductType.Revit == pt ) // 2013 246 | { 247 | AddRibbonPanel( a ); 248 | return Result.Succeeded; 249 | } 250 | return Result.Cancelled; 251 | } 252 | 253 | public Result OnShutdown( UIControlledApplication a ) 254 | { 255 | return Result.Succeeded; 256 | } 257 | } 258 | } 259 | 260 | // C:\Program Files\Autodesk\Revit Architecture 2011\Program\Revit.exe 261 | // C:\a\j\adn\train\revit\2011\src\rme\test\hvac_project.rvt 262 | 263 | // C:\Program Files\Autodesk\Revit MEP 2011\Program\Revit.exe 264 | // C:\a\j\adn\train\revit\2011\src\rme\test\elec_project.rvt 265 | -------------------------------------------------------------------------------- /AdnRme/Bip.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeremytammik/AdnRme/d2764222508f2dce275815bf95b755ae94754415/AdnRme/Bip.cs -------------------------------------------------------------------------------- /AdnRme/CmdAbout.cs: -------------------------------------------------------------------------------- 1 | #region Header 2 | // Revit MEP API sample application 3 | // 4 | // Copyright (C) 2007-2021 by Jeremy Tammik, Autodesk, Inc. 5 | // 6 | // Permission to use, copy, modify, and distribute this software 7 | // for any purpose and without fee is hereby granted, provided 8 | // that the above copyright notice appears in all copies and 9 | // that both that copyright notice and the limited warranty and 10 | // restricted rights notice below appear in all supporting 11 | // documentation. 12 | // 13 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 14 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 15 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. 16 | // AUTODESK, INC. DOES NOT WARRANT THAT THE OPERATION OF THE 17 | // PROGRAM WILL BE UNINTERRUPTED OR ERROR FREE. 18 | // 19 | // Use, duplication, or disclosure by the U.S. Government is subject 20 | // to restrictions set forth in FAR 52.227-19 (Commercial Computer 21 | // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) 22 | // (Rights in Technical Data and Computer Software), as applicable. 23 | #endregion // Header 24 | 25 | #region Namespaces 26 | using System; 27 | using Autodesk.Revit.Attributes; 28 | using Autodesk.Revit.DB; 29 | using Autodesk.Revit.UI; 30 | using DialogResult = System.Windows.Forms.DialogResult; 31 | #endregion // Namespaces 32 | 33 | namespace AdnRme 34 | { 35 | /// 36 | /// Command to display "About..." box. 37 | /// 38 | [Transaction( TransactionMode.ReadOnly )] 39 | public class CmdAbout : IExternalCommand 40 | { 41 | #region Execute Command 42 | /// 43 | /// Execute the command to display "About..." box. 44 | /// 45 | public Result Execute( 46 | ExternalCommandData commandData, 47 | ref String message, 48 | ElementSet elements ) 49 | { 50 | try 51 | { 52 | AboutBox a = new AboutBox(); 53 | DialogResult r = a.ShowDialog(); 54 | return Result.Cancelled; 55 | } 56 | catch( Exception ex ) 57 | { 58 | message = ex.Message; 59 | return Result.Failed; 60 | } 61 | } 62 | #endregion // Execute Command 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /AdnRme/CmdAssignFlowToTerminals.cs: -------------------------------------------------------------------------------- 1 | #region Header 2 | // Revit MEP API sample application 3 | // 4 | // Copyright (C) 2007-2021 by Jeremy Tammik, Autodesk, Inc. 5 | // 6 | // Permission to use, copy, modify, and distribute this software 7 | // for any purpose and without fee is hereby granted, provided 8 | // that the above copyright notice appears in all copies and 9 | // that both that copyright notice and the limited warranty and 10 | // restricted rights notice below appear in all supporting 11 | // documentation. 12 | // 13 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 14 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 15 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. 16 | // AUTODESK, INC. DOES NOT WARRANT THAT THE OPERATION OF THE 17 | // PROGRAM WILL BE UNINTERRUPTED OR ERROR FREE. 18 | // 19 | // Use, duplication, or disclosure by the U.S. Government is subject 20 | // to restrictions set forth in FAR 52.227-19 (Commercial Computer 21 | // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) 22 | // (Rights in Technical Data and Computer Software), as applicable. 23 | #endregion // Header 24 | 25 | #region Namespaces 26 | using System; 27 | using System.Collections.Generic; 28 | using System.Diagnostics; 29 | using Autodesk.Revit.ApplicationServices; 30 | using Autodesk.Revit.Attributes; 31 | using Autodesk.Revit.DB; 32 | using Autodesk.Revit.DB.Mechanical; 33 | using Autodesk.Revit.UI; 34 | #endregion // Namespaces 35 | 36 | namespace AdnRme 37 | { 38 | [Transaction( TransactionMode.Manual )] 39 | class CmdAssignFlowToTerminals : IExternalCommand 40 | { 41 | #region Get Terminals Per Space 42 | /// 43 | /// Helper class for sorting the spaces by space number before listing them 44 | /// 45 | class NumericalComparer : IComparer 46 | { 47 | public int Compare( string x, string y ) 48 | { 49 | return int.Parse( x ) - int.Parse( y ); 50 | } 51 | } 52 | 53 | static Dictionary> GetTerminalsPerSpace( 54 | Document doc ) 55 | { 56 | FilteredElementCollector terminals = Util.GetSupplyAirTerminals( doc ); 57 | 58 | Dictionary> terminalsPerSpace 59 | = new Dictionary>(); 60 | 61 | foreach( FamilyInstance terminal in terminals ) 62 | { 63 | //string roomNr = terminal.Room.Number; 64 | string spaceNr = terminal.Space.Number; // changed Room to Space 65 | if( !terminalsPerSpace.ContainsKey( spaceNr ) ) 66 | { 67 | terminalsPerSpace.Add( spaceNr, new List() ); 68 | } 69 | terminalsPerSpace[spaceNr].Add( terminal ); 70 | } 71 | 72 | List keys = new List( terminalsPerSpace.Keys ); 73 | keys.Sort( new NumericalComparer() ); 74 | 75 | string ids; 76 | List spaceTerminals; 77 | int n, nTerminals = 0; 78 | 79 | foreach( string key in keys ) 80 | { 81 | spaceTerminals = terminalsPerSpace[key]; 82 | n = spaceTerminals.Count; 83 | ids = Util.IdList( spaceTerminals ); 84 | 85 | Debug.WriteLine( string.Format( 86 | "Space {0} contains {1} air terminal{2}{3} {4}", 87 | key, n, Util.PluralSuffix( n ), Util.DotOrColon( n ), ids ) ); 88 | 89 | nTerminals += n; 90 | } 91 | n = terminalsPerSpace.Count; 92 | 93 | Debug.WriteLine( string.Format( 94 | "Processing a total of {0} space{1} containing {2} air terminal{3}.", 95 | n, Util.PluralSuffix( n ), nTerminals, Util.PluralSuffix( nTerminals ) ) ); 96 | 97 | return terminalsPerSpace; 98 | } 99 | #endregion // Get Terminals Per Space 100 | 101 | #region AssignFlowToTerminals 102 | 103 | static double RoundFlowTo( double a ) 104 | { 105 | a = a / Const.RoundTerminalFlowTo; 106 | a = Math.Round( a, 0, MidpointRounding.AwayFromZero ); 107 | a = a * Const.RoundTerminalFlowTo; 108 | return a; 109 | } 110 | 111 | static void AssignFlowToTerminals( List terminals, double flow ) 112 | { 113 | foreach( FamilyInstance terminal in terminals ) 114 | { 115 | Parameter p = Util.GetTerminalFlowParameter( terminal ); 116 | p.Set( flow ); 117 | } 118 | } 119 | 120 | static void AssignFlowToTerminalsForSpace( 121 | List terminals, 122 | Space space ) 123 | { 124 | Debug.Assert( null != terminals, "expected valid list of terminals" ); 125 | int n = terminals.Count; 126 | 127 | double calculatedSupplyAirFlow = Util.GetSpaceParameterValue( 128 | space, Bip.CalculatedSupplyAirFlow, ParameterName.CalculatedSupplyAirFlow ); 129 | 130 | double flowCfm = calculatedSupplyAirFlow * Const.SecondsPerMinute; 131 | double flowCfmPerOutlet = flowCfm / n; 132 | double flowCfmPerOutletRounded = RoundFlowTo( flowCfmPerOutlet ); 133 | double flowPerOutlet = flowCfmPerOutletRounded / Const.SecondsPerMinute; 134 | 135 | string format = "Space {0} has calculated supply airflow {1} f^3/s = {2} CFM and {3} terminal{4}" 136 | + " --> flow {5} CFM per terminal, rounded to {6} = {7} f^3/s"; 137 | 138 | Debug.WriteLine( string.Format( format, 139 | space.Number, Util.RealString( calculatedSupplyAirFlow ), Util.RealString( flowCfm ), 140 | n, Util.PluralSuffix( n ), Util.RealString( flowCfmPerOutlet ), 141 | Util.RealString( flowCfmPerOutletRounded ), Util.RealString( flowPerOutlet ) ) ); 142 | 143 | AssignFlowToTerminals( terminals, flowPerOutlet ); 144 | } 145 | #endregion // AssignFlowToTerminals 146 | 147 | #region Execute Command 148 | public Result Execute( 149 | ExternalCommandData commandData, 150 | ref String message, 151 | ElementSet elements ) 152 | { 153 | try 154 | { 155 | WaitCursor waitCursor = new WaitCursor(); 156 | UIApplication uiapp = commandData.Application; 157 | Document doc = uiapp.ActiveUIDocument.Document; 158 | // 159 | // 1. determine air terminals for each space. 160 | // determine the relationship between all air terminals and all spaces: 161 | // extract and group all air terminals per space 162 | // (key=space, val=set of air terminals) 163 | // 164 | Debug.WriteLine( "\nDetermining terminals per space..." ); 165 | Dictionary> terminalsPerSpace = GetTerminalsPerSpace( doc ); 166 | // 167 | // 2. assign flow to the air terminals depending on the space's calculated supply air flow. 168 | // 169 | //ElementFilterIterator it = doc.get_Elements( typeof( Room ) ); // 2008 170 | //ElementIterator it = doc.get_Elements( typeof( Space ) ); // 2009 171 | //List spaces = new List(); // 2009 172 | //doc.get_Elements( typeof( Space ), spaces ); // 2009 173 | //FilteredElementCollector collector = new FilteredElementCollector( doc ); 174 | //collector.OfClass( typeof( Space ) ); 175 | //IList spaces = collector.ToElements(); 176 | 177 | using( Transaction tx = new Transaction( doc ) ) 178 | { 179 | List spaces = Util.GetSpaces( doc ); 180 | int n = spaces.Count; 181 | 182 | string s = "{0} of " + n.ToString() + " spaces processed..."; 183 | string caption = "Assign Flow to Terminals"; 184 | tx.Start( caption ); 185 | 186 | using( ProgressForm pf = new ProgressForm( caption, s, n ) ) 187 | { 188 | foreach( Space space in spaces ) 189 | { 190 | if( terminalsPerSpace.ContainsKey( space.Number ) ) 191 | { 192 | AssignFlowToTerminalsForSpace( terminalsPerSpace[space.Number], space ); 193 | } 194 | pf.Increment(); 195 | } 196 | } 197 | tx.Commit(); 198 | Debug.WriteLine( "Completed." ); 199 | return Result.Succeeded; 200 | } 201 | } 202 | catch( Exception ex ) 203 | { 204 | message = ex.Message; 205 | return Result.Failed; 206 | } 207 | } 208 | #endregion // Execute Command 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /AdnRme/CmdChangeSize.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeremytammik/AdnRme/d2764222508f2dce275815bf95b755ae94754415/AdnRme/CmdChangeSize.cs -------------------------------------------------------------------------------- /AdnRme/CmdElectricalConnectors.cs: -------------------------------------------------------------------------------- 1 | #region Header 2 | // Revit MEP API sample application 3 | // 4 | // Copyright (C) 2007-2021 by Jeremy Tammik, Autodesk, Inc. 5 | // 6 | // Permission to use, copy, modify, and distribute this software 7 | // for any purpose and without fee is hereby granted, provided 8 | // that the above copyright notice appears in all copies and 9 | // that both that copyright notice and the limited warranty and 10 | // restricted rights notice below appear in all supporting 11 | // documentation. 12 | // 13 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 14 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 15 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. 16 | // AUTODESK, INC. DOES NOT WARRANT THAT THE OPERATION OF THE 17 | // PROGRAM WILL BE UNINTERRUPTED OR ERROR FREE. 18 | // 19 | // Use, duplication, or disclosure by the U.S. Government is subject 20 | // to restrictions set forth in FAR 52.227-19 (Commercial Computer 21 | // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) 22 | // (Rights in Technical Data and Computer Software), as applicable. 23 | #endregion // Header 24 | 25 | #region Namespaces 26 | using System; 27 | using System.Collections.Generic; 28 | using System.Diagnostics; 29 | using TreeNode = System.Windows.Forms.TreeNode; 30 | using Autodesk.Revit.ApplicationServices; 31 | using Autodesk.Revit.Attributes; 32 | using Autodesk.Revit.DB; 33 | using Autodesk.Revit.DB.Electrical; 34 | using Autodesk.Revit.UI; 35 | #endregion // Namespaces 36 | 37 | namespace AdnRme 38 | { 39 | [Transaction( TransactionMode.ReadOnly )] 40 | class CmdElectricalConnectors : IExternalCommand 41 | { 42 | #region Test code 43 | #if TEST_CODE 44 | /// 45 | /// Get the connected connector of one connector 46 | /// 47 | /// The connector to be analyzed 48 | /// The connected connector 49 | static Connector GetConnectedConnector( Connector connector ) 50 | { 51 | Connector connectedConnector = null; 52 | ConnectorSet allRefs = connector.AllRefs; 53 | foreach( Connector c in allRefs ) 54 | { 55 | // ignore non-EndConn connectors and connectors of the current element: 56 | if( ConnectorType.EndConn != c.ConnectorType 57 | || c.Owner.Id.Equals( connector.Owner.Id ) ) 58 | { 59 | continue; 60 | } 61 | connectedConnector = c; 62 | break; 63 | } 64 | return connectedConnector; 65 | } 66 | 67 | static void PopulateChildren( 68 | MapParentToChildren mapParentToChildren, 69 | Element parent ) 70 | { 71 | Connector c2 = null; 72 | ElementId id = parent.Id; 73 | FamilyInstance fi = parent as FamilyInstance; 74 | ElectricalSystem eq = parent as ElectricalSystem; 75 | Debug.Assert( null != fi || null != eq, "expected element to be family instance or electrical system" ); 76 | ConnectorSet connectors = (null == eq) 77 | ? fi.MEPModel.ConnectorManager.Connectors 78 | : eq.ConnectorManager.Connectors; 79 | foreach( Connector c in connectors ) 80 | { 81 | Debug.Assert( c.Owner.Id.Equals( id ), "expected connector owner to be this element" ); 82 | //if( c.IsConnected ) // only valid for PhysicalConn 83 | //MEPSystem mepSystem = c.MEPSystem; // null for electrical connector 84 | //if( null == mepSystem ) // || !mepSystem.Id.IntegerValue.Equals( m_system.Id.IntegerValue ) 85 | //{ 86 | // continue; 87 | //} 88 | //c2 = GetConnectedConnector( c ); 89 | 90 | ConnectorSet refs = c.AllRefs; 91 | Debug.Assert( 1 == refs.Size, "expected one single connected connector" ); 92 | foreach( Connector tmp in refs ) 93 | { 94 | c2 = tmp; 95 | } 96 | if( null != c2 ) 97 | { 98 | Element e = c2.Owner; 99 | Debug.Assert( null != e, "expected valid connector owner" ); 100 | Debug.Assert( e is FamilyInstance || e is ElectricalSystem, "expected electrical connector owner to be family instance or electrical equipment" ); 101 | mapParentToChildren.Add( id, e ); 102 | } 103 | } 104 | } 105 | #endif // TEST_CODE 106 | #endregion // Test code 107 | 108 | public Result Execute( 109 | ExternalCommandData commandData, 110 | ref String message, 111 | ElementSet elements ) 112 | { 113 | UIApplication app = commandData.Application; 114 | Document doc = app.ActiveUIDocument.Document; 115 | // 116 | // retrieve electrical equipment: 117 | // 118 | List equipment = Util.GetElectricalEquipment( doc ); 119 | int n = equipment.Count; 120 | Debug.WriteLine( string.Format( 121 | "Retrieved {0} electrical equipment instance{1}{2}", 122 | n, Util.PluralSuffix( n ), Util.DotOrColon( n ) ) ); 123 | // 124 | // determine which equipment has parents; 125 | // the remaining ones are root nodes: 126 | // 127 | Dictionary equipmentParents 128 | = new Dictionary(); 129 | 130 | foreach( FamilyInstance fi in equipment ) 131 | { 132 | foreach( Connector c in fi.MEPModel.ConnectorManager.Connectors ) 133 | { 134 | ConnectorSet refs = c.AllRefs; 135 | foreach( Connector c2 in refs ) 136 | { 137 | Debug.Assert( null != c2.Owner, 138 | "expected valid connector owner" ); 139 | 140 | Debug.Assert( c2.Owner is ElectricalSystem, 141 | "expected panel element to be electrical system" ); 142 | 143 | ElectricalSystem eq = c2.Owner as ElectricalSystem; 144 | foreach( Element e2 in eq.Elements ) 145 | { 146 | Debug.Assert( e2 is FamilyInstance, 147 | "expected electrical system element to be family instance" ); 148 | 149 | if( !e2.Id.Equals( fi.Id ) ) 150 | { 151 | if( equipment.Exists( 152 | delegate( Element e ) 153 | { return e.Id.Equals( e2.Id ); } ) ) 154 | { 155 | equipmentParents[e2.Id] = eq.Id; 156 | } 157 | } 158 | } 159 | } 160 | } 161 | } 162 | 163 | //n = equipment.RemoveAll( delegate( Element e ) { return subequipment.Exists( delegate( Element e2 ) { return e2.Id.Equals( e.Id ); } ); } ); 164 | 165 | // 166 | // populate parent to children mapping: 167 | // 168 | ElementId nullId = ElementId.InvalidElementId; 169 | MapParentToChildren mapParentToChildren = new MapParentToChildren(); 170 | 171 | foreach( FamilyInstance fi in equipment ) 172 | { 173 | //ElementId parentId = equipmentParents.ContainsKey( fi.Id ) ? equipmentParents[fi.Id] : nullId; 174 | //mapParentToChildren.Add( parentId, fi ); 175 | 176 | // 177 | // handle root nodes; 178 | // non-roots are handled below a children: 179 | // 180 | if( !equipmentParents.ContainsKey( fi.Id ) ) 181 | { 182 | mapParentToChildren.Add( nullId, fi ); 183 | } 184 | 185 | foreach( Connector c in fi.MEPModel.ConnectorManager.Connectors ) 186 | { 187 | ConnectorSet refs = c.AllRefs; 188 | foreach( Connector c2 in refs ) 189 | { 190 | Debug.Assert( null != c2.Owner, 191 | "expected valid connector owner" ); 192 | 193 | Debug.Assert( c2.Owner is ElectricalSystem, 194 | "expected panel element to be electrical system" ); 195 | 196 | ElectricalSystem eq = c2.Owner as ElectricalSystem; 197 | mapParentToChildren.Add( fi.Id, eq ); 198 | foreach( Element e2 in eq.Elements ) 199 | { 200 | Debug.Assert( e2 is FamilyInstance, 201 | "expected electrical system element to be family instance" ); 202 | 203 | if( !e2.Id.Equals( fi.Id ) ) 204 | { 205 | mapParentToChildren.Add( eq.Id, e2 ); 206 | } 207 | } 208 | } 209 | } 210 | } 211 | 212 | #region Test code 213 | #if TEST_CODE 214 | // 215 | // retrieve electrical systems: 216 | // 217 | List systems = new List(); 218 | doc.get_Elements( typeof( ElectricalSystem ), systems ); 219 | n = systems.Count; 220 | Debug.WriteLine( string.Format( "Retrieved {0} electrical system{1}{2}", 221 | n, Util.PluralSuffix( n ), Util.DotOrColon( n ) ) ); 222 | // 223 | // iterate over all electrical systems and recursively add 224 | // connected ecomponents starting from the system base equipment: 225 | // 226 | /* 227 | Dictionary systemDict = new Dictionary( n ); 228 | foreach( ElectricalSystem s in systems ) 229 | { 230 | systemDict[s.Name] = s; 231 | } 232 | List keys = new List( systemDict.Keys ); 233 | keys.Sort(); 234 | foreach( string key in keys ) 235 | { 236 | FamilyInstance b = systemDict[key].BaseEquipment; 237 | if( null != b ) 238 | { 239 | mapParentToChildren.Add( nullId, b ); // root node 240 | PopulateChildren( mapParentToChildren, b ); 241 | } 242 | } 243 | foreach( ElectricalSystem s in systems ) 244 | { 245 | FamilyInstance b = s.BaseEquipment; 246 | if( null != b ) 247 | { 248 | mapParentToChildren.Add( nullId, b ); // root node 249 | PopulateChildren( mapParentToChildren, b ); 250 | } 251 | } 252 | #endif // TEST_CODE 253 | #endregion // Test code 254 | 255 | // 256 | // get the electrical equipment category id: 257 | // 258 | Categories categories = doc.Settings.Categories; 259 | ElementId electricalEquipmentCategoryId = categories.get_Item( 260 | BuiltInCategory.OST_ElectricalEquipment ).Id; 261 | 262 | // 263 | // display hierarchical structure in tree view: 264 | // 265 | CmdInspectElectricalForm2 dialog 266 | = new CmdInspectElectricalForm2( 267 | mapParentToChildren, electricalEquipmentCategoryId, equipment ); 268 | 269 | dialog.Show(); 270 | return Result.Failed; 271 | } 272 | } 273 | } 274 | -------------------------------------------------------------------------------- /AdnRme/CmdElectricalHierarchy2.cs: -------------------------------------------------------------------------------- 1 | #region Header 2 | // Revit MEP API sample application 3 | // 4 | // Copyright (C) 2007-2021 by Jeremy Tammik, Autodesk, Inc. 5 | // 6 | // Permission to use, copy, modify, and distribute this software 7 | // for any purpose and without fee is hereby granted, provided 8 | // that the above copyright notice appears in all copies and 9 | // that both that copyright notice and the limited warranty and 10 | // restricted rights notice below appear in all supporting 11 | // documentation. 12 | // 13 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 14 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 15 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. 16 | // AUTODESK, INC. DOES NOT WARRANT THAT THE OPERATION OF THE 17 | // PROGRAM WILL BE UNINTERRUPTED OR ERROR FREE. 18 | // 19 | // Use, duplication, or disclosure by the U.S. Government is subject 20 | // to restrictions set forth in FAR 52.227-19 (Commercial Computer 21 | // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) 22 | // (Rights in Technical Data and Computer Software), as applicable. 23 | #endregion // Header 24 | 25 | #region Namespaces 26 | using System; 27 | using System.Collections.Generic; 28 | using System.Diagnostics; 29 | using TreeNode = System.Windows.Forms.TreeNode; 30 | using Autodesk.Revit.ApplicationServices; 31 | using Autodesk.Revit.Attributes; 32 | using Autodesk.Revit.DB; 33 | using Autodesk.Revit.DB.Electrical; 34 | using Autodesk.Revit.UI; 35 | #endregion // Namespaces 36 | 37 | namespace AdnRme 38 | { 39 | #region MapParentToChildren 40 | /// 41 | /// Map tree node parents to their children. 42 | /// 43 | /// The various possible combinations of parent and child 44 | /// element types include: 45 | /// 46 | /// null --> root panels 47 | /// panel --> systems 48 | /// system --> circuit elements, further panels, ... 49 | /// 50 | /// This map is populated as follows: as we iterate over all the relevant 51 | /// electrical equipment, systems, and circuit objects. Each object 52 | /// attempts to identify its parent, i.e. its destination parent node 53 | /// in the tree and registers itself in the parent's list of elements. 54 | /// We attempted to use the parent element itself as a key, but that 55 | /// does not work, so we reverted to using the parent element id as 56 | /// a key instead. 57 | /// 58 | public class MapParentToChildren : Dictionary> 59 | { 60 | /// 61 | /// Add a new parent, or a new child to a parent, ensuring that a new container 62 | /// list is created if this parent has not yet been registered. 63 | /// 64 | /// Parent element id 65 | /// New child element 66 | public void Add( ElementId parentId, Element child ) 67 | { 68 | if( !this.ContainsKey( parentId ) ) 69 | { 70 | this.Add( parentId, new List() ); 71 | } 72 | if( null != child ) 73 | { 74 | this[parentId].Add( child ); 75 | } 76 | } 77 | } 78 | 79 | #region Using Element as Key 80 | /// 81 | /// I tried to use the Element instance itself as a key into this map, 82 | /// but apparently the comparison does not always work correctly, so I 83 | /// had to revert to using the element id instead. 84 | /// 85 | public class MapParentToChildren2 : Dictionary> 86 | { 87 | Element _root; 88 | 89 | public MapParentToChildren2( Element root ) 90 | { 91 | _root = root; 92 | } 93 | 94 | public Element Root 95 | { 96 | get 97 | { 98 | return _root; 99 | } 100 | } 101 | 102 | public void Add( Element parent, Element child ) 103 | { 104 | if( !this.ContainsKey( parent ) ) 105 | { 106 | this.Add( parent, new List() ); 107 | } 108 | this[parent].Add( child ); 109 | } 110 | } 111 | #endregion // Using Element as Key 112 | #endregion // MapParentToChildren 113 | 114 | #region CmdElectricalHierarchy2 115 | /// 116 | /// Inspect the electrical system. 117 | /// 118 | /// Analyse the electrical system connection graph and display it in 119 | /// tree view in a a modeless dialogue, i.e. it remains visible after 120 | /// the command has completed. 121 | /// 122 | /// This presents a more direct approach than the first implementation 123 | /// in CmdElectricalSystemBrowser. In this implementation, we directly 124 | /// build the tree hierarchy in a MapParentToChildren dictionary from 125 | /// the element relationships. Also, we use element ids wherever 126 | /// possible, instead of key strings of the form 127 | /// "panel name : circuit or system name". 128 | /// 129 | /// Note: this sample was written before the introduction of the 130 | /// Connector and ConnectionManager classes. The complex determination 131 | /// of the connection hierarchy based on parameter values performed 132 | /// here can be much simplified using the connectors, as demonstrated 133 | /// by CmdElectricalConnectors. 134 | /// 135 | [Transaction( TransactionMode.ReadOnly )] 136 | class CmdElectricalHierarchy2 : IExternalCommand 137 | { 138 | public Result Execute( 139 | ExternalCommandData commandData, 140 | ref String message, 141 | ElementSet elements ) 142 | { 143 | try 144 | { 145 | // 146 | // dictionary defining tree view info displayed in modeless 147 | // dialogue mapping parent node to all its circuit elements: 148 | // null --> root panels 149 | // panel --> systems 150 | // system --> circuit elements, panels, ... 151 | // 152 | MapParentToChildren mapParentToChildren = new MapParentToChildren(); 153 | ElementId electricalEquipmentCategoryId = ElementId.InvalidElementId; 154 | List equipment; 155 | { 156 | // 157 | // run the analysis in its own scope, so the wait cursor 158 | // disappears before we display the modeless dialogue: 159 | // 160 | WaitCursor waitCursor = new WaitCursor(); 161 | UIApplication app = commandData.Application; 162 | Document doc = app.ActiveUIDocument.Document; 163 | ElementId nullId = ElementId.InvalidElementId; 164 | // 165 | // retrieve electrical equipment instances: 166 | // 167 | equipment = Util.GetElectricalEquipment( doc ); 168 | int n = equipment.Count; 169 | Debug.WriteLine( string.Format( "Retrieved {0} electrical equipment instance{1}{2}", 170 | n, Util.PluralSuffix( n ), Util.DotOrColon( n ) ) ); 171 | Dictionary mapPanel = new Dictionary(); 172 | foreach( FamilyInstance e in equipment ) 173 | { 174 | // 175 | // ensure that every panel shows up in the list, 176 | // even if it does not have children: 177 | // 178 | mapParentToChildren.Add( e.Id, null ); 179 | mapPanel[e.Name] = e; 180 | MEPModel mepModel = e.MEPModel; 181 | //ElectricalSystemSet systems2 = mepModel.ElectricalSystems; // 2020 182 | ISet systems2 = mepModel.GetElectricalSystems(); // 2021 183 | string panelAndSystem = string.Empty; 184 | if( null == systems2 ) 185 | { 186 | panelAndSystem = CmdElectricalSystemBrowser.Unassigned; // this is a root node 187 | } 188 | else 189 | { 190 | Debug.Assert( 1 == systems2.Count, 191 | "expected equipment to belong to one single panel and system" ); 192 | 193 | foreach( ElectricalSystem system in systems2 ) 194 | { 195 | if( 0 < panelAndSystem.Length ) 196 | { 197 | panelAndSystem += ", "; 198 | } 199 | panelAndSystem += system.PanelName + ":" + system.Name + ":" + system.Id.IntegerValue.ToString(); 200 | } 201 | } 202 | Debug.WriteLine( " " + Util.ElementDescriptionAndId( e ) + " " + panelAndSystem ); 203 | } 204 | // 205 | // retrieve electrical systems: 206 | // these are also returned by Util.GetCircuitElements(), by the way, 207 | // since they have the parameters RBS_ELEC_CIRCUIT_PANEL_PARAM and 208 | // RBS_ELEC_CIRCUIT_NUMBER that we use to identify those. 209 | // 210 | FilteredElementCollector c = new FilteredElementCollector( doc ); 211 | IList systems = c.OfClass( typeof( ElectricalSystem ) ).ToElements(); 212 | n = systems.Count; 213 | Debug.WriteLine( string.Format( "Retrieved {0} electrical system{1}{2}", 214 | n, Util.PluralSuffix( n ), Util.DotOrColon( n ) ) ); 215 | foreach( ElectricalSystem system in systems ) 216 | { 217 | string panelName = system.PanelName; 218 | if( 0 == panelName.Length ) 219 | { 220 | panelName = CmdElectricalSystemBrowser.Unassigned; // will not appear in tree 221 | } 222 | else 223 | { 224 | // 225 | // todo: is there a more direct way to identify 226 | // what panel a system belongs to? this seems error 227 | // prone ... what if a panel name occurs multiple times? 228 | // how do we identify which one to use? 229 | // 230 | FamilyInstance panel = mapPanel[panelName]; 231 | mapParentToChildren.Add( panel.Id, system ); 232 | } 233 | string panelAndSystem = panelName + ":" + system.Name + ":" + system.Id.IntegerValue.ToString(); 234 | Debug.WriteLine( " " + Util.ElementDescriptionAndId( system ) + " " + panelAndSystem ); 235 | Debug.Assert( system.ConnectorManager.Owner.Id.Equals( system.Id ), "expected electrical system's connector manager owner to be system itself" ); 236 | } 237 | // 238 | // now we have the equipment and systems, 239 | // we can build the non-leaf levels of the tree: 240 | // 241 | foreach( FamilyInstance e in equipment ) 242 | { 243 | MEPModel mepModel = e.MEPModel; 244 | //ElectricalSystemSet systems2 = mepModel.ElectricalSystems; // 2020 245 | ISet systems2 = mepModel.GetElectricalSystems(); // 2021 246 | if( null == systems2 ) 247 | { 248 | mapParentToChildren.Add( nullId, e ); // root node 249 | } 250 | else 251 | { 252 | Debug.Assert( 1 == systems2.Count, "expected equipment to belong to one single panel and system" ); 253 | foreach( ElectricalSystem system in systems2 ) 254 | { 255 | mapParentToChildren.Add( system.Id, e ); 256 | } 257 | } 258 | } 259 | // 260 | // list all circuit elements: 261 | // 262 | BuiltInParameter bipPanel = BuiltInParameter.RBS_ELEC_CIRCUIT_PANEL_PARAM; 263 | BuiltInParameter bipCircuit = BuiltInParameter.RBS_ELEC_CIRCUIT_NUMBER; 264 | IList circuitElements = Util.GetCircuitElements( doc ); 265 | n = circuitElements.Count; 266 | Debug.WriteLine( string.Format( "Retrieved {0} circuit element{1}...", 267 | n, Util.PluralSuffix( n ) ) ); 268 | n = 0; 269 | foreach( Element e in circuitElements ) 270 | { 271 | if( e is ElectricalSystem ) 272 | { 273 | ++n; 274 | } 275 | else 276 | { 277 | string circuitName = e.get_Parameter( bipCircuit ).AsString(); 278 | string panelName = e.get_Parameter( bipPanel ).AsString(); 279 | string key = panelName + ":" + circuitName; 280 | string panelAndSystem = string.Empty; 281 | FamilyInstance inst = e as FamilyInstance; 282 | Debug.Assert( null != inst, "expected all circuit elements to be family instances" ); 283 | MEPModel mepModel = inst.MEPModel; 284 | //ElectricalSystemSet systems2 = mepModel.ElectricalSystems; // 2020 285 | ISet systems2 = mepModel.GetElectricalSystems(); // 2021 286 | Debug.Assert( null != systems2, "expected circuit element to belong to an electrical system" ); 287 | Debug.Assert( 0 < systems2.Count, "expected circuit element to belong to an electrical system" ); 288 | 289 | // this fails in "2341_MEP - 2009 Central.rvt", says martin: 290 | // 291 | // a circuit element can belong to several systems ... imagine 292 | // a piece of telephone equipment which hooks up to a phone line 293 | // and also requires power ... so i removed this assertion: 294 | // 295 | //Debug.Assert( 1 == systems2.Size, "expected circuit element to belong to one single system" ); 296 | 297 | foreach( ElectricalSystem system in systems2 ) 298 | { 299 | if( 0 < panelAndSystem.Length ) 300 | { 301 | panelAndSystem += ", "; 302 | } 303 | panelAndSystem += system.PanelName + ":" + system.Name + ":" + system.Id.IntegerValue.ToString(); 304 | Debug.Assert( system.PanelName == panelName, "expected same panel name in parameter and electrical system" ); 305 | // this fails in "2341_MEP - 2009 Central.rvt", says martin: 306 | //Debug.Assert( system.Name == circuitName, "expected same name in circuit parameter and system" ); 307 | mapParentToChildren.Add( system.Id, e ); 308 | } 309 | Debug.WriteLine( string.Format( " {0} panel:circuit {1}", Util.ElementDescriptionAndId( e ), panelAndSystem ) ); 310 | } 311 | } 312 | Debug.WriteLine( string.Format( "{0} circuit element{1} were the electrical systems.", 313 | n, Util.PluralSuffix( n ) ) ); 314 | // 315 | // get the electrical equipment category id: 316 | // 317 | Categories categories = doc.Settings.Categories; 318 | electricalEquipmentCategoryId = categories.get_Item( BuiltInCategory.OST_ElectricalEquipment ).Id; 319 | } 320 | // 321 | // we have assembled the entire required tree view structure, so let us display it: 322 | // 323 | CmdInspectElectricalForm2 dialog = new CmdInspectElectricalForm2( mapParentToChildren, electricalEquipmentCategoryId, equipment ); 324 | dialog.Show(); 325 | return Result.Succeeded; 326 | } 327 | catch( Exception ex ) 328 | { 329 | message = ex.Message; 330 | return Result.Failed; 331 | } 332 | } 333 | } 334 | #endregion // CmdElectricalHierarchy2 335 | } 336 | -------------------------------------------------------------------------------- /AdnRme/CmdElectricalSystemBrowser.cs: -------------------------------------------------------------------------------- 1 | #region Header 2 | // Revit MEP API sample application 3 | // 4 | // Copyright (C) 2007-2021 by Jeremy Tammik, Autodesk, Inc. 5 | // 6 | // Permission to use, copy, modify, and distribute this software 7 | // for any purpose and without fee is hereby granted, provided 8 | // that the above copyright notice appears in all copies and 9 | // that both that copyright notice and the limited warranty and 10 | // restricted rights notice below appear in all supporting 11 | // documentation. 12 | // 13 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 14 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 15 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. 16 | // AUTODESK, INC. DOES NOT WARRANT THAT THE OPERATION OF THE 17 | // PROGRAM WILL BE UNINTERRUPTED OR ERROR FREE. 18 | // 19 | // Use, duplication, or disclosure by the U.S. Government is subject 20 | // to restrictions set forth in FAR 52.227-19 (Commercial Computer 21 | // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) 22 | // (Rights in Technical Data and Computer Software), as applicable. 23 | #endregion // Header 24 | 25 | #region Namespaces 26 | using System; 27 | using System.Collections.Generic; 28 | using System.Diagnostics; 29 | using Autodesk.Revit.ApplicationServices; 30 | using Autodesk.Revit.Attributes; 31 | using Autodesk.Revit.DB; 32 | using Autodesk.Revit.DB.Electrical; 33 | using Autodesk.Revit.UI; 34 | #endregion // Namespaces 35 | 36 | namespace AdnRme 37 | { 38 | #region CmdElectricalSystemBrowser 39 | /// 40 | /// Inspect the electrical system. 41 | /// 42 | /// We reproduce the information provided in the Power section of the 43 | /// Revit MEP mechanical system browser and display it in a modeless 44 | /// dialogue, i.e. it remains visible after the command has completed. 45 | /// 46 | /// The challenge here is to reproduce all the nodes, and the sorting order. 47 | /// 48 | /// The system browser has three levels of nodes, panel > system > element, 49 | /// as well as one 'Unassigned' top level node, where 'Unassigned' replaces 50 | /// the panel. System may also be circuit number. 51 | /// 52 | /// In this implementation, the nodes come from two sources: 53 | /// 54 | /// - electrical equipment, which always has a system name and is 55 | /// either unassigned or has a panel name 56 | /// - circuit elements, which have a non-empty circuit number 57 | /// parameter value. 58 | /// 59 | /// The electrical equipment can be selected by filtering for its type, 60 | /// ElectricalEquipment, the circuit elements by filtering for 61 | /// BuiltInParameter.RBS_ELEC_CIRCUIT_NUMBER. 62 | /// 63 | /// Each of these two sets can be sorted into dictionaries using the keys 64 | /// 65 | /// panel:circuit number or 66 | /// panel:system name or 67 | /// Unassigned:system name 68 | /// 69 | /// and mapping these to the connected elements. 70 | /// 71 | /// These two dictionaries, merged together and appropriately sorted, 72 | /// represent the same information as the system browser. 73 | /// 74 | /// Important note: this whole sample was implemented while exploring 75 | /// how the systm is actually hooked up. Once that is fully understood, 76 | /// a much more straightforward and efficient algorithm for traversing 77 | /// and displaying it can be implemented. So please don't simply reuse 78 | /// this code, understand it first and then rewrite it. 79 | /// 80 | /// Important note 2: this sample was originally written for Revit 2008, 81 | /// before the introduction of the Connector and ConnectionManager classes, 82 | /// or even any MEP-specific API at all. The complex determination of the 83 | /// connection hierarchy based on parameter values performed here can be 84 | /// much simplified using the connectors, as demonstrated by 85 | /// CmdElectricalConnectors. 86 | /// 87 | [Transaction( TransactionMode.ReadOnly )] 88 | class CmdElectricalSystemBrowser : IExternalCommand 89 | { 90 | public const string Unassigned = "Unassigned"; 91 | 92 | #region Sorting comparers 93 | 94 | #region NumericalComparer 95 | /// 96 | /// Helper class for sorting strings numerically by number. 97 | /// 98 | class NumericalComparer : IComparer 99 | { 100 | public int Compare( string x, string y ) 101 | { 102 | return int.Parse( x ) - int.Parse( y ); 103 | } 104 | } 105 | #endregion // NumericalComparer 106 | 107 | #region PanelCircuitComparer 108 | /// 109 | /// Helper class for sorting panel:circuit key strings 110 | /// alphabetically by panel name and numerically by circuit number. 111 | /// We also need to handle the format "MDP:1,3,5". 112 | /// 2010-06-11: we need to handle "<unnamed>". 113 | /// 114 | class PanelCircuitComparer : IComparer 115 | { 116 | public int Compare( string x, string y ) 117 | { 118 | int d = x.CompareTo( y ); 119 | if( 0 != d ) 120 | { 121 | string[] a = x.Split( ':' ); 122 | string[] b = y.Split( ':' ); 123 | d = a[0].CompareTo( b[0] ); 124 | if( 0 == d ) 125 | { 126 | string[] a2 = a[1].Split( ',' ); 127 | string[] b2 = b[1].Split( ',' ); 128 | d = a2.Length - b2.Length; 129 | if( 0 == d ) 130 | { 131 | for( int i = 0; i < a2.Length && 0 == d; ++i ) 132 | { 133 | d = int.Parse( a2[0] ) - int.Parse( b2[0] ); 134 | } 135 | } 136 | } 137 | } 138 | return d; 139 | } 140 | } 141 | #endregion // PanelCircuitComparer 142 | 143 | #region PanelSystemComparer 144 | /// 145 | /// Helper class for sorting panel:system key strings, 146 | /// first alphabetically by panel name, second either 147 | /// alphabetically by system name or numerically by 148 | /// circuit number. 149 | /// 150 | public class PanelSystemComparer : IComparer 151 | { 152 | #region JtIsDigit 153 | // 154 | // JtIsDigit is faster than using char.IsDigit() in a lop, cf. 155 | // http://weblogs.asp.net/justin_rogers/archive/2004/03/29/100982.aspx 156 | // Performance: Different methods for testing string input for numeric values... 157 | // by Justin Rogers 158 | // 159 | /// 160 | /// Test whether all characters in given string are decimal digits. 161 | /// 162 | public static bool JtIsDigit( string s ) 163 | { 164 | foreach( char a in s ) 165 | { 166 | if( a < '0' || '9' < a ) 167 | { 168 | return false; 169 | } 170 | } 171 | return true; 172 | } 173 | 174 | public static bool JtIsDigitOrComma( string s ) 175 | { 176 | foreach( char a in s ) 177 | { 178 | if( (a < '0' || '9' < a) && (',' != a) ) 179 | { 180 | return false; 181 | } 182 | } 183 | return true; 184 | } 185 | #endregion // JtIsDigit 186 | 187 | int CompareCommaDelimitedIntegerLists( string x, string y ) 188 | { 189 | int nx = x.IndexOf( ',' ); 190 | int ny = y.IndexOf( ',' ); 191 | int ix = ( 0 < nx ) ? int.Parse( x.Substring( 0, nx ) ) : int.Parse( x ); 192 | int iy = ( 0 < ny ) ? int.Parse( y.Substring( 0, ny ) ) : int.Parse( y ); 193 | int d = ix - iy; 194 | return ( 0 == d && 0 < nx && 0 < ny ) 195 | ? CompareCommaDelimitedIntegerLists( x.Substring( nx + 1 ), y.Substring( ny + 1 ) ) 196 | : (0 == d ? nx - ny : d); 197 | } 198 | 199 | public int Compare( string x, string y ) 200 | { 201 | string[] a = x.Split( ':' ); 202 | string[] b = y.Split( ':' ); 203 | int d = a[0].CompareTo( b[0] ); 204 | if( 0 == d 205 | && 1 < a.GetLength( 0 ) 206 | && 1 < b.GetLength( 0 ) ) 207 | { 208 | d = ( JtIsDigitOrComma( a[1] ) && JtIsDigitOrComma( b[1] ) ) 209 | ? CompareCommaDelimitedIntegerLists( a[1], b[1] ) 210 | : a[1].CompareTo( b[1] ); 211 | } 212 | return d; 213 | } 214 | } 215 | #endregion // PanelSystemComparer 216 | #endregion // Sorting comparers 217 | 218 | #region ListEquipment 219 | /// 220 | /// List an electrical equipment instance and insert its data into 221 | /// the dictionary mapping panel + system name to equipment instances. 222 | /// 223 | static void ListEquipment( 224 | FamilyInstance elecEqip, 225 | IDictionary> mapPanelAndSystemToEquipment ) 226 | { 227 | MEPModel mepModel = elecEqip.MEPModel; 228 | //ElectricalSystemSet systems = mepModel.ElectricalSystems; // 2020 229 | ISet systems = mepModel.GetElectricalSystems(); // 2021 230 | string s = string.Empty; 231 | if( null == systems ) 232 | { 233 | s = Unassigned + ":" + elecEqip.Name; 234 | } 235 | else 236 | { 237 | Debug.Assert( 1 == systems.Count, 238 | "expected equipment to belong to one single panel and system" ); 239 | 240 | foreach( ElectricalSystem system in systems ) 241 | { 242 | if( 0 < s.Length ) 243 | { 244 | s += ", "; 245 | } 246 | s += system.PanelName + ":" + system.Name; 247 | } 248 | } 249 | Debug.WriteLine( " " + elecEqip.Name + ": " + s ); 250 | Debug.Assert( !mapPanelAndSystemToEquipment.ContainsKey( s ), "expected each panel and system to occur in one equipment element only" ); 251 | if( !mapPanelAndSystemToEquipment.ContainsKey( s ) ) 252 | { 253 | mapPanelAndSystemToEquipment.Add( s, new List() ); 254 | } 255 | mapPanelAndSystemToEquipment[s].Add( elecEqip ); 256 | } 257 | #endregion // ListEquipment 258 | 259 | static public Result Execute2( 260 | ExternalCommandData commandData, 261 | ref String message, 262 | ElementSet elements, 263 | bool populateFullHierarchy ) 264 | { 265 | try 266 | { 267 | WaitCursor waitCursor = new WaitCursor(); 268 | UIApplication app = commandData.Application; 269 | Document doc = app.ActiveUIDocument.Document; 270 | // 271 | // display electrical equipment instance data, 272 | // i.e. equipment_name:system_name, and convert it to 273 | // a map from key = panel:circuit --> equipment: 274 | // 275 | List equipment = Util.GetElectricalEquipment( doc ); 276 | int n = equipment.Count; 277 | Debug.WriteLine( string.Format( "Retrieved {0} electrical equipment instance{1}{2}", 278 | n, Util.PluralSuffix( n ), Util.DotOrColon( n ) ) ); 279 | Dictionary> mapPanelAndSystemToEquipment = new Dictionary>(); 280 | foreach( FamilyInstance elecEqip in equipment ) 281 | { 282 | ListEquipment( elecEqip, mapPanelAndSystemToEquipment ); 283 | } 284 | // 285 | // determine mapping from panel to circuit == electrical system: 286 | // 287 | Dictionary> mapPanelToSystems 288 | = new Dictionary>(); 289 | 290 | IList systems = Util.GetElectricalSystems( doc ); 291 | n = systems.Count; 292 | Debug.WriteLine( string.Format( "Retrieved {0} electrical system{1}.", 293 | n, Util.PluralSuffix( n ) ) ); 294 | // 295 | // all circuits which are fed from the same family instance have 296 | // the same panel name, so you can retrieve all of these circuits. 297 | // 298 | // todo: there is an issue here if there are several different panels 299 | // with the same name! they will get merged in the tree view, 300 | // but they should stay separate. possible workaround: add the 301 | // element id to keep them separate, and then remove it again 302 | // when displaying in tree view. 303 | // 304 | foreach( ElectricalSystem system in systems ) 305 | { 306 | string panelName = system.PanelName; 307 | 308 | Debug.WriteLine( " system " + system.Name + ": panel " + panelName 309 | + " load classifications " + system.LoadClassifications ); 310 | 311 | if( !mapPanelToSystems.ContainsKey( panelName ) ) 312 | { 313 | mapPanelToSystems.Add( panelName, 314 | new SortedSet() ); 315 | } 316 | mapPanelToSystems[panelName].Add( system ); 317 | } 318 | n = mapPanelToSystems.Count; 319 | //Debug.WriteLine( string.Format( "Mapping from the {0} panel{1} to systems, system name :circuit name(connectors/unused connectors):", n, Util.PluralSuffix( n ) ) ); 320 | Debug.WriteLine( string.Format( "Mapping from the {0} panel{1} to electrical systems == circuits:", 321 | n, Util.PluralSuffix( n ) ) ); 322 | List keys = new List( mapPanelToSystems.Keys ); 323 | keys.Sort(); 324 | string s; 325 | foreach( string panelName in keys ) 326 | { 327 | s = string.Empty; 328 | foreach( ElectricalSystem system in mapPanelToSystems[panelName] ) 329 | { 330 | ConnectorManager cmgr = system.ConnectorManager; 331 | 332 | // the connector manager does not include any logical connectors 333 | // in the Revit 2009 fcs and wu1 API, only physical ones: 334 | //Debug.Assert( 0 == cmgr.Connectors.Size, 335 | // "electrical connector count is always zero" ); 336 | 337 | Debug.Assert( cmgr.UnusedConnectors.Size <= cmgr.Connectors.Size, 338 | "unused connectors is a subset of connectors" ); 339 | 340 | Debug.Assert( system.Name.Equals( system.CircuitNumber ), 341 | "ElectricalSystem Name and CircuitNumber properties are always identical" ); 342 | 343 | //s += ( 0 < s.Length ? ", " : ": " ) + system.Name; 344 | 345 | s += ( 0 < s.Length ? ", " : ": " ) + system.Name // + ":" + system.CircuitNumber 346 | + "(" + cmgr.Connectors.Size.ToString() 347 | + "/" + cmgr.UnusedConnectors.Size.ToString() + ")"; 348 | } 349 | Debug.WriteLine( " " + panelName + s ); 350 | } 351 | /* 352 | Debug.WriteLine( "Mapping from panels to systems to connected elements:" ); 353 | foreach( string panelName in keys ) 354 | { 355 | Debug.WriteLine( " panel " + panelName + ":" ); 356 | foreach( ElectricalSystem system in mapPanelToSystems[panelName] ) 357 | { 358 | ConnectorManager cmgr = system.ConnectorManager; 359 | n = cmgr.Connectors.Size; 360 | Debug.WriteLine( string.Format( " system {0} has {1} connector{2}{3}", system.Name, n, Util.PluralSuffix( n ), Util.DotOrColon( n ) ) ); 361 | foreach( Connector connector in system.ConnectorManager.Connectors ) 362 | { 363 | Element owner = connector.Owner; 364 | Debug.WriteLine( string.Format( " owner {0} {1}, domain {2}", owner.Name, owner.Id.IntegerValue, connector.Domain ) ); 365 | } 366 | } 367 | } 368 | */ 369 | 370 | // 371 | // list all circuit elements: 372 | // 373 | // this captures all elements in circuits H-2: 2, 4, 6 etc, 374 | // but not the element T2 in H-2:1,3,5, because it has no circuit number, 375 | // just a panel number. 376 | // 377 | BuiltInParameter bipPanel = BuiltInParameter.RBS_ELEC_CIRCUIT_PANEL_PARAM; 378 | BuiltInParameter bipCircuit = BuiltInParameter.RBS_ELEC_CIRCUIT_NUMBER; 379 | IList circuitElements = Util.GetCircuitElements( doc ); 380 | n = circuitElements.Count; 381 | Debug.WriteLine( string.Format( "Retrieved {0} circuit element{1}{2}", 382 | n, Util.PluralSuffix( n ), Util.DotOrColon( n ) ) ); 383 | Dictionary> mapPanelAndCircuitToElements = new Dictionary>(); 384 | foreach( Element e in circuitElements ) 385 | { 386 | string circuitName = e.get_Parameter( bipCircuit ).AsString(); 387 | // 388 | // do not map an electrical system to itself: 389 | // 390 | if( !(e is ElectricalSystem && e.Name.Equals( circuitName )) ) 391 | { 392 | string panelName = e.get_Parameter( bipPanel ).AsString(); 393 | string key = panelName + ":" + circuitName; 394 | Debug.WriteLine( string.Format( " {0} <{1} {2}> panel:circuit {3}", e.GetType().Name, e.Name, e.Id.IntegerValue, key ) ); 395 | if( !mapPanelAndCircuitToElements.ContainsKey( key ) ) 396 | { 397 | mapPanelAndCircuitToElements.Add( key, new List() ); 398 | } 399 | mapPanelAndCircuitToElements[key].Add( e ); 400 | } 401 | } 402 | n = mapPanelAndCircuitToElements.Count; 403 | Debug.WriteLine( string.Format( "Mapped circuit elements to {0} panel:circuit{1}{2}", 404 | n, Util.PluralSuffix( n ), Util.DotOrColon( n ) ) ); 405 | keys.Clear(); 406 | keys.AddRange( mapPanelAndCircuitToElements.Keys ); 407 | keys.Sort( new PanelCircuitComparer() ); 408 | foreach( string panelAndCircuit in keys ) 409 | { 410 | List a = new List( mapPanelAndCircuitToElements[panelAndCircuit].Count ); 411 | foreach( Element e in mapPanelAndCircuitToElements[panelAndCircuit] ) 412 | { 413 | FamilyInstance inst = e as FamilyInstance; 414 | a.Add( ( null == inst ? e.Category.Name : inst.Symbol.Family.Name) + " " + e.Name ); 415 | } 416 | a.Sort(); 417 | s = string.Join( ", ", a.ToArray() ); 418 | Debug.WriteLine( " " + panelAndCircuit + ": " + s ); 419 | } 420 | 421 | #region Aborted attempt to use RBS_ELEC_CIRCUIT_PANEL_PARAM 422 | #if USE_RBS_ELEC_CIRCUIT_PANEL_PARAM 423 | // 424 | // list all panel elements: 425 | // 426 | // selecting all elements with a BuiltInParameter.RBS_ELEC_CIRCUIT_NUMBER 427 | // captures all elements in circuits H-2: 2, 4, 6 etc, but not the element 428 | // T2 in H-2:1,3,5, because it has no circuit number, just a panel number. 429 | // 430 | // so grab everything with a panel number instead. 431 | // 432 | // all this added to the selection was lots of wires, so forget it again. 433 | // 434 | BuiltInParameter bipCircuit = BuiltInParameter.RBS_ELEC_CIRCUIT_NUMBER; 435 | BuiltInParameter bipPanel = BuiltInParameter.RBS_ELEC_CIRCUIT_PANEL_PARAM; 436 | List circuitElements = new List(); 437 | Util.GetElementsWithParameter( circuitElements, bipPanel, app ); 438 | n = circuitElements.Count; 439 | Debug.WriteLine( string.Format( "Retrieved {0} circuit element{1}{2}", 440 | n, Util.PluralSuffix( n ), Util.DotOrColon( n ) ) ); 441 | Dictionary> mapCircuitToElements = new Dictionary>(); 442 | foreach( Element e in circuitElements ) 443 | { 444 | string panelName = e.get_Parameter( bipPanel ).AsString(); 445 | Parameter p = e.get_Parameter( bipCircuit ); 446 | if( null == p ) 447 | { 448 | Debug.WriteLine( string.Format( " {0} <{1} {2}> panel:circuit {3}:null", e.GetType().Name, e.Name, e.Id.IntegerValue, panelName ) ); 449 | } 450 | else 451 | { 452 | string circuitName = p.AsString(); 453 | // 454 | // do not map an electrical system to itself: 455 | // 456 | if( !( e is ElectricalSystem && e.Name.Equals( circuitName ) ) ) 457 | { 458 | string key = panelName + ":" + circuitName; 459 | Debug.WriteLine( string.Format( " {0} <{1} {2}> panel:circuit {3}", e.GetType().Name, e.Name, e.Id.IntegerValue, key ) ); 460 | if( !mapCircuitToElements.ContainsKey( key ) ) 461 | { 462 | mapCircuitToElements.Add( key, new List() ); 463 | } 464 | mapCircuitToElements[key].Add( e ); 465 | } 466 | } 467 | } 468 | n = mapCircuitToElements.Count; 469 | Debug.WriteLine( string.Format( "Mapped circuit elements to {0} panel:circuit{1}{2}", 470 | n, Util.PluralSuffix( n ), Util.DotOrColon( n ) ) ); 471 | keys.Clear(); 472 | keys.AddRange( mapCircuitToElements.Keys ); 473 | keys.Sort( new PanelCircuitComparer() ); 474 | foreach( string circuitName in keys ) 475 | { 476 | List a = new List( mapCircuitToElements[circuitName].Count ); 477 | foreach( Element e in mapCircuitToElements[circuitName] ) 478 | { 479 | FamilyInstance inst = e as FamilyInstance; 480 | a.Add( ( null == inst ? e.Category.Name : inst.Symbol.Family.Name ) + " " + e.Name ); 481 | } 482 | a.Sort(); 483 | s = string.Join( ", ", a.ToArray() ); 484 | Debug.WriteLine( " " + circuitName + ": " + s ); 485 | } 486 | #endif // USE_RBS_ELEC_CIRCUIT_PANEL_PARAM 487 | #endregion // Aborted attempt to use RBS_ELEC_CIRCUIT_PANEL_PARAM 488 | 489 | // 490 | // merge the two trees of equipment and circuit elements 491 | // to reproduce the content of the system browser ... the 492 | // hardest part of this is setting up the PanelSystemComparer 493 | // to generate the same sort order as the system browser: 494 | // 495 | //n = mapPanelAndSystemToEquipment.Count + mapPanelAndCircuitToElements.Count; 496 | //Dictionary> mapSystemBrowser = new Dictionary>( n ); 497 | Dictionary> mapSystemBrowser = new Dictionary>( mapPanelAndCircuitToElements ); 498 | foreach( KeyValuePair> pair in mapPanelAndSystemToEquipment ) 499 | { 500 | mapSystemBrowser[pair.Key] = pair.Value; 501 | } 502 | n = mapSystemBrowser.Count; 503 | Debug.WriteLine( string.Format( "Mapped equipment + circuit elements to {0} panel:system{1}{2}", 504 | n, Util.PluralSuffix( n ), Util.DotOrColon( n ) ) ); 505 | keys.Clear(); 506 | keys.AddRange( mapSystemBrowser.Keys ); 507 | keys.Sort( new PanelSystemComparer() ); 508 | foreach( string panelAndSystem in keys ) 509 | { 510 | List a = new List( mapSystemBrowser[panelAndSystem].Count ); 511 | foreach( Element e in mapSystemBrowser[panelAndSystem] ) 512 | { 513 | a.Add( Util.BrowserDescription( e ) ); 514 | } 515 | a.Sort(); 516 | s = string.Join( ", ", a.ToArray() ); 517 | Debug.WriteLine( string.Format( " {0}({1}): ", panelAndSystem, a.Count ) + s ); 518 | } 519 | // 520 | // get the electrical equipment category id: 521 | // 522 | Categories categories = doc.Settings.Categories; 523 | ElementId electricalEquipmentCategoryId = categories.get_Item( BuiltInCategory.OST_ElectricalEquipment ).Id; 524 | // 525 | // we have assembled the required information and structured it 526 | // sufficiently for the tree view, so now let us go ahead and display it: 527 | // 528 | CmdInspectElectricalForm dialog = new CmdInspectElectricalForm( mapSystemBrowser, electricalEquipmentCategoryId, populateFullHierarchy ); 529 | dialog.Show(); 530 | return Result.Succeeded; 531 | } 532 | catch (Exception ex) 533 | { 534 | message = ex.Message; 535 | return Result.Failed; 536 | } 537 | } 538 | 539 | public Result Execute( 540 | ExternalCommandData commandData, 541 | ref String message, 542 | ElementSet elements ) 543 | { 544 | return Execute2( commandData, ref message, elements, false ); 545 | } 546 | } 547 | #endregion // CmdElectricalSystemBrowser 548 | 549 | #region CmdElectricalHierarchy 550 | [Transaction( TransactionMode.ReadOnly )] 551 | class CmdElectricalHierarchy : IExternalCommand 552 | { 553 | public Result Execute( 554 | ExternalCommandData commandData, 555 | ref String message, 556 | ElementSet elements ) 557 | { 558 | return CmdElectricalSystemBrowser.Execute2( commandData, ref message, elements, true ); 559 | } 560 | } 561 | #endregion // CmdElectricalHierarchy 562 | } 563 | -------------------------------------------------------------------------------- /AdnRme/CmdInspectElectricalForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace AdnRme 2 | { 3 | partial class CmdInspectElectricalForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose( bool disposing ) 15 | { 16 | if( disposing && ( components != null ) ) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose( disposing ); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.tv = new System.Windows.Forms.TreeView(); 32 | this.SuspendLayout(); 33 | // 34 | // tv 35 | // 36 | this.tv.Anchor = ( ( System.Windows.Forms.AnchorStyles ) ( ( ( ( System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom ) 37 | | System.Windows.Forms.AnchorStyles.Left ) 38 | | System.Windows.Forms.AnchorStyles.Right ) ) ); 39 | this.tv.Location = new System.Drawing.Point( 0, 0 ); 40 | this.tv.Name = "tv"; 41 | this.tv.Size = new System.Drawing.Size( 294, 276 ); 42 | this.tv.TabIndex = 0; 43 | // 44 | // CmdInspectElectricaForm 45 | // 46 | this.AutoScaleDimensions = new System.Drawing.SizeF( 6F, 13F ); 47 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 48 | this.ClientSize = new System.Drawing.Size( 292, 273 ); 49 | this.Controls.Add( this.tv ); 50 | this.Name = "CmdInspectElectricaForm"; 51 | this.Text = "Inspect Electrical System"; 52 | this.ResumeLayout( false ); 53 | 54 | } 55 | 56 | #endregion 57 | 58 | private System.Windows.Forms.TreeView tv; 59 | } 60 | } -------------------------------------------------------------------------------- /AdnRme/CmdInspectElectricalForm.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jeremytammik/AdnRme/d2764222508f2dce275815bf95b755ae94754415/AdnRme/CmdInspectElectricalForm.cs -------------------------------------------------------------------------------- /AdnRme/CmdInspectElectricalForm.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /AdnRme/CmdInspectElectricallForm2.cs: -------------------------------------------------------------------------------- 1 | #region Header 2 | // Revit MEP API sample application 3 | // 4 | // Copyright (C) 2007-2021 by Jeremy Tammik, Autodesk, Inc. 5 | // 6 | // Permission to use, copy, modify, and distribute this software 7 | // for any purpose and without fee is hereby granted, provided 8 | // that the above copyright notice appears in all copies and 9 | // that both that copyright notice and the limited warranty and 10 | // restricted rights notice below appear in all supporting 11 | // documentation. 12 | // 13 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 14 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 15 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. 16 | // AUTODESK, INC. DOES NOT WARRANT THAT THE OPERATION OF THE 17 | // PROGRAM WILL BE UNINTERRUPTED OR ERROR FREE. 18 | // 19 | // Use, duplication, or disclosure by the U.S. Government is subject 20 | // to restrictions set forth in FAR 52.227-19 (Commercial Computer 21 | // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) 22 | // (Rights in Technical Data and Computer Software), as applicable. 23 | #endregion // Header 24 | 25 | #region Namespaces 26 | using System; 27 | using System.Collections.Generic; 28 | using System.Diagnostics; 29 | using System.Drawing; 30 | using System.Windows.Forms; 31 | using WinForm = System.Windows.Forms.Form; 32 | using Autodesk.Revit.Attributes; 33 | using Autodesk.Revit.DB; 34 | using Autodesk.Revit.DB.Electrical; 35 | using Autodesk.Revit.UI; 36 | #endregion // Namespaces 37 | 38 | namespace AdnRme 39 | { 40 | /// 41 | /// Form displaying electrical system elements in a tree view 42 | /// according to their connection hierarchy, and a list view 43 | /// of electrical equipment providing immediate access to jump 44 | /// directly into the appropriate location in the tree view. 45 | /// 46 | public partial class CmdInspectElectricalForm2 : WinForm 47 | { 48 | ElementId _electricalEquipmentCategoryId; 49 | Dictionary _done = new Dictionary(); 50 | ElectricalElementComparer _comparer; 51 | 52 | static public string ElectricalElementText( Element e, ElementId electricalEquipmentCategoryId ) 53 | { 54 | bool isCircuit = e is ElectricalSystem; 55 | bool isEquipment = e.Category.Id.Equals( electricalEquipmentCategoryId ); 56 | return ( isEquipment || isCircuit ) ? e.Name : Util.BrowserDescription( e ); 57 | } 58 | 59 | #region PopulateFromMapParentToChildren 60 | void PopulateFromMapParentToChildren( 61 | TreeNodeCollection tnc, 62 | ElementId parentId, 63 | MapParentToChildren map ) 64 | { 65 | if( map.ContainsKey( parentId ) ) 66 | { 67 | List children = map[parentId]; 68 | children.Sort( _comparer ); 69 | string key, text; 70 | bool isEquipment; // isCircuit 71 | foreach( Element e in children ) 72 | { 73 | if( !_done.ContainsKey( e.Id ) ) 74 | { 75 | _done[e.Id] = 1; 76 | //isCircuit = e is ElectricalSystem; 77 | isEquipment = e.Category.Id.Equals( _electricalEquipmentCategoryId ); 78 | key = Util.ElementDescriptionAndId( e ); 79 | //text = ( isEquipment || isCircuit ) ? e.Name : Util.BrowserDescription( e ); 80 | text = ElectricalElementText( e, _electricalEquipmentCategoryId ); 81 | TreeNode tn = tnc.Add( key, text ); 82 | CmdInspectElectricalForm.AddLoadNodes( tn, e ); 83 | if( map.ContainsKey( e.Id ) ) 84 | { 85 | // 86 | // highlight circuit e.g. electrical system node that has 87 | // electrical equipment connected to it; also avoid setting 88 | // it to bold multiple times over: 89 | // 90 | if( isEquipment ) 91 | { 92 | TreeNode p = tn.Parent; 93 | listBox1.Items.Add( new PanelTreeNodeHelper( e, tn ) ); 94 | if( null != p && ( null == p.NodeFont || !p.NodeFont.Bold ) ) 95 | { 96 | p.NodeFont = new System.Drawing.Font( this.Font, FontStyle.Bold ); 97 | } 98 | } 99 | PopulateFromMapParentToChildren( tn.Nodes, e.Id, map ); 100 | } 101 | } 102 | } 103 | } 104 | } 105 | #endregion // PopulateFromMapParentToChildren 106 | 107 | #region Constructor 108 | /// 109 | /// Constructor used to populate from a dictionary mapping element ids 110 | /// to a list of child elements. 111 | /// 112 | public CmdInspectElectricalForm2( 113 | MapParentToChildren map, 114 | ElementId electricalEquipmentCategoryId, 115 | IList electricalEquipment ) 116 | { 117 | _electricalEquipmentCategoryId = electricalEquipmentCategoryId; 118 | _comparer = new ElectricalElementComparer( electricalEquipmentCategoryId ); 119 | InitializeComponent(); 120 | tv.BeginUpdate(); 121 | PopulateFromMapParentToChildren( tv.Nodes, ElementId.InvalidElementId, map ); 122 | tv.EndUpdate(); 123 | //listBox1.SelectedIndex = 0; 124 | } 125 | #endregion // Constructor 126 | 127 | #region Selected equipment changed 128 | private void listBox1_SelectedIndexChanged( object sender, EventArgs e ) 129 | { 130 | PanelTreeNodeHelper ptnh = listBox1.SelectedItem as PanelTreeNodeHelper; 131 | if( null != ptnh ) 132 | { 133 | TreeNode tn = ptnh.TreeNode; 134 | tv.CollapseAll(); 135 | tv.SelectedNode = tn; 136 | tv.Select(); 137 | tn.Expand(); 138 | } 139 | } 140 | #endregion // Selected equipment changed 141 | } 142 | 143 | /// 144 | /// Helper class for string comparison of child elements for sorting the tree node order. 145 | /// 146 | class ElectricalElementComparer : IComparer 147 | { 148 | ElementId _electricalEquipmentCategoryId; 149 | 150 | public ElectricalElementComparer( ElementId electricalEquipmentCategoryId ) 151 | { 152 | _electricalEquipmentCategoryId = electricalEquipmentCategoryId; 153 | } 154 | 155 | public int Compare( Element x, Element y ) 156 | { 157 | string sx = CmdInspectElectricalForm2.ElectricalElementText( x, _electricalEquipmentCategoryId ); 158 | string sy = CmdInspectElectricalForm2.ElectricalElementText( y, _electricalEquipmentCategoryId ); 159 | return sx.CompareTo( sy ); 160 | } 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /AdnRme/CmdInspectElectricallForm2.designer.cs: -------------------------------------------------------------------------------- 1 | namespace AdnRme 2 | { 3 | partial class CmdInspectElectricalForm2 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.splitContainer1 = new System.Windows.Forms.SplitContainer(); 32 | this.listBox1 = new System.Windows.Forms.ListBox(); 33 | this.tv = new System.Windows.Forms.TreeView(); 34 | this.splitContainer1.Panel1.SuspendLayout(); 35 | this.splitContainer1.Panel2.SuspendLayout(); 36 | this.splitContainer1.SuspendLayout(); 37 | this.SuspendLayout(); 38 | // 39 | // splitContainer1 40 | // 41 | this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; 42 | this.splitContainer1.Location = new System.Drawing.Point( 0, 0 ); 43 | this.splitContainer1.Name = "splitContainer1"; 44 | // 45 | // splitContainer1.Panel1 46 | // 47 | this.splitContainer1.Panel1.Controls.Add( this.listBox1 ); 48 | // 49 | // splitContainer1.Panel2 50 | // 51 | this.splitContainer1.Panel2.Controls.Add( this.tv ); 52 | this.splitContainer1.Size = new System.Drawing.Size( 459, 556 ); 53 | this.splitContainer1.SplitterDistance = 153; 54 | this.splitContainer1.TabIndex = 0; 55 | // 56 | // listBox1 57 | // 58 | this.listBox1.Dock = System.Windows.Forms.DockStyle.Fill; 59 | this.listBox1.FormattingEnabled = true; 60 | this.listBox1.Location = new System.Drawing.Point( 0, 0 ); 61 | this.listBox1.Name = "listBox1"; 62 | this.listBox1.Size = new System.Drawing.Size( 153, 550 ); 63 | this.listBox1.Sorted = true; 64 | this.listBox1.TabIndex = 0; 65 | this.listBox1.SelectedIndexChanged += new System.EventHandler( this.listBox1_SelectedIndexChanged ); 66 | // 67 | // tv 68 | // 69 | this.tv.Dock = System.Windows.Forms.DockStyle.Fill; 70 | this.tv.Location = new System.Drawing.Point( 0, 0 ); 71 | this.tv.Name = "tv"; 72 | this.tv.Size = new System.Drawing.Size( 302, 556 ); 73 | this.tv.TabIndex = 0; 74 | // 75 | // CmdInspectElectricalForm2 76 | // 77 | this.AutoScaleDimensions = new System.Drawing.SizeF( 6F, 13F ); 78 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 79 | this.ClientSize = new System.Drawing.Size( 459, 556 ); 80 | this.Controls.Add( this.splitContainer1 ); 81 | this.Name = "CmdInspectElectricalForm2"; 82 | this.Text = "Electrical System Inspector"; 83 | this.splitContainer1.Panel1.ResumeLayout( false ); 84 | this.splitContainer1.Panel2.ResumeLayout( false ); 85 | this.splitContainer1.ResumeLayout( false ); 86 | this.ResumeLayout( false ); 87 | 88 | } 89 | 90 | #endregion 91 | 92 | private System.Windows.Forms.SplitContainer splitContainer1; 93 | private System.Windows.Forms.ListBox listBox1; 94 | private System.Windows.Forms.TreeView tv; 95 | } 96 | } -------------------------------------------------------------------------------- /AdnRme/CmdInspectElectricallForm2.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /AdnRme/CmdPopulateCfmPerSf.cs: -------------------------------------------------------------------------------- 1 | #region Header 2 | // Revit MEP API sample application 3 | // 4 | // Copyright (C) 2007-2021 by Jeremy Tammik, Autodesk, Inc. 5 | // 6 | // Permission to use, copy, modify, and distribute this software 7 | // for any purpose and without fee is hereby granted, provided 8 | // that the above copyright notice appears in all copies and 9 | // that both that copyright notice and the limited warranty and 10 | // restricted rights notice below appear in all supporting 11 | // documentation. 12 | // 13 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 14 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 15 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. 16 | // AUTODESK, INC. DOES NOT WARRANT THAT THE OPERATION OF THE 17 | // PROGRAM WILL BE UNINTERRUPTED OR ERROR FREE. 18 | // 19 | // Use, duplication, or disclosure by the U.S. Government is subject 20 | // to restrictions set forth in FAR 52.227-19 (Commercial Computer 21 | // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) 22 | // (Rights in Technical Data and Computer Software), as applicable. 23 | #endregion // Header 24 | 25 | #region Namespaces 26 | using System; 27 | using System.Collections.Generic; 28 | using System.Diagnostics; 29 | using Autodesk.Revit.Attributes; 30 | using Autodesk.Revit.DB; 31 | using Autodesk.Revit.DB.Mechanical; 32 | using Autodesk.Revit.UI; 33 | #endregion // Namespaces 34 | 35 | namespace AdnRme 36 | { 37 | [Transaction( TransactionMode.Manual )] 38 | class CmdPopulateCfmPerSf : IExternalCommand 39 | { 40 | #region Set CFM/SF 41 | /// 42 | /// Populate the value of the 'CFM per SF' variable on the given space. 43 | /// Throws an exception if something goes wrong. 44 | /// 45 | /// Given space element 46 | static void SetCfmPerSf( Space space ) 47 | { 48 | double flow = Util.GetSpaceParameterValue( space, Bip.Airflow, "Actual Supply Airflow" ); 49 | double area = Util.GetSpaceParameterValue( space, Bip.Area, "Area" ); 50 | double cfm = Const.SecondsPerMinute * flow; 51 | double cfmPerSf = cfm / area; 52 | Debug.WriteLine( string.Format( "Space {0} flow {1} CFM / area {2} f^2 --> {3} CFM/SF", 53 | space.Number, Util.RealString( cfm ), Util.RealString( area ), Util.RealString( cfmPerSf ) ) ); 54 | Parameter pCfmPerSf = Util.GetSpaceParameter( space, ParameterName.CfmPerSf ); 55 | pCfmPerSf.Set( cfmPerSf ); 56 | } 57 | #endregion // Set CFM/SF 58 | 59 | #region Execute Command 60 | public Result Execute( 61 | ExternalCommandData commandData, 62 | ref string message, 63 | ElementSet elements ) 64 | { 65 | try 66 | { 67 | WaitCursor waitCursor = new WaitCursor(); 68 | 69 | UIApplication app = commandData.Application; 70 | Document doc = app.ActiveUIDocument.Document; 71 | 72 | //ElementIterator it = doc.get_Elements( typeof( Room ) ); 73 | //ElementIterator it = doc.get_Elements( typeof( Space ) ); // changed Room to Space 74 | //FilteredElementCollector spaces = new FilteredElementCollector( doc ); 75 | //spaces.OfClass( typeof( Space ) ); 76 | 77 | using( Transaction tx = new Transaction( doc ) ) 78 | { 79 | tx.Start( "Set Air Flow per SqFt on Spaces" ); 80 | List spaces = Util.GetSpaces( doc ); 81 | 82 | foreach( Space space in spaces ) 83 | { 84 | SetCfmPerSf( space ); // set CFM/SF on the space AFTER assigning flow to the terminals 85 | } 86 | tx.Commit(); 87 | } 88 | return Result.Succeeded; 89 | } 90 | catch( Exception ex ) 91 | { 92 | message = ex.Message; 93 | return Result.Failed; 94 | } 95 | } 96 | #endregion // Execute Command 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /AdnRme/CmdResetDemo.cs: -------------------------------------------------------------------------------- 1 | #region Header 2 | // Revit MEP API sample application 3 | // 4 | // Copyright (C) 2007-2021 by Jeremy Tammik, Autodesk, Inc. 5 | // 6 | // Permission to use, copy, modify, and distribute this software 7 | // for any purpose and without fee is hereby granted, provided 8 | // that the above copyright notice appears in all copies and 9 | // that both that copyright notice and the limited warranty and 10 | // restricted rights notice below appear in all supporting 11 | // documentation. 12 | // 13 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 14 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 15 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. 16 | // AUTODESK, INC. DOES NOT WARRANT THAT THE OPERATION OF THE 17 | // PROGRAM WILL BE UNINTERRUPTED OR ERROR FREE. 18 | // 19 | // Use, duplication, or disclosure by the U.S. Government is subject 20 | // to restrictions set forth in FAR 52.227-19 (Commercial Computer 21 | // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) 22 | // (Rights in Technical Data and Computer Software), as applicable. 23 | #endregion // Header 24 | 25 | #region Namespaces 26 | using System; 27 | using System.Collections.Generic; 28 | using Autodesk.Revit.Attributes; 29 | using Autodesk.Revit.DB; 30 | using Autodesk.Revit.DB.Mechanical; 31 | using Autodesk.Revit.UI; 32 | #endregion // Namespaces 33 | 34 | namespace AdnRme 35 | { 36 | [Transaction( TransactionMode.Manual )] 37 | class CmdResetDemo : IExternalCommand 38 | { 39 | #region Execute Command 40 | /// 41 | /// Reset the Revit model to pre-demo conditions. 42 | /// 43 | public Result Execute( 44 | ExternalCommandData commandData, 45 | ref String message, 46 | ElementSet elements ) 47 | { 48 | try 49 | { 50 | UIApplication app = commandData.Application; 51 | Document doc = app.ActiveUIDocument.Document; 52 | 53 | using( Transaction tx = new Transaction( doc ) ) 54 | { 55 | tx.Start( "Reset Demo" ); 56 | ResetSupplyAirTerminals( doc ); 57 | SetSpaceCfmPerSfToZero( doc ); 58 | tx.Commit(); 59 | } 60 | return Result.Succeeded; 61 | } 62 | catch( Exception ex ) 63 | { 64 | message = ex.Message; 65 | return Result.Failed; 66 | } 67 | } 68 | 69 | private void SetSpaceCfmPerSfToZero( Document doc ) 70 | { 71 | //FilteredElementCollector collector = new FilteredElementCollector( doc ); 72 | //collector.OfClass( typeof( Space ) ); 73 | //IList spaces = collector.ToElements(); 74 | //int n = spaces.Count; 75 | 76 | List spaces = Util.GetSpaces( doc ); 77 | int n = spaces.Count; 78 | 79 | string s = "{0} of " + n.ToString() + " spaces reset..."; 80 | 81 | using( ProgressForm pf = new ProgressForm( "Reset parameter", s, n ) ) 82 | { 83 | foreach( Space space in spaces ) 84 | { 85 | SetCfmPerSf( space, 0.0 ); 86 | pf.Increment(); 87 | } 88 | } 89 | } 90 | 91 | static void SetCfmPerSf( Space space, double value ) 92 | { 93 | Parameter pCfmPerSf = Util.GetSpaceParameter( space, ParameterName.CfmPerSf ); 94 | pCfmPerSf.Set( value ); 95 | } 96 | 97 | private void ResetSupplyAirTerminals( Document doc ) 98 | { 99 | WaitCursor waitCursor = new WaitCursor(); 100 | FilteredElementCollector collector = Util.GetSupplyAirTerminals( doc ); 101 | 102 | IList terminals = collector.ToElements(); 103 | int n = terminals.Count; 104 | 105 | string s = "{0} of " + n.ToString() + " terminals reset..."; 106 | string caption = "Resetting Supply Air Termainal Flows and Sizes"; 107 | 108 | using( ProgressForm pf = new ProgressForm( caption, s, n ) ) 109 | { 110 | foreach( FamilyInstance terminal in terminals ) 111 | { 112 | // Reset flow 113 | 114 | Parameter p = Util.GetTerminalFlowParameter( terminal ); 115 | p.Set( 0 ); 116 | 117 | // Reset size 118 | 119 | ISet symbolIds 120 | = terminal.Symbol.Family 121 | .GetFamilySymbolIds(); 122 | 123 | foreach( ElementId id in symbolIds ) 124 | { 125 | FamilySymbol sym = doc.GetElement( id ) 126 | as FamilySymbol; 127 | 128 | terminal.Symbol = sym; // simply set to first symbol found 129 | 130 | break; // done after getting the first symbol 131 | } 132 | pf.Increment(); 133 | } 134 | } 135 | } 136 | #endregion // Execute Command 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /AdnRme/CmdUnhostedElements.cs: -------------------------------------------------------------------------------- 1 | #region Header 2 | // Revit MEP API sample application 3 | // 4 | // Copyright (C) 2007-2021 by Jeremy Tammik, Autodesk, Inc. 5 | // 6 | // Permission to use, copy, modify, and distribute this software 7 | // for any purpose and without fee is hereby granted, provided 8 | // that the above copyright notice appears in all copies and 9 | // that both that copyright notice and the limited warranty and 10 | // restricted rights notice below appear in all supporting 11 | // documentation. 12 | // 13 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 14 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 15 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. 16 | // AUTODESK, INC. DOES NOT WARRANT THAT THE OPERATION OF THE 17 | // PROGRAM WILL BE UNINTERRUPTED OR ERROR FREE. 18 | // 19 | // Use, duplication, or disclosure by the U.S. Government is subject 20 | // to restrictions set forth in FAR 52.227-19 (Commercial Computer 21 | // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) 22 | // (Rights in Technical Data and Computer Software), as applicable. 23 | #endregion // Header 24 | 25 | #region Namespaces 26 | using System; 27 | using System.Collections.Generic; 28 | using System.Diagnostics; 29 | using Autodesk.Revit.ApplicationServices; 30 | using Autodesk.Revit.Attributes; 31 | using Autodesk.Revit.DB; 32 | using Autodesk.Revit.UI; 33 | #endregion // Namespaces 34 | 35 | namespace AdnRme 36 | { 37 | [Transaction( TransactionMode.ReadOnly )] 38 | class CmdUnhostedElements : IExternalCommand 39 | { 40 | #region Determine unhosted elements 41 | static bool IsValidHost( string hostValue ) 42 | { 43 | bool rc = ( "" != hostValue ) 44 | && ( "None" != hostValue ); 45 | return rc; 46 | } 47 | 48 | /// 49 | /// Determine unhosted elements. 50 | /// 51 | static bool DetermineUnhostedElements( Document doc ) 52 | { 53 | int nHosted = 0; 54 | int nUnhosted = 0; 55 | bool needHeader = true; 56 | List unhosted = new List(); 57 | { 58 | WaitCursor waitCursor = new WaitCursor(); 59 | FilteredElementCollector collector = new FilteredElementCollector( doc ); 60 | collector.OfClass( typeof( FamilyInstance ) ); 61 | //int j = 0; 62 | 63 | // temporary problem: running this in rac_basic_sample_project.rvt throws an exception 64 | // Unable to cast object of type 'Autodesk.Revit.DB.Panel' to type 'Autodesk.Revit.DB.FamilyInstance'. 65 | // fixed in http://srd.autodesk.com/srdapp/ReportForm.asp?number=176141 66 | 67 | foreach( FamilyInstance inst in collector ) 68 | { 69 | //Debug.WriteLine( ++j ); 70 | Parameter p = inst.get_Parameter( Bip.Host ); 71 | if( null != p ) 72 | { 73 | if( needHeader ) 74 | { 75 | Debug.WriteLine( "\nHosted and unhosted elements:" ); 76 | needHeader = false; 77 | } 78 | string description = Util.ElementDescriptionAndId( inst ); 79 | string hostValue = p.AsString(); 80 | bool hosted = IsValidHost( hostValue ); 81 | if( hosted ) { ++nHosted; } 82 | else 83 | { 84 | ++nUnhosted; 85 | //if( null == unhosted ) 86 | //{ 87 | // unhosted = new string[1]; 88 | // unhosted[0] = description; 89 | //} 90 | //else 91 | //{ 92 | // unhosted.se 93 | //} 94 | unhosted.Add( description ); 95 | } 96 | Debug.WriteLine( string.Format( "{0} {1} host is '{2}' --> {3}hosted", 97 | description, inst.Id.IntegerValue, hostValue, hosted ? "" : "un" ) ); 98 | } 99 | } 100 | } 101 | if( 0 < nHosted + nUnhosted ) 102 | { 103 | Debug.WriteLine( string.Format( "{0} hosted and {1} unhosted elements.", nHosted, nUnhosted ) ); 104 | } 105 | if( 0 < nUnhosted ) 106 | { 107 | string[] a = new string[unhosted.Count]; 108 | int i = 0; 109 | foreach( string s in unhosted ) 110 | { 111 | a[i++] = s; 112 | } 113 | // todo: present the element ids in a separete edit box for easier copy and paste: 114 | string msg = string.Format( "{0} unhosted element{1}:\n\n", nUnhosted, Util.PluralSuffix( nUnhosted ) ) 115 | + string.Join( "\n", a ); 116 | Util.InfoMsg( msg ); 117 | } 118 | return true; 119 | } 120 | #endregion // Determine unhosted elements 121 | 122 | #region Execute Command 123 | public Result Execute( 124 | ExternalCommandData commandData, 125 | ref String message, 126 | ElementSet elements ) 127 | { 128 | try 129 | { 130 | UIApplication app = commandData.Application; 131 | Document doc = app.ActiveUIDocument.Document; 132 | // 133 | // 5. determine unhosted elements (cf. SPR 134098). 134 | // list all hosted versus unhosted elements: 135 | // 136 | bool rc = DetermineUnhostedElements( doc ); 137 | return Result.Cancelled; 138 | } 139 | catch( Exception ex ) 140 | { 141 | message = ex.Message; 142 | return Result.Failed; 143 | } 144 | } 145 | #endregion // Execute Command 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /AdnRme/Command.cs: -------------------------------------------------------------------------------- 1 | #region Namespaces 2 | using System; 3 | using System.Collections.Generic; 4 | using Autodesk.Revit.ApplicationServices; 5 | using Autodesk.Revit.Attributes; 6 | using Autodesk.Revit.DB; 7 | using Autodesk.Revit.UI; 8 | #endregion 9 | 10 | namespace AdnRme 11 | { 12 | [Transaction( TransactionMode.Manual )] 13 | public class Command : IExternalCommand 14 | { 15 | public Result Execute( 16 | ExternalCommandData commandData, 17 | ref string message, 18 | ElementSet elements ) 19 | { 20 | return Result.Succeeded; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /AdnRme/Const.cs: -------------------------------------------------------------------------------- 1 | #region Header 2 | // Revit MEP API sample application 3 | // 4 | // Copyright (C) 2007-2021 by Jeremy Tammik, Autodesk, Inc. 5 | // 6 | // Permission to use, copy, modify, and distribute this software 7 | // for any purpose and without fee is hereby granted, provided 8 | // that the above copyright notice appears in all copies and 9 | // that both that copyright notice and the limited warranty and 10 | // restricted rights notice below appear in all supporting 11 | // documentation. 12 | // 13 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 14 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 15 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. 16 | // AUTODESK, INC. DOES NOT WARRANT THAT THE OPERATION OF THE 17 | // PROGRAM WILL BE UNINTERRUPTED OR ERROR FREE. 18 | // 19 | // Use, duplication, or disclosure by the U.S. Government is subject 20 | // to restrictions set forth in FAR 52.227-19 (Commercial Computer 21 | // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) 22 | // (Rights in Technical Data and Computer Software), as applicable. 23 | #endregion // Header 24 | 25 | namespace AdnRme 26 | { 27 | class Const 28 | { 29 | /// 30 | /// Unit conversion factor for calculating CFM/SF from CFS internal units 31 | /// 32 | public const double SecondsPerMinute = 60; 33 | /// 34 | /// Round-up factor factor for rounding up terminal flow 35 | /// 36 | public const double RoundTerminalFlowTo = 5; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /AdnRme/FamilySelector.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace AdnRme 2 | { 3 | partial class FamilySelector 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose( bool disposing ) 15 | { 16 | if( disposing && ( components != null ) ) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose( disposing ); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.checkedListBox1 = new System.Windows.Forms.CheckedListBox(); 32 | this.btnOk = new System.Windows.Forms.Button(); 33 | this.btnCancel = new System.Windows.Forms.Button(); 34 | this.SuspendLayout(); 35 | // 36 | // checkedListBox1 37 | // 38 | this.checkedListBox1.Anchor = ( (System.Windows.Forms.AnchorStyles) ( ( ( ( System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom ) 39 | | System.Windows.Forms.AnchorStyles.Left ) 40 | | System.Windows.Forms.AnchorStyles.Right ) ) ); 41 | this.checkedListBox1.FormattingEnabled = true; 42 | this.checkedListBox1.Location = new System.Drawing.Point( 9, 11 ); 43 | this.checkedListBox1.Name = "checkedListBox1"; 44 | this.checkedListBox1.Size = new System.Drawing.Size( 224, 109 ); 45 | this.checkedListBox1.TabIndex = 0; 46 | // 47 | // btnOk 48 | // 49 | this.btnOk.Anchor = ( (System.Windows.Forms.AnchorStyles) ( ( System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left ) ) ); 50 | this.btnOk.DialogResult = System.Windows.Forms.DialogResult.OK; 51 | this.btnOk.Location = new System.Drawing.Point( 9, 132 ); 52 | this.btnOk.Name = "btnOk"; 53 | this.btnOk.Size = new System.Drawing.Size( 104, 32 ); 54 | this.btnOk.TabIndex = 1; 55 | this.btnOk.Text = "OK"; 56 | this.btnOk.UseVisualStyleBackColor = true; 57 | // 58 | // btnCancel 59 | // 60 | this.btnCancel.Anchor = ( (System.Windows.Forms.AnchorStyles) ( ( System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left ) ) ); 61 | this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; 62 | this.btnCancel.Location = new System.Drawing.Point( 136, 132 ); 63 | this.btnCancel.Name = "btnCancel"; 64 | this.btnCancel.Size = new System.Drawing.Size( 97, 34 ); 65 | this.btnCancel.TabIndex = 2; 66 | this.btnCancel.Text = "Cancel"; 67 | this.btnCancel.UseVisualStyleBackColor = true; 68 | // 69 | // FamilySelector 70 | // 71 | this.AcceptButton = this.btnOk; 72 | this.AutoScaleDimensions = new System.Drawing.SizeF( 6F, 13F ); 73 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 74 | this.CancelButton = this.btnCancel; 75 | this.ClientSize = new System.Drawing.Size( 243, 174 ); 76 | this.Controls.Add( this.btnCancel ); 77 | this.Controls.Add( this.btnOk ); 78 | this.Controls.Add( this.checkedListBox1 ); 79 | this.MinimumSize = new System.Drawing.Size( 251, 201 ); 80 | this.Name = "FamilySelector"; 81 | this.Text = "Please Select Families to Resize"; 82 | this.ResumeLayout( false ); 83 | 84 | } 85 | 86 | #endregion 87 | 88 | private System.Windows.Forms.CheckedListBox checkedListBox1; 89 | private System.Windows.Forms.Button btnOk; 90 | private System.Windows.Forms.Button btnCancel; 91 | } 92 | } -------------------------------------------------------------------------------- /AdnRme/FamilySelector.cs: -------------------------------------------------------------------------------- 1 | #region Header 2 | // Revit MEP API sample application 3 | // 4 | // Copyright (C) 2007-2021 by Jeremy Tammik, Autodesk, Inc. 5 | // 6 | // Permission to use, copy, modify, and distribute this software 7 | // for any purpose and without fee is hereby granted, provided 8 | // that the above copyright notice appears in all copies and 9 | // that both that copyright notice and the limited warranty and 10 | // restricted rights notice below appear in all supporting 11 | // documentation. 12 | // 13 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 14 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 15 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. 16 | // AUTODESK, INC. DOES NOT WARRANT THAT THE OPERATION OF THE 17 | // PROGRAM WILL BE UNINTERRUPTED OR ERROR FREE. 18 | // 19 | // Use, duplication, or disclosure by the U.S. Government is subject 20 | // to restrictions set forth in FAR 52.227-19 (Commercial Computer 21 | // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) 22 | // (Rights in Technical Data and Computer Software), as applicable. 23 | #endregion // Header 24 | 25 | #region Namespaces 26 | using System; 27 | using System.Collections; 28 | using System.Diagnostics; 29 | using System.Windows.Forms; 30 | #endregion // Namespaces 31 | 32 | namespace AdnRme 33 | { 34 | public partial class FamilySelector : Form 35 | { 36 | public FamilySelector( IEnumerable a ) 37 | { 38 | InitializeComponent(); 39 | foreach( string s in a ) 40 | { 41 | checkedListBox1.Items.Add( s, true ); 42 | } 43 | } 44 | 45 | public bool IsChecked( string s ) 46 | { 47 | int i = checkedListBox1.Items.IndexOf( s ); 48 | Debug.Assert( -1 < i, "expected item to be contained in listbox" ); 49 | return ( -1 < i ) ? checkedListBox1.GetItemChecked( i ) : false; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /AdnRme/FamilySelector.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /AdnRme/PanelTreeNodeHelper.cs: -------------------------------------------------------------------------------- 1 | using Autodesk.Revit.DB; 2 | 3 | namespace AdnRme 4 | { 5 | class PanelTreeNodeHelper 6 | { 7 | System.Windows.Forms.TreeNode _tn; 8 | Autodesk.Revit.DB.Element _element; 9 | 10 | public PanelTreeNodeHelper( Element e ) 11 | { 12 | _element = e; 13 | } 14 | 15 | public PanelTreeNodeHelper( Element e, System.Windows.Forms.TreeNode tn ) 16 | { 17 | _element = e; 18 | _tn = tn; 19 | } 20 | 21 | public System.Windows.Forms.TreeNode TreeNode 22 | { 23 | get { return _tn; } 24 | //set { _tn = value; } 25 | } 26 | 27 | public Element Element 28 | { 29 | get { return _element; } 30 | //set { _element = value; } 31 | } 32 | 33 | public override string ToString() 34 | { 35 | return Element.Name; 36 | } 37 | 38 | 39 | public static int CompareByName( PanelTreeNodeHelper x, PanelTreeNodeHelper y ) 40 | { 41 | return string.Compare( x.ToString(), y.ToString() ); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /AdnRme/ParameterName.cs: -------------------------------------------------------------------------------- 1 | #region Header 2 | // Revit MEP API sample application 3 | // 4 | // Copyright (C) 2007-2021 by Jeremy Tammik, Autodesk, Inc. 5 | // 6 | // Permission to use, copy, modify, and distribute this software 7 | // for any purpose and without fee is hereby granted, provided 8 | // that the above copyright notice appears in all copies and 9 | // that both that copyright notice and the limited warranty and 10 | // restricted rights notice below appear in all supporting 11 | // documentation. 12 | // 13 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 14 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 15 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. 16 | // AUTODESK, INC. DOES NOT WARRANT THAT THE OPERATION OF THE 17 | // PROGRAM WILL BE UNINTERRUPTED OR ERROR FREE. 18 | // 19 | // Use, duplication, or disclosure by the U.S. Government is subject 20 | // to restrictions set forth in FAR 52.227-19 (Commercial Computer 21 | // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) 22 | // (Rights in Technical Data and Computer Software), as applicable. 23 | #endregion // Header 24 | 25 | namespace AdnRme 26 | { 27 | class ParameterName 28 | { 29 | // 30 | // used for display only 31 | // 32 | public const string CalculatedSupplyAirFlow = "Calculated Supply Air Flow"; 33 | // 34 | // The "CFM per SF" is a project parameter, and as such, there is no enumeration for this; 35 | // In 2009, "Calculated Supply Airflow per area" exists, built-in parameter 36 | // ROOM_CALCULATED_SUPPLY_AIRFLOW_PER_AREA_PARAM: 37 | // 38 | public const string CfmPerSf = "CFM per SF"; 39 | // 40 | // The other issue regarding the two 'Flow' params is quite simple ... 41 | // the Flow we are accessing is not a Built-in-Parameter of the Air Terminal itself ... 42 | // the Flow is simply a Family Parameter that is mapped to the Connector on the Air Terminal ... 43 | // I would guess that the 'Flow' that is the built-in-parameter is actually the Flow on the connector 44 | // (and/or - perhaps it is the Flow parameter of a Duct object) ... 45 | // at this point, the API doesn't expose Connector objects, so to get the Flow from the connector, 46 | // we have to get it via the Family parameter on the terminal. 47 | // The Flow in our case could be named anything, i.e., it could be "SomeFlowParameter" ... 48 | // it really just depends on how the Family is created, which in our case could be problematic 49 | // if the user is using a custom Family that doesn't have the parameter named "Flow" ... 50 | // but they could also create an air terminal that has >1 connector ... 51 | // would they actually do that? Hmm ... likely not, but you never know :). 52 | // 53 | // The way the "Flow" family parameter is mapped to the Flow built-in-parameter of the Connector 54 | // is through Family Editor (FE). In FE, select the connector object, click Element Properties, 55 | // and note that the Flow parameter here has a button in the right hand column ... 56 | // click this, and you will see that the "Flow" family parameter is selected. 57 | // 58 | public const string Flow = "Flow"; 59 | // 60 | // air terminal family symbol parameters used in CmdChangeSize: 61 | // 62 | public const string MaxFlow = "Max Flow"; 63 | public const string MinFlow = "Min Flow"; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /AdnRme/ParameterValue.cs: -------------------------------------------------------------------------------- 1 | #region Header 2 | // Revit MEP API sample application 3 | // 4 | // Copyright (C) 2007-2021 by Jeremy Tammik, Autodesk, Inc. 5 | // 6 | // Permission to use, copy, modify, and distribute this software 7 | // for any purpose and without fee is hereby granted, provided 8 | // that the above copyright notice appears in all copies and 9 | // that both that copyright notice and the limited warranty and 10 | // restricted rights notice below appear in all supporting 11 | // documentation. 12 | // 13 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 14 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 15 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. 16 | // AUTODESK, INC. DOES NOT WARRANT THAT THE OPERATION OF THE 17 | // PROGRAM WILL BE UNINTERRUPTED OR ERROR FREE. 18 | // 19 | // Use, duplication, or disclosure by the U.S. Government is subject 20 | // to restrictions set forth in FAR 52.227-19 (Commercial Computer 21 | // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) 22 | // (Rights in Technical Data and Computer Software), as applicable. 23 | #endregion // Header 24 | 25 | namespace AdnRme 26 | { 27 | class ParameterValue 28 | { 29 | // 30 | // In Revit 2008, there are built-in parameters to access the actual, 31 | // calculated and specified supply airflows, but not for the "Supply Air": 32 | // 33 | // Actual Supply Airflow : ROOM_ACTUAL_SUPPLY_AIRFLOW_PARAM = Double: 2.08333333333333 34 | // Calculated Supply Airflow : ROOM_CALCULATED_SUPPLY_AIRFLOW_PARAM = Double: 2.29236666666667 35 | // Specified Supply Airflow : ROOM_DESIGN_SUPPLY_AIRFLOW_PARAM = Double: 2.29236666666667 36 | // 37 | public const string SupplyAir = "Supply Air"; 38 | // 39 | // Revit 2009 provides Autodesk.Revit.MEP.Enums.DuctSystemType.SupplyAir. 40 | // But that is not a parameter value, and I do not see where it can be queried. 41 | // 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /AdnRme/ProgressForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace AdnRme 2 | { 3 | partial class ProgressForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.progressBar1 = new System.Windows.Forms.ProgressBar(); 32 | this.label1 = new System.Windows.Forms.Label(); 33 | this.SuspendLayout(); 34 | // 35 | // progressBar1 36 | // 37 | this.progressBar1.Location = new System.Drawing.Point( 11, 25 ); 38 | this.progressBar1.Name = "progressBar1"; 39 | this.progressBar1.Size = new System.Drawing.Size( 406, 23 ); 40 | this.progressBar1.TabIndex = 0; 41 | // 42 | // label1 43 | // 44 | this.label1.AutoSize = true; 45 | this.label1.Location = new System.Drawing.Point( 8, 7 ); 46 | this.label1.Name = "label1"; 47 | this.label1.Size = new System.Drawing.Size( 68, 13 ); 48 | this.label1.TabIndex = 1; 49 | this.label1.Text = "Processing..."; 50 | // 51 | // ProgressForm 52 | // 53 | this.AutoScaleDimensions = new System.Drawing.SizeF( 6F, 13F ); 54 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 55 | this.ClientSize = new System.Drawing.Size( 429, 61 ); 56 | this.ControlBox = false; 57 | this.Controls.Add( this.label1 ); 58 | this.Controls.Add( this.progressBar1 ); 59 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; 60 | this.MaximizeBox = false; 61 | this.MinimizeBox = false; 62 | this.Name = "ProgressForm"; 63 | this.ShowIcon = false; 64 | this.ShowInTaskbar = false; 65 | this.Text = "Working..."; 66 | this.TopMost = true; 67 | this.ResumeLayout( false ); 68 | this.PerformLayout(); 69 | 70 | } 71 | 72 | #endregion 73 | 74 | private System.Windows.Forms.Label label1; 75 | private System.Windows.Forms.ProgressBar progressBar1; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /AdnRme/ProgressForm.cs: -------------------------------------------------------------------------------- 1 | #region Header 2 | // Revit MEP API sample application 3 | // 4 | // Copyright (C) 2007-2021 by Jeremy Tammik, Autodesk, Inc. 5 | // 6 | // Permission to use, copy, modify, and distribute this software 7 | // for any purpose and without fee is hereby granted, provided 8 | // that the above copyright notice appears in all copies and 9 | // that both that copyright notice and the limited warranty and 10 | // restricted rights notice below appear in all supporting 11 | // documentation. 12 | // 13 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 14 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 15 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. 16 | // AUTODESK, INC. DOES NOT WARRANT THAT THE OPERATION OF THE 17 | // PROGRAM WILL BE UNINTERRUPTED OR ERROR FREE. 18 | // 19 | // Use, duplication, or disclosure by the U.S. Government is subject 20 | // to restrictions set forth in FAR 52.227-19 (Commercial Computer 21 | // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) 22 | // (Rights in Technical Data and Computer Software), as applicable. 23 | #endregion // Header 24 | 25 | #region Namespaces 26 | using System; 27 | using System.Windows.Forms; 28 | #endregion // Namespaces 29 | 30 | namespace AdnRme 31 | { 32 | public partial class ProgressForm : Form 33 | { 34 | string _format; 35 | 36 | /// 37 | /// Set up progress bar form and immediately display it modelessly. 38 | /// 39 | /// Form caption 40 | /// Progress message string 41 | /// Number of elements to process 42 | public ProgressForm( string caption, string format, int max ) 43 | { 44 | _format = format; 45 | InitializeComponent(); 46 | Text = caption; 47 | label1.Text = (null == format) ? caption : string.Format( format, 0 ); 48 | progressBar1.Minimum = 0; 49 | progressBar1.Maximum = max; 50 | progressBar1.Value = 0; 51 | Show(); 52 | Application.DoEvents(); 53 | } 54 | 55 | public void Increment() 56 | { 57 | ++progressBar1.Value; 58 | 59 | if( null != _format ) 60 | { 61 | label1.Text = string.Format( _format, progressBar1.Value ); 62 | } 63 | Application.DoEvents(); 64 | } 65 | 66 | #if USE_MARTINS_PROGRESS_FORM 67 | public void SetText(string text) 68 | { 69 | label1.Text = text; 70 | System.Windows.Forms.Application.DoEvents(); 71 | } 72 | 73 | public void SetProgressBarMinMax(int min, int max) 74 | { 75 | progressBar1.Minimum = min; 76 | progressBar1.Maximum = max; 77 | progressBar1.Value = 0; 78 | } 79 | 80 | public void IncrementProgressBar() 81 | { 82 | progressBar1.Value++; 83 | System.Windows.Forms.Application.DoEvents(); 84 | } 85 | 86 | public void HideProgressBar() 87 | { 88 | progressBar1.Visible = false; 89 | System.Windows.Forms.Application.DoEvents(); 90 | } 91 | 92 | public void ShowProgressBar() 93 | { 94 | progressBar1.Visible = true; 95 | System.Windows.Forms.Application.DoEvents(); 96 | } 97 | #endif // USE_MARTINS_PROGRESS_FORM 98 | 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /AdnRme/ProgressForm.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /AdnRme/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle( "Revit MEP Sample Application" )] 9 | [assembly: AssemblyDescription 10 | ( "Demonstrate use of the Revit API for MEP: " 11 | + "1. use of the generic API for HVAC specific tasks: " 12 | + "determine air terminals for each space; " 13 | + "assign flow to the air terminals depending on the space's calculated supply air flow; " 14 | + "change size of diffuser based on flow; " 15 | + "populate the value of the 'CFM per SF' variable on all spaces; " 16 | + "determine unhosted elements; " 17 | + "reset demo. " 18 | + "2. use of the MEP specific API to traverse an electrical system " 19 | + "and display its hierarchy in a tree view." )] 20 | [assembly: AssemblyConfiguration( "" )] 21 | [assembly: AssemblyCompany( "ADN Autodesk Developer Network, Autodesk, Inc." )] 22 | [assembly: AssemblyProduct( "Revit MEP Sample Application" )] 23 | [assembly: AssemblyCopyright( "Copyright © 2007-2021 by Jeremy Tammik, Autodesk, Inc." )] 24 | [assembly: AssemblyTrademark( "" )] 25 | [assembly: AssemblyCulture( "" )] 26 | 27 | // Setting ComVisible to false makes the types in this assembly not visible 28 | // to COM components. If you need to access a type in this assembly from 29 | // COM, set the ComVisible attribute to true on that type. 30 | [assembly: ComVisible( false )] 31 | 32 | // The following GUID is for the ID of the typelib if this project is exposed to COM 33 | [assembly: Guid( "118f7279-630d-4661-afe5-c23c23acf46f" )] 34 | 35 | // Version information for an assembly consists of the following four values: 36 | // 37 | // Major Version 38 | // Minor Version 39 | // Build Number 40 | // Revision 41 | // 42 | // You can specify all the values or you can default the Build and Revision Numbers 43 | // by using the '*' as shown below: 44 | // [assembly: AssemblyVersion("1.0.*")] 45 | // 46 | // History: 47 | // 2014-09-02 2015.0.0.2 reformatted before removing obsolete API usage 48 | // 2014-09-02 2015.0.0.3 removed obsolete API usage, specifically replaced Family.Symbols property by GetFamilySymbolIds 49 | // 2014-09-02 2015.0.0.4 bumped the copyright message year from 2013 or whatever to 2014 50 | // 2015-02-02 2015.0.0.5 bumped the copyright message year from 2014 to 2015 51 | // 2015-06-04 2016.0.0.0 flat migration to Revit 2016 52 | // 2016-04-13 2016.0.0.1 incremented copyright year from 2015 to 2016 53 | // 2018-02-02 2018.0.0.0 migrated to Revit 2018, incremented copyright year, eliminated automatic transactions 54 | // 2018-04-18 2019.0.0.0 migrated to Revit 2019 55 | // 2020-11-05 2020.0.0.0 migrated to Revit 2020 56 | // 2020-11-05 2021.0.0.0 flat migration to Revit 2021 API produces 11 deprecated API usage warnings 57 | // 2020-11-05 2021.0.0.1 eliminated deprecated API usage 58 | // 2021-01-11 2021.0.0.2 incremented copyright year 59 | // 60 | [assembly: AssemblyVersion( "2021.0.0.2" )] 61 | [assembly: AssemblyFileVersion( "2021.0.0.2" )] 62 | -------------------------------------------------------------------------------- /AdnRme/Util.cs: -------------------------------------------------------------------------------- 1 | #region Header 2 | // Revit MEP API sample application 3 | // 4 | // Copyright (C) 2007-2021 by Jeremy Tammik, Autodesk, Inc. 5 | // 6 | // Permission to use, copy, modify, and distribute this software 7 | // for any purpose and without fee is hereby granted, provided 8 | // that the above copyright notice appears in all copies and 9 | // that both that copyright notice and the limited warranty and 10 | // restricted rights notice below appear in all supporting 11 | // documentation. 12 | // 13 | // AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS. 14 | // AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 15 | // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE. 16 | // AUTODESK, INC. DOES NOT WARRANT THAT THE OPERATION OF THE 17 | // PROGRAM WILL BE UNINTERRUPTED OR ERROR FREE. 18 | // 19 | // Use, duplication, or disclosure by the U.S. Government is subject 20 | // to restrictions set forth in FAR 52.227-19 (Commercial Computer 21 | // Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) 22 | // (Rights in Technical Data and Computer Software), as applicable. 23 | #endregion // Header 24 | 25 | #region Namespaces 26 | using System; 27 | using System.Collections.Generic; 28 | using System.Diagnostics; 29 | using System.Linq; 30 | using WinForms = System.Windows.Forms; 31 | using Autodesk.Revit.ApplicationServices; 32 | using Autodesk.Revit.DB; 33 | using Autodesk.Revit.DB.Electrical; 34 | using Autodesk.Revit.DB.Mechanical; 35 | #endregion // Namespaces 36 | 37 | namespace AdnRme 38 | { 39 | class Util 40 | { 41 | #region Exceptions 42 | public class ParameterException : Exception 43 | { 44 | public ParameterException( string parameterName, string description, Element elem ) 45 | : base( string.Format( "'{0}' parameter not defined for {1} {2}", parameterName, description, elem.Id.IntegerValue.ToString() ) ) 46 | { 47 | } 48 | } 49 | 50 | public class SpaceParameterException : Exception 51 | { 52 | public SpaceParameterException( string parameterName, Space space ) 53 | : base( string.Format( "'{0}' parameter not defined for space {1}", parameterName, space.Number ) ) 54 | { 55 | } 56 | } 57 | 58 | public class TerminalParameterException : ParameterException 59 | { 60 | public TerminalParameterException( string parameterName, FamilyInstance terminal ) 61 | : base( parameterName, "terminal", terminal ) 62 | { 63 | } 64 | } 65 | #endregion // Exceptions 66 | 67 | #region Formatting 68 | public static string PluralSuffix( int n ) 69 | { 70 | return 1 == n ? "" : "s"; 71 | } 72 | 73 | public static string DotOrColon( int n ) 74 | { 75 | return 0 == n ? "." : ":"; 76 | } 77 | 78 | public static string IdList( IList elements ) 79 | { 80 | string s = string.Empty; 81 | foreach( Element e in elements ) 82 | { 83 | if( 0 < s.Length ) 84 | { 85 | s += ", "; 86 | } 87 | s += e.Id.IntegerValue.ToString(); 88 | } 89 | return s; 90 | } 91 | 92 | /// 93 | /// Format a real number and return its string representation. 94 | /// 95 | public static string RealString( double a ) 96 | { 97 | return a.ToString( "0.##" ); 98 | } 99 | 100 | /// 101 | /// Return a description string for a given element. 102 | /// 103 | public static string ElementDescription( Element e ) 104 | { 105 | string description = ( null == e.Category ) 106 | ? e.GetType().Name 107 | : e.Category.Name; 108 | if( null != e.Name ) 109 | { 110 | description += " '" + e.Name + "'"; 111 | } 112 | return description; 113 | } 114 | 115 | /// 116 | /// Return a description string including element id for a given element. 117 | /// 118 | public static string ElementDescriptionAndId( Element e ) 119 | { 120 | string description = e.GetType().Name; 121 | if( null != e.Category ) 122 | { 123 | description += " " + e.Category.Name; 124 | } 125 | string identity = e.Id.IntegerValue.ToString(); 126 | if( null != e.Name ) 127 | { 128 | identity = e.Name + " " + identity; 129 | } 130 | return string.Format( "{0} <{1}>", description, identity ); 131 | } 132 | 133 | /// 134 | /// Return an element description string for an electrical system browser leaf node. 135 | /// 136 | public static string BrowserDescription( Element e ) 137 | { 138 | FamilyInstance inst = e as FamilyInstance; 139 | return ( null == inst ? e.Category.Name : inst.Symbol.Family.Name ) + " " + e.Name; 140 | } 141 | #endregion // Formatting 142 | 143 | #region Message 144 | const string _caption = "Revit MEP API Sample"; 145 | 146 | /// 147 | /// MessageBox wrapper for informational message. 148 | /// 149 | /// 150 | public static void InfoMsg( string msg ) 151 | { 152 | WinForms.MessageBox.Show( msg, _caption, WinForms.MessageBoxButtons.OK, WinForms.MessageBoxIcon.Information ); 153 | } 154 | 155 | /// 156 | /// MessageBox wrapper for error message. 157 | /// 158 | /// 159 | public static void ErrorMsg( string msg ) 160 | { 161 | WinForms.MessageBox.Show( msg, _caption, WinForms.MessageBoxButtons.OK, WinForms.MessageBoxIcon.Error ); 162 | } 163 | 164 | /// 165 | /// MessageBox wrapper for question message. 166 | /// 167 | public static bool QuestionMsg( string msg ) 168 | { 169 | return WinForms.DialogResult.Yes 170 | == WinForms.MessageBox.Show( msg, _caption, WinForms.MessageBoxButtons.YesNo, WinForms.MessageBoxIcon.Question ); 171 | } 172 | #endregion // Message 173 | 174 | #region Parameter Access 175 | /// 176 | /// Helper to get a specific parameter by name. 177 | /// 178 | static Parameter GetParameterFromName( Element elem, string name ) 179 | { 180 | foreach( Parameter p in elem.Parameters ) 181 | { 182 | if( p.Definition.Name == name ) 183 | { 184 | return p; 185 | } 186 | } 187 | return null; 188 | } 189 | 190 | public static Definition GetParameterDefinitionFromName( Element elem, string name ) 191 | { 192 | Parameter p = GetParameterFromName( elem, name ); 193 | return ( null == p ) ? null : p.Definition; 194 | } 195 | 196 | public static double GetParameterValueFromName( Element elem, string name ) 197 | { 198 | Parameter p = GetParameterFromName( elem, name ); 199 | if( null == p ) 200 | { 201 | throw new ParameterException( name, "element", elem ); 202 | } 203 | return p.AsDouble(); 204 | } 205 | 206 | public static string GetStringParameterValueFromName(Element elem, string name) 207 | { 208 | Parameter p = GetParameterFromName(elem, name); 209 | if (null == p) 210 | { 211 | throw new ParameterException(name, "element", elem); 212 | } 213 | return p.AsString(); 214 | } 215 | 216 | static void DumpParameters( Element elem ) 217 | { 218 | foreach( Parameter p in elem.Parameters ) 219 | { 220 | Debug.WriteLine( p.Definition.ParameterType + " " + p.Definition.Name ); 221 | } 222 | } 223 | 224 | public static double GetSpaceParameterValue( Space space, BuiltInParameter bip, string name ) 225 | { 226 | Parameter p = space.get_Parameter( bip ); 227 | if( null == p ) 228 | { 229 | throw new SpaceParameterException( name, space ); 230 | } 231 | return p.AsDouble(); 232 | } 233 | 234 | public static Parameter GetSpaceParameter( Space space, string name ) 235 | { 236 | Parameter p = GetParameterFromName( space, name ); 237 | if( null == p ) 238 | { 239 | throw new SpaceParameterException( name, space ); 240 | } 241 | return p; 242 | } 243 | 244 | public static double GetSpaceParameterValue( Space space, string name ) 245 | { 246 | Parameter p = GetSpaceParameter( space, name ); 247 | return p.AsDouble(); 248 | } 249 | 250 | #if NEED_IS_SUPPLY_AIR_METHOD 251 | public static bool IsSupplyAir( FamilyInstance terminal ) 252 | { 253 | Parameter p = terminal.get_Parameter( Bip.SystemType ); 254 | if( null == p ) 255 | { 256 | throw new TerminalParameterException( Bip.SystemType.ToString(), terminal ); 257 | } 258 | bool rc = p.AsString().Equals( ParameterValue.SupplyAir ); 259 | 260 | #if DEBUG 261 | ElementId typeId = terminal.GetTypeId(); 262 | ElementType t = terminal.Document.get_Element( typeId ) as ElementType; 263 | MEPSystemType t2 = terminal.Document.get_Element( typeId ) as MEPSystemType; 264 | Debug.Assert( (MEPSystemClassification.SupplyAir == t2.SystemClassification) == rc, 265 | "expected parameter check to return correct system classification" ); 266 | #endif // DEBUG 267 | 268 | return rc; 269 | } 270 | #endif // NEED_IS_SUPPLY_AIR_METHOD 271 | 272 | public static Parameter GetTerminalFlowParameter( FamilyInstance terminal ) 273 | { 274 | // 275 | // the built-in parameter "Flow" is read-only: 276 | // 277 | //Parameter p = terminal.get_Parameter( _bipFlow ); 278 | // 279 | // The parameter we are interested in is not the BuiltInParameter... 280 | // 281 | Definition d = Util.GetParameterDefinitionFromName( terminal, ParameterName.Flow ); 282 | Parameter p = terminal.get_Parameter( d ); 283 | if( null == p ) 284 | { 285 | throw new Util.TerminalParameterException( ParameterName.Flow, terminal ); 286 | } 287 | return p; 288 | } 289 | #endregion // Parameter Access 290 | 291 | #region HVAC Element Access 292 | /// 293 | /// Retrieve all supply air terminals from given document. 294 | /// Select all family instance elements of BuiltInCategory 295 | /// OST_DuctTerminal with system type equal to suppy air. 296 | /// 297 | public static FilteredElementCollector GetSupplyAirTerminals( Document doc ) 298 | { 299 | FilteredElementCollector collector = new FilteredElementCollector( doc ); 300 | collector.OfCategory( BuiltInCategory.OST_DuctTerminal ); 301 | collector.OfClass( typeof( FamilyInstance ) ); 302 | 303 | //int n1 = collector.ToElements().Count; // 61 in sample model 304 | 305 | // ensure that system type equals supply air: 306 | // 307 | // in Revit 2009 and 2010 API, this did it: 308 | // 309 | //ParameterFilter parameterFilter = a.Filter.NewParameterFilter( 310 | // Bip.SystemType, CriteriaFilterType.Equal, ParameterValue.SupplyAir ); 311 | 312 | // in Revit 2011, create an ElementParameter filter. 313 | // Create filter by provider and evaluator: 314 | 315 | ParameterValueProvider provider = new ParameterValueProvider( new ElementId( Bip.SystemType ) ); 316 | FilterStringRuleEvaluator evaluator = new FilterStringEquals(); 317 | string ruleString = ParameterValue.SupplyAir; 318 | FilterRule rule = new FilterStringRule( provider, evaluator, ruleString, false ); 319 | ElementParameterFilter filter = new ElementParameterFilter( rule ); 320 | 321 | collector.WherePasses( filter ); 322 | 323 | //int n2 = collector.ToElements().Count; // 51 in sample model 324 | 325 | return collector; 326 | } 327 | 328 | /// 329 | /// Retrieve all spaces in given document. 330 | /// 331 | public static List GetSpaces( Document doc ) 332 | { 333 | FilteredElementCollector collector 334 | = new FilteredElementCollector( doc ); 335 | 336 | // trying to collect all spaces directly causes 337 | // the following error: 338 | // 339 | // Input type is of an element type that exists 340 | // in the API, but not in Revit's native object 341 | // model. Try using Autodesk.Revit.DB.Enclosure 342 | // instead, and then postprocessing the results 343 | // to find the elements of interest. 344 | // 345 | //collector.OfClass( typeof( Space ) ); 346 | 347 | collector.OfClass( typeof( SpatialElement ) ); 348 | 349 | //return ( from e in collector.ToElements() // 2011 350 | // where e is Space 351 | // select e as Space ) 352 | // .ToList(); 353 | 354 | return collector.ToElements().OfType().ToList(); // 2012 355 | } 356 | #endregion // HVAC Element Access 357 | 358 | #region Electrical Element Access 359 | /// 360 | /// Return all elements of the requested class i.e. System.Type 361 | /// matching the given built-in category in the active document. 362 | /// 363 | public static FilteredElementCollector GetElementsOfType( 364 | Document doc, 365 | Type type, 366 | BuiltInCategory bic ) 367 | { 368 | FilteredElementCollector collector 369 | = new FilteredElementCollector( doc ); 370 | 371 | collector.OfCategory( bic ); 372 | collector.OfClass( type ); 373 | 374 | return collector; 375 | } 376 | 377 | /// 378 | /// Retrieve all electrical equipment elements in the given document, 379 | /// identified by the built-in category OST_ElectricalEquipment. 380 | /// 381 | public static List GetElectricalEquipment( 382 | Document doc ) 383 | { 384 | FilteredElementCollector collector 385 | = GetElementsOfType( doc, typeof( FamilyInstance ), 386 | BuiltInCategory.OST_ElectricalEquipment ); 387 | 388 | // return a List instead of IList, because we need the method Exists() on it: 389 | 390 | return new List( collector.ToElements() ); 391 | } 392 | 393 | /// 394 | /// Retrieve all electrical system elements in the given document. 395 | /// 396 | public static IList GetElectricalSystems( Document doc ) 397 | { 398 | FilteredElementCollector collector = new FilteredElementCollector( doc ); 399 | collector.OfClass( typeof( ElectricalSystem ) ); 400 | return collector.ToElements(); 401 | } 402 | 403 | /// 404 | /// Retrieve all circuit elements in current active document, 405 | /// which we identify as all family instance or electrical system 406 | /// elements with a non-empty RBS_ELEC_CIRCUIT_NUMBER or "Circuit Number" 407 | /// parameter. 408 | /// 409 | public static IList GetCircuitElements( Document doc ) 410 | { 411 | // 412 | // prepend as many 'fast' filters as possible, because parameter access is 'slow': 413 | // 414 | ElementClassFilter f1 = new ElementClassFilter( typeof( FamilyInstance ) ); 415 | ElementClassFilter f2 = new ElementClassFilter( typeof( ElectricalSystem ) ); 416 | LogicalOrFilter f3 = new LogicalOrFilter( f1, f2 ); 417 | FilteredElementCollector collector = new FilteredElementCollector( doc ).WherePasses( f3 ); 418 | 419 | BuiltInParameter bip = BuiltInParameter.RBS_ELEC_CIRCUIT_NUMBER; 420 | 421 | #if DEBUG 422 | int n1 = collector.ToElements().Count; 423 | 424 | List a = new List(); 425 | foreach( Element e in collector ) 426 | { 427 | Parameter p = e.get_Parameter( BuiltInParameter.RBS_ELEC_CIRCUIT_NUMBER ); 428 | if( null != p && 0 < p.AsString().Length ) 429 | { 430 | a.Add( e ); 431 | } 432 | } 433 | int n2 = a.Count; 434 | Debug.Assert( n1 > n2, "expected filter to eliminate something" ); 435 | 436 | List b = ( 437 | from e in collector.ToElements() 438 | where ( null != e.get_Parameter( bip ) ) && ( 0 < e.get_Parameter( bip ).AsString().Length ) 439 | select e ).ToList(); 440 | 441 | int n3 = b.Count; 442 | Debug.Assert( n2 == n3, "expected to reproduce same result" ); 443 | #endif // DEBUG 444 | 445 | // 446 | // this is unclear ... negating the rule that says the parameter 447 | // exists and is empty could mean that elements pass if the parameter 448 | // is non-empty, but also if the parameter does not exist ... 449 | // so maybe returning the collection b instead of c would be a safer bet? 450 | // 451 | ParameterValueProvider provider = new ParameterValueProvider( new ElementId( bip ) ); 452 | FilterStringRuleEvaluator evaluator = new FilterStringEquals(); 453 | FilterRule rule = new FilterStringRule( provider, evaluator, string.Empty, false ); 454 | ElementParameterFilter filter = new ElementParameterFilter( rule, true ); 455 | 456 | collector.WherePasses( filter ); 457 | IList c = collector.ToElements(); 458 | int n4 = c.Count; 459 | Debug.Assert( n2 == n4, "expected to reproduce same result" ); 460 | 461 | return c; 462 | } 463 | 464 | /// 465 | /// Return the one and only project information element using Revit 2009 filtering 466 | /// by searching for the "Project Information" category. Only one such element exists. 467 | /// 468 | public static Element GetProjectInfoElem( Document doc ) 469 | { 470 | //Filter filterCategory = app.Create.Filter.NewCategoryFilter( BuiltInCategory.OST_ProjectInformation ); 471 | //ElementIterator i = app.ActiveDocument.get_Elements( filterCategory ); 472 | //i.MoveNext(); 473 | //Element e = i.Current as Element; 474 | 475 | FilteredElementCollector collector = new FilteredElementCollector( doc ); 476 | collector.OfCategory( BuiltInCategory.OST_ProjectInformation ); 477 | Debug.Assert( 1 == collector.ToElements().Count, "expected one single element to be returned" ); 478 | Element e = collector.FirstElement(); 479 | Debug.Assert( null != e, "expected valid project information element" ); 480 | return e; 481 | } 482 | #endregion // Electrical Element Access 483 | } 484 | } 485 | -------------------------------------------------------------------------------- /AdnRme/WaitCursor.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Forms; 2 | 3 | namespace AdnRme 4 | { 5 | class WaitCursor 6 | { 7 | Cursor _oldCursor; 8 | 9 | public WaitCursor() 10 | { 11 | _oldCursor = Cursor.Current; 12 | Cursor.Current = Cursors.WaitCursor; 13 | } 14 | 15 | ~WaitCursor() 16 | { 17 | Cursor.Current = _oldCursor; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2015 Jeremy Tammik 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AdnRme 2 | 3 | ![Revit API](https://img.shields.io/badge/Revit%20API-2021-blue.svg) 4 | ![Platform](https://img.shields.io/badge/platform-Windows-lightgray.svg) 5 | ![.NET](https://img.shields.io/badge/.NET-4.8-blue.svg) 6 | [![License](http://img.shields.io/:license-mit-blue.svg)](http://opensource.org/licenses/MIT) 7 | 8 | Revit MEP Sample Application for Revit MEP HVAC and electrical. 9 | 10 | Demonstrate use of the Revit API for MEP specific tasks. 11 | 12 | Keywords: Revit API C# .NET add-in. 13 | 14 | ## HVAC 15 | 16 | Use of the generic Revit API for HVAC specific tasks, using only standard Revit element properties and parameters: 17 | 18 | - Determine air terminals for each space. 19 | - Assign flow to the air terminals depending on the space's calculated supply air flow. 20 | - Change size of diffuser based on flow. 21 | - Populate the value of the 'CFM per SF' variable on all spaces. 22 | - Determine unhosted elements. 23 | - Reset demo. 24 | 25 | ## Electrical 26 | 27 | Use of the MEP specific API to traverse an electrical system and display its hierarchy in a tree view. 28 | 29 | ## Documentation 30 | 31 | - The Building Coder topic group for 32 | [The ADN Revit MEP HVAC and Electrical Sample AdnRme](https://thebuildingcoder.typepad.com/blog/about-the-author.html#5.40) 33 | - [The Revit MEP API](http://thebuildingcoder.typepad.com/blog/2009/06/revit-mep-api.html) 34 | - [MEP Sample Ribbon Panel](http://thebuildingcoder.typepad.com/blog/2009/08/mep-sample-ribbon-panel.html) 35 | - [The Revit MEP API](http://thebuildingcoder.typepad.com/blog/2009/09/the-revit-mep-api.html) 36 | - [The Revit MEP 2011 API](http://thebuildingcoder.typepad.com/blog/2010/05/the-revit-mep-2011-api.html) 37 | - Summary of [AU 2010 Session ID 1573 – *All Systems Go in Revit MEP Programming*](http://thebuildingcoder.typepad.com/blog/2010/05/voting-open-for-au-2010-sessions.html) 38 | - [AU 2010 Classes](http://thebuildingcoder.typepad.com/blog/2010/09/autodesk-university-2010-classes.html) 39 | - [Autodesk University 2010 Class Materials](https://thebuildingcoder.typepad.com/blog/2010/11/autodesk-university-2010-class-materials.html) 40 | for *CP316-3U All Systems Go in Autodesk Revit MEP Programming* 41 | - [MEP Sample Code for Revit 2012](https://thebuildingcoder.typepad.com/blog/2011/08/mep-sample-code-for-revit-2012.html) 42 | - [The ADN MEP Sample AdnRme for Revit MEP 2013](http://thebuildingcoder.typepad.com/blog/2012/05/the-adn-mep-sample-adnrme-for-revit-mep-2013.html) 43 | - [Updated Revit MEP 2013 Material](http://thebuildingcoder.typepad.com/blog/2012/08/updated-revit-mep-2013-material.html) 44 | - [AU Classes on the View, MEP and Link APIs](http://thebuildingcoder.typepad.com/blog/2012/11/au-classes-on-the-view-mep-and-link-apis.html) 45 | - [The ADN Sample AdnRme for Revit MEP 2014](http://thebuildingcoder.typepad.com/blog/2013/06/the-adn-sample-adnrme-for-revit-mep-2014.html) 46 | - [AdnRme Migrated to Revit MEP 2015 on GitHub](http://thebuildingcoder.typepad.com/blog/2014/06/adnrme-migrated-to-revit-mep-2015-on-github.html) 47 | - [ArchSample, Active Transaction and AdnRme for 2016](http://thebuildingcoder.typepad.com/blog/2015/06/archsample-active-transaction-and-adnrme-for-revit-mep-2016.html) 48 | 49 | ## Author 50 | 51 | Jeremy Tammik, 52 | [The Building Coder](http://thebuildingcoder.typepad.com), 53 | [ADN](http://www.autodesk.com/adn) 54 | [Open](http://www.autodesk.com/adnopen), 55 | [Autodesk Inc.](http://www.autodesk.com) 56 | 57 | 58 | ## License 59 | 60 | This sample is licensed under the terms of the [MIT License](http://opensource.org/licenses/MIT). 61 | Please see the [LICENSE](LICENSE) file for full details. 62 | --------------------------------------------------------------------------------