Hi
How do I achieve the same function as the ‘Model Object’ component in Grasshopper, in RhinoCommon?
There doesn’t seem to be a way to construct a new model object with the modelobject.attributes…
modelobject_constructor.gh (15.1 KB)
Hi
How do I achieve the same function as the ‘Model Object’ component in Grasshopper, in RhinoCommon?
There doesn’t seem to be a way to construct a new model object with the modelobject.attributes…
modelobject_constructor.gh (15.1 KB)
Hi Kyuubimode,
Constructing a ModelObject with new attributes
ModelObject.ToAttributes() returns a ModelObject.Attributes (a Grasshopper type) whose Geometry setter is internal — so you can’t build one and swap
geometry into it.
Instead, use the public constructor that takes classic Rhino attributes:
ModelObject(RhinoDoc doc, Rhino.DocObjects.ObjectAttributes atts, GeometryBase geometry)
So the pattern is: get/create a Rhino.DocObjects.ObjectAttributes, then hand it to the constructor with your new geometry.
// start fresh, or copy the source object's attributes to preserve layer/name/user text
var atts = new ObjectAttributes();
if (mo.Id.HasValue)
{
var robj = doc.Objects.FindId(mo.Id.Value);
if (robj != null) atts = robj.Attributes.Duplicate();
}
atts.Name = "Sphere"; // set whatever you want
var newObj = new ModelObject(doc, atts, brep);
Two things to know:
re_modelobject_constructor.gh (9.4 KB)
Hi Japhy,
For my use-case, there are a lot of attributes I modify in the GH document so I will have to copy these by hand in c# each time which is fine. The only issue now is that the GUID cannot be copied by hand so I cannot push this into the document with the content cache and replace the point object. The R8 ModelObject component allows for this workflow. What can I do to mimic it?
What is the intended workflow?
RhinoCommon Replace functions swap geometry on an existing GUID directly with no ModelObject involved.
re2_Re_modelobject_constructor.gh (12.6 KB)
This is not using the Content Cache workflow then?
The user makes Breps in the Rhino. In Grasshopper I query these objects and add Usertext to them via some arbitrary rules (like which boundary does the brep lie in on an architecture plan). There are times where I might also change the geometry of their Brep (maybe I collapse short edges, if their geometry has holes I cap it, I explode and reconstruct their Brep, I convert them to extrusions for easier handling, etc). Up till now I have been able to replace the user’s geometry using the ‘ModelObject’ component followed by ‘Content Cache’ to update the user’s problematic geometry without them having to worry about it.
Right now I am converting parts of a huge grasshopper script into reusable c# script components so I don’t want to rely on the ‘ModelObject’ component. Ideally apart from the ‘Query Model Objects’ and ‘Content Cache’, everything else on the canvas will be a c# script component. I need to mimic the ‘ModelObject’ component’s replace geometry function so I can update the user’s objects. Does this help explain?
Hi @Japhy here is a distilled example
This script queries one Brep in Rhino and combines co-planar faces. The intention is to push this new brep in place of the existing brep which is what the GH8 Model Object and Content Cache components do.
I am unable to replicate the behavior of the Model Object component in my c# script component i.e. getting a model object with desired geometry but the same GUID so it can be used with with the Content Cache at the end of the script.
Hope this is clear example of the workflow.
merge_faces.3dm (87.3 KB)
merge_faces.gh (21.8 KB)
Hi Kyuubimode,
Thanks for the distilled example, made it easy to test against your exact file.
The id of a ModelObject rides on Grasshopper’s referenced goo mechanism, not the attributes. Set ReferenceID on the geometry goo, then cast — the resulting Model Object carries the original guid and Content Cache treats it as a replace, same as the native component.
var src = ModelObject.Cast(x); // Model Object from Query
Brep brep = null;
src.CastTo(out brep); // get the geometry
brep = brep.DuplicateBrep();
brep.MergeCoplanarFaces(RhinoDocument.ModelAbsoluteTolerance);
var goo = new GH_Brep(brep);
goo.ReferenceID = src.Id.Value; // <- the whole trick
var result = ModelObject.Cast(goo); // Id == original guid now
var attrs = result.ToAttributes(); // attributes don't ride the cast —
var srcAttrs = src.ToAttributes(); // copy them over (public setters)
attrs.Layer = srcAttrs.Layer; attrs.Name = srcAttrs.Name;
attrs.UserText = srcAttrs.UserText;
attrs.Display = srcAttrs.Display; attrs.Render = srcAttrs.Render;
attrs.Drafting = srcAttrs.Drafting;
a = new ModelObject(attrs);
The cast doesn’t bring attributes with it, so copy the ones you need from the source — the setters on ModelObject.Attributes are public. UserText assigns wholesale; ModelUserText also has MergeRange/UpdateRange if you’re combining.
i tested in your merge_faces.gh — the Guid param that was failing on your c# branch now reports the same {6dd4b911…} as the native Model Object branch.
re_merge_faces.gh (15.2 KB)