Can I invoke Python script when develop GH component with C# and VSStudio?

I used to use ghpythonlib.components to invoke some Grasshopper functions when they are not offered by rhinoscriptssyntax, which is efficient. Recently I am trying to develop scripts using C# with VSstudio considering its user-friendly features and constructability(means that I don’t have to write all of the code in a single python file).

While, when I tried to invoke functions of GH components from Rhino.NodeInCode.Components.FindComponent in Rhinocommon, I could sincerely feel its stalling. Then I tried to write a test program that shows the speed gap between the performance using the similar function in Python and C#. I’d realized the speed of C# should be faster than Python theoretically, I can not understand what’s happening.

Now I suppose I call the Python code directly in C#, and build them together in a battery, so as to solve the efficiency problem. But I haven’t found a relevant method. I hope you can dispel my problem.
Snipaste_2021-08-30_09-17-28

Here are the C# and the Python code of the test:

  1. C#:
  private void RunScript(Circle A, Circle B, Circle C, Point3d Pt, ref object Result)
  {
    var cttt = Rhino.NodeInCode.Components.FindComponent("CircleTanTanTan");
    if(cttt == null) return;
    var cttt_function = (System.Func<object,object,object,object,object>) cttt.Delegate;
    Result = cttt_function(A, B, C, Pt);
  }
  1. Python
import rhinoscriptsyntax as rs
import ghpythonlib as gp

Result = gp.components.CircleTanTanTan(A, B, C, Pt)

Have you run the c# component multiple times after writing it? C# scripts are always slow on the first run as they compile the code (which on my pc takes around 200ms).

You probably already know this but I just thought I’d check.

1 Like

Yes, I also realized after I published the question, the performance will rise dramatically after first running, tks!
While back to the question, I still want to know how to invoke python and 3rd library script in C#, since I spent an entire afternoon on the IronPython document🤣

Ok I did it. It turns out this is really really slow, 800ms slow, but is was fun trying to make it work. It maybe could be faster if I knew more about invoking iron python in C#, but this worked.

This really helped with calling IronPython in C#

I used it to call ghpythonlib from C# and do the circle function in your original post.

There’s a lot of setting up the scope in python, some to of the paths point to my user directory which you would have to change. I may have imported too many directories, didn’t bother trying to find out which weren’t needed.

You need to add the assemblies “Microsoft.Scripting.dll” and “IronPython.dll” located in
“C:\Program Files\Rhino 7\Plug-ins\IronPython”

Now for the code

using IronPython.Hosting
private void RunScript(Circle A, Circle B, Circle C, Point3d Pt, ref object D)
  {
    var engine = Python.CreateEngine();
    dynamic scope = engine.CreateScope();
    //now the python script as one big string literal
    var script =
      @"
#Always have to shit tab this to the far left whenever I open the C# editor to get appropriate python indenting
#A lot of building the appropriate scope now follows, probably could have done more efficiently
import clr
import sys

#typical sys.path list taken from ghpython component (I removed one or two paths)
paths = ['C:\\Program Files\\Rhino 7\\Plug-ins\\IronPython\\Lib', 'C:\\Users\\d.beer\\AppData\\Roaming\\McNeel\\Rhinoceros\\7.0\\Plug-ins\\IronPython (814d908a-e25c-493d-97e9-ee3861957f49)\\settings\\lib', 'C:\\Users\\d.beer\\AppData\\Roaming\\McNeel\\Rhinoceros\\7.0\\scripts']
sys.path.extend(paths)

#seemed to need the below assemblies
sys.path.append('C:\\Program Files\\Rhino 7\\System')
sys.path.append('C:\\Program Files\\Rhino 7\\Plug-ins\\Grasshopper\\Components')
sys.path.append('C:\\Program Files\\Rhino 7\\Plug-ins\\IronPython')
clr.AddReferenceToFile('RhinoCommon.dll')
clr.AddReferenceToFile('RhinoPythonHost.dll')
clr.AddReferenceToFile('GhPython.gha')

#and now the script
import ghpythonlib as gp
Result = gp.components.CircleTanTanTan(A, B, C, Pt)
      ";

    //Add variables to the scope
    scope.SetVariable("A", A);
    scope.SetVariable("B", B);
    scope.SetVariable("C", C);
    scope.SetVariable("Pt", Pt);

    //run script
    engine.Execute(script, scope);

    //retrieve result
    D = scope.GetVariable("Result");

  }

Given than ghpythonlib itself calls Rhino.NodeInCode this does seem a really silly way of doing it. Silly, but kind of beautiful at the same time.

I’ve added the gh file. Have fun.Grasshopper in Python in CSharp in Grasshopper.gh (3.3 KB)

1 Like

Wow, marvelous work! I tried to achieve the goal this week many times, but the rhino had broken at the round that I almost succeed. I wanted to try again this weekend, and then I saw your answer.

You’re right that it is really fun to try these niche technologies. I am excited to hear that someone was in the same mood as me.:grin::grin::grin:

Thanks for all your efforts on the issue!

1 Like