{"id":2422,"date":"2025-08-21T10:30:00","date_gmt":"2025-08-21T00:30:00","guid":{"rendered":"https:\/\/digitalbbq.au\/?p=2422"},"modified":"2025-07-12T11:27:37","modified_gmt":"2025-07-12T01:27:37","slug":"building-a-material-cube-farm","status":"publish","type":"post","link":"https:\/\/digitalbbq.au\/index.php\/2025\/08\/21\/building-a-material-cube-farm\/","title":{"rendered":"Building a Material Cube Farm"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">When you\u2019ve got 200+ materials in your model and someone in the viz team asks for a preview, the last thing you want to do is manually place and assign materials one by one to a cube. But that\u2019s exactly what we were staring down on a recent project \u2014 a clean export of every used material in the Revit model for the visualisation team, so they could prep their Datasmith material mapping ahead of time.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So, we automated it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We needed a Revit project with:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>One cube per material<\/li>\n\n\n\n<li>The material applied via Object Styles using a subcategory<\/li>\n\n\n\n<li>A clean, spatially separated grid of cubes ready for export to Datasmith<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">This is useful because instead of visualising materials in context (which can be too late in the process), this approach allows the visualisation team to:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Spot duplicated or near-identical materials early<\/li>\n\n\n\n<li>Consolidate materials before they become an issue<\/li>\n\n\n\n<li>Build material mapping tables ahead of time<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">The Macro<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The macro does a full sweep of the model:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Finds all materials <strong>currently in use<\/strong><\/li>\n\n\n\n<li>For each material:\n<ul class=\"wp-block-list\">\n<li>Generates a safe name<\/li>\n\n\n\n<li>Opens a base cube family (you&#8217;ll need to preload this)<\/li>\n\n\n\n<li>Creates or reuses a subcategory<\/li>\n\n\n\n<li>Applies the material to that subcategory<\/li>\n\n\n\n<li>Saves the family with a new name<\/li>\n\n\n\n<li>Loads it back into the model<\/li>\n\n\n\n<li>Places the cube at 1.5\u202fm intervals along the X-axis<\/li>\n\n\n\n<li>Assigns the original material to the subcategory in Object Styles<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"797\" height=\"322\" src=\"https:\/\/digitalbbq.au\/wp-content\/uploads\/2025\/07\/Screenshot-2025-07-12-111833.png\" alt=\"\" class=\"wp-image-2423\" srcset=\"https:\/\/digitalbbq.au\/wp-content\/uploads\/2025\/07\/Screenshot-2025-07-12-111833.png 797w, https:\/\/digitalbbq.au\/wp-content\/uploads\/2025\/07\/Screenshot-2025-07-12-111833-300x121.png 300w, https:\/\/digitalbbq.au\/wp-content\/uploads\/2025\/07\/Screenshot-2025-07-12-111833-768x310.png 768w, https:\/\/digitalbbq.au\/wp-content\/uploads\/2025\/07\/Screenshot-2025-07-12-111833-576x233.png 576w\" sizes=\"auto, (max-width: 797px) 100vw, 797px\" \/><\/figure>\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-function\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-keyword\">void<\/span> <span class=\"hljs-title\">SubCatter<\/span>(<span class=\"hljs-params\"><\/span>)<\/span>\n{\n    <span class=\"hljs-comment\">\/\/ Get the UI document and model Document<\/span>\n    UIDocument uidoc = <span class=\"hljs-keyword\">this<\/span>.ActiveUIDocument;\n    Document doc = uidoc.Document;\n\n    <span class=\"hljs-comment\">\/\/ Prep for the family<\/span>\n    Family family = <span class=\"hljs-literal\">null<\/span>;\n\n    <span class=\"hljs-comment\">\/\/ Find unused elements (includes materials)<\/span>\n    ISet&lt;ElementId&gt; unusedIds = doc.GetUnusedElements(<span class=\"hljs-keyword\">new<\/span> HashSet&lt;ElementId&gt;());\n\n    <span class=\"hljs-comment\">\/\/ Get all the materials in the document<\/span>\n    ICollection&lt;ElementId&gt; materialIds = <span class=\"hljs-keyword\">new<\/span> FilteredElementCollector(doc)\n        .OfClass(<span class=\"hljs-keyword\">typeof<\/span>(Material))\n        .ToElementIds();\n    <span class=\"hljs-keyword\">if<\/span> (materialIds.Count == <span class=\"hljs-number\">0<\/span>)\n    {\n        TaskDialog.Show(<span class=\"hljs-string\">\"Error\"<\/span>, <span class=\"hljs-string\">\"No materials found in the document.\"<\/span>);\n        <span class=\"hljs-keyword\">return<\/span>;\n    }\n\n    <span class=\"hljs-keyword\">int<\/span> row = <span class=\"hljs-number\">0<\/span>;\n    <span class=\"hljs-keyword\">double<\/span> yStep = UnitUtils.ConvertToInternalUnits(<span class=\"hljs-number\">1500<\/span>, UnitTypeId.Millimeters);\n\n    <span class=\"hljs-comment\">\/\/ For each material, make a new family called Cube with the material name as a suffix<\/span>\n    <span class=\"hljs-comment\">\/\/ and assign the material to the family<\/span>\n    <span class=\"hljs-comment\">\/\/ This will create a family for each material in the document<\/span>\n    <span class=\"hljs-keyword\">foreach<\/span> (ElementId materialId <span class=\"hljs-keyword\">in<\/span> materialIds)\n    {\n        Material mat = doc.GetElement(materialId) <span class=\"hljs-keyword\">as<\/span> Material;\n\n        <span class=\"hljs-keyword\">if<\/span> (mat == <span class=\"hljs-literal\">null<\/span>) <span class=\"hljs-keyword\">continue<\/span>;\n\n        <span class=\"hljs-comment\">\/\/ Skip if the material has not been assigned to any geometry in the project<\/span>\n        <span class=\"hljs-keyword\">if<\/span> (unusedIds.Contains(materialId))\n        {\n            <span class=\"hljs-keyword\">continue<\/span>; <span class=\"hljs-comment\">\/\/ Skip unused materials<\/span>\n        }\n\n        <span class=\"hljs-comment\">\/\/ Build a safe name so the new family can be saved to a file<\/span>\n        <span class=\"hljs-keyword\">string<\/span> safeName = Regex.Replace(mat.Name, <span class=\"hljs-string\">@\"&#91;\\\\\/:*?\"\"&lt;&gt;|]\"<\/span>, <span class=\"hljs-string\">\"_\"<\/span>);\n        <span class=\"hljs-keyword\">string<\/span> subcatName = safeName;\n        <span class=\"hljs-keyword\">string<\/span> familyName = <span class=\"hljs-string\">\"Cube_\"<\/span> + safeName;\n        <span class=\"hljs-keyword\">string<\/span> rootFolder = <span class=\"hljs-string\">@\"C:\\temp\\\"<\/span>; <span class=\"hljs-comment\">\/\/ Replace with your folder location<\/span>\n        <span class=\"hljs-keyword\">string<\/span> projFolder = Path.Combine(rootFolder, Path.GetFileNameWithoutExtension(doc.Title));\n        <span class=\"hljs-keyword\">if<\/span> (!Directory.Exists(projFolder))\n            Directory.CreateDirectory(projFolder);\n\n        <span class=\"hljs-keyword\">string<\/span> savePath = Path.Combine(projFolder, familyName + <span class=\"hljs-string\">\".rfa\"<\/span>);\n\n        <span class=\"hljs-comment\">\/\/ Find the base family<\/span>\n        Family baseFam = <span class=\"hljs-keyword\">new<\/span> FilteredElementCollector(doc)\n            .OfClass(<span class=\"hljs-keyword\">typeof<\/span>(Family))\n            .Cast&lt;Family&gt;()\n            .FirstOrDefault(f =&gt; f.Name == <span class=\"hljs-string\">\"Cube\"<\/span>);\n\n        <span class=\"hljs-keyword\">if<\/span> (baseFam == <span class=\"hljs-literal\">null<\/span>) { <span class=\"hljs-comment\">\/* error *\/<\/span> <span class=\"hljs-keyword\">break<\/span>; }\n\n        <span class=\"hljs-comment\">\/\/ Open and edit<\/span>\n        Document famDoc = doc.EditFamily(baseFam);\n\n        <span class=\"hljs-keyword\">if<\/span> (famDoc == <span class=\"hljs-literal\">null<\/span>)\n        {\n            TaskDialog.Show(<span class=\"hljs-string\">\"Error\"<\/span>, <span class=\"hljs-string\">\"Failed to open family for editing.\"<\/span>);\n            <span class=\"hljs-keyword\">return<\/span>;\n        }\n\n        <span class=\"hljs-comment\">\/\/ Create a subcategory inside the family document<\/span>\n        <span class=\"hljs-keyword\">using<\/span> (Transaction t = <span class=\"hljs-keyword\">new<\/span> Transaction(famDoc, <span class=\"hljs-string\">\"Assign Subcategory\"<\/span>))\n        {\n            t.Start();\n\n            <span class=\"hljs-comment\">\/\/ Get Generic Models category (the cube is a generic model)<\/span>\n            Category genericModelCat = famDoc.Settings.Categories.get_Item(BuiltInCategory.OST_GenericModel);\n\n            <span class=\"hljs-comment\">\/\/ Create subcategory (skip if exists)<\/span>\n            Category newSubcat = <span class=\"hljs-literal\">null<\/span>;\n            <span class=\"hljs-keyword\">try<\/span>\n            {\n                newSubcat = famDoc.Settings.Categories.NewSubcategory(genericModelCat, subcatName);\n                <span class=\"hljs-comment\">\/\/ Customize properties (optional)<\/span>\n                newSubcat.LineColor = <span class=\"hljs-keyword\">new<\/span> Color(<span class=\"hljs-number\">0<\/span>, <span class=\"hljs-number\">255<\/span>, <span class=\"hljs-number\">0<\/span>); <span class=\"hljs-comment\">\/\/ Green lines. You don't need to do this, I was using this as testing<\/span>\n            }\n            <span class=\"hljs-keyword\">catch<\/span> (Autodesk.Revit.Exceptions.ArgumentException)\n            {\n                <span class=\"hljs-comment\">\/\/ Subcategory exists, retrieve it<\/span>\n                newSubcat = genericModelCat.SubCategories.Cast&lt;Category&gt;()\n                    .First(sc =&gt; sc.Name == subcatName);\n            }\n\n            <span class=\"hljs-comment\">\/\/ Assign to ALL geometry in the family<\/span>\n            FilteredElementCollector collector = <span class=\"hljs-keyword\">new<\/span> FilteredElementCollector(famDoc);\n            <span class=\"hljs-keyword\">var<\/span> geometricElements = collector.OfClass(<span class=\"hljs-keyword\">typeof<\/span>(GenericForm)) <span class=\"hljs-comment\">\/\/ Extrusions, blends, sweeps<\/span>\n                    .Cast&lt;GenericForm&gt;();\n\n            <span class=\"hljs-keyword\">foreach<\/span> (GenericForm geom <span class=\"hljs-keyword\">in<\/span> geometricElements)\n            {\n                geom.Subcategory = newSubcat; <span class=\"hljs-comment\">\/\/ Apply subcategory<\/span>\n            }\n\n            t.Commit();\n        }\n\n        <span class=\"hljs-comment\">\/\/ Save the family document to the path C:\\temp\\ with the subcategory name appended as a suffix<\/span>\n        <span class=\"hljs-keyword\">try<\/span>\n        {\n            famDoc.SaveAs(savePath);\n            <span class=\"hljs-comment\">\/\/ TaskDialog.Show(\"Success\", \"Family saved successfully to: \" + savePath); \/\/ Uncomment this line if you want a dialogue to confirm. You'll need to click for every material though!<\/span>\n        }\n        <span class=\"hljs-keyword\">catch<\/span> (Exception ex)\n        {\n            <span class=\"hljs-comment\">\/\/ TaskDialog.Show(\"Error\", \"Failed to save family: \" + ex.Message);<\/span>\n        }\n\n        <span class=\"hljs-comment\">\/\/ Close the family document<\/span>\n        <span class=\"hljs-keyword\">if<\/span> (famDoc.IsModified)\n        {\n            famDoc.Save();\n        }\n        famDoc.Close(<span class=\"hljs-literal\">false<\/span>);\n\n        <span class=\"hljs-comment\">\/\/ Load the family into the project<\/span>\n        <span class=\"hljs-keyword\">using<\/span> (Transaction tx = <span class=\"hljs-keyword\">new<\/span> Transaction(doc, <span class=\"hljs-string\">\"Load Family\"<\/span>))\n        {\n            tx.Start();\n\n            Family loadedFamily;\n            <span class=\"hljs-keyword\">bool<\/span> wasLoaded = doc.LoadFamily(savePath, <span class=\"hljs-keyword\">out<\/span> loadedFamily);\n\n            <span class=\"hljs-comment\">\/\/ Uncomment this line if you want a dialogue to confirm. You'll need to click for every material though!<\/span>\n            <span class=\"hljs-comment\">\/*\n            if (wasLoaded)\n                TaskDialog.Show(\"Success\", \"Family '\" + loadedFamily.Name + \"' loaded into project.\");\n            else\n                TaskDialog.Show(\"Error\", \"Family failed to load or was already present.\");\n            *\/<\/span>\n\n            <span class=\"hljs-comment\">\/\/ Place the family instance at 0,0,0 in the project, then step 1500mm for each instance after<\/span>\n            <span class=\"hljs-keyword\">if<\/span> (loadedFamily != <span class=\"hljs-literal\">null<\/span>)\n            {\n                FamilySymbol symbol = loadedFamily.GetFamilySymbolIds()\n                    .Select(id =&gt; doc.GetElement(id) <span class=\"hljs-keyword\">as<\/span> FamilySymbol)\n                    .FirstOrDefault();\n                <span class=\"hljs-keyword\">if<\/span> (symbol != <span class=\"hljs-literal\">null<\/span> &amp;&amp; !symbol.IsActive)\n                {\n                    symbol.Activate();\n                }\n                XYZ location = <span class=\"hljs-keyword\">new<\/span> XYZ(row * yStep, <span class=\"hljs-number\">0<\/span>, <span class=\"hljs-number\">0<\/span>);\n                FamilyInstance instance = doc.Create.NewFamilyInstance(location, symbol, Autodesk.Revit.DB.Structure.StructuralType.NonStructural);\n                <span class=\"hljs-comment\">\/\/ TaskDialog.Show(\"Success\", \"Family instance '\" + instance.Name + \"' created at {location}.\"); \/\/ Uncomment this line if you want a dialogue to confirm. You'll need to click for every material though!<\/span>\n\n                row++;\n\n                <span class=\"hljs-comment\">\/\/ And then set the material on the subcategory<\/span>\n                <span class=\"hljs-comment\">\/\/ Get the Generic Models root category<\/span>\n                Category genericCat = doc.Settings.Categories\n                        .get_Item(BuiltInCategory.OST_GenericModel);\n\n                <span class=\"hljs-comment\">\/\/ Find subcategory by name<\/span>\n                Category mySubcat = genericCat.SubCategories\n                        .Cast&lt;Category&gt;()\n                        .FirstOrDefault(c =&gt; c.Name == subcatName);\n                <span class=\"hljs-comment\">\/\/ subcatName is the same safeName you used when creating\/saving the family<\/span>\n\n                <span class=\"hljs-comment\">\/\/ Here mat.Name is the original project material looped on<\/span>\n\n                <span class=\"hljs-keyword\">if<\/span> (mySubcat != <span class=\"hljs-literal\">null<\/span> &amp;&amp; mat != <span class=\"hljs-literal\">null<\/span>)\n                {\n                    mySubcat.Material = mat;\n                }\n            }\n\n            tx.Commit();\n        }\n    }\n\n    <span class=\"hljs-comment\">\/\/ Refresh the UI document to reflect changes<\/span>\n    uidoc.RefreshActiveView();\n}<\/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\">No manual fiddling. Just cubes, colour-coded and ready for export.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Requirements:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>A preloaded base cube family named Cube (rename as needed)<\/li>\n\n\n\n<li>A working folder path (update the script to suit your system)<\/li>\n\n\n\n<li>Materials must be assigned to geometry to be included<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Even though these cubes aren\u2019t in context, they provide a fast, deterministic way to review what\u2019s going into Datasmith. Better yet, and it\u2019s scalable, it doesn\u2019t care if you\u2019ve got 20 materials or 300.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">You could tweak this to work with nested families, assign metadata, or even generate CSVs for review. But for us, the simple cube farm was enough to speed up the process and remove a ton of manual effort.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Let me know if this is something you\u2019d use. Always happy to share the macro if anyone wants to take it for a spin.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>When you\u2019ve got 200+ materials in your model and someone in the viz team asks for a preview, the last thing you want to do is manually place and assign materials one by one to a cube. But that\u2019s exactly what we were staring down on a recent project \u2014 a clean export of every used material in the Revit&#8230;<\/p>\n","protected":false},"author":1,"featured_media":2424,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"advanced_seo_description":"Quickly create preview cubes for each material in your Revit model. Automate family creation, assignment and placement with a simple macro.","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":"Ever needed to preview all materials in a Revit model before exporting to Datasmith?\n\nI got sick of manually creating and placing cubes, so I wrote a macro to automate the whole thing. One cube per material, placed and colour-assigned in a grid.\n\nNot glamorous, but it saves time and helps the viz team get ahead.","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[78],"tags":[77,73],"class_list":["post-2422","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-how-to-guides","tag-automation","tag-process"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/digitalbbq.au\/wp-content\/uploads\/2025\/07\/colour-wooden-cube.jpg","jetpack-related-posts":[{"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":2422,"position":0},"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":[]},{"id":2403,"url":"https:\/\/digitalbbq.au\/index.php\/2025\/07\/17\/why-your-pipe-fittings-are-missing-materials-in-ifc-exports-and-how-to-fix-it\/","url_meta":{"origin":2422,"position":1},"title":"Your Pipe Fittings Are Grey in IFC? Here&#8217;s Why (And How to Fix It)","author":"Ryan Lenihan","date":"17 July 2025","format":false,"excerpt":"You\u2019ve exported your model to IFC. Pipes look great. Fittings? Grey. Again. What\u2019s going on? This one trips up a lot of teams, because pipe fittings in Revit don\u2019t actually carry system data, even though they look like they do. So when you rely on system-assigned materials for your IFC\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":"Set of blue PVC pipe fittings isolated on dark background. Blue plastic water pipe. PVC accessories","src":"https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2025\/07\/set-of-blue-pvc-pipe-fittings-isolated-on-dark-background-blue-plastic-water-pipe-pvc-accessories.jpg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2025\/07\/set-of-blue-pvc-pipe-fittings-isolated-on-dark-background-blue-plastic-water-pipe-pvc-accessories.jpg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2025\/07\/set-of-blue-pvc-pipe-fittings-isolated-on-dark-background-blue-plastic-water-pipe-pvc-accessories.jpg?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2025\/07\/set-of-blue-pvc-pipe-fittings-isolated-on-dark-background-blue-plastic-water-pipe-pvc-accessories.jpg?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2025\/07\/set-of-blue-pvc-pipe-fittings-isolated-on-dark-background-blue-plastic-water-pipe-pvc-accessories.jpg?resize=1050%2C600&ssl=1 3x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2025\/07\/set-of-blue-pvc-pipe-fittings-isolated-on-dark-background-blue-plastic-water-pipe-pvc-accessories.jpg?resize=1400%2C800&ssl=1 4x"},"classes":[]},{"id":1765,"url":"https:\/\/digitalbbq.au\/index.php\/2024\/01\/18\/purging-material-assets-using-the-revit-api-the-right-way\/","url_meta":{"origin":2422,"position":2},"title":"Purging Material Assets Using the Revit API the Right Way","author":"Ryan Lenihan","date":"18 January 2024","format":false,"excerpt":"I was asked about a problematic Revit model with 57,000 purgeable material assets. \"Just purge them\", you say, but the problem is that even using a shift+click to select the assets locked up the user's Revit for around 30 minutes while Revit thought about its life choices. I had experience\u2026","rel":"","context":"In &quot;Digital&quot;","block_context":{"text":"Digital","link":"https:\/\/digitalbbq.au\/index.php\/category\/digital\/"},"img":{"alt_text":"cleaning","src":"https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2024\/01\/cleaning.jpg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2024\/01\/cleaning.jpg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2024\/01\/cleaning.jpg?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2024\/01\/cleaning.jpg?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2024\/01\/cleaning.jpg?resize=1050%2C600&ssl=1 3x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2024\/01\/cleaning.jpg?resize=1400%2C800&ssl=1 4x"},"classes":[]},{"id":2413,"url":"https:\/\/digitalbbq.au\/index.php\/2025\/08\/07\/setting-ifc-material-overrides-for-cable-tray-and-conduit\/","url_meta":{"origin":2422,"position":3},"title":"Setting IFC Material Overrides for Cable Tray and Conduit","author":"Ryan Lenihan","date":"7 August 2025","format":false,"excerpt":"In a previous post, we looked at how to set IFC material overrides for pipe fittings. But when it comes to cable tray and conduit, things get a bit trickier. Unlike pipe and duct, cable tray and conduit don\u2019t belong to a system in Revit, so there's no MEP System\u2026","rel":"","context":"In &quot;Digital&quot;","block_context":{"text":"Digital","link":"https:\/\/digitalbbq.au\/index.php\/category\/digital\/"},"img":{"alt_text":"Low angle view of steel network cable trunking box.","src":"https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2025\/07\/low-angle-view-of-steel-network-cable-trunking-box-.jpg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2025\/07\/low-angle-view-of-steel-network-cable-trunking-box-.jpg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2025\/07\/low-angle-view-of-steel-network-cable-trunking-box-.jpg?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2025\/07\/low-angle-view-of-steel-network-cable-trunking-box-.jpg?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2025\/07\/low-angle-view-of-steel-network-cable-trunking-box-.jpg?resize=1050%2C600&ssl=1 3x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2025\/07\/low-angle-view-of-steel-network-cable-trunking-box-.jpg?resize=1400%2C800&ssl=1 4x"},"classes":[]},{"id":2595,"url":"https:\/\/digitalbbq.au\/index.php\/2026\/03\/26\/revit-cloud-model-upgrades-part-3-the-pre-upgrade-checklist-that-actually-prevents-pain\/","url_meta":{"origin":2422,"position":4},"title":"Revit Cloud Model Upgrades Part 3 &#8211; The Pre\u2011Upgrade Checklist That Actually Prevents Pain","author":"Ryan Lenihan","date":"26 March 2026","format":false,"excerpt":"Most upgrade failures don\u2019t happen during the upgrade. They happen six months earlier when everyone was \u201cjust trying to get drawings out the door\u201d. By the time you hit Upgrade, the Revit upgrade process is simply showing you the consequences. This is the checklist I run before pushing a single\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\/checklist_sm.jpg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2026\/03\/checklist_sm.jpg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2026\/03\/checklist_sm.jpg?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2026\/03\/checklist_sm.jpg?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2026\/03\/checklist_sm.jpg?resize=1050%2C600&ssl=1 3x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2026\/03\/checklist_sm.jpg?resize=1400%2C800&ssl=1 4x"},"classes":[]},{"id":2400,"url":"https:\/\/digitalbbq.au\/index.php\/2025\/09\/04\/optimising-ifc-files-in-python\/","url_meta":{"origin":2422,"position":5},"title":"Optimising IFC Files in Python","author":"Ryan Lenihan","date":"4 September 2025","format":false,"excerpt":"I came across a Python-based IFC optimiser built on top of IfcOpenShell. It was solid, removing unused spaces, orphaned entities, and redundant metadata, but I saw room to push it further. The original script handled: Removing empty attributes Cleaning up orphaned or unused relationships Removing tiny geometry Flattening the spatial\u2026","rel":"","context":"In &quot;Digital&quot;","block_context":{"text":"Digital","link":"https:\/\/digitalbbq.au\/index.php\/category\/digital\/"},"img":{"alt_text":"Big and small yellow rubber ducks on pink background","src":"https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2025\/07\/big-and-small-yellow-rubber-ducks-on-pink-background.jpg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2025\/07\/big-and-small-yellow-rubber-ducks-on-pink-background.jpg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2025\/07\/big-and-small-yellow-rubber-ducks-on-pink-background.jpg?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2025\/07\/big-and-small-yellow-rubber-ducks-on-pink-background.jpg?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2025\/07\/big-and-small-yellow-rubber-ducks-on-pink-background.jpg?resize=1050%2C600&ssl=1 3x, https:\/\/i0.wp.com\/digitalbbq.au\/wp-content\/uploads\/2025\/07\/big-and-small-yellow-rubber-ducks-on-pink-background.jpg?resize=1400%2C800&ssl=1 4x"},"classes":[]}],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/digitalbbq.au\/index.php\/wp-json\/wp\/v2\/posts\/2422","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=2422"}],"version-history":[{"count":2,"href":"https:\/\/digitalbbq.au\/index.php\/wp-json\/wp\/v2\/posts\/2422\/revisions"}],"predecessor-version":[{"id":2426,"href":"https:\/\/digitalbbq.au\/index.php\/wp-json\/wp\/v2\/posts\/2422\/revisions\/2426"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/digitalbbq.au\/index.php\/wp-json\/wp\/v2\/media\/2424"}],"wp:attachment":[{"href":"https:\/\/digitalbbq.au\/index.php\/wp-json\/wp\/v2\/media?parent=2422"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/digitalbbq.au\/index.php\/wp-json\/wp\/v2\/categories?post=2422"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/digitalbbq.au\/index.php\/wp-json\/wp\/v2\/tags?post=2422"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}