BrepSplit multiple surfaces/polysurfaces by a single or mutiple surfaces?

I cannot wrap my head around this could someone give me a simple example using this RhinoCommon?

What do I do after selecting the surfaces/polysurfaces?

import Rhino
import rhinoscriptsyntax as rs
import scriptcontext as sc
import time




tol=sc.doc.ModelAbsoluteTolerance

objs_ids = rs.GetObjects("Select Objects: ",rs.filter.surface,rs.filter.polysurface)
objs = [rs.coercebrep(ID) for ID in objs_ids]
cutter_id = rs.GetObject("Select split plane: ", rs.filter.surface)
cutter = rs.coerceboundingbox(cutter_id)




ts = time.time()
for obj in objs:
    
    obj.Split(cutter,tol)
    
    
te = time.time()

print "Elapsed time is {:.2f}".format(te-ts)

I want just like Rhino command to just split the object and all properties to be the same as the original, just split

What does this mean:

RhinoScriptSyntax works but rs.SplitBrep() appears to just work with surfaces not polysurfaces and it doesn’t assign any of the attributes to the original object. Not really what the Rhino command does.

import Rhino
import rhinoscriptsyntax as rs
import scriptcontext as sc
import time

tol=sc.doc.ModelAbsoluteTolerance

objs_ids = rs.GetObjects("Select Objects: ",rs.filter.surface+rs.filter.polysurface)
objs = [rs.coercebrep(ID) for ID in objs_ids]
cutter_id = rs.GetObject("Select split plane: ", rs.filter.surface)
#cutter = rs.coerceboundingbox(cutter_id) #this is wrong
cutter = rs.coercebrep(cutter_id)

ts = time.time()
split_part_IDs=[]
for i,obj in enumerate(objs):
    breps=obj.Split(cutter,tol)
    #breps are "virtual" geometry, you need to add them to the document (scriptcontext)
    if breps:
        for brep in breps: split_part_IDs.append(sc.doc.Objects.AddBrep(brep))
        #if something happened, delete the original object in the file
        rs.DeleteObject(objs_ids[i])
te = time.time()

print "Elapsed time is {:.2f}".format(te-ts)
1 Like

rs.SplitBrep() only works between two breps - but they can be surfaces or polysurfaces. If you want to split multiple breps with a single cutter, you can loop. If you want to split multiple breps with multiple breps, it’s more complicated, I posted about that once here, you might look for that post.

Yep. Remember what I said before about levels? rhinoscriptsyntax is a lower level language than native Rhino commands. That means you need to code more of it yourself. So you need to get the original object attributes before you start splitting and re-attribute them to the split parts afterwards. Have a look at rs.MatchObjectAttributes().

Doing it in RhinoCommon would be another level down, which means more lines of code still, because you have to deal with the transition from the document space (GUIDS + attributes) to virtual geometry and then back again.

1 Like

Thanks Mitch,

One question regarding rhinoscriptsyntax vs RhinoCommon.

Is performance better if you use RhinoCommon?

It can be… One of the things that takes time is reading and writing things to the document. As most rs methods write the result to the document (creating new objects), if you have an intermediate result that you will delete later anyway for example, that will “waste” time.

However, you are unlikely to see a significant difference if you are only working on a few objects and your script is set up efficiently. It’s only when you have thousands of them in a loop that you can begin to see some detectable speed gain.

1 Like

So far I have identified two things that increase performance. One is to disable redraw during the script. The second is to avoid executing commands on objects you know will fail. e.g. the script you shared above runs for 2.6 sec on my case, but if I check for intersection and then execute split only on those objects it finishes in 0.6 seconds.

I wonder how many other tricks there are

This is exactly my case. I need to figure out how breps work to make this split more efficient with RhinoCommon

Using hash tables instead of lists for checking presence /absence
my_obj in my_set
Instead of
my_obj in my_list
And rtrees built in to rhino seem even more effective

Yes, redraw is a biggy

1 Like

Well, I did a quick test here.
First I created a file with 100 copies of a polysurface object in a line, plus a cut plane that intersects them all. I also random rotated the objects so that all the intersections will be different

I then ran the Rhino native command Split, splitting the 100 objects with the plane surface. That took around 19.5 seconds including mesh creation, which was over half the time.

I undid that and ran this script in rhinoscriptsyntax:

import rhinoscriptsyntax as rs
import Rhino, time

objs=rs.GetObjects("Select polysurface objects to split",16,preselect=True)
cutter=rs.GetObject("Select cutting surface",8)

st=time.time()
rs.EnableRedraw(False)
for obj in objs: rs.SplitBrep(obj,cutter)
rs.EnableRedraw()
print "Elapsed time = {:.2f}".format(time.time()-st)

The result was 16.38 seconds including meshing, so a little speed gain on the Native Rhino command, but not much. The actual split time was around 6.5 seconds, the rest meshing.

I then ran a similar test in RhinoCommon:

import rhinoscriptsyntax as rs
import scriptcontext as sc
import Rhino, time

objs=rs.GetObjects("Select polysurface objects to split",16,preselect=True)
cutter=rs.GetObject("Select cutting surface",8)

st=time.time()
tol=sc.doc.ModelAbsoluteTolerance
breps=[rs.coercebrep(obj) for obj in objs]
cut_plane=rs.coercebrep(cutter)
splits=[]
to_delete=[]
for i,brep in enumerate(breps):
    result=brep.Split(cut_plane,tol)
    if result:
        splits.extend(result)
        to_delete.append(objs[i])
if splits:
    for s_brep in splits: sc.doc.Objects.AddBrep(s_brep)
if to_delete:
    for objID in to_delete: sc.doc.Objects.Delete(objID,True)
sc.doc.Views.Redraw()
Rhino.RhinoApp.Wait()
print "Elapsed time = {:.2f}".format(time.time()-st)

The result was virtually identical to the rhinoscriptsyntax version, to within a few hundredths of a second. That is pretty much expected, as rhinoscriptsyntax is calling RhinoCommon code behind the scenes and it still has to so the same thing - get the object IDs, get the geometry associated with the ID, split the objects, write the split parts to the document and delete the originals…

So, not much to be gained in this particular situation by running in “pure” RhinoCommon over rhinoscriptsyntax.

(the Rhino file is a bit to big to post here)

1 Like

did you try disabling the redraw?
perhaps if you do that the difference will become more noticeable.

I mean the RhinoCommon piece

Redraw is disabled in all… Check the scripts.
(Rhino native functions also disable the redraw)

No need to disable redraw during RhinoCommon operations, as all the geometry is virtual, hence no objects are drawn on the screen.

Ah, did not know that. I’m sorry.

just fyi,

the case I’m working on has 12k surfaces

Can you try something. Before splitting try to see if there’s an intersection, this will improve performance quite a bit. For me with the 12k surfaces case I improved it 10+ times

Yes, doing that now…

OK, if I move a random selection of 50 of the objects away from the plane so they do not intersect, and I check for intersection first (and only run split if an intersection is found), the total time goes down to 9.9 seconds (meshing included). However, we are only re-meshing half the objects. If I just calculate just the split time I get about 5 seconds, a small improvement over the previous 6.5 seconds.

Edit - however, for example if only 5 of the 100 objects actually intersect the plane, the time goes down to about 1.5 seconds, including meshing. So if you have many, many objects but only few of them actually intersect the cutter, checking for intersection first (via RhinoCommon where no objects are created in the file) will gain you a lot of speed. Below the variant of the script I used for reference:

import rhinoscriptsyntax as rs
import scriptcontext as sc
import Rhino, time

objs=rs.GetObjects("Select polysurface objects to split",16,preselect=True)
cutter=rs.GetObject("Select cutting surface",8)

st=time.time()
tol=sc.doc.ModelAbsoluteTolerance
breps=[rs.coercebrep(obj) for obj in objs]
cut_plane=rs.coercebrep(cutter)
splits=[]
to_delete=[]
for i,brep in enumerate(breps):
    insec=Rhino.Geometry.Intersect.Intersection.BrepBrep(brep,cut_plane,tol)
    if insec:
        if len(insec[1])>0:
            #intersection found
            result=brep.Split(cut_plane,tol)
            if result:
                splits.extend(result)
                to_delete.append(objs[i])
if splits:
    for s_brep in splits: sc.doc.Objects.AddBrep(s_brep)
if to_delete:
    for objID in to_delete: sc.doc.Objects.Delete(objID,True)
sc.doc.Views.Redraw()
Rhino.RhinoApp.Wait()
print "Elapsed time = {:.2f}".format(time.time()-st)
1 Like