Site Tools


Passing Data from a .NET Plug-in to RhinoScript

Problem

I am trying to use the plug-in object's GetPlugInObjectInterface facility to return information from my .NET plug-in to be used in RhinoScript. I can successfully define a class with the ComVisible attribute and return an object of that class type to RhinoScript used in a sample script. Yet, I can not find a way to return a collection or array of objects of that type and use it in the script.

Solution

A quick review: Rhino 4.0 plug-ins can extend the RhinoScript with new objects and methods. Do this by declaring .NET classes with the ComVisible(true) parameter, and by overriding the plug-in object's GetPlugInObjectInterface to return these classes when requested by RhinoScript.

The following sample code demonstrates how to return different data types from .NET to RhinoScript, including objects and arrays of objects. The code samples are written in C#, but could easily be written in VB.NET.

Also, the code samples assume the following COM visible class has been declared:

//C# class declaration
[System.Runtime.InteropServices.ComVisible(true)]
public class TestRhinoScriptObject
{
  ...
}

and that our plug-in object's GetPlugInObjectInterface override will look something like this:

public override object GetPlugInObjectInterface(ref System.Guid iid)
{
  return new TestRhinoScriptObject();
}

Returning simple data types

Simple data types, such as integers, doubles, and strings are easily marshalled between .NET and RhinoScript because their values can be easily converted to the Object .NET data type.

To return integers, doubles, and strings from our TestRhinoScriptObject object, we could add the following public members:

public int GetInteger()
{
  //Returns an integer
  return 24;
}
public double GetDouble()
{
  //Returns a double-precision number
  return OnUtil.On_PI;
}
public string GetString()
{
  //Returns a text string
  return "Hello RhinoScript!";
}

Returning arrays

In RhinoScript, 3-D points are represented as zero-based, one-dimensional arrays that contain three numbers. And, arrays of 3-D points are zero-based, one-dimensional arrays of 3-D points.

Arrays are a little more difficult to deal with, but not impossible. The .NET array classes have a ToArray member that will copy the elements of the array to a new Object array. A .NET Object array will marshall to COM as a SafeArray.

To return a 3-D point or an array of 3-D points from our TestRhinoScriptObject object, we could add the following public members:

     public object GetPoint()
     {
        Returns a 3-D point
       ArrayList pt = new ArrayList(3);
       pt.Add(2.0);
       pt.Add(1.0);
       pt.Add(0.0);
       return pt.ToArray();
     }
 
     public object GetPoints()
     {
        Returns an array of 3-D points
       ArrayList pts = new ArrayList();
 
       ArrayList p0 = new ArrayList();
       p0.Add(0.0);
       p0.Add(0.0);
       p0.Add(0.0);
       pts.Add(p0.ToArray());
 
       ArrayList p1 = new ArrayList();
       p1.Add(10.0);
       p1.Add(0.0);
       p1.Add(0.0);
       pts.Add(p1.ToArray());
 
       ArrayList p2 = new ArrayList();
       p2.Add(10.0);
       p2.Add(10.0);
       p2.Add(0.0);
       pts.Add(p2.ToArray());
 
       ArrayList p3 = new ArrayList();
       p3.Add(0.0);
       p3.Add(10.0);
       p3.Add(0.0);
       pts.Add(p3.ToArray());
 
       return pts.ToArray();
     }

Returning arrays of objects

Now, lets define another COM visible class in our .NET plug-in:

[System.Runtime.InteropServices.ComVisible(true)]
public class TestSimpleClass
{
  //data member
  private double m_d;
 
  //constructor
  public TestSimpleClass(double d)
  {
    m_d = d;
  }
 
  //property member
  public double DoubleValue
  {
    get { return m_d; }
    set { m_d = value; }
  }
}

Knowing what we know (now) about passing arrays from .NET to RhinoScript, we can pass instances of the above class from our our TestRhinoScriptObject object as follows:

public object GetTestSimpleClass()
{
  //Return an object
  object rc = new TestSimpleClass(System.Math.PI);
  return rc;
}
 
public object GetTestSimpleClasses()
{
  //Return an array of objects
  ArrayList objs = new ArrayList();
  for( int i=0; i<10; i++ )
    objs.Add(new TestSimpleClass(i));
  return objs.ToArray();
}

Using .NET objects from RhinoScript

The following sample RhinoScript code demonstrates how to get the above objects and print their return values to Rhino's command history window.

Option Explicit
 
Sub TestRhinoScriptObject()
  Dim objPlugIn, objTest, arrPts, arrObjs, i
 
  ' Get the TestRhinoScript plugin's
  ' primary COM visible object
  On Error Resume Next
  Set objPlugIn = Rhino.GetPlugInObject("TestRhinoScript")
  If Err Then
    MsgBox Err.Description
    Exit Sub
  End If
 
  ' Print the simple data    
  Rhino.Print "TestRhinoScript.GetInteger = " & objPlugIn.GetInteger
  Rhino.Print "TestRhinoScript.GetDouble = " & objPlugIn.GetDouble
  Rhino.Print "TestRhinoScript.GetString = " & objPlugIn.GetString
 
  ' Print the point
  Rhino.Print "TestRhinoScript.GetPoint = " & Rhino.Pt2Str(objPlugIn.GetPoint)
 
  ' Print the array of points
  arrPts = objPlugIn.GetPoints
  For i = 0 To UBound(arrPts)
    Set objTest = arrObjs(i)
    Rhino.Print "TestRhinoScript.GetPoints(" & i & ") = " & Rhino.Pt2Str(arrPts(i))
  Next
 
  ' Print the object
  Set objTest = objPlugIn.GetTestSimpleClass
  Rhino.Print "TestSimpleClass.DoubleValue = " & objTest.DoubleValue
 
  ' Print the array of objects    
  arrObjs = objPlugIn.GetTestSimpleClasses
  For i = 0 To UBound(arrObjs)
    Set objTest = arrObjs(i)
    Rhino.Print "TestSimpleClass.DoubleValue(" & i & ") = " & objTest.DoubleValue
  Next
End Sub
developer/dotnettorhinoscript.txt ยท Last modified: 2016/02/09 by sandy