Pass RhinoDoc to Grasshopper in a C# Plugin hosted by Rhino.Compute

I’d like to be able to pass a .3dm file to Rhino.Compute, apply a Grasshopper definition to it which modifies the document, and then stream the modified document back to the caller.

  • I have a C# class which inherits Rhino.Plugins.Plugin, which is installed on a Rhino.Compute instance and exposes a custom endpoint named “Modify” using HostUtils.RegisterComputeEndpoint during OnLoad, which is all working fine.

  • The “Modify” method takes as input the .3dm file as a base64 string, and the string path to a GH definition file. The 3dm file is written to disk as a temp file and then loaded into memory via
    var rhinoDoc = RhinoDoc.CreateHeadless(tempFilePath).

  • My first optimistic attempt was to just call
    RhinoApp.RunScript($"_-GrasshopperPlayer \"{pathToGHDef}\"", false)
    but my .GH file uses eleFront components for document IO, which threw NullReferenceException. From this post on the forums (Hops and Elefront), I’m guessing my issue is that my plugin code does not provide the Grasshopper engine with a reference to the “current” RhinoDoc. I verified this by making a GH definition with a single C# script component which outputs a bool if this.RhinoDocument==null.

  • I then saw that RhinoApp.RunScript has an overload which takes a uint documentSerialNumber, so I tried passing it my loaded rhinoDoc.RuntimeSerialNumber, which caused the same exception again.

Is there a way to invoke the grasshopper solver where you supply the RhinoDoc reference for it to operate on?

Could another option be to import the 3dm file to Grasshopper directly using Resthopper?

I would do something like this from a GH component executed in a rhino compute context (inspired from @fraguada’s earlier post):

string tmpPath = "<path to file>"
using( var doc = Rhino.RhinoDoc.CreateHeadless(null)){
  doc.Import(tmpPath);
  var ros = doc.Objects.FindByObjectType(Rhino.DocObjects.ObjectType.Mesh);
  var meshes = new List<Rhino.Geometry.Mesh>();
  foreach( Rhino.DocObjects.RhinoObject obj in ros )
  {
    meshes.Add(obj.DuplicateGeometry() as Rhino.Geometry.Mesh);
  }
}
//output the meshes or whatever from the component

Then you pass these meshes out to the GH defintion where it’s processed further. Finally you create a new modified version of the 3dm file using the File3dm class which then is streamed back to the client.

I realized it’s way simpler than I was making it. From inside the context of C# code running as a plugin inside Rhino.Compute, I can just load the definition into a GH_Document, populate the GH_Structures for inputs, run definition.NewSolution(…) and just collect the result parameters.

1 Like