{"id":1828,"date":"2024-02-22T10:30:00","date_gmt":"2024-02-22T00:30:00","guid":{"rendered":"https:\/\/digitalbbq.au\/?p=1828"},"modified":"2024-02-09T08:29:15","modified_gmt":"2024-02-08T22:29:15","slug":"revit-bulk-unit-conversion-addin","status":"publish","type":"post","link":"https:\/\/digitalbbq.au\/index.php\/2024\/02\/22\/revit-bulk-unit-conversion-addin\/","title":{"rendered":"Revit Bulk Unit Conversion Addin"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Journal scripting once offered a quick fix for converting Revit model and family units; it helped speed up the process, but it had the habit of failing on certain family types or dialogue boxes. To tackle this, I developed an add-in, which I shared on <a href=\"https:\/\/www.revit.com.au\/downloads\/revit-unit-conversion-addin\/\" data-type=\"link\" data-id=\"https:\/\/www.revit.com.au\/downloads\/revit-unit-conversion-addin\/\">revit.com.au<\/a>; which both overcame the errors that caused the journal to stumble, and was also <a href=\"https:\/\/www.revit.com.au\/unit-conversion-addin\/\" data-type=\"link\" data-id=\"https:\/\/www.revit.com.au\/unit-conversion-addin\/\">significantly faster<\/a>. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Unexpectedly, this tool found a wider audience than anticipated. Yet, as the Revit API evolved, the add-in did not, and so it no longer worked. After a recent request, I have open-sourced the old, non-working version of the code <a href=\"https:\/\/github.com\/ryanlenihan\/Revit_UnitConversion_Old\" data-type=\"link\" data-id=\"https:\/\/github.com\/ryanlenihan\/Revit_UnitConversion_Old\">on GitHub<\/a>. However, I&#8217;m not the kind of person who can leave these things sit there, which means it&#8217;s time for an upgrade.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Back in The Day<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">My previous approach to writing this code was to take a known-good metric and imperial file and export the unit settings in a way that wrote the code for me.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For example, this is how I set the length:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-comment\">\/\/UTLength<\/span>\n<span class=\"hljs-keyword\">var<\/span> foUTLength = units.GetFormatOptions(UnitType.UT_Length);\nfoUTLength.Accuracy = <span class=\"hljs-number\">1<\/span>;\nfoUTLength.DisplayUnits = DisplayUnitType.DUT_MILLIMETERS;\nunits.SetFormatOptions(UnitType.UT_Length, foUTLength);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The macro I used extracted the details of the measurement type (Length) and the display unit type (DUT_MILLIMETERS) and extracted the accuracy value; the rest of the code was consistent across all measurement types, and I was able to spin up a functional add-in quickly.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Current Day<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The API changed back in 2021\/2022 and had a transitional period of 1 year in the API to be able to convert between the new and old methods easily. I won&#8217;t go into detail on the changes as they have been discussed extensively, but for those interested, both Jeremy and Konrad have posted great details on the changes and how to handle them.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Essentially, my code for adjusting length would need to change from what you see above, to this:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\"><span class=\"hljs-comment\">\/\/UTLength<\/span>\n<span class=\"hljs-keyword\">var<\/span> foUTLength = units.GetFormatOptions(SpecTypeId.Length);\nfoUTLength.Accuracy = <span class=\"hljs-number\">1<\/span>;\nfoUTLength.SetUnitTypeId(UnitTypeId.Millimeters);\nunits.SetFormatOptions(SpecTypeId.Length, foUTLength);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">This might seem easy enough, but as there was only a 1-year grace period in the API, extracting the data from Revit to figure out what UnitType is equivalent to which SpecTypeId wasn&#8217;t going to be so easy. My addin changes over one hundred unit dispay types, I didn&#8217;t want to have to look them up and type them out manually. I was determined not to install Revit 2021 or ask for a loan of a machine that had it, so I had to give things a little more thought.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I started with some code from the <a href=\"https:\/\/github.com\/jeremytammik\/the_building_coder_samples\/blob\/master\/BuildingCoder\/Util.cs\" data-type=\"link\" data-id=\"https:\/\/github.com\/jeremytammik\/the_building_coder_samples\/blob\/master\/BuildingCoder\/Util.cs\">Building Coder Samples<\/a>, I created a few C# macros to help me extract a list of all ForgeTypeIds, and another to list out all valid ForgeTypeIds for each SpectTypeId.<\/p>\n\n\n\n<details class=\"wp-block-details is-layout-flow wp-block-details-is-layout-flow\"><summary>Code (click to expand)<\/summary><pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\">\t\t<span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">ListForgeTypeIdsToFile<\/span>(<span class=\"hljs-params\"><\/span>)<\/span>\n\t\t{\n\t\t\t<span class=\"hljs-keyword\">string<\/span> filePath = <span class=\"hljs-string\">@\"C:\\temp\\unitconfig.txt\"<\/span>; <span class=\"hljs-comment\">\/\/ Specify your file path here<\/span>\n\n\t\t\t<span class=\"hljs-keyword\">using<\/span> (StreamWriter writer = <span class=\"hljs-keyword\">new<\/span> StreamWriter(filePath))\n\t\t\t{\n\t\t\t\t<span class=\"hljs-keyword\">var<\/span> spityp = <span class=\"hljs-keyword\">typeof<\/span>(SpecTypeId);\n\t\t\t\t<span class=\"hljs-keyword\">var<\/span> ps = spityp.GetProperties(BindingFlags.Public | BindingFlags.Static);\n\n\t\t\t\tArray.Sort(ps, (p1, p2) =&gt; p1.Name.CompareTo(p2.Name));\n\n\t\t\t\twriter.WriteLine(String.Format(<span class=\"hljs-string\">\"{0} properties:\"<\/span>, ps.Length));\n\n\t\t\t\t<span class=\"hljs-keyword\">foreach<\/span> (<span class=\"hljs-keyword\">var<\/span> pi <span class=\"hljs-keyword\">in<\/span> ps)\n\t\t\t\t{\n\t\t\t\t\t<span class=\"hljs-keyword\">if<\/span> (pi.PropertyType == <span class=\"hljs-keyword\">typeof<\/span>(ForgeTypeId))\n\t\t\t\t\t{\n\t\t\t\t\t\t<span class=\"hljs-keyword\">var<\/span> obj = pi.GetValue(<span class=\"hljs-literal\">null<\/span>, <span class=\"hljs-literal\">null<\/span>) <span class=\"hljs-keyword\">as<\/span> ForgeTypeId;\n\t\t\t\t\t\twriter.WriteLine(String.Format(<span class=\"hljs-string\">\"{0}: {1}\"<\/span>, pi.Name, obj.TypeId));\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t<span class=\"hljs-keyword\">var<\/span> specs = UnitUtils.GetAllMeasurableSpecs();\n\t\t\t\twriter.WriteLine(String.Format(<span class=\"hljs-string\">\"{0} specs:\"<\/span>, specs.Count));\n\n\t\t\t\tAutodesk.Revit.DB.Units units_metric = <span class=\"hljs-keyword\">new<\/span> Autodesk.Revit.DB.Units(UnitSystem.Metric);\n\n\t\t\t\t<span class=\"hljs-keyword\">foreach<\/span> (<span class=\"hljs-keyword\">var<\/span> fti <span class=\"hljs-keyword\">in<\/span> specs)\n\t\t\t\t{\n\t\t\t\t\twriter.WriteLine(String.Format(<span class=\"hljs-string\">\"{0}: {1}, {2}, {3}, {4}\"<\/span>,\n\t\t\t\t\t                               fti, fti.TypeId,\n\t\t\t\t\t                               UnitUtils.GetTypeCatalogStringForSpec(fti),\n\t\t\t\t\t                               LabelUtils.GetLabelForSpec(fti),\n\t\t\t\t\t                               UnitFormatUtils.Format(units_metric, fti, <span class=\"hljs-number\">1<\/span>, <span class=\"hljs-literal\">false<\/span>)));\n\t\t\t\t}\n\n\t\t\t\t<span class=\"hljs-keyword\">var<\/span> units = UnitUtils.GetAllUnits();\n\t\t\t\twriter.WriteLine(String.Format(<span class=\"hljs-string\">\"{0} units:\"<\/span>, units.Count));\n\n\t\t\t\t<span class=\"hljs-keyword\">foreach<\/span> (<span class=\"hljs-keyword\">var<\/span> fti <span class=\"hljs-keyword\">in<\/span> units)\n\t\t\t\t{\n\t\t\t\t\twriter.WriteLine(String.Format(<span class=\"hljs-string\">\"{0}: {1}, {2}, {3}\"<\/span>,\n\t\t\t\t\t                               fti, fti.TypeId,\n\t\t\t\t\t                               UnitUtils.GetTypeCatalogStringForUnit(fti),\n\t\t\t\t\t                               LabelUtils.GetLabelForUnit(fti)));\n\t\t\t\t}\n\t\t\t}\n\t\t}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">and<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"C#\" data-shcb-language-slug=\"cs\"><span><code class=\"hljs language-cs\">\t\t<span class=\"hljs-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">ExportValidUnitsForSpecTypes<\/span>(<span class=\"hljs-params\"><\/span>)<\/span>\n\t\t{\n\t\t\t<span class=\"hljs-comment\">\/\/writer.WriteLine(String.Format(\"SpecTypeId: {0}, Valid UnitTypeId: {1}\",specType,validUnit));<\/span>\n\t\t\t\n\t\t\tDocument doc = <span class=\"hljs-keyword\">this<\/span>.ActiveUIDocument.Document;\n\t\t\t<span class=\"hljs-keyword\">var<\/span> units = doc.GetUnits();\n\t\t\t<span class=\"hljs-keyword\">var<\/span> specTypes = UnitUtils.GetAllMeasurableSpecs();\n\t\t\t\n\t\t\t<span class=\"hljs-keyword\">string<\/span> filePath = <span class=\"hljs-string\">@\"C:\\temp\\validspecs.txt\"<\/span>; <span class=\"hljs-comment\">\/\/ Specify your file path here<\/span>\n\n\t\t\t<span class=\"hljs-keyword\">using<\/span> (StreamWriter writer = <span class=\"hljs-keyword\">new<\/span> StreamWriter(filePath))\n\t\t\t{\n\t\t\t\t<span class=\"hljs-keyword\">foreach<\/span> (ForgeTypeId specType <span class=\"hljs-keyword\">in<\/span> specTypes)\n\t\t\t\t{\n\t\t\t\t\tIList&lt;ForgeTypeId&gt; validUnits = UnitUtils.GetValidUnits(specType); <span class=\"hljs-comment\">\/\/ Get valid units for each spec type<\/span>\n\t\t\t\t\t<span class=\"hljs-keyword\">foreach<\/span> (ForgeTypeId validUnit <span class=\"hljs-keyword\">in<\/span> validUnits)\n\t\t\t\t\t{\n\t\t\t\t\t\t<span class=\"hljs-comment\">\/\/ Access the TypeId property to get the string identifier<\/span>\n\t\t\t\t\t\twriter.WriteLine(String.Format(<span class=\"hljs-string\">\"SpecTypeId: {0}, Valid UnitTypeId: {1}\"<\/span>,specType.TypeId,validUnit.TypeId));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">C#<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">cs<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre><\/details>\n\n\n\n<p class=\"wp-block-paragraph\">Which resulted in the following files:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"306\" src=\"https:\/\/digitalbbq.au\/wp-content\/uploads\/2024\/02\/image-1024x306.png\" alt=\"\" class=\"wp-image-1854\" srcset=\"https:\/\/digitalbbq.au\/wp-content\/uploads\/2024\/02\/image-1024x306.png 1024w, https:\/\/digitalbbq.au\/wp-content\/uploads\/2024\/02\/image-300x90.png 300w, https:\/\/digitalbbq.au\/wp-content\/uploads\/2024\/02\/image-768x230.png 768w, https:\/\/digitalbbq.au\/wp-content\/uploads\/2024\/02\/image.png 1026w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">In the above examples, I have the configuration properties for a valid Imperial file, and another with a list of all valid specs for each SpecTypeId, which is super handy if you want to change things.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">From here we need to align all the UnitTypeIds that were listed with the <a href=\"https:\/\/www.revitapidocs.com\/2024\/4245c082-629c-9ab0-7d43-fbb771db7991.htm\">UnitTypeId members from the API<\/a> however the two lists aren&#8217;t a 1:1 equivelance, so a little finessing of the lists is required. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Figuring this out, though is easy enough with Excel by extracting the portion of the data from Revit<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"500\" height=\"25\" src=\"https:\/\/digitalbbq.au\/wp-content\/uploads\/2024\/02\/image-2.png\" alt=\"\" class=\"wp-image-1856\" srcset=\"https:\/\/digitalbbq.au\/wp-content\/uploads\/2024\/02\/image-2.png 500w, https:\/\/digitalbbq.au\/wp-content\/uploads\/2024\/02\/image-2-300x15.png 300w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">I could then compare the two strings quickly using a formula that checked the lowercase version of the value in column A against the lowercase version of the value in column B.<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">=IF(LOWER(A1)=LOWER(B1),1,0)<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">With the results of that formula and some basic conditional formatting, I could very quickly identify the discrepancies or misalignment between the two lists and validate that the data aligned and matched.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"880\" height=\"215\" src=\"https:\/\/digitalbbq.au\/wp-content\/uploads\/2024\/02\/image-3.png\" alt=\"\" class=\"wp-image-1857\" srcset=\"https:\/\/digitalbbq.au\/wp-content\/uploads\/2024\/02\/image-3.png 880w, https:\/\/digitalbbq.au\/wp-content\/uploads\/2024\/02\/image-3-300x73.png 300w, https:\/\/digitalbbq.au\/wp-content\/uploads\/2024\/02\/image-3-768x188.png 768w\" sizes=\"auto, (max-width: 880px) 100vw, 880px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">From here, we can take the data exported from the file we want to base our conversion configuration from, combine it with the data produced to look up the correct formatting of the UnitTypeId member, and generate working code using basic Excel functions.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In my Excel, I have created a named region &#8220;lookuptable&#8221; and used that in a VLOOKUP to build my code:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">=<span class=\"hljs-string\">\"\/\/\"<\/span>&amp;A1&amp;<span class=\"hljs-string\">\"\nvar fo\"<\/span>&amp;A1&amp;<span class=\"hljs-string\">\" = units.GetFormatOptions(SpecTypeId.\"<\/span>&amp;A1&amp;<span class=\"hljs-string\">\");\nfo\"<\/span>&amp;A1&amp;<span class=\"hljs-string\">\".\"<\/span>&amp;B1&amp;<span class=\"hljs-string\">\";\nfo\"<\/span>&amp;A1&amp;<span class=\"hljs-string\">\".SetUnitTypeId(UnitTypeId.\"<\/span>&amp;VLOOKUP(LEFT(D1,LEN(D1)<span class=\"hljs-number\">-6<\/span>),lookuptable,<span class=\"hljs-number\">2<\/span>,<span class=\"hljs-keyword\">FALSE<\/span>)&amp;<span class=\"hljs-string\">\");\nunits.SetFormatOptions(SpecTypeId.\"<\/span>&amp;A1&amp;<span class=\"hljs-string\">\", fo\"<\/span>&amp;A1&amp;<span class=\"hljs-string\">\");\"<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"180\" src=\"https:\/\/digitalbbq.au\/wp-content\/uploads\/2024\/02\/image-5-1024x180.png\" alt=\"\" class=\"wp-image-1859\" srcset=\"https:\/\/digitalbbq.au\/wp-content\/uploads\/2024\/02\/image-5-1024x180.png 1024w, https:\/\/digitalbbq.au\/wp-content\/uploads\/2024\/02\/image-5-300x53.png 300w, https:\/\/digitalbbq.au\/wp-content\/uploads\/2024\/02\/image-5-768x135.png 768w, https:\/\/digitalbbq.au\/wp-content\/uploads\/2024\/02\/image-5-1536x270.png 1536w, https:\/\/digitalbbq.au\/wp-content\/uploads\/2024\/02\/image-5.png 1698w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">What we are doing here is<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Value in column A becomes the suffix of the variable, and the SpecTypeId<\/li>\n\n\n\n<li>The value in column B is the accuracy value<\/li>\n\n\n\n<li>The lookup result from column D and the lookup table is the UnitTypeId<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The result of the formula in column E is a working code snip that can be added to a macro or add-in.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Whether you&#8217;re looking to adapt a customised version to your specific needs, for either newer versions of Revit or for maintaining legacy projects, the updated add-ins are designed to streamline your workflows. Download the version that fits your needs:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/github.com\/ryanlenihan\/Revit_UnitConversion_Old\" data-type=\"link\" data-id=\"https:\/\/github.com\/ryanlenihan\/Revit_UnitConversion_Old\">Revit Unit Conversion Addin for Revit 2017-2021<\/a> (source code only)<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/github.com\/ryanlenihan\/Revit_UnitConversion\" data-type=\"link\" data-id=\"https:\/\/github.com\/ryanlenihan\/Revit_UnitConversion\">Revit Unit Conversion Addin for Revit 2022-2024<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/github.com\/ryanlenihan\/Revit_UnitConversion\/releases\/tag\/v1.240207\" data-type=\"link\" data-id=\"https:\/\/github.com\/ryanlenihan\/Revit_UnitConversion\/releases\/tag\/v1.240207\">Revit Unit Conversion Addin for Revit 2022-2024 Installer<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Journal scripting once offered a quick fix for converting Revit model and family units; it helped speed up the process, but it had the habit of failing on certain family types or dialogue boxes. To tackle this, I developed an add-in, which I shared on revit.com.au; which both overcame the errors that caused the journal to stumble, and was also&#8230;<\/p>\n","protected":false},"author":1,"featured_media":1829,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"advanced_seo_description":"Upgrade Revit content with the Bulk Unit Conversion Add-in, updated for compatibility Revit 2022 and newer","jetpack_seo_html_title":"","jetpack_seo_noindex":false,"jetpack_seo_schema_type":"","_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[1],"tags":[77],"class_list":["post-1828","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-digital","tag-automation"],"jetpack_publicize_connections":[],"jetpack-related-posts":[{"id":2516,"url":"https:\/\/digitalbbq.au\/index.php\/2025\/11\/06\/introducing-the-bim-cache-cleaner\/","url_meta":{"origin":1828,"position":0},"title":"Introducing the BIM Cache Cleaner","author":"Ryan Lenihan","date":"6 November 2025","format":false,"excerpt":"Back in 2017, I wrote a post about cleaning up Autodesk Collaboration for Revit (C4R) cache files. I then wrote a small windows application, C4R Cache Cleaner, that helped the end user work through that process without having to trawl through the journal files manually. That application became one of\u2026","rel":"","context":"In &quot;Digital&quot;","block_context":{"text":"Digital","link":"https:\/\/digitalbbq.au\/index.php\/category\/digital\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2025\/10\/bim_cleaner.jpg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2025\/10\/bim_cleaner.jpg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2025\/10\/bim_cleaner.jpg?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2025\/10\/bim_cleaner.jpg?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2025\/10\/bim_cleaner.jpg?resize=1050%2C600&ssl=1 3x"},"classes":[]},{"id":2560,"url":"https:\/\/digitalbbq.au\/index.php\/2026\/02\/26\/revit-cloud-model-upgrades-part-1-how-the-acc-project-updater-works-and-common-misconceptions\/","url_meta":{"origin":1828,"position":1},"title":"Revit Cloud Model Upgrades Part 1 &#8211; How the ACC Project Updater Works and Common Misconceptions","author":"Ryan Lenihan","date":"26 February 2026","format":false,"excerpt":"Upgrading cloud-shared Revit models via Autodesk Construction Cloud\u2019s Cloud Model Upgrade tool can initially feel daunting. It often surfaces a flurry of errors and warnings, but the key insight is that most issues indicate pre-existing model \u201ctechnical debt\u201d, not bugs in Autodesk\u2019s tool. Understanding Technical Debt Technical debt is a\u2026","rel":"","context":"In &quot;Digital&quot;","block_context":{"text":"Digital","link":"https:\/\/digitalbbq.au\/index.php\/category\/digital\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2026\/02\/yell_at_cloud.jpg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2026\/02\/yell_at_cloud.jpg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2026\/02\/yell_at_cloud.jpg?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2026\/02\/yell_at_cloud.jpg?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2026\/02\/yell_at_cloud.jpg?resize=1050%2C600&ssl=1 3x"},"classes":[]},{"id":2409,"url":"https:\/\/digitalbbq.au\/index.php\/2025\/07\/31\/dynamo-vs-revit-api-choosing-the-right-tool-for-your-bim-automation-needs\/","url_meta":{"origin":1828,"position":2},"title":"Dynamo vs. Revit API. Choosing the Right Tool for Your BIM Automation Needs","author":"Ryan Lenihan","date":"31 July 2025","format":false,"excerpt":"A recent post on the r\/BIM subreddit sparked an interesting discussion: should you learn Dynamo or the Revit API for automating tasks in Revit? As a BIM professional, you're likely no stranger to the quest for efficiency and automation in your workflows. But with multiple tools at your disposal, it\u2026","rel":"","context":"In &quot;Digital&quot;","block_context":{"text":"Digital","link":"https:\/\/digitalbbq.au\/index.php\/category\/digital\/"},"img":{"alt_text":"Programmer working with program code","src":"https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2025\/07\/programmer-working-with-program-code.jpg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2025\/07\/programmer-working-with-program-code.jpg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2025\/07\/programmer-working-with-program-code.jpg?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2025\/07\/programmer-working-with-program-code.jpg?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2025\/07\/programmer-working-with-program-code.jpg?resize=1050%2C600&ssl=1 3x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2025\/07\/programmer-working-with-program-code.jpg?resize=1400%2C800&ssl=1 4x"},"classes":[]},{"id":2572,"url":"https:\/\/digitalbbq.au\/index.php\/2026\/03\/12\/revit-cloud-model-upgrades-part-2-diagnosing-common-upgrade-errors-and-root-causes\/","url_meta":{"origin":1828,"position":3},"title":"Revit Cloud Model Upgrades Part 2 \u2013 Diagnosing Common Upgrade Errors and Root Causes","author":"Ryan Lenihan","date":"12 March 2026","format":false,"excerpt":"Upgrading a Revit model isn\u2019t just a file conversion, it\u2019s a forced rebuild of geometry, constraints, joins, and parametric logic. And when that rebuild fails, the cause is rarely the upgrade itself. More often, it\u2019s exposing instability that was already baked into the model. As discussed in Revit Cloud Model\u2026","rel":"","context":"In &quot;Digital&quot;","block_context":{"text":"Digital","link":"https:\/\/digitalbbq.au\/index.php\/category\/digital\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2026\/03\/modern-architectural-structure_sm.jpg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2026\/03\/modern-architectural-structure_sm.jpg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2026\/03\/modern-architectural-structure_sm.jpg?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2026\/03\/modern-architectural-structure_sm.jpg?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2026\/03\/modern-architectural-structure_sm.jpg?resize=1050%2C600&ssl=1 3x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2026\/03\/modern-architectural-structure_sm.jpg?resize=1400%2C800&ssl=1 4x"},"classes":[]},{"id":2322,"url":"https:\/\/digitalbbq.au\/index.php\/2025\/02\/13\/automating-metadata-cleanup-in-revit-a-custom-live-updater\/","url_meta":{"origin":1828,"position":4},"title":"Automating Metadata Cleanup in Revit \u2013 A Custom Live Updater","author":"Ryan Lenihan","date":"13 February 2025","format":false,"excerpt":"When working in Revit, copied elements will inherit instance parameter values that should be unique\u2014room numbers, tracking codes, asset IDs, or any other metadata that doesn\u2019t logically carry over. Problem: Copying elements can introduce data inconsistencies if certain instance parameters retain values they shouldn\u2019t. Solution: A Revit API Updater that\u2026","rel":"","context":"In &quot;Digital&quot;","block_context":{"text":"Digital","link":"https:\/\/digitalbbq.au\/index.php\/category\/digital\/"},"img":{"alt_text":"Vintage computer from the seventies representing retro technology and innovation","src":"https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2025\/01\/vintage-computer-from-the-seventies-representing-retro-technology-and-innovation.jpg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2025\/01\/vintage-computer-from-the-seventies-representing-retro-technology-and-innovation.jpg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2025\/01\/vintage-computer-from-the-seventies-representing-retro-technology-and-innovation.jpg?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2025\/01\/vintage-computer-from-the-seventies-representing-retro-technology-and-innovation.jpg?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2025\/01\/vintage-computer-from-the-seventies-representing-retro-technology-and-innovation.jpg?resize=1050%2C600&ssl=1 3x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2025\/01\/vintage-computer-from-the-seventies-representing-retro-technology-and-innovation.jpg?resize=1400%2C800&ssl=1 4x"},"classes":[]},{"id":2672,"url":"https:\/\/digitalbbq.au\/index.php\/2026\/07\/09\/a-short-story-about-how-nested-families-work-when-exported-to-ifc\/","url_meta":{"origin":1828,"position":5},"title":"A Short Story About How Nested Families Work When Exported to Ifc.","author":"Ryan Lenihan","date":"9 July 2026","format":false,"excerpt":"I had a question come through that\u2019ll sound familiar if you\u2019ve ever pushed Revit \u2192 IFC on a live job: Nested families are carrying asset data in Revit, but that data disappears in the IFC. LOI attributes, classification, IDs.. gone. What's going on? This comes up more than it should,\u2026","rel":"","context":"In &quot;How to guides&quot;","block_context":{"text":"How to guides","link":"https:\/\/digitalbbq.au\/index.php\/category\/how-to-guides\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2026\/07\/house-model-on-floor-real-estate-and-housing-aspi-2026-03-25-09-14-22-utc.jpg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2026\/07\/house-model-on-floor-real-estate-and-housing-aspi-2026-03-25-09-14-22-utc.jpg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2026\/07\/house-model-on-floor-real-estate-and-housing-aspi-2026-03-25-09-14-22-utc.jpg?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2026\/07\/house-model-on-floor-real-estate-and-housing-aspi-2026-03-25-09-14-22-utc.jpg?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2026\/07\/house-model-on-floor-real-estate-and-housing-aspi-2026-03-25-09-14-22-utc.jpg?resize=1050%2C600&ssl=1 3x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2026\/07\/house-model-on-floor-real-estate-and-housing-aspi-2026-03-25-09-14-22-utc.jpg?resize=1400%2C800&ssl=1 4x"},"classes":[]}],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"https:\/\/digitalbbq.au\/wp-content\/uploads\/2024\/02\/tape-measure-with-numbers.jpg","_links":{"self":[{"href":"https:\/\/digitalbbq.au\/index.php\/wp-json\/wp\/v2\/posts\/1828","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/digitalbbq.au\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/digitalbbq.au\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/digitalbbq.au\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/digitalbbq.au\/index.php\/wp-json\/wp\/v2\/comments?post=1828"}],"version-history":[{"count":4,"href":"https:\/\/digitalbbq.au\/index.php\/wp-json\/wp\/v2\/posts\/1828\/revisions"}],"predecessor-version":[{"id":1861,"href":"https:\/\/digitalbbq.au\/index.php\/wp-json\/wp\/v2\/posts\/1828\/revisions\/1861"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/digitalbbq.au\/index.php\/wp-json\/wp\/v2\/media\/1829"}],"wp:attachment":[{"href":"https:\/\/digitalbbq.au\/index.php\/wp-json\/wp\/v2\/media?parent=1828"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/digitalbbq.au\/index.php\/wp-json\/wp\/v2\/categories?post=1828"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/digitalbbq.au\/index.php\/wp-json\/wp\/v2\/tags?post=1828"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}