Rhino 8 WIP - Python - Get Geometry From Model Object?

Hello,

I have a simple python script that returns the curve degree from the input curves.

I am primarily passing geometry as “Model Objects” throughout the script.

If I use the G output of the Model Objects node and feed that into python or put a geometry type node such as “Curve” between the Model Object O output and the Python input, the script functions as expected.

I am stuck on how to, inside python, extract the geometry from a Model Object so that I don’t need an intermediary node between the Model Object and the Python script.

Please see the snip below noting that the G output of the MO node, or a Curve node after the O, solves the input needs of the python component. (I would like to skip this step and feed the O straight into python)

Graph Space:

Thanks for your help!

Script:

import rhinoscriptsyntax as rs

if C is None:
    D = C
elif rs.IsCurve(C):
    degree = rs.CurveDegree(C)
    print "Curve degree:", degree

    D = degree

One way?

Thank you @Helvetosaur , I started with the coerce method but had no luck as I need to go from Model Curve to Curve.

The Rhino 8 Model Object node handles this by giving you access to a “G” output but I’m wanting to pull the G result directly out of the Model Object as I am trying to avoid splicing in a Model Object node anytime I need to access the geometry of Model Objects.

I hope that makes sense, I’m unsure of the exact terminology or syntax to use for this.

@AndyPayne can I bother you to weigh in on this one? The short, how to pass/cast/get Model Objects as geometry in python. Thanks!

1 Like

Hi Michael, I hope I resolve your issue since I was just having the same problem searching the web and api’s of RhinoCommon looking for a way to convert the rhino object coming from the new Rhino tab in Rhino 8 (which by the way, its the most exiting update ever made for me at least!) and have solved it with this:

Considering “x” is the input

import Grasshopper
rhinoObj = x.Id #To get the object guid
ghGeometry = Grasshopper.Kernel.GH_Convert.ToGeometryBase(rhinoObj)

Regards!

1 Like

I guess this really involves the conversion between Rhino.Object and the newer Grasshopper.ModelObject.

To get Geometry out of a ModelObject I might use this:

"""Grasshopper Script"""
import Rhino.Geometry as RG
import Grasshopper.Kernel.Types as GT

res, a = x.CastTo[GT.GH_Brep]()

I expect these Types are possible to convert to: Grasshopper.Kernel.Types Namespace

2 Likes

Thanks @scottd, very helpful! So the model object is actually GH specific, that makes sense.

A silly question perhaps but we can use GH model objects to store, get, set model object meta data of a Rhino object(geometry) without ever having to need GH to be running.

Is that correct?

Actually that is not a silly question at all, as it has led to a few discussions internally here.

Rhino.Object is geometry with attributes. It contains the methods to get to the attributes and it’s on geo.

GH.Modelobject is Grasshopper specific and can contain many of the same attributes that you might find in a Rhino.Object. So in many ways they look the silmilar.

One thing I am trying to determine is when using python in grasshopper is it better to use model objects because they can be passed downstream to other components along with their attributes. As apposed to a rhino object that could only pass it’s geometry or an attribute value separately down the grasshopper pipe.

What we need to experiment with is when to use model object and when to use rhino.object.

But another important part of model object is that it can carry an ID of a object that is in the rhino doc, so at the time it gets pushed back into rhino it will replace the object, not create a new one.

1 Like

I think this is really important.

Personally I think it’s very powerful that a Model Object can be a model object even without geometry. The fact that you can generate and or carry data along in a container and at any time in the execution flow append or remove portions of that data or inject or replace geometry etc is great and very flexible.

And of course I love to be able to use it both on reference GH geometry AND rhino.objects that are already in the doc.

I’ve been experimenting heavily with these differences since MO components came into R8 WIP and at one point in time I was convinced I never needed to bake/cache anything to Rhino ever again since I could now have ALL the possible data I could need living in data space via the Model Object.

The only reason I switched back to primarily caching most of the created geometry was for the UX of being able to “snap” to the cached geometry in the Rhino model while creating new geometry directly in Rhino or referencing said snaps/vertices with osnaps settings to easily place points and things that would get referenced into GH to “do complex things”.

More recently I’m very much interested in seeing how I can get the behavior of custom grips, snaps, etc. while still working primarily with GH model objects only and then ONLY caching geometry for reasons of exporting solids/meshes for interop with other softwares that can’t read a GH geometry preview of course.

I recently discovered the kangaroo Mouse component that lets you drag GH preview geometry around and it got me thinking of entire workflows of manipulating the GH preview geometry from within Rhino without the need to bloat the Rhino file size with Caching all that geometry.

In summary, the fact that Model Objects can support meta data, render materials, geometry, etc. it’s essentially everything I could want/need to manipulate a 3D environment. Now I’m focused on what kind of UX/UI and scripts enable us to work inside a GPU/data oriented workflow.

I guess all that GH preview geometry needs to be stored somewhere, GH file size? Memory? GPU memory? I don’t quite understand where it all lives but it seems like it has great potential to offload a lot of work from the CPU and to drastically reduce Rhino file sizes and such if everything is just “data” that is being dynamically called when it is time for it to “appear” or be referenced.

Likely I’m over simplifying but model objects are the best thing to happen to GH since GH :laughing: in my opinion… So very curious what that could mean for Rhino itself… I don’t have the answer but am eager to find out

Talking about Dynamic drawing have you seen this material?

2 Likes

Yes, I’ve read both of those .PDFs and played around with the example code snippets as well. Good stuff!

Here is a little bit of code to take a Rhino object and then convert it into a Modelobject that includes the ID. So it ever sent into a Content cache it can replace the original object:

"""Grasshopper Script"""
import Rhino
import Grasshopper

rh_obj_list = []

rh_objs = Rhino.RhinoDoc.ActiveDoc.Objects.FindByLayer(x)

for obj in rh_objs:
   refobj = Rhino.DocObjects.ObjRef(obj)
   goo = Grasshopper.Kernel.GH_Convert.ObjRefToGeometry(refobj)
   rh_obj_list.append(goo)

a = rh_obj_list

4 Likes

Thank you @David_Ramos_Luna and @scottd ,

You covered going both ways between object types and I think that will do it for my development needs for now, much appreciated!

1 Like

Hi @scottd

I’m trying to add ModelObjects to RhinoDoc, but I can’t figure out how to do this based on the documentation.

from Rhino import FileIO, RhinoDoc

doc = RhinoDoc.CreateHeadless(None)

for obj in objects: # objects are GH ModelObjects
    doc.Objects.Add(obj)

opt = FileIO.FileWriteOptions()
doc.WriteFile(path, opt)
doc.Dispose();

following:

Grasshopper.Rhinoceros.Model.ModelObject value cannot be converted to Rhino.Geometry.GeometryBase

Best,
Johan

I would run those Model objects through the Modelobject component and strip the Geometry off it it as shown here:

Or the Type hint on the input can be set to GeometryBase:

Might either one of these work?

3 Likes

Hi @scottd

Thank you for getting back to me. This means a lot.

I might have been a bit unclear in my question—my apologies.

I’m trying to preserve the ModelObject attributes (layer, name, and all the rest) so the geometry in the exported file retains the same information.

I’ve attached an example file.
ModelObject to RhinoDoc.gh (7.7 KB)

import Rhino.Geometry as RG
import Grasshopper.Kernel.Types as GT
from Rhino import FileIO, RhinoDoc

doc = RhinoDoc.CreateHeadless(None)

for obj in modelObj: # objects are GH ModelObjects
    res, gh_obj = obj.CastTo[GT.GH_Brep]()
    att = obj.ToAttributes()
    doc.Objects.Add(gh_obj,att)

opt = FileIO.FileWriteOptions()
doc.WriteFile(path, opt)
doc.Dispose();

Best,
Johan

Hi @Johan_Lund_Pedersen,

The script should be something like this.

import Rhino.Geometry as RG
import Grasshopper.Kernel as GK
from Rhino import FileIO, RhinoDoc

# Create a headless document
doc = RhinoDoc.CreateHeadless(None)
try:
    # Copy units & tolerances from active doc
    doc.ModelUnitSystem = RhinoDoc.ActiveDoc.ModelUnitSystem
    doc.ModelAbsoluteTolerance = RhinoDoc.ActiveDoc.ModelAbsoluteTolerance
    doc.ModelAngleToleranceRadians = RhinoDoc.ActiveDoc.ModelAngleToleranceRadians

    # Bake ModelObjects into the headless document
    for obj in modelObj:
        guid = GK.IGH_BakeAwareData(obj).BakeGeometry(doc, None)

    # Save the headless document
    opt = FileIO.FileWriteOptions()
    doc.WriteFile(path, opt)
finally:
    doc.Dispose();

ModelObject to RhinoDoc.gh (18.6 KB)

3 Likes

Hi @kike,

Perfect! Thank you! This is of great help to me.

Best,
Johan