C# Component in Revit
Grasshopper has three scripted components. One for C# programming language and another two for VB.NET and python (IronPython to be specific). These scripted components allows a user to create custom logic for a Grasshopper component. The component, therefore, can accept a configurable number of input and output connection points.
Since Rhino.Inside.Revit project brings Rhino and Grasshopper into the Autodesk Revit® environment, the scripted components also get access to the Revit API runtime. In this article we will discuss using the C# component to create custom components for Revit.
Setting Up
API Bindings
When adding a new C# component into the Grasshopper definition, you will get the default bindings:
Under current implementation, the C# component does not automatically bind the Revit API assemblies. This step is manual but will be automated in future releases |
In order to access the various APIs we need to import them into the script scope first. To access Revit and Rhino.Inside.Revit we need to reference the Revit API assemblies:
- RevitAPI.dll
- RevitAPIUI.dll
These two DLLs (Dynamically Linked Libraries) are located under the Revit installation directory (by default at %PROGRAMFILES%/Autodesk/Revit XXXX
where XXXX
is Revit version e.g. 2019
). To bind these DLLs to your C# component, Right-Click on the component and select Manage Assemblies:
Click Add inside the Manage Assemblies window (or Drag and Drop from the Recent Assemblies list on the right, to the left panel):
Navigate to the Revit installation directory and add the DLLs listed above to the window:
Now we can safely add the Revit API to the script scope:
Rhino.Inside.Revit API
Rhino.Inside.Revit provides a few utility methods as well. Later on this guide, we are going to use one of these utility functions to bake a sphere into a Revit model. To access these methods, we need to add another binding to RhinoInside.Revit.dll
assembly which is shipped with Rhino.Inside.Revit.
Please follow the steps described above, and add a reference to this assembly as well. Typically, you can find the DLL under %PROGRAMDATA%/Autodesk/Revit/XXXX/RhinoInside.Revit
where XXXX
is the Revit version e.g. 2019
In some cases (such as with some older installations of Rhino.Inside.Revit) the dll may be under %APPDATA%/Autodesk/Revit/Addins/XXXX/RhinoInside.Revit/
Then modify the lines shown above to add a reference to this assembly as well:
Implement RunScript
The code structure for C# Components is a bit more complex than the python scripted components due the complexity of the C# language itself. In C#, you can only create functions as methods of a class. Therefore, Grasshopper creates a required class named Script_Instance
and will automatically create a RunScript
method for this class. These pre-prepared code parts are marked with gray background and can not be deleted. The is the starting point for your code:
Custom User Component
Since the imports mentioned above need to be done for every single C# component, the process can get tedious. You can setup a template C# component with a default script importing all the most frequently used APIs and save that as a User Component in Grasshopper:
After the user object has been created, you can easily create a new C# component from the user object and it will have the template C# script with all your default imports:
Example
This example component will create a sphere of an adjustable radius in Revit and Rhino. It will pass that sphere onto other Grasshopper components through the output and it will create the sphere in Revit and bake into Rhino if the button connected to the input is pressed.
As you see in the image above, we have renamed the input components and also the input and output parameters on the C# components. This is a really good practice and it makes the definition a lot more clear to a new user.
Once this foundation is ready, then we can continue to create the script.
Creating Sphere Geometry
To show how a geometry that is created in Grasshopper, previews in both Rhino and Revit dynamically we will use the script below. This script will create a sphere based on the Radius
input value:
The Sphere()
method is from the Rhino.Geometry
namespace and is part of the RhinoCommon
API.
By setting the output to Sphere
Grasshopper will preview the results in both Rhino and Revit (Grasshopper is smart to know that some geometry is set on the output parameter). It also allows the Preview option on the component to be toggled and the sphere geometry to be passed down to the next component.
Now we can change the slider value to adjust the radius. Make sure the slider values are set to a big-enough value to the resulting sphere is visible in your Revit and Rhino models.
Baking to Revit and Rhino
We can add a custom baking method in this script. This can serve as a template to almost an unlimited number of ways and elements that one might want to create Revit objects from Grasshopper.
Because baking objects to Revit can take a long time and many times only should be done once, this bake method will only execute if the Trigger
input is set to True
on the component. This way we can decide to bake the object once we are happy with the results.
First, let’s create a bake method:
Notice that there is a reference to _sphere
on the third line of the script above. Since Revit requires Transactions when making changes to the model, and since Rhino.Inside.Revit manages the Transactions required by all the components to make changes to the Revit model, we will not handle the Transaction inside our script and will need to ask Rhino.Inside.Revit to run the new method for us:
But the RIR.Revit.EnqueueAction
only accepts an Action<DB.Document>
so we will need to store the created sphere on a private field first, so CreateGeometry
can later access and bake this sphere. Hence we will need to define this private property:
Once we are done creating this function and the private property, we can modify the RunScript
method to listen for the trigger and call this function. Notice that we are now storing the new sphere into _sphere
first so the CreateGeometry
can access that bake this sphere:
And here is the complete sample code:
Handling Transactions
To effectively create new transactions and handle the changes to your model in Grasshopper C# components, use the using pattern example below:
Inspecting Revit
To inspect which version of Revit you are using, check the Revit version number as shown below. Remember that your script still needs to compile against the active Revit API without errors:
Node In Code
You can also use the Grasshopper components that you love, inside your code, as functions and therefore create much more complex and powerful scripted components without writing the necessary complicated codes. The Grasshopper components basically become like powerful library functions that help you get your job done and have a smaller script to maintain. Here is what you need to add to use the Grasshopper components in your code. First we need to import the Node-in-Code handle:
Now you can access the component, like a function. These function names are prefixed with the name of their Grasshopper plugin to avoid naming conflicts. The example below shows how we can access the Add Material inside the code:
Now lets put this knowledge into use and create a custom scripted component that imports a Brep geometry into Revit and assigns a material to it. This scripted component effectively combines 3 different Grasshopper components into one. Note that there are obviously easier ways to do the same task, however this is a simple example of how components can be chained together in a script.
We will start with the template script component that we created above. Add it to your Grasshopper definition and modify the variable parameters to make it look like this:
Let’s find our components first, and notify the user if any of them does not exist.
Let’s also notify the user if any of these components do not exist:
Now let’s create the main logic of our script:
And here is the complete script:
Additional Resources
Here are a few links to more resources about all the APIs mentioned here: