How to add custom User Data to Rhino Objects
Objects in Rhino (the 3D modelling software, not the organs of the animal) have the option to attach custom user data that you may wish to share across tools. This might be of particular use in Grasshopper, enabling you to send one piece of geometry down the wires with custom data attached, rather than having to send them separately. Alternatively it might help send custom data between plug-ins. Either way, the ability to add custom data is a useful one, but actually doing so is not as intuitive as it might seem. Hopefully this post will give a handy how-to guide to allow you to add your own custom data to Rhino geometry.
What is user data?
User data comes from the Rhino.DocObjects.Custom namespace, but you can’t implement a new variable to store your user data in – the user data class is abstract. Which means you’ll have to create your own custom data class (which I’ll give a brief demo of further down). The user data itself is then stored in a user data list (from the same namespace) which acts as a list would normally act in C# (the implementation from the documentation looks similar to that used for polylines). You can add your user data to this list, and it’ll be attached to the object.
Creating a user data class
If you already know how to implement an abstract class you can move onto the next section. If not, then this will give a short demo of implementing one.
For this example, we’re going to be attaching custom data to a mesh, namely the list of doubles which make up the colours of the mesh. To do this, we create our own MeshUserData class that implements the abstract UserData Rhino class, like so.
namespace MyNamespace { class MeshUserData : Rhino.DocObjects.Custom.UserData { private List<double> meshResults; //Storing the results that colour the mesh public MeshUserData() { meshResults = new List<double>(); } } }
This is the skeletal of our custom data class, from here we need to provide functionality to add, remove or clear the list. We could do a simple method which returns the list and allows the calling method to handle everything related to the list. However, this would be dangerous as the caller can then do anything to the list as they would a normal list. Thus, it is safer to provide access methods to control what the calling method can do with the list. We then end up with a class like so.
namespace MyNamespace { class MeshUserData : Rhino.DocObjects.Custom.UserData { private List<double> meshResults; //Storing the results that colour the mesh public MeshUserData() { meshResults = new List<double>(); } public void AddResults(Listresults) { meshResults = results; //Simple implementation - overwriting the previous results for the new ones. Alternatively we could loop through the incoming list and add them to the meshResults, compounding the meshResults list. } public void ClearResults() { meshResults.Clear(); } } }
Now that we have successfully implemented the abstract Rhino UserData class, we can add it to the geometry.
Adding custom data to Rhino objects
Now that we have our custom data class, we can add it to the UserDataList of Rhino objects to share it across as we wish. Doing this is fairly simple, all we need to do is access the UserData variable of the object and add our custom data to it. This isn’t necessarily as straight forward as it seems, as the UserData variable is read only, and it isn’t immediately obvious that you can modify it as if it were a list. Nevertheless, you can add, remove or modify the user data list as if it were a normal C# list, and we can add our custom data like so.
MeshUserData meshUserData = new MeshUserData(); meshUserData.AddResults(myResults); object.UserData.Add(meshUserData);
Here, object refers to the Rhino object we wish to add our user data to. You would replace this with the name of your object variable (myMesh for example).
Hopefully this help you add your own custom data to Rhino objects which can then be sent to other Grasshopper components or Rhino plugins as you require where it can then be read and worked on.
I cannot get this to work.
I am in Grasshopper, I have a c# script that takes a Rhino GeometryBase (myGeometry) as an input. I’ve copied and pasted your MeshUserData class definiton into the script, and tried the following:
MeshUserData meshUserData = new MeshUserData();
meshUserData.AddResults(myResults);
myGeometry.UserData.Add(meshUserData);
After that, If i set the grasshopper c# component output to:
output = myGeometry.UserData
it comes out as Null.
Could you help me figure out what i am doing wrong?
Thank you,
Mike
Hi Mike,
Apologies for the late response – work and holidays have drowned me recently and I missed the emails about this comment!
The code here isn’t designed for the C# script component in Grasshopper, rather it’s best to use in custom Grasshopper components (compiled in your IDE of choice such as Visual Studio).
All I can think of without seeing the full GH solution is that it can’t identify the MeshUserData at runtime because the C# script component wouldn’t allow it to be visible outside of the class.
I’d recommend trying to create a compiled component and see if that provides the same issue?
Best regards,
Fraser