Background: As part of an effort to automate mechanical tasks in our (architecture) office, I am developing a Grasshopper definition that relies on Rhinocommon to bake trimmed surfaces to Rhino, so that the user (my coworkers) can then manually select the ones they want to use for further processing with GH. The problem is that I cannot figure out how to bake the trimmed surfaces and not the underlying, untrimmed rectangles. It seems that if I manually bake the surfaces I get what I want, but I want to automate this part so that non-Rhino colleagues (i.e. most of them) can also use the script without tweaking things.
Upstream/Downstream: The pipeline starts with a BIM output that contains the elementary building volume as adjacent blocks, specifically one block per floor. These blocks are exploded and their outputs are split into the different types (surfaces, meshes, etc). I need to extract the roof surfaces and groundfloor surfaces for the purpose of casting shadows on a mesh or a plane, but since the exploded elements are kind of complex to handle programmatically I would like to bake all surfaces in Rhino and then let the users pick manually the ones that they want to use.
Already tried:
Transforming trimmed surfaces in curves, exploding them and then connecting vertices as polylines. I have surfaces with holes and these don’t seem to work with “explode curve”.
Using ShrinkTrimmedSurface before baking: surfaces with holes cannot be shrunk (says that brep couldn’t be converted to curve/surface) and the ones that do not throw errors are still baked as untrimmed surfaces.
Do you have any suggestions on how to move forward, or where I shoud look to do so? I am stuck at the moment.
Thank you very much in advance!
Left: what I get with GhPython/Rhinocommon. Right: what I would like to get with GhPython but can only get by manually baking.
Take a look at this, I believe it is what you are after?
FYI you have multiple overlapping surfaces in your aptly named “messed_up_surfaces” input.
I switched the type hint of expl_volume_srf input to Brep to simplify the code
Code:
import rhinoscriptsyntax as rs
import scriptcontext as sc
import Rhino
if go_ahead_in:
# Set the Rhino document to the active Rhino document
sc.doc = Rhino.RhinoDoc.ActiveDoc
rs.AddLayer("Default")
rs.CurrentLayer("Default")
layer_names = rs.LayerNames()
for layer in layer_names:
#print(layer)
if layer == "Default":
continue
else:
rs.LayerVisible(layer, visible=False)
rs.AddLayer("volume_srf", color=rs.CreateColor(9, 255, 0))
srf_ids = []
trimmed_srf = []
for srf in expl_volume_srf:
#print("Looped once")
#Shrink The Surface
srf.Faces.ShrinkFaces()
#Add Shrinked Surface To List
trimmed_srf.append(srf)
for srf in trimmed_srf:
# Add each Brep to the Rhino document and get the ID
obj_id = sc.doc.Objects.AddBrep(srf)
srf_ids.append(obj_id)
# Set the layer for the added object
rs.ObjectLayer(obj_id, "volume_srf")
# Set the Rhino document back to the Grasshopper document
sc.doc = ghdoc
Turns out the problem is the type hint. If you just change the type hint in @vongree’s original file everything works as expected. I reported the behavior here: IGH_Goo.CastTo<GeometryBase> bug. It’s a bug in the grasshopper API and happens when grasshopper casts geometry from a surface.
As I initially said, a “trimmed surface” is not a NurbsSurface, but a Brep with one Face.
What you do here is dangerous. You “cast” from an interface reference to an abstract base class. Consider the IGH_Goo is a GH_Surface and you try to cast it to a GeometryBase. Well, what is it supposed to be? A Nurbs or a Brep? The constructor of GH_Surface supports both. But if you don’t explicitly tell its meant to be Brep, it chooses a NurbsSurface as its probably the first option to pick from. The only bug I see here is that api allows you to do such nasty things. Better would be to throw an exception here.
Amazing, I am still very fresh with Rhinocommon so the provided code is very helpful. Thank you!
Quick question: is there a reason why you separated the process into two different loops instead of just doing it all at once? Or why you create the srf_ids list if you never use it afterwards?
Makes perfect sense. I like asking about the rationale behind code snippets because there are “unsaid” best practices that aren’t always easy to pick up. What you do with GUIDs, for example, is very helpful for future reference. Thank you!
I don’t know what the etiquette is here on the forums, but since @michaelvollrath made the extra effort with code/files/images, I will check his answer as the solution to my issue. Nonetheless, thank you everyone for your answers and the interesting discussion in the related post linked here. They were all very helpful.