Jekyll2023-08-04T20:50:00+00:00https://www.bim42.com/feed.xmlBIM 42The Answer to the Great Question of BIM, the Universe and EverythingDesign Automation For Revit - Part 22021-03-03T10:00:00+00:002021-03-03T10:00:00+00:00https://www.bim42.com/2021/02/design-automation-2<p>After the <a href="https://www.bim42.com/2021/02/design-automation-revit-1">first part</a> where we explore how to build an Revit addin for the Design Automation API, we can now upload and run this addin on the Forge server.</p>
<h1 id="part-3-create-the-application-on-forge">Part 3: Create the application on Forge</h1>
<p>After creating a new Forge App with the Data Management API and the Design Automation API, we use the Postman definitions provided <a href="https://github.com/Autodesk-Forge/forge-tutorial-postman/tree/master/DA4Revit">here</a> to create our Design Automation application.</p>
<p>We need to create a bundle, a package containing our Revit addin to upload it on the cloud. We create the folder structure in our solution, then add the following to the post-build event in visual Studio</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>xcopy /Y /F <span class="s2">"</span><span class="si">$(</span>TargetDir<span class="si">)</span><span class="s2">*.dll"</span> <span class="s2">"</span><span class="si">$(</span>ProjectDir<span class="si">)</span><span class="s2">IFCExport.bundle</span><span class="se">\C</span><span class="s2">ontents</span><span class="se">\"</span><span class="s2">
xcopy /Y /F "</span><span class="si">$(</span>ProjectDir<span class="si">)</span><span class="k">*</span>.addin<span class="s2">" "</span><span class="si">$(</span>ProjectDir<span class="si">)</span>IFCExport.bundle<span class="se">\C</span>ontents<span class="se">\"</span>
<span class="s2">"C:</span><span class="se">\P</span><span class="s2">rogram Files</span><span class="se">\7</span><span class="s2">-Zip</span><span class="se">\7</span><span class="s2">z.exe"</span> a <span class="nt">-tzip</span> <span class="s2">"</span><span class="si">$(</span>ProjectDir<span class="si">)$(</span>OutputPath<span class="si">)</span><span class="s2">IFCExport.zip"</span> <span class="s2">"</span><span class="si">$(</span>ProjectDir<span class="si">)</span><span class="s2">IFCExport.bundle</span><span class="se">\"</span><span class="s2"> -xr0!*.pdb
</span></code></pre></div></div>
<p>This small script will use <a href="https://www.7-zip.org/">7-Zip</a> to create a zip file containing the folder structure and application files (.dll and .addin)</p>
<p>We then register an AppBundle on the Forge server where we upload the bundle zip file containing our Revit addin.</p>
<p>We now need to create an Activity. An Activity is a function definition you create on the Forge server before running it. In this Activity, we add the AppBundle created at the previous step and describe input and output files with the following JSON body:</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
</span><span class="nl">"commandLine"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w"> </span><span class="s2">"$(engine.path)</span><span class="se">\\\\</span><span class="s2">revitcoreconsole.exe /i $(args[rvtFile].path) /al $(appbundles[IFCExportApp].path)"</span><span class="w"> </span><span class="p">],</span><span class="w">
</span><span class="nl">"parameters"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"rvtFile"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"zip"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
</span><span class="nl">"ondemand"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
</span><span class="nl">"verb"</span><span class="p">:</span><span class="w"> </span><span class="s2">"get"</span><span class="p">,</span><span class="w">
</span><span class="nl">"description"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Input Revit model"</span><span class="p">,</span><span class="w">
</span><span class="nl">"required"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
</span><span class="nl">"localName"</span><span class="p">:</span><span class="w"> </span><span class="s2">"input.rvt"</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="nl">"param"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"zip"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
</span><span class="nl">"ondemand"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
</span><span class="nl">"verb"</span><span class="p">:</span><span class="w"> </span><span class="s2">"get"</span><span class="p">,</span><span class="w">
</span><span class="nl">"description"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Json Parameter file"</span><span class="p">,</span><span class="w">
</span><span class="nl">"required"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
</span><span class="nl">"localName"</span><span class="p">:</span><span class="w"> </span><span class="s2">"params.json"</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="nl">"result"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"zip"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
</span><span class="nl">"ondemand"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
</span><span class="nl">"verb"</span><span class="p">:</span><span class="w"> </span><span class="s2">"put"</span><span class="p">,</span><span class="w">
</span><span class="nl">"description"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Results"</span><span class="p">,</span><span class="w">
</span><span class="nl">"required"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
</span><span class="nl">"localName"</span><span class="p">:</span><span class="w"> </span><span class="s2">"IFCExport.ifc"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="nl">"engine"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Autodesk.Revit+2021"</span><span class="p">,</span><span class="w">
</span><span class="nl">"appbundles"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w"> </span><span class="s2">".IFCExportApp+test"</span><span class="w"> </span><span class="p">],</span><span class="w">
</span><span class="nl">"description"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Export a Revit file to IFC."</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>This json text describe the behaviour of our activity:</p>
<ul>
<li>The engine used: Here, Revit 2021</li>
<li>The name and description of the input files. Here, we have a Revit file named input.rvt and a json parameter file name param.json</li>
<li>The name and description of the output. Here, we have an IFC file named IFCExport.ifc</li>
</ul>
<p>We also need to create an alias, a name, for the activity, as Forge does not allow us to call an activity with its id, but only with its alias. I create the alias “test”. This feature can also be used to retrieve a specific version of an activity (test, production, …)</p>
<p>Now that our activity is created, our application is ready to receive the input Revit model. To upload it on the Forge server, we need a public URL pointing to our Revit file. To create such an URL, we use the Data Management API and create a bucket to store temporary our Revit model. We then get a temporary upload URL that we will pass to the Data Management API to retrieve our uploaded Revit model.</p>
<p>Within this storage, we also get a temporary download url that the Data Management API will use to store the result of our application, in our case the csv file containing the schedule.</p>
<p>We are now ready to run our application on the Forge server. We create a WorkItem (an instance of an Activity previously described) and pass it the URL of the input RVT file along with an URL to upload the exported IFC model.</p>
<p>After some trial and error, I end up with this response:</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
</span><span class="nl">"status"</span><span class="p">:</span><span class="w"> </span><span class="s2">"success"</span><span class="p">,</span><span class="w">
</span><span class="nl">"reportUrl"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://dasprod-store.s3.amazonaws.com/workItem/IFCExport/327ecd7e417d4146ac9fee526dadc77a/report.txt?AWSAccessKeyId=ASIATGVJZKM3MOAUUELC&Expires=1598475306&x-amz-security-token=IQoJb3JpZ2luX2VjEPP%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCXVzLWVhc3QtMSJGMEQCIB8CCQH%2ByhzCLGy8j%2BSnjyl5iWGHSDcBoOE13qfbvoXtAiBJ%2Fcb29l7c3%2BpofB871knrAtzCdjrSF56lyHalu84RaCreAQjb%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F8BEAIaDDIyMDQ3MzE1MjMxMCIMIabmNymt9h8FvhNxKrIBitnBT9n07Kcl5GaR%2BxbVXeyFmHUm8xiJbI10zddAHM0CO5M%2FLE5SZy5wpMI44GPpZ7iD9DhLmVxfhOtaaKLXKcFHd3lj58VnKvT6bL5pfyG7NpXqWkHDZuatll5iZO6oRqZUFkhdUMebIk85Nq9%2BipticovIB%2B1zQJpEO9NWXkTojNUXdMWyJ9dA7E%2BJDMkIc4YcIF%2BlhsfiG4rjsfMawaCj%2BmeZyueHO5HIToHmll8S2zCKzpr6BTrhAbzfws2iAs2p1%2FieP%2F4GAskwreGMcx9d0IXPOkYJD%2BWV1GDtke9azMF%2Ftu%2FBP%2FVdA0lzqtIEcAVDsqp9z%2FSMTl1nyxBXA16eMRajpzY5d5dvBRTBuXEacNoOABs4wbmj46kzFlT3HT50mlnvcCmchqwqSIe0ZqsEWAhgOE8F2yS1h2%2B89%2FnD9B1qz9B6ukc9VU7d0N5ifH%2Bkh%2FQ8zRmtlLoGDSE%2Fhy8fs7ia8qLPn7%2FNNE7m4sloHX3TiMO1UFOkDdfVaG29tdwWw7%2FwtCdYaXX%2FjaVJJm3YgWoO8YgQyzWV6A%3D%3D&Signature=j4gt9S5NO1bNlR5KrGiVCwsKmLw%3D"</span><span class="p">,</span><span class="w">
</span><span class="nl">"stats"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"timeQueued"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2020-08-26T19:52:13.8851515Z"</span><span class="p">,</span><span class="w">
</span><span class="nl">"timeDownloadStarted"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2020-08-26T19:52:14.4542928Z"</span><span class="p">,</span><span class="w">
</span><span class="nl">"timeInstructionsStarted"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2020-08-26T19:52:15.3584001Z"</span><span class="p">,</span><span class="w">
</span><span class="nl">"timeInstructionsEnded"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2020-08-26T19:54:14.3353297Z"</span><span class="p">,</span><span class="w">
</span><span class="nl">"timeUploadEnded"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2020-08-26T19:54:14.4511254Z"</span><span class="p">,</span><span class="w">
</span><span class="nl">"timeFinished"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2020-08-26T19:54:14.6601308Z"</span><span class="p">,</span><span class="w">
</span><span class="nl">"bytesDownloaded"</span><span class="p">:</span><span class="w"> </span><span class="mi">18907171</span><span class="p">,</span><span class="w">
</span><span class="nl">"bytesUploaded"</span><span class="p">:</span><span class="w"> </span><span class="mi">4344</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"327ecd7e417d4146ac9fee526dadc77a"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>I then grab the download URL used to store the result, download it and get the resulting IFC conversion.</p>
<h1 id="part-4-final-thoughts">Part 4: Final thoughts:</h1>
<p>At first, this application seems slow. I used the ordinary architectural sample file on this experience (18 Mo), it takes 2 minutes and one second to run the entire WorkItem. The download part is actually very fast (2 second to upload the Revit model, a tenth of a second to download the resulting conversion). However, opening the model and running the app takes 1:59 on the Forge server. Running it my Surface Book 2 takes only 54 seconds.
However, subsequent runs where faster, my guess is that the server need some time to start the first time.</p>
<p>The Design Automation API allows to upload multiple linked files, with a default error handler that allows us to manage the annoying Revit warnings we sometime get when opening a file. However, a warning that need to delete elements to be resolved will prevent the Design Automation API from opening the file and send back an error.</p>
<p>Nonetheless, this open a LOT of possibilities. You can now do basically anything on a Revit file without having to open Revit on your workstation and I see a bright future for web-based applications making use of Revit files.</p>Simon MoreauAfter the first part where we explore how to build an Revit addin for the Design Automation API, we can now upload and run this addin on the Forge server.Design Automation For Revit - Part 12021-02-01T10:00:00+00:002021-02-01T10:00:00+00:00https://www.bim42.com/2021/02/design-automation<p>I recently published a <a href="https://www.bim42.com/2021/01/revit-to-ifc-reloaded">new version</a> of my <a href="https://rvt-to-ifc.bim42.com/">RVT To IFC</a> online converter. Among other modifications, this new version now uses the <a href="https://forge.autodesk.com/en/docs/design-automation/v3/developers_guide/overview/">Autodesk Design Automation API</a> instead of the Model Derivative API.</p>
<p>What is this Design Automation API? It is a set of features of Autodesk Forge to run a Revit add-in on the cloud. Instead of executing an add-in on your own Revit on your local computer, you upload this add-in on the Autodesk Forge server where it is executed in a Revit engine specially designed to run in this environment. It allows you to manipulate Revit files without having Revit locally installed.</p>
<p>In this two-parts series, we will see how this API works and build together a Forge plugin to export a Revit file to IFC without having to open Revit.</p>
<p>To do so, we will need an Autodesk Forge application and a custom Revit add-in to upload to this application. This application will be exactly the same that the one running RVT To IFC.</p>
<p>Most of the explanation presented here came from the <a href="https://forge.autodesk.com/en/docs/design-automation/v3/tutorials/revit/">Design Automation official documentation</a>.</p>
<h1 id="part-1-create-the-revit-plugin">Part 1: Create the Revit plugin</h1>
<p>We start by creating a new class library on Visual Studio that we call “RevitToIFCBundle”. In this project, we add the “RevitAPI.dll” and set its “Copy Local” property to “False” (1)</p>
<p><img src="https://www.bim42.com/assets/2021/02/Copy%20Local.png" alt="Copy Local" /></p>
<p>We then add the “Autodesk.Forge.DesignAutomation.Revit” <a href="https://www.nuget.org/packages/Autodesk.Forge.DesignAutomation.Revit/">Nuget package</a> to our soution.</p>
<p>Since we will be running this plugin on a headless server, we cannot use the RevitAPIUI.dll (the Revit interface) or any other UI-based libraries like Windows Form or WPF.</p>
<p>We also need an .addin file for our application, with the type set as “DBApplication”:</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp"><?xml version="1.0" encoding="utf-8"?></span>
<span class="nt"><RevitAddIns></span>
<span class="nt"><AddIn</span> <span class="na">Type=</span><span class="s">"DBApplication"</span><span class="nt">></span>
<span class="nt"><Name></span>RevitToIFCBundle<span class="nt"></Name></span>
<span class="nt"><Assembly></span>.\RevitToIFCBundle\RevitToIFCBundle.dll<span class="nt"></Assembly></span>
<span class="nt"><AddInId></span>1ac3f34e-453b-4183-968f-47c753f60a89<span class="nt"></AddInId></span>
<span class="nt"><FullClassName></span>RevitToIFCBundle.RevitToIFCBundleApp<span class="nt"></FullClassName></span>
<span class="nt"><Description></span>"Export to IFC"<span class="nt"></Description></span>
<span class="nt"><VendorId></span>BIM42<span class="nt"></VendorId></span>
<span class="nt"><VendorDescription></span>
<span class="nt"></VendorDescription></span>
<span class="nt"></AddIn></span>
<span class="nt"></RevitAddIns></span>
</code></pre></div></div>
<p>We create a new class “RevitToIFCBundleApp” where the bulk of our add-in will reside. This class inherit from IExternalDBApplication. Since we won’t have access to the Revit interface when running our plugin, we won’t have any button to start our application. To handle this, we implement two method, OnStartup and OnShutdown :</p>
<pre><code class="language-C#"> public ExternalDBApplicationResult OnStartup(
Autodesk.Revit.ApplicationServices.ControlledApplication app)
{
DesignAutomationBridge.DesignAutomationReadyEvent += HandleDesignAutomationReadyEvent;
return ExternalDBApplicationResult.Succeeded;
}
public ExternalDBApplicationResult OnShutdown(
Autodesk.Revit.ApplicationServices.ControlledApplication app)
{
return ExternalDBApplicationResult.Succeeded;
}
</code></pre>
<p>The entry point to our code is handled by the DesignAutomationReadyEvent handler. The DesignAutomationReadyEvent is raised when the Revit engine is ready to run our add-in.</p>
<pre><code class="language-C#"> public void HandleDesignAutomationReadyEvent(object sender, DesignAutomationReadyEventArgs e)
{
e.Succeeded = true;
DeleteAllWalls(e.DesignAutomationData);
}
</code></pre>
<p>We finally create a ExportToIFC function where our code resides. The code here is straightforward, we get the Revit document, create a transaction, and export the model to IFC.</p>
<p>The entire source for this plugin is <a href="https://github.com/simonmoreau/RevitToIFCBundle">available on Github</a>.</p>
<h1 id="part-2-debug-the-add-in-locally">Part 2: Debug the add-in locally</h1>
<p>Before uploading the add-in to the Forge server, we need to debug it locally. To do this, we need the <a href="https://github.com/Autodesk-Forge/design.automation-csharp-revit.local.debug.tool">local debug tool</a> for Design Automation for Revit.After cloning the repository, we build the solution and get a Revit plugin.</p>
<p>We also need to copy the .addin file and the .dll of the plugin to the Revit add-in folder. We add these lines to the Post-Build even in Visual Studio:</p>
<pre><code class="language-Bash">if exist "$(AppData)\Autodesk\REVIT\Addins\2021"
copy "$(ProjectDir)*.addin" "$(AppData)\Autodesk\REVIT\Addins\2021"
if exist "$(AppData)\Autodesk\REVIT\Addins\2021"
copy "$(ProjectDir)$(OutputPath)*.dll" "$(AppData)\Autodesk\REVIT\Addins\2021"
</code></pre>
<p>We also add Revit.exe as the starting program for our debugging session (1).</p>
<p>We also need a working directory that will simulate the working directory of the Forge server. We add this directory in Visual Studio, like below (2). In this case, our plugin will need one input file, the Revit file to be converted to IFC, we add its path in the command line arguments (3).</p>
<p><img src="https://www.bim42.com/assets/2021/02/Visual%20Studio%20Configuration.png" alt="Visual Studio Configuration" /></p>
<p>We can then start the debugging session on Visual Studio. The input file opens, we go to the Add-ins tab and run the DesignAutomationHandler command:</p>
<p><img src="https://www.bim42.com/assets/2021/02/DesignAutomationHandler.png" alt="Design Automation Handler" /></p>
<p>The plugin run smoothly, and the resulting IFC file is saved in the working directory.</p>
<p>In the next post, we will see how to create and run the Forge application.</p>Simon MoreauI recently published a new version of my RVT To IFC online converter. Among other modifications, this new version now uses the Autodesk Design Automation API instead of the Model Derivative API.Revit To IFC Reloaded2021-01-04T10:00:00+00:002021-01-04T10:00:00+00:00https://www.bim42.com/2021/01/revit-to-ifc-reloaded<p>A while ago, I created an online conversion tool to transform Revit files to IFC. At the time, I wanted to experiment with the Model Derivate API of Autodesk Forge. I published this small service for free and made use of the free Tier of my Autodesk Forge account to allow anyone to use it.</p>
<p>This solution ended up being more successful than I expected and my free Forge credits where quickly depleted. Since I can’t really fund the conversion of every Revit file in the work, I had to stop the service.</p>
<p>However, it seemed to be a valuable solution for a lot of people without a Revit licence. So, I build a new version of the Revit To IFC, this time with an actual business model behind it.</p>
<p>This new version is now named <a href="https://rvt-to-ifc.bim42.com/">RVT To IFC</a> and is a new application build from the ground up. However, the main and only feature remains the same, uploading a Revit file and downloading back its conversion in IFC.</p>
<p><img src="https://www.bim42.com/assets/2021/01/01%20-%20Home.png" alt="The main page" /></p>
<p>Behind the scene, the application makes use of a different service in the Autodesk Forge offering. Instead of converting directly with the Model Derivative API, I am using the Design Automation API to run online my own Revit plugin to export IFC.</p>
<p><img src="https://www.bim42.com/assets/2021/01/02%20-%20Architecture.png" alt="The application architecture" /></p>
<p>This offers a more interesting cost structure based on the time of the conversion. Furthermore, this will allow access to the settings of the IFC export, something that what not possible with the Model Derivative API. I have yet to implement this feature, it should come with my next version of the application.</p>
<p><img src="https://www.bim42.com/assets/2021/01/03%20-%20Upload.png" alt="The upload page" /></p>
<p>I am also using the Forge Data Management API to upload and download Revit and resulting IFC. All Revit and IFC files are only stored for the time of the conversion and are deleted afterward. The entire back-end is built with Azure Functions to keep the solution easy to build and deploy.</p>
<p>In this new version, each conversion will cost you one euro. They are sold as bundles of 10 or 50 conversions, with a fixed unit price. Even if the Design Automation API is the less expensive solution, I can’t offer any free tier.</p>
<p>If you want to use your own Forge account to run the conversion, the entire solution is open-source and available <a href="https://github.com/simonmoreau/RevitToIFCApp">on GitHub</a>.
I hope you will find this application useful, don’t hesitate to share it with all your ArchiCAD-lover friends who ended up with a Revit model from their contractor or engineer.</p>Simon MoreauA while ago, I created an online conversion tool to transform Revit files to IFC. At the time, I wanted to experiment with the Model Derivate API of Autodesk Forge. I published this small service for free and made use of the free Tier of my Autodesk Forge account to allow anyone to use it.Group Clashes 2020 Update2020-11-10T10:00:00+00:002020-11-10T10:00:00+00:00https://www.bim42.com/2020/11/group-clashes-update<p>I have finally found the time to update Group Clashes, my Navisworks plugin for grouping clash results. The app now supports Navisworks version from 2016 to 2021.</p>
<p>Along with the update, I added a new grouping mode called “Model”. This mode will help you grouping clashes in a test containing elements from multiple models.</p>
<p>In my example below, I run a clash test between structural walls (Selection A) and all services (Selection B). In the Selection B, we have elements coming from 3 models (Duplex_Plumbing.rvt, Duplex_Mechanical.rvt and Duplex_Electrical.rvt).</p>
<p><img src="https://www.bim42.com/assets/2020/11/01%20-%20Clash%20Test.png" alt="The Products page" /></p>
<p>I select this clash test in the Group Clashes panel and group the result using the “ModelB” grouping rule. I end up with a group for each model in the Selection B.</p>
<p><img src="https://www.bim42.com/assets/2020/11/02%20-%20Grouped%20Clashes.png" alt="The Products page" /></p>
<p>As usual, you will find this new version of Group Clashes on the <a href="https://apps.autodesk.com/NAVIS/en/Detail/Index?id=7544208847822212204&appLang=en&os=Win64">Autodesk App Store</a>. If you want to develop your own grouping rules, you can also find the entire source code on <a href="https://github.com/simonmoreau/GroupClashes">Github</a>.</p>
<p>Happy grouping!</p>Simon MoreauI have finally found the time to update Group Clashes, my Navisworks plugin for grouping clash results. The app now supports Navisworks version from 2016 to 2021.A new “Products” page2020-10-23T10:00:00+00:002020-10-23T10:00:00+00:00https://www.bim42.com/2020/10/products-page<p>Over the year, I have built a collection of applications around BIM. These tools range from Revit plugins to fully-fledged web applications through small desktop utilities.</p>
<p>I present these tools in a blog post as they come out. But these posts get quickly buried in the (quite alternative) amount of content on this blog.</p>
<p>So I created a new Product page. In this page, you will find all piece of software produced in a neatly organized table.</p>
<p><img src="https://www.bim42.com/assets/2020/10/01%20-%20Products.png" alt="The Products page" /></p>
<p>Each solution come with its own page describing it. You will also find here a link to download or open it, a link to the source code if it is available and a list of related blog post.</p>
<p><img src="https://www.bim42.com/assets/2020/10/02%20-%20GroupClashesPage.png" alt="The Group Clashes page" /></p>
<p>For now, only 6 applications are available, but I plan on extending that list as I dig out my old developments.</p>
<p>I hope you find something useful in this page, don’t hesitate to ask for more on the comments.</p>Simon MoreauOver the year, I have built a collection of applications around BIM. These tools range from Revit plugins to fully-fledged web applications through small desktop utilities.Generative Design with the Wave Function Collapse Algorithm2020-09-28T10:00:00+00:002020-09-28T10:00:00+00:00https://www.bim42.com/2020/09/WFC<p>Like many other in the AEC space, I have been following the development of <a href="https://store.steampowered.com/app/1291340/Townscaper/">Townscaper</a>, the town-building game made by <a href="https://twitter.com/OskSta">Oskar Stålberg</a>. Behind this game, there is a lot to learn on how to generate building geometry.</p>
<p>One of the main algorithms used in this game is the Wave function collapse algorithm. Initially developed for <a href="https://github.com/mxgmn/WaveFunctionCollapse">generating images</a> from a small input, its principle can be applied to a lot of use cases, like <a href="https://github.com/marian42/wavefunctioncollapse">town planning</a>, <a href="https://robertheaton.com/2018/12/17/wavefunction-collapse-algorithm/">wedding seating plan</a> and even <a href="https://github.com/mewo2/oisin">poetry</a>.</p>
<p>The main idea behind the Wave Function collapse algorithm start from a grid. On this grid, we place an element from a list (a list pixels for generating an image or a list of building/road for generating a town). As we place the first element, a series of rules constrains which elements can be placed nearby on the grid.</p>
<p>I stole <a href="https://robertheaton.com/2018/12/17/wavefunction-collapse-algorithm/">the great example from Robert Heaton</a> to explain how this algorithm works.</p>
<p>Let say we want to create a simple landscape. In this landscape, we can have either Land, Sea, Coast or Mountain. Each type of terrain is represented by a square tile:</p>
<p><img src="https://www.bim42.com/assets/2020/09/01%20-%20Tiles.png" alt="The tiles to compose our landscape" /></p>
<p>These four tiles can be placed anywhere on a grid:</p>
<p><img src="https://www.bim42.com/assets/2020/09/02%20-%20The%20Grid.png" alt="The grid where to place these tiles" /></p>
<p>Then, rules constrain the position of a tile relative to one another. Here,</p>
<ul>
<li>Sea can only be near Coast or itself</li>
<li>Mountain can only be near Land or itself</li>
<li>Coast must have Land on one side and Sea on the other</li>
</ul>
<p>We then pick a first case on the grid and randomly select the first tile. Here, we go with a Mountain tile:</p>
<p><img src="https://www.bim42.com/assets/2020/09/03%20-%20Starting%20Tile.png" alt="We place the first tile" /></p>
<p>Since Mountain can only be near Land or itself, we can place the following tiles near it. If we have more than one possibility, we randomly select the tile among the possibilities:</p>
<p><img src="https://www.bim42.com/assets/2020/09/04%20-%20Step2.png" alt="We then place the surrounding tiles" /></p>
<p>We then keep on filling the grid, following the rules for each successive tile:</p>
<p><img src="https://www.bim42.com/assets/2020/09/05%20-%20Step%203.png" alt="We finally complete the grid" /></p>
<p>We end up with a nice landscape. With such an algorithm, you can generate a lot of landscape by changing the position or the type of the first tile. A weight system allowing the algorithm to choose among the possible tiles can also replace the random part of this implementation.</p>
<p>This idea seemed quite interesting for generating an office floor plan. To implement this system in Revit, I begin by drawing the tile as a Revit group.
I start with a 2.70 m * 2.70 m tile. In this square, I model an office space with a partition wall and three segments of façade.</p>
<p><img src="https://www.bim42.com/assets/2020/09/06%20-%20Basic%20Revit%20tiles.png" alt="The base tiles in Revit" /></p>
<p>I then use a Group to create a single tile out of these models.</p>
<p>To be able to connect these tiles together, we need to rotate them. Instead of implementing the rotation on the code, I created four groups for each tile, each group containing the tile rotated a quarter turn.</p>
<p><img src="https://www.bim42.com/assets/2020/09/07%20-%20Groups%20rotation.png" alt="How to take rotation into account" /></p>
<p>We end up with 16 Revit groups that will form the basis for generating our floor plan.</p>
<p><img src="https://www.bim42.com/assets/2020/09/08%20-%20All%20Tiles.png" alt="The resulting tiles" /></p>
<p>I also add a 17th group named “Void” to represent space outside the building.</p>
<p>I then create an Excel spreadsheet where I formalize all adjacency rules. In this spreadsheet, I describe for each tile, i.e. each Revit group, which group can be attached above, below, on the left or on the right. The last column, “Weight”, allows to rank some tiles over the other.</p>
<p><img src="https://www.bim42.com/assets/2020/09/09%20-%20Rules%20spreadsheets.png" alt="The table defining the adjacency rules" /></p>
<p>I then create a <a href="https://gist.github.com/simonmoreau/131b125d476a6a75c262dc63b330f74c">C# console application</a> containing the actual Wave Function Collapse implementation. This application takes the rules spreadsheet and output a csv file describing the resulting grid. This csv file contains the name of the group to be created for each position on the grid.</p>
<p>I then use this file in a <a href="https://www.bim42.com/assets/2020/09/WFC%20-%20OfficeSpace.dyn">small Dynamo solution</a> to place all groups instances in the model.</p>
<p>By running this process a bunch of time, I get a series of floor plans fully modelled in Revit.</p>
<p><img src="https://www.bim42.com/assets/2020/09/WFC.gif" alt="Some of the generated floorplan" /></p>
<p>Resulting layouts are not very interesting. Even if they more or less “look good”, with actual office spaces bordered by a facade, they are not credible architectural solutions. And the <a href="https://www.danieldavis.com/generative-design-doomed-to-fail/">ability to make a lot of them</a> will not make them any better. Since the algorithm is building the entire floor plan by only looking at the surrounding tiles, it locally seems fine, but is still a mess globally. The algorithm lacks some sort of global overview of the objective.</p>
<p><img src="https://www.bim42.com/assets/2020/09/11%20-%20Local%20vs%20Global.png" alt="A detail of the floor plan vs the entire plan" /></p>
<p>But even if my naive approach of using it for generating an entire floor plan will not work, the principle seems nonetheless interesting, maybe for something like facade design.</p>
<p>For now, the whole system is a bit tedious to run in Revit. I hope to improve it by integrating the entire code in Dynamo. I will then be able to use on different use cases.</p>Simon MoreauLike many other in the AEC space, I have been following the development of Townscaper, the town-building game made by Oskar Stålberg. Behind this game, there is a lot to learn on how to generate building geometry.Revit to Cricut2020-09-07T10:00:00+00:002020-09-07T10:00:00+00:00https://www.bim42.com/2020/09/Revit-to-cricut<p>One of my relative recently buy a Cricut Maker and I had the opportunity to play a little bit with it.</p>
<p><img src="https://www.bim42.com/assets/2020/09/01%20-%20Cricut.png" alt="The Cricut Maker" /></p>
<p>The Cricut Maker is a computer numerical control cutting machine design to cut small parts out of paper or fabrics. Its small scale make it mostly suited for hobbyist to create any kind of small production with paper, fabrics, leather, and balsa wood.</p>
<p><img src="https://www.bim42.com/assets/2020/09/02%20-%20Tools.png" alt="Available tools for the Cricut" /></p>
<p>Along with the cutter, the Cricut Maker can also be equipped with pens or other kind of tools</p>
<p>My ideas behind this was to see how to plot Revit drawing with a “hand-draw” feeling to it. I also wanted to create small paper model from a pattern designed from a Revit model.</p>
<p>I started with the drawing of a cube. I draw it in perspective manually in Autocad.</p>
<p>After various test, I finally nailed the best procedure to import a design into the Cricut Software. I start the design in AutoCAd, where I am the most proficient. There, I create two layers, one for the drawing and one for the cutting. I then import the result in Adobe Illustrator.</p>
<p><img src="https://www.bim42.com/assets/2020/09/03%20-%20IllustratorDesign.png" alt="The design in Illustrator" /></p>
<p>In Illustrator, I ungroup every path and create one compound path for each layer.</p>
<p><img src="https://www.bim42.com/assets/2020/09/04%20-%20Illustrator%20layers.png" alt="The resulting layers in Illustrator" /></p>
<p>I finally import this design as an SVG file in Cricut Design Space where I can send it to the machine.</p>
<p><img src="https://www.bim42.com/assets/2020/09/05%20-%20CricutDesign.png" alt="The design in Cricut Design Space" /></p>
<p>The result is quite nice, with some of the hand draw feeling I was looking for:</p>
<p><img src="https://www.bim42.com/assets/2020/09/06%20-%20ResultingCube.png" alt="The resulting plotted cube" /></p>
<p>After this first test, I created an elevation in Revit and exported it in DWG. I then imported the DWG in Illustrator, created a svg file, launched the Cricut, waited two hours…</p>
<p><img src="https://www.bim42.com/assets/2020/09/Plotting.gif" alt="The plotting process" /></p>
<p>..and got this nice “hand drawn” elevation:</p>
<p><img src="https://www.bim42.com/assets/2020/09/07%20-%20Elevation.png" alt="The resulting plotted Revit elevation" /></p>
<p>I also had in mind the creation of small paper model from a Revit model. I tried with plotting and cutting at the same time and get a nice cube (again) but didn’t go very far in this direction.</p>
<p><img src="https://www.bim42.com/assets/2020/09/08%20-%20CubeModel.png" alt="The paper model of the cube" /></p>
<p>There is a lot of possibilities with this kind of machine. I only tried the standard pen and cutter, but the available tools make for a lot of interesting combinations, like drawing and cutting paper model out of a building 3D model.</p>
<p>I also love the “hand draw” feeling I get with this plotter. My next productions with this machine will probably be more experiences with different pens. I will also need to find a way to get the shadows out of the Revit view.</p>
<hr />
<p><em>I just want to emphasise that I was not paid by Cricut nor receive the Cricut Maker as gift in exchange for this blog post. I just append to kind of like this machine!</em></p>Simon MoreauOne of my relative recently buy a Cricut Maker and I had the opportunity to play a little bit with it.DynamoMEP samples2020-08-12T10:00:00+00:002020-08-12T10:00:00+00:00https://www.bim42.com/2020/08/dynamoMEP-samples<p>I released last week a new version of my dynamo package DynamoMEP. To help you around the new features, I build a few samples making use of these nodes.</p>
<h2 id="get-the-opening-side-of-a-door">Get the opening side of a door</h2>
<p>Among the new nodes, the FamilyInstance nodes allow you to use family reference. These references give you access to reference planes contained in the family. In this example, I show you how to use these references to find if a door is opening inside or outside of the room.</p>
<p>In all door families, I make sure that a “Front” reference plane is positioned on the opening side. In the OOTB Revit families, such a reference plane generally already exists, I change its name and type to “Front”:</p>
<p><img src="https://www.bim42.com/assets/2020/08/01%20-%20DoorFamily.png" alt="The Front plane in the door family" /></p>
<p>In the model, I retrieve all rooms and use the “Room.Doors” node from DynanoMEP to get all doors associated with a given room. Then, I use the “FamilyInstance.GetReferencesPlanesByType” to get the plane “Front” for every door instance.</p>
<p>Using “CoordinateSystem.ByPlane”, I get a coordinate system aligned with the door. This coordinate system allows me to create a point placed on the opening side of the door.</p>
<p><img src="https://www.bim42.com/assets/2020/08/02%20-%20CoordinateSystem.png" alt="The coordinate system of the Front plane" /></p>
<p>To find in which room the door is opening, we just find if the point is in the room or not. I am using the Revit node “Room.IsInsideRoom”. We end up for each room a list of boolean indicating if the associated door is opening in the room or not.</p>
<p><img src="https://www.bim42.com/assets/2020/08/03%20-%20DoorOpeningDefinition.png" alt="The complete definition" /></p>
<p>This simple example can be adapted to any family, as long as they contain named reference planes.</p>
<p>The complete definition can be found <a href="https://www.bim42.com/assets/2020/08/DoorOpeningSide.dyn">here</a>.</p>
<hr />
<h2 id="a-word-about-flipped-family-instance-and-reference-plane">A word about flipped family instance and reference plane</h2>
<p>Every family instance can have up to two flip controls, one horizontal (the “Hand” orientation) and one vertical (the “Facing” orientation).</p>
<p><img src="https://www.bim42.com/assets/2020/08/04%20-%20Flip%20button.png" alt="Two flip controls" /></p>
<p>These controls will mirror the family with its centre plane acting as the mirror reference.</p>
<p><img src="https://www.bim42.com/assets/2020/08/05%20-%20FlippedInstance.png" alt="Mirroring family instance" /></p>
<p>If your reference plane is aligned with the hand or facing direction, flipping the family will not change the orientation of this plane. In all other cases, the plane will be mirrored like the rest of the geometry of the family.</p>
<p><img src="https://www.bim42.com/assets/2020/08/06%20-%20Flipped%20reference%20plane.png" alt="Mirroring family instance" /></p>
<hr />
<h2 id="create-area-boundaries-from-a-dwg">Create area boundaries from a DWG</h2>
<p>In France, the legal definition of the building area (“Surface de Plancher”) is slightly different that the area calculated by Revit rooms. For example, we must include in this area the footprint of internal walls and columns. During the development of the project, the Revit room area is enough. But before submitting the building permit, a quantity surveyor must measure a more accurate area. These surfaces are measured with polylines in AutoCAD.</p>
<p>Since I wanted to retrieve these polylines in Revit, I created specific nodes to create Room, Space or Area boundaries in Dynamo.</p>
<p>I import the DWG containing the polylines in Revit and create an “Area - Level 0” area plan to draw my area boundaries in it. The definition is then rather simple, I am using the “CAD.CurvesFromCADLayers” node from BimorphNodes to retrieve the curve from the DWG. I select manually the area plan view and use the « AreaBoundary.ByCurveAndView» to create the area boundaries.</p>
<p><img src="https://www.bim42.com/assets/2020/08/07%20-%20AreaBoundariesFromDWG.png" alt="Area boundaries from CAD" /></p>
<p>The complete definition can be found <a href="https://www.bim42.com/assets/2020/08/AreaBoundaryFromCAD.dyn">here</a>.</p>
<p><img src="https://www.bim42.com/assets/2020/08/08%20-%20AreaBoundaries.png" alt="The created boundaries" /></p>
<h2 id="place-lightning-fixtures-along-a-grid-in-a-room">Place lightning fixtures along a grid in a room</h2>
<p>DynamoMEP contains a node to generate a grid of points in a room. These points can be used to create regularly spaced elements in a room. In this example, we use this node to place lighting fixtures in a room.</p>
<p>To get the corresponding points on the ceiling, we use the “RayBounce.ByOriginDirection” node. This node will create a “ray” and return the intersection point and the intersecting elements.</p>
<p><img src="https://www.bim42.com/assets/2020/08/09%20-%20Ray.png" alt="The RayBounce node" /></p>
<p>We then use these points and elements to get the underside face of the ceiling and place our face-based pendant light family instance:</p>
<p><img src="https://www.bim42.com/assets/2020/08/10%20-%20PendantLights.png" alt="The resulting pendant lights" /></p>
<p>Obviously, this definition could be adapted for any kind of face-based family.</p>
<p><img src="https://www.bim42.com/assets/2020/08/11%20-%20PlacePendantLights.png" alt="The resulting pendant lights" /></p>
<p>The complete definition can be found <a href="https://www.bim42.com/assets/2020/08/PlacePendantLights.dyn">here</a>.</p>
<h2 id="create-areas-from-floors">Create areas from floors</h2>
<p>The last example aims at answering a question from Tom who wanted to create areas based on a slab profile.</p>
<p>To do so, I start by manually creating an area plan for every level. From a selection of slabs, I extract their faces and find the upper face using the Z coordinate of the normal vector of surface. Using again the “Surface.PointAtParameter”, I find the elevation of each slab and use this value to group and sort slabs by their elevation.</p>
<p>I end up with a group of slab face for each level. I manually create the corresponding list of area plan views in the same order. I extract the boundary curves of the grouped surfaces and use them with my list of area plan to create a series of area boundary on each area view plan.</p>
<p><img src="https://www.bim42.com/assets/2020/08/12%20-%20AreaFromFloor.png" alt="The resulting areas" /></p>
<p>I am then using the same list to create an area for each floor.</p>
<p><img src="https://www.bim42.com/assets/2020/08/13%20-%20AreaFromFloor%20definition.png" alt="The defintion to create areas boundaries from slabs" /></p>
<p>The complete definition can be found <a href="https://www.bim42.com/assets/2020/08/CreateAreaFromFloor.dyn">here</a>.</p>
<p>Since the boundaries are linked to the slab geometry, they are updated each time the geometry is updated, like when I create this star-shaped shaft through all levels:</p>
<p><img src="https://www.bim42.com/assets/2020/08/14%20-%20UpdatedAreas.png" alt="The updated areas" /></p>
<p>A lot of workflows can make use of DynamoMEP, I hope these few samples will help you getting started with it.</p>Simon MoreauI released last week a new version of my dynamo package DynamoMEP. To help you around the new features, I build a few samples making use of these nodes.DynamoMEP update2020-08-05T10:00:00+00:002020-08-05T10:00:00+00:00https://www.bim42.com/2020/08/dynamoMEP-update<p>A few years ago, I released a <a href="https://www.bim42.com/2015/10/mep-design-and-dynamo/">Dynamo package</a> that was intended to be the groundwork for a comprehensive solution for designing MEP systems in Revit. But as I move on to another company, I oriented myself to other BIM-related issues and let this package unattended.</p>
<p>But a quick exchange with <a href="https://twitter.com/solamour">Sol Amour</a> about MEP in Dynamo make me realized that people where still using my package. So I should at least update it for the latest versions of Dynamo.</p>
<p>One thing leading to another, the update end up being more important that I had initially planed. I add a bunch of new functions that I needed and hope will be useful to you as well.</p>
<h3 id="area">Area</h3>
<p><img src="https://www.bim42.com/assets/2020/08/01%20-%20AreaNodes.png" alt="Area nodes" /></p>
<p>Use these nodes to create areas. Areas can only be created in an Area Plan view, you will need to either select such a view or make sure that the current view is an area plan.</p>
<p>You can also use these nodes to extract information from an area, like boundary lines or associated level.</p>
<h3 id="areaboundary">AreaBoundary</h3>
<p><img src="https://www.bim42.com/assets/2020/08/02%20-%20AreaBoundaryNodes.png" alt="Area Boundary nodes" /></p>
<p>These nodes allow you to create area boundaries in the current view or a selected one. Area boundary lines can be created from any curves in Dynamo. However, this node will not work with Polycurves, make sure that you explode them before using them has input curves.</p>
<h3 id="familyinstance">FamilyInstance</h3>
<p><img src="https://www.bim42.com/assets/2020/08/03%20-%20FamilyInstanceNodes.png" alt="Familly Instance nodes" /></p>
<p>These nodes are used to manipulate family instance references. References give you access to all planes available in a given family. These planes are available directly in your model for every family instance.</p>
<p><img src="https://www.bim42.com/assets/2020/08/04%20-%20ReferencesPlanes.png" alt="References in a family" /></p>
<p>You can select them by type, by name or just retrieve all of them. You can select a plane in the family editor to see its name (1) and reference type (2).</p>
<p><img src="https://www.bim42.com/assets/2020/08/05%20-%20ResultingPLane.png" alt="The plane associated with the reference" /></p>
<h3 id="group">Group</h3>
<p><img src="https://www.bim42.com/assets/2020/08/06%20-%20GroupNodes.png" alt="Group nodes" /></p>
<p>Use these nodes to create an instance of a Revit group. You will need a location point and a group type to use this node.</p>
<h3 id="grouptype">GroupType</h3>
<p><img src="https://www.bim42.com/assets/2020/08/07%20-%20GroupTypeNodes.png" alt="GroupType nodes" /></p>
<p>These nodes are used to create a new group from Revit elements. You can also retrieve an existing group type from your model, based on its name or on your selection.</p>
<h3 id="room">Room</h3>
<p><img src="https://www.bim42.com/assets/2020/08/08%20-%20RoomNodes.png" alt="Room nodes" /></p>
<p>These nodes are now fully integrated with the default Dynamo Room nodes. They complete the out of the box offering by allowing you to retrieve bounding elements (wall, room separation lines, column, …), doors and windows in this room or create. You can also use them to create a grid of points in a room.</p>
<h3 id="roomseparator">RoomSeparator</h3>
<p><img src="https://www.bim42.com/assets/2020/08/09%20-%20RoomSeparationNodes.png" alt="RoomSeparation nodes" /></p>
<p>These nodes allow you to create room separation lines from Dynamo curve. Since room separation lines must be created in a specific view, you can either select the view or let dynamo use the current active view.</p>
<p>Room separation lines can be created from any curves in dynamo. However, this node will not work with Polycurves, make sure that you explode these before using them has input curves</p>
<p>The node will project curves into the plane of the view. In some case, that could create weird issues with your curve not being properly projected. If you encounter such issues, project the input curve in a plane parallel to the plane of the view beforehand.</p>
<h3 id="space">Space</h3>
<p><img src="https://www.bim42.com/assets/2020/08/10%20-%20SpaceNodes.png" alt="Space nodes" /></p>
<p>Space nodes allow you to use MEP Spaces in Dynamo. You can use them to create new spaces, based on a point or on a point and its associated level. You can also use this note to retrieve identification data, associated level, location point or to create a grid of points in the space.</p>
<h3 id="spaceseparator">SpaceSeparator</h3>
<p><img src="https://www.bim42.com/assets/2020/08/11%20-%20SpaceSeparatorNode.png" alt="SpaceSeparator node" /></p>
<p>Space separations lines works like their counterpart for rooms. Just make sure you don’t use Polycurves.</p>
<h3 id="general-modifications">General modifications</h3>
<p>The structure of the plugin has be modified, it will not be compatible with the previous version. If one of your Dynamo definitions relies on the previous version of DynamoMEP, you will need to update it for the new version.</p>
<p>In this release, I updated every node to make sure that they integrate nicely with the out of the box nodes of Dynamo for Revit. I also removed some redundant nodes. I updated the icons to be more consistent both inside the package and with the Revit icons. By the way, if you are looking for some guidance on how to design icons for Revit or Dynamo, you can look into the Revit icon guideline in the <a href="https://www.autodesk.com/developer-network/platform-technologies/revit">Revit SDK</a>. This document was of great help to me.</p>
<p>I hope these new functionalities will be useful to you. Don’t hesitate to comment below if you see new way to expand this package, I would love to have your feedback.</p>Simon MoreauA few years ago, I released a Dynamo package that was intended to be the groundwork for a comprehensive solution for designing MEP systems in Revit. But as I move on to another company, I oriented myself to other BIM-related issues and let this package unattended.DynaWeb - Part 22020-07-21T10:00:00+00:002020-07-21T10:00:00+00:00https://www.bim42.com/2020/07/dynaweb-2<p>After a <a href="https://www.bim42.com/2020/07/dynaweb-1">first article</a> where I introduced you to both <a href="http://airtable.com/">Airtable</a> and <a href="https://github.com/radumg/DynaWeb">DynaWeb</a>, we go on using web API with DynaWeb. In this post, we see how to create more complex request.</p>
<h2 id="retrieve-a-specific-record">Retrieve a specific record</h2>
<p>If we want to retrieve a specific line in our Airtable, we need to add to the URL the id of the line we are looking for. So, to retrieve a particular record, we must get before the list of all record with their id. We will need two requests, one for the list of records and one for the specific request.</p>
<p><img src="https://www.bim42.com/assets/2020/07/07%20-%20RetrieveSpecificReccord.png" alt="Retrieve a specific record" /></p>
<p>A request can be slow, so we need to wait for the first one before using its result (the list of records) to execute the second one. To do so, we use the DataStream.Await node from <a href="https://github.com/erfajo/OrchidForDynamo">the Orchid package</a>. This will allow us to wait for the first request to complete before running the second one.</p>
<p><img src="https://www.bim42.com/assets/2020/07/08%20-%20WaitFor.png" alt="Wait for the request to complete" /></p>
<p>We then get the selected node, still as a JSON file:</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
</span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"rec05TzOsAsrWLXD4"</span><span class="p">,</span><span class="w">
</span><span class="nl">"fields"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"Code"</span><span class="p">:</span><span class="w"> </span><span class="s2">"201"</span><span class="p">,</span><span class="w">
</span><span class="nl">"Material"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Steel"</span><span class="p">,</span><span class="w">
</span><span class="nl">"Width"</span><span class="p">:</span><span class="w"> </span><span class="mi">915</span><span class="p">,</span><span class="w">
</span><span class="nl">"Height"</span><span class="p">:</span><span class="w"> </span><span class="mi">2134</span><span class="p">,</span><span class="w">
</span><span class="nl">"Fire Rating"</span><span class="p">:</span><span class="w"> </span><span class="s2">"3/4 Hours"</span><span class="p">,</span><span class="w">
</span><span class="nl">"Level"</span><span class="p">:</span><span class="w"> </span><span class="s2">"02 - Floor"</span><span class="p">,</span><span class="w">
</span><span class="nl">"Frame Finish"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Polyester powder coated"</span><span class="p">,</span><span class="w">
</span><span class="nl">"Doorstop"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Floor mounted door stop"</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="nl">"createdTime"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2020-06-26T14:50:25.000Z"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>The complete definition can be found <a href="https://www.bim42.com/assets/2020/07/AirTable-GetLine.dyn">here</a>.</p>
<h2 id="create-records">Create records</h2>
<p>In the two previous examples, we were only getting information from Airtable. Let see now how add new lines to our Airtable table. To do so, we now need to send information to Airtable with a new method: POST. This type of request will not only have an URL but also a payload, the “body”, send to this URL.</p>
<p>I will add two rows to my table, two steel doors respectively coded “328” and “328”. These two rows will be encoded in the body of my request as a Json text.</p>
<p>To create such a request in Dynamo, we first need a list of dictionaries representing these two rows. We start by creating a dictionary for each door, then add them manually to a new list. The Airtable API documentation states that this list must be nested inside a “records” object. We create the corresponding dictionary:</p>
<p><img src="https://www.bim42.com/assets/2020/07/09%20-%20CreateRequestBody.png" alt="Create the request body" /></p>
<p>When then add this dictionary to the request with the WebRequest.AddParameter node:</p>
<p><img src="https://www.bim42.com/assets/2020/07/10%20-%20AddBodyToRequest.png" alt="Add the JSON body to the request" /></p>
<p>“application/json” (1) means that the body is a JSON string. The “Data.StringifyJSON” convert the dictionary to a JSON string (2). The “RequestBody” node allows us to define the added parameter is the body of the request (3).</p>
<p>Going back to Airtable, we can see the newly created lines:</p>
<p><img src="https://www.bim42.com/assets/2020/07/11%20-%20CreatedLinesInAirtable.png" alt="Created lines in Airtable" /></p>
<p>The complete definition can be found <a href="https://www.bim42.com/assets/2020/07/AirTable-AddLine.dyn">here</a>.</p>
<p><img src="https://www.bim42.com/assets/2020/07/12%20-%20CompletePostRequest.png" alt="The complete post request" /></p>
<h2 id="update-records">Update records</h2>
<p>Using the PATCH or PUT method on the request will allows us to edit a specific line. This request is very similar to the POST request previously described, expected that the id of the row to be updated must be included in the body.</p>
<p>To do so, we need to add the id to the dictionary used to create the previous body with a Dictionary.ByKeysValues node:</p>
<p><img src="https://www.bim42.com/assets/2020/07/13%20-%20BodyWithId.png" alt="Add the Id to the body" /></p>
<p>We then use this updated body with WebRequest.AddParameter node, set the method to PATCH and run the request again.
The corresponding line in our table is updated, we see the modification in the “Activity” panel in Airtable:</p>
<p><img src="https://www.bim42.com/assets/2020/07/13-1%20-%20PATCH.png" alt="The result of the PATCH request" /></p>
<p>Since we use a PATCH method, the only updated columns are the one specified in the body of our request. If we use the PUT method, the request will clear all unspecified cell value:</p>
<p><img src="https://www.bim42.com/assets/2020/07/13-2%20-%20PUT.png" alt="The result of the PUT request" /></p>
<p>The complete definition is available <a href="https://www.bim42.com/assets/2020/07/AirTable-UpdateLine.dyn">here</a>.</p>
<p><img src="https://www.bim42.com/assets/2020/07/14%20-%20UpdateLine.png" alt="The complete update request" /></p>
<h2 id="delete-records">Delete records</h2>
<p>To delete a line, we use the DELETE method on a specific line. We just build the request URL with the row id and apply the method to the request:</p>
<p><img src="https://www.bim42.com/assets/2020/07/15%20-%20DeleteRow.png" alt="Delete a line" /></p>
<p>The complete definition is available <a href="https://www.bim42.com/assets/2020/07/AirTable-DeleteLine.dyn">here</a>.</p>
<h2 id="a-few-more-tips">A few more tips</h2>
<p>While working with DynaWeb, you might need these few more tips.</p>
<h3 id="debugging-request">Debugging request</h3>
<p>To be able to debug your solution, you need to analyse the resulting request with a proxy server application. Such an application will list and log all requests sent from your computer. You will then be able to see the detail of your request and fix eventual issues. I am using <a href="https://www.telerik.com/fiddler">Fiddler</a> which is free and really nice.</p>
<h3 id="restarting-dynamo">Restarting Dynamo</h3>
<p>Dynamo use a cache system to store in memory the result of every unchanged node. While generally very useful, this feature can create issues with DynaWeb. If your request stays the same after you edited your Dynamo definition, just close and restart this definition to clear the cache and send the request again.</p>
<h3 id="write-the-response">Write the response</h3>
<p>I am used to write the response of my request in a text file that I keep open in a text editor. I am using Visual Studio Code, but you can use any code editor. This give me a nice view of this response that I can easily parse and format without having to look at the small window of the Watch node.</p>
<p>The DynaWeb package give you access to an entire new ecosystem of web-based application through Dynamo. Using it in your workflows allows you to integrate solution like Office 360, Dropbox or Airtable within desktop-based CAD applications like Revit.
Since I am using DynaWeb more and more, I wanted with this post to contribute even a little to this great package, hoping it will make it known and used by many of you.</p>Simon MoreauAfter a first article where I introduced you to both Airtable and DynaWeb, we go on using web API with DynaWeb. In this post, we see how to create more complex request.