In a GHPython script, I am trying to use clr.Reference function to obtain a C# reference type, so that I can return a value from a RhinoCommon function (MeshTopologyEdgeList.GetEdgesForFace). But I am always getting the error:
AttributeError: module 'clr' has no attribute 'Reference'
I am running Rhino WIP 8 version (8.0.23241.14305, 2023-08-29)
Commercial. This is a new install, but I also had the same issue with Rhino 7 (which I also re-installed to see if that would help), but always got the same error. Where is GHPython pulling its modules from? Is it possible that my installation of Visual Studio with the C# workload is shadowing or replacing the CLR module?
Here is my script (edited down to just the essentials):
import rhinoscriptsyntax as rs
import Rhino
import System
from System import Array
import clr
# (I was trying StrongBox as an alternative but the GetEdgesForFace method wouldn't accept it.)
# r = System.Runtime.CompilerServices.StrongBox[Array[bool]]()
dir = clr.Reference[Array[bool]]() #this line throws an AttributeError
print(dir)
edge_topo = M.TopologyEdges
print(*edge_topo.GetEdgesForFace(0, dir))
I’ve also noted that Reference doesn’t appear in the code completion tools:
It is, and I got it working with your script’s help. Thank you!
Would be nice to understand why my clr module is missing this method, but ultimately C# is probably the way to go if I’m hacking around in RhinoCommon.
Thanks so much Dale!
So it turns out that the my problem appears only when using the new Python 3.9 script component in Rhino 8 WIP. Everything is fine with the older Python 2.7 script components. There must have been some change in the clr module as neither StrongBox nor its alias Reference are available.
if mesh:
faceCount = mesh.Faces.Count
if faceIndex >= 0 and faceIndex < faceCount:
#two versions of StrongBox:
orientation = out_naked = clr.StrongBox[System.Array[System.Boolean]]()
#AttributeError: module 'clr' has no attribute 'StrongBox'
orientation = out_naked = System.Runtime.CompilerServices.StrongBox[System.Array[System.Boolean]]()
# TypeError: No method matches given arguments for MeshTopologyEdgeList.GetEdgesForFace: (<class 'int'>, <class 'System.Runtime.CompilerServices.StrongBox[Boolean[]]'>)
edges = mesh.TopologyEdges.GetEdgesForFace(faceIndex,orientation)
edgeIndices = edges
sameOrientation = list(orientation.Value)
Anyway I’m going to keep going with C#, no need to spend extra time on this, but thought it may be of interest!
When using Python 2 component, you are basically using IronPython 2.
IronPython, requires you to initialize the GetEdgesForFace method’s out parameter with clr.StrongBox[Type]()
When using Python 3 component, you are using Python.NET. Python.NET deals differently with out parameters, an its syntax is less “C# like”.
You need to define some initial value of the out parameter (any value, it’s irrelevant, as long as the type is correct), and then method will return a new value of the out parameter.
I don’t have Rhino 8 WIP to test this, but something like this may work on Python 3 component:
faceIndex = 0
orientation_dumm = False # it could have been 'True', it does not matter.
edgeIndices, orientation = mesh.TopologyEdges.GetEdgesForFace(faceIndex, orientation_dumm)