Version: Rhino 4.0
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.
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(); }
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!"; }
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(); }
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(); }
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