@TomTom
Moving this discussion ("Baking" Trimmed surfaces using Rhinocommon - #6 by TomTom) over here since the other thread was explicitly about baking trimmed surfaces in a python node. This a long, wordy reply, I don’t know your background knowledge so I’m going to attempt to build up to why I believe the behavior I’m seeing here is as least something that users should be provided with a visual warning about, if not a full on bug.
I’ve looked through the API documentation for both RhinoCommon and OpenNurbs just in case the RhinoCommon interface through to the C++ code had a different inheritance structure, they don’t.
Some things to note about objects in C++ and C#, it doesn’t matter which version of a reference or a pointer you have to an object (interface, abstract base class, void*, a concrete class, etc) the object is still the full version of that object. Object slicing bugs aside, casting up an inheritance tree shouldn’t be dangerous, you just have access to less of an object that you would have at more explicit version of that object. Casting back down a tree can be, and C# protects you from that by returning a null object if the cast isn’t valid. Both Brep and Surface inherit from the same base class (GeometryBase in C# and ON_Geometry in C++) and therefore casting either to that base class should be safe and result in no loss of data.
In the grasshopper API, IGH_Goo
, is the interface for a data inside of Grasshopper. It provides a means to pass arbitrary data around from node to node, and serialize that data. GH_Goo<T>
is the recommended abstract base class for implementing additional data types, most if not all data types in grasshopper implement GH_Goo<T>
. Further more, IGH_Geometric_Goo
and GH_GeometricGoo<T>
serve as extensions of IGH_Goo
and GH_Goo<T>
respectively for geometry classes in grasshopper. If you implement GH_Goo<T>
you’ll notice that it includes a property Value
of the type you provide. This indicates that it’s meant as a wrapping class.
Okay so then what should the expected behavior of IGH_Goo.CastTo<T>
(IGH_Goo.CastTo(T) Method) be? The documentation says that it attempts to cast to type T. My intuition here is that IGH_Goo.CastTo<T>
is meant to attempt to cast the underlying data value to the presented type. This is supported by the way we interact with IGH_Goo
values in grasshopper component implementations, how we retrieve values from the parameters in the API, how custom parameter types interact with base grasshopper components, and because by making it an explicit function, the interface is providing us a means to cast to objects that do not implement the interface.
This brings me to behavior that feels like a bug to me. With a debugger, I can see that Value
propery on the GH_GeometricGoo
object in the node has the trimming information attached whether it gets passed into the node as a brep (GH_Brep
) or as a trimmed surface (GH_Surface
). The fact that this information is present on the Value
property of the before the call to IGH_Goo.CastTo<T>
but not on the data passed out of the function is why I believe this to be a bug. If I was casting to a GH_Brep
to a Rhino.Geometry.Surface
, then yeah, losing the trimming information makes sense, but I’m not. I’m casting to the common abstract base class of their underlying values, Rhino.Geometry.GeometryBase
, so I should not be losing data in the process. Interestingly enough, Both GH_Surface
and GH_Brep
implement GH_GeometricGoo<Brep>
. This means that under the hood, both are storing their data as a brep, and are just providing different views of the same object. But CastTo<GeometryBase>
removes the trimming information when called on a GH_Surface
while it’s preserved when called on a GH_Brep
.
To correct my comment in the other thread, it’s not that it’s a bug when grasshopper casts an object to a Surface
, it’s a bug when grasshopper casts from a Surface
.
I hope this is helpful. I’ll upload an example later today that isolates and demonstrates this behavior.
-Cullen